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

Commit94d1c88

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 parent32c0295 commit94d1c88

File tree

5 files changed

+123
-32
lines changed

5 files changed

+123
-32
lines changed

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

Lines changed: 101 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -6030,6 +6030,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
60306030
*/
60316031
staticTransactionId
60326032
FreezeMultiXactId(MultiXactIdmulti,uint16t_infomask,
6033+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
60336034
TransactionIdcutoff_xid,MultiXactIdcutoff_multi,
60346035
uint16*flags)
60356036
{
@@ -6056,16 +6057,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
60566057
*flags |=FRM_INVALIDATE_XMAX;
60576058
returnInvalidTransactionId;
60586059
}
6060+
elseif (MultiXactIdPrecedes(multi,relminmxid))
6061+
ereport(ERROR,
6062+
(errcode(ERRCODE_DATA_CORRUPTED),
6063+
errmsg_internal("found multixact %u from before relminmxid %u",
6064+
multi,relminmxid)));
60596065
elseif (MultiXactIdPrecedes(multi,cutoff_multi))
60606066
{
60616067
/*
6062-
* This old multi cannot possibly have members still running. If it
6063-
* was a locker only, it can be removed without any further
6064-
* consideration; but if it contained an update, we might need to
6065-
* preserve it.
6068+
* This old multi cannot possibly have members still running, but
6069+
*verify just in case. If itwas a locker only, it can be removed
6070+
*without any furtherconsideration; but if it contained an update, we
6071+
*might need topreserve it.
60666072
*/
6067-
Assert(!MultiXactIdIsRunning(multi,
6068-
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)));
6073+
if (MultiXactIdIsRunning(multi,
6074+
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6075+
ereport(ERROR,
6076+
(errcode(ERRCODE_DATA_CORRUPTED),
6077+
errmsg_internal("multixact %u from before cutoff %u found to be still running",
6078+
multi,cutoff_multi)));
6079+
60696080
if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
60706081
{
60716082
*flags |=FRM_INVALIDATE_XMAX;
@@ -6079,13 +6090,22 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
60796090
/* wasn't only a lock, xid needs to be valid */
60806091
Assert(TransactionIdIsValid(xid));
60816092

6093+
if (TransactionIdPrecedes(xid,relfrozenxid))
6094+
ereport(ERROR,
6095+
(errcode(ERRCODE_DATA_CORRUPTED),
6096+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6097+
xid,relfrozenxid)));
6098+
60826099
/*
60836100
* If the xid is older than the cutoff, it has to have aborted,
60846101
* otherwise the tuple would have gotten pruned away.
60856102
*/
60866103
if (TransactionIdPrecedes(xid,cutoff_xid))
60876104
{
6088-
Assert(!TransactionIdDidCommit(xid));
6105+
if (TransactionIdDidCommit(xid))
6106+
ereport(ERROR,
6107+
(errcode(ERRCODE_DATA_CORRUPTED),
6108+
errmsg_internal("cannot freeze committed update xid %u",xid)));
60896109
*flags |=FRM_INVALIDATE_XMAX;
60906110
xid=InvalidTransactionId;/* not strictly necessary */
60916111
}
@@ -6157,6 +6177,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
61576177
{
61586178
TransactionIdxid=members[i].xid;
61596179

6180+
Assert(TransactionIdIsValid(xid));
6181+
if (TransactionIdPrecedes(xid,relfrozenxid))
6182+
ereport(ERROR,
6183+
(errcode(ERRCODE_DATA_CORRUPTED),
6184+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6185+
xid,relfrozenxid)));
6186+
61606187
/*
61616188
* It's an update; should we keep it? If the transaction is known
61626189
* aborted or crashed then it's okay to ignore it, otherwise not.
@@ -6185,18 +6212,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
61856212
update_committed= true;
61866213
update_xid=xid;
61876214
}
6188-
6189-
/*
6190-
* Not in progress, not committed -- must be aborted or crashed;
6191-
* we can ignore it.
6192-
*/
6215+
else
6216+
{
6217+
/*
6218+
* Not in progress, not committed -- must be aborted or crashed;
6219+
* we can ignore it.
6220+
*/
6221+
}
61936222

61946223
/*
61956224
* Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6196-
* update Xid cannot possibly be older than the xid cutoff.
6225+
* update Xid cannot possibly be older than the xid cutoff. The
6226+
* presence of such a tuple would cause corruption, so be paranoid
6227+
* and check.
61976228
*/
6198-
Assert(!TransactionIdIsValid(update_xid)||
6199-
!TransactionIdPrecedes(update_xid,cutoff_xid));
6229+
if (TransactionIdIsValid(update_xid)&&
6230+
TransactionIdPrecedes(update_xid,cutoff_xid))
6231+
ereport(ERROR,
6232+
(errcode(ERRCODE_DATA_CORRUPTED),
6233+
errmsg_internal("found update xid %u from before xid cutoff %u",
6234+
update_xid,cutoff_xid)));
62006235

62016236
/*
62026237
* If we determined that it's an Xid corresponding to an update
@@ -6291,8 +6326,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
62916326
* recovery. We really need to remove old xids.
62926327
*/
62936328
bool
6294-
heap_prepare_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6295-
TransactionIdcutoff_multi,
6329+
heap_prepare_freeze_tuple(HeapTupleHeadertuple,
6330+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6331+
TransactionIdcutoff_xid,TransactionIdcutoff_multi,
62966332
xl_heap_freeze_tuple*frz)
62976333

62986334
{
@@ -6307,11 +6343,25 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
63076343

63086344
/* Process xmin */
63096345
xid=HeapTupleHeaderGetXmin(tuple);
6310-
if (TransactionIdIsNormal(xid)&&
6311-
TransactionIdPrecedes(xid,cutoff_xid))
6346+
if (TransactionIdIsNormal(xid))
63126347
{
6313-
frz->t_infomask |=HEAP_XMIN_FROZEN;
6314-
changed= true;
6348+
if (TransactionIdPrecedes(xid,relfrozenxid))
6349+
ereport(ERROR,
6350+
(errcode(ERRCODE_DATA_CORRUPTED),
6351+
errmsg_internal("found xmin %u from before relfrozenxid %u",
6352+
xid,relfrozenxid)));
6353+
6354+
if (TransactionIdPrecedes(xid,cutoff_xid))
6355+
{
6356+
if (!TransactionIdDidCommit(xid))
6357+
ereport(ERROR,
6358+
(errcode(ERRCODE_DATA_CORRUPTED),
6359+
errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen",
6360+
xid,cutoff_xid)));
6361+
6362+
frz->t_infomask |=HEAP_XMIN_FROZEN;
6363+
changed= true;
6364+
}
63156365
}
63166366

63176367
/*
@@ -6331,6 +6381,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
63316381
uint16flags;
63326382

63336383
newxmax=FreezeMultiXactId(xid,tuple->t_infomask,
6384+
relfrozenxid,relminmxid,
63346385
cutoff_xid,cutoff_multi,&flags);
63356386

63366387
if (flags&FRM_INVALIDATE_XMAX)
@@ -6376,10 +6427,30 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
63766427
Assert(flags&FRM_NOOP);
63776428
}
63786429
}
6379-
elseif (TransactionIdIsNormal(xid)&&
6380-
TransactionIdPrecedes(xid,cutoff_xid))
6430+
elseif (TransactionIdIsNormal(xid))
63816431
{
6382-
freeze_xmax= true;
6432+
if (TransactionIdPrecedes(xid,relfrozenxid))
6433+
ereport(ERROR,
6434+
(errcode(ERRCODE_DATA_CORRUPTED),
6435+
errmsg_internal("found xmax %u from before relfrozenxid %u",
6436+
xid,relfrozenxid)));
6437+
6438+
if (TransactionIdPrecedes(xid,cutoff_xid))
6439+
{
6440+
/*
6441+
* If we freeze xmax, make absolutely sure that it's not an XID
6442+
* that is important. (Note, a lock-only xmax can be removed
6443+
* independent of committedness, since a committed lock holder has
6444+
* released the lock).
6445+
*/
6446+
if (!(tuple->t_infomask&HEAP_XMAX_LOCK_ONLY)&&
6447+
TransactionIdDidCommit(xid))
6448+
ereport(ERROR,
6449+
(errcode(ERRCODE_DATA_CORRUPTED),
6450+
errmsg_internal("cannot freeze committed xmax %u",
6451+
xid)));
6452+
freeze_xmax= true;
6453+
}
63836454
}
63846455

63856456
if (freeze_xmax)
@@ -6473,13 +6544,16 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
64736544
* Useful for callers like CLUSTER that perform their own WAL logging.
64746545
*/
64756546
bool
6476-
heap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6477-
TransactionIdcutoff_multi)
6547+
heap_freeze_tuple(HeapTupleHeadertuple,
6548+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6549+
TransactionIdcutoff_xid,TransactionIdcutoff_multi)
64786550
{
64796551
xl_heap_freeze_tuplefrz;
64806552
booldo_freeze;
64816553

6482-
do_freeze=heap_prepare_freeze_tuple(tuple,cutoff_xid,cutoff_multi,
6554+
do_freeze=heap_prepare_freeze_tuple(tuple,
6555+
relfrozenxid,relminmxid,
6556+
cutoff_xid,cutoff_multi,
64836557
&frz);
64846558

64856559
/*

‎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
@@ -447,6 +447,8 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
447447
blkno;
448448
HeapTupleDatatuple;
449449
char*relname;
450+
TransactionIdrelfrozenxid=onerel->rd_rel->relfrozenxid;
451+
TransactionIdrelminmxid=onerel->rd_rel->relminmxid;
450452
BlockNumberempty_pages,
451453
vacuumed_pages;
452454
doublenum_tuples,
@@ -842,6 +844,13 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
842844
* tuple, we choose to keep it, because it'll be a lot
843845
* cheaper to get rid of it in the next pruning pass than
844846
* to treat it like an indexed tuple.
847+
*
848+
* If this were to happen for a tuple that actually needed
849+
* to be deleted, we'd be in trouble, because it'd
850+
* possibly leave a tuple below the relation's xmin
851+
* horizon alive. heap_prepare_freeze_tuple() is prepared
852+
* to detect that case and abort the transaction,
853+
* preventing corruption.
845854
*/
846855
if (HeapTupleIsHotUpdated(&tuple)||
847856
HeapTupleIsHeapOnly(&tuple))
@@ -931,8 +940,10 @@ lazy_scan_heap(Relation onerel, LVRelStats *vacrelstats,
931940
* Each non-removable tuple must be checked to see if it needs
932941
* freezing. Note we already have exclusive buffer lock.
933942
*/
934-
if (heap_prepare_freeze_tuple(tuple.t_data,FreezeLimit,
935-
MultiXactCutoff,&frozen[nfrozen]))
943+
if (heap_prepare_freeze_tuple(tuple.t_data,
944+
relfrozenxid,relminmxid,
945+
FreezeLimit,MultiXactCutoff,
946+
&frozen[nfrozen]))
936947
frozen[nfrozen++].offset=offnum;
937948
}
938949
}/* scan along page */

‎src/include/access/heapam.h‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -160,8 +160,9 @@ extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple,
160160
boolfollow_update,
161161
Buffer*buffer,HeapUpdateFailureData*hufd);
162162
externvoidheap_inplace_update(Relationrelation,HeapTupletuple);
163-
externboolheap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
164-
TransactionIdcutoff_multi);
163+
externboolheap_freeze_tuple(HeapTupleHeadertuple,
164+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
165+
TransactionIdcutoff_xid,TransactionIdcutoff_multi);
165166
externboolheap_tuple_needs_freeze(HeapTupleHeadertuple,TransactionIdcutoff_xid,
166167
MultiXactIdcutoff_multi,Bufferbuf);
167168

‎src/include/access/heapam_xlog.h‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,6 +377,8 @@ extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
377377
TransactionIdcutoff_xid,xl_heap_freeze_tuple*tuples,
378378
intntuples);
379379
externboolheap_prepare_freeze_tuple(HeapTupleHeadertuple,
380+
TransactionIdrelfrozenxid,
381+
TransactionIdrelminmxid,
380382
TransactionIdcutoff_xid,
381383
TransactionIdcutoff_multi,
382384
xl_heap_freeze_tuple*frz);

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp