Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commitd3044f8

Browse files
committed
Perform a lot more sanity checks when freezing tuples.
The previous commit has shown that the sanity checks around freezingaren't strong enough. Strengthening them seems especially importantbecause the existance of the bug has caused corruption that we don'twant to make even worse during future vacuum cycles.The errors are emitted with ereport rather than elog, despite being"should never happen" messages, so a proper error code is emitted. Toavoid superflous translations, mark messages as internal.Author: Andres Freund and Alvaro HerreraReviewed-By: Alvaro Herrera, Michael PaquierDiscussion:https://postgr.es/m/20171102112019.33wb7g5wp4zpjelu@alap3.anarazel.deBackpatch: 9.3-
1 parent1224383 commitd3044f8

File tree

5 files changed

+114
-25
lines changed

5 files changed

+114
-25
lines changed

‎src/backend/access/heap/heapam.c

Lines changed: 92 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6338,6 +6338,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
63386338
*/
63396339
staticTransactionId
63406340
FreezeMultiXactId(MultiXactIdmulti,uint16t_infomask,
6341+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
63416342
TransactionIdcutoff_xid,MultiXactIdcutoff_multi,
63426343
uint16*flags)
63436344
{
@@ -6364,16 +6365,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
63646365
*flags |=FRM_INVALIDATE_XMAX;
63656366
returnInvalidTransactionId;
63666367
}
6368+
elseif (MultiXactIdPrecedes(multi,relminmxid))
6369+
ereport(ERROR,
6370+
(errcode(ERRCODE_DATA_CORRUPTED),
6371+
errmsg_internal("found multixact %u from before relminmxid %u",
6372+
multi,relminmxid)));
63676373
elseif (MultiXactIdPrecedes(multi,cutoff_multi))
63686374
{
63696375
/*
6370-
* This old multi cannot possibly have members still running. If it
6371-
* was a locker only, it can be removed without any further
6372-
* consideration; but if it contained an update, we might need to
6373-
* preserve it.
6376+
* This old multi cannot possibly have members still running, but
6377+
*verify just in case. If itwas a locker only, it can be removed
6378+
*without any furtherconsideration; but if it contained an update, we
6379+
*might need topreserve it.
63746380
*/
6375-
Assert(!MultiXactIdIsRunning(multi,
6376-
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)));
6381+
if (MultiXactIdIsRunning(multi,
6382+
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6383+
ereport(ERROR,
6384+
(errcode(ERRCODE_DATA_CORRUPTED),
6385+
errmsg_internal("multixact %u from before cutoff %u found to be still running",
6386+
multi,cutoff_multi)));
6387+
63776388
if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
63786389
{
63796390
*flags |=FRM_INVALIDATE_XMAX;
@@ -6387,13 +6398,22 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
63876398
/* wasn't only a lock, xid needs to be valid */
63886399
Assert(TransactionIdIsValid(xid));
63896400

6401+
if (TransactionIdPrecedes(xid,relfrozenxid))
6402+
ereport(ERROR,
6403+
(errcode(ERRCODE_DATA_CORRUPTED),
6404+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6405+
xid,relfrozenxid)));
6406+
63906407
/*
63916408
* If the xid is older than the cutoff, it has to have aborted,
63926409
* otherwise the tuple would have gotten pruned away.
63936410
*/
63946411
if (TransactionIdPrecedes(xid,cutoff_xid))
63956412
{
6396-
Assert(!TransactionIdDidCommit(xid));
6413+
if (TransactionIdDidCommit(xid))
6414+
ereport(ERROR,
6415+
(errcode(ERRCODE_DATA_CORRUPTED),
6416+
errmsg_internal("cannot freeze committed update xid %u",xid)));
63976417
*flags |=FRM_INVALIDATE_XMAX;
63986418
xid=InvalidTransactionId;/* not strictly necessary */
63996419
}
@@ -6465,6 +6485,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64656485
{
64666486
TransactionIdxid=members[i].xid;
64676487

6488+
Assert(TransactionIdIsValid(xid));
6489+
if (TransactionIdPrecedes(xid,relfrozenxid))
6490+
ereport(ERROR,
6491+
(errcode(ERRCODE_DATA_CORRUPTED),
6492+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6493+
xid,relfrozenxid)));
6494+
64686495
/*
64696496
* It's an update; should we keep it? If the transaction is known
64706497
* aborted or crashed then it's okay to ignore it, otherwise not.
@@ -6493,18 +6520,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64936520
update_committed= true;
64946521
update_xid=xid;
64956522
}
6496-
6497-
/*
6498-
* Not in progress, not committed -- must be aborted or crashed;
6499-
* we can ignore it.
6500-
*/
6523+
else
6524+
{
6525+
/*
6526+
* Not in progress, not committed -- must be aborted or crashed;
6527+
* we can ignore it.
6528+
*/
6529+
}
65016530

65026531
/*
65036532
* Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6504-
* update Xid cannot possibly be older than the xid cutoff.
6533+
* update Xid cannot possibly be older than the xid cutoff. The
6534+
* presence of such a tuple would cause corruption, so be paranoid
6535+
* and check.
65056536
*/
6506-
Assert(!TransactionIdIsValid(update_xid)||
6507-
!TransactionIdPrecedes(update_xid,cutoff_xid));
6537+
if (TransactionIdIsValid(update_xid)&&
6538+
TransactionIdPrecedes(update_xid,cutoff_xid))
6539+
ereport(ERROR,
6540+
(errcode(ERRCODE_DATA_CORRUPTED),
6541+
errmsg_internal("found update xid %u from before xid cutoff %u",
6542+
update_xid,cutoff_xid)));
65086543

65096544
/*
65106545
* If we determined that it's an Xid corresponding to an update
@@ -6601,8 +6636,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
66016636
* recovery. We really need to remove old xids.
66026637
*/
66036638
bool
6604-
heap_prepare_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6605-
TransactionIdcutoff_multi,
6639+
heap_prepare_freeze_tuple(HeapTupleHeadertuple,
6640+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6641+
TransactionIdcutoff_xid,TransactionIdcutoff_multi,
66066642
xl_heap_freeze_tuple*frz,bool*totally_frozen_p)
66076643
{
66086644
boolchanged= false;
@@ -6619,8 +6655,20 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66196655
xid=HeapTupleHeaderGetXmin(tuple);
66206656
if (TransactionIdIsNormal(xid))
66216657
{
6658+
if (TransactionIdPrecedes(xid,relfrozenxid))
6659+
ereport(ERROR,
6660+
(errcode(ERRCODE_DATA_CORRUPTED),
6661+
errmsg_internal("found xmin %u from before relfrozenxid %u",
6662+
xid,relfrozenxid)));
6663+
66226664
if (TransactionIdPrecedes(xid,cutoff_xid))
66236665
{
6666+
if (!TransactionIdDidCommit(xid))
6667+
ereport(ERROR,
6668+
(errcode(ERRCODE_DATA_CORRUPTED),
6669+
errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen",
6670+
xid,cutoff_xid)));
6671+
66246672
frz->t_infomask |=HEAP_XMIN_FROZEN;
66256673
changed= true;
66266674
}
@@ -6645,6 +6693,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66456693
uint16flags;
66466694

66476695
newxmax=FreezeMultiXactId(xid,tuple->t_infomask,
6696+
relfrozenxid,relminmxid,
66486697
cutoff_xid,cutoff_multi,&flags);
66496698

66506699
if (flags&FRM_INVALIDATE_XMAX)
@@ -6694,8 +6743,28 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66946743
}
66956744
elseif (TransactionIdIsNormal(xid))
66966745
{
6746+
if (TransactionIdPrecedes(xid,relfrozenxid))
6747+
ereport(ERROR,
6748+
(errcode(ERRCODE_DATA_CORRUPTED),
6749+
errmsg_internal("found xmax %u from before relfrozenxid %u",
6750+
xid,relfrozenxid)));
6751+
66976752
if (TransactionIdPrecedes(xid,cutoff_xid))
6753+
{
6754+
/*
6755+
* If we freeze xmax, make absolutely sure that it's not an XID
6756+
* that is important. (Note, a lock-only xmax can be removed
6757+
* independent of committedness, since a committed lock holder has
6758+
* released the lock).
6759+
*/
6760+
if (!(tuple->t_infomask&HEAP_XMAX_LOCK_ONLY)&&
6761+
TransactionIdDidCommit(xid))
6762+
ereport(ERROR,
6763+
(errcode(ERRCODE_DATA_CORRUPTED),
6764+
errmsg_internal("cannot freeze committed xmax %u",
6765+
xid)));
66986766
freeze_xmax= true;
6767+
}
66996768
else
67006769
totally_frozen= false;
67016770
}
@@ -6800,14 +6869,17 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
68006869
* Useful for callers like CLUSTER that perform their own WAL logging.
68016870
*/
68026871
bool
6803-
heap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6804-
TransactionIdcutoff_multi)
6872+
heap_freeze_tuple(HeapTupleHeadertuple,
6873+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6874+
TransactionIdcutoff_xid,TransactionIdcutoff_multi)
68056875
{
68066876
xl_heap_freeze_tuplefrz;
68076877
booldo_freeze;
68086878
booltuple_totally_frozen;
68096879

6810-
do_freeze=heap_prepare_freeze_tuple(tuple,cutoff_xid,cutoff_multi,
6880+
do_freeze=heap_prepare_freeze_tuple(tuple,
6881+
relfrozenxid,relminmxid,
6882+
cutoff_xid,cutoff_multi,
68116883
&frz,&tuple_totally_frozen);
68126884

68136885
/*

‎src/backend/access/heap/rewriteheap.c

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -407,7 +407,10 @@ rewrite_heap_tuple(RewriteState state,
407407
* While we have our hands on the tuple, we may as well freeze any
408408
* eligible xmin or xmax, so that future VACUUM effort can be saved.
409409
*/
410-
heap_freeze_tuple(new_tuple->t_data,state->rs_freeze_xid,
410+
heap_freeze_tuple(new_tuple->t_data,
411+
state->rs_old_rel->rd_rel->relfrozenxid,
412+
state->rs_old_rel->rd_rel->relminmxid,
413+
state->rs_freeze_xid,
411414
state->rs_cutoff_multi);
412415

413416
/*

‎src/backend/commands/vacuumlazy.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -462,6 +462,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
462462
blkno;
463463
HeapTupleDatatuple;
464464
char*relname;
465+
TransactionIdrelfrozenxid=onerel->rd_rel->relfrozenxid;
466+
TransactionIdrelminmxid=onerel->rd_rel->relminmxid;
465467
BlockNumberempty_pages,
466468
vacuumed_pages;
467469
doublenum_tuples,
@@ -993,6 +995,13 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
993995
* tuple, we choose to keep it, because it'll be a lot
994996
* cheaper to get rid of it in the next pruning pass than
995997
* to treat it like an indexed tuple.
998+
*
999+
* If this were to happen for a tuple that actually needed
1000+
* to be deleted, we'd be in trouble, because it'd
1001+
* possibly leave a tuple below the relation's xmin
1002+
* horizon alive. heap_prepare_freeze_tuple() is prepared
1003+
* to detect that case and abort the transaction,
1004+
* preventing corruption.
9961005
*/
9971006
if (HeapTupleIsHotUpdated(&tuple)||
9981007
HeapTupleIsHeapOnly(&tuple))
@@ -1084,8 +1093,10 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
10841093
* Each non-removable tuple must be checked to see if it needs
10851094
* freezing. Note we already have exclusive buffer lock.
10861095
*/
1087-
if (heap_prepare_freeze_tuple(tuple.t_data,FreezeLimit,
1088-
MultiXactCutoff,&frozen[nfrozen],
1096+
if (heap_prepare_freeze_tuple(tuple.t_data,
1097+
relfrozenxid,relminmxid,
1098+
FreezeLimit,MultiXactCutoff,
1099+
&frozen[nfrozen],
10891100
&tuple_totally_frozen))
10901101
frozen[nfrozen++].offset=offnum;
10911102

‎src/include/access/heapam.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -168,8 +168,9 @@ extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple,
168168
boolfollow_update,
169169
Buffer*buffer,HeapUpdateFailureData*hufd);
170170
externvoidheap_inplace_update(Relationrelation,HeapTupletuple);
171-
externboolheap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
172-
TransactionIdcutoff_multi);
171+
externboolheap_freeze_tuple(HeapTupleHeadertuple,
172+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
173+
TransactionIdcutoff_xid,TransactionIdcutoff_multi);
173174
externboolheap_tuple_needs_freeze(HeapTupleHeadertuple,TransactionIdcutoff_xid,
174175
MultiXactIdcutoff_multi,Bufferbuf);
175176
externboolheap_tuple_needs_eventual_freeze(HeapTupleHeadertuple);

‎src/include/access/heapam_xlog.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -384,6 +384,8 @@ extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
384384
TransactionIdcutoff_xid,xl_heap_freeze_tuple*tuples,
385385
intntuples);
386386
externboolheap_prepare_freeze_tuple(HeapTupleHeadertuple,
387+
TransactionIdrelfrozenxid,
388+
TransactionIdrelminmxid,
387389
TransactionIdcutoff_xid,
388390
TransactionIdcutoff_multi,
389391
xl_heap_freeze_tuple*frz,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp