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

Commit699bf7d

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 parent9c2f0a6 commit699bf7d

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
@@ -6357,6 +6357,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
63576357
*/
63586358
staticTransactionId
63596359
FreezeMultiXactId(MultiXactIdmulti,uint16t_infomask,
6360+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
63606361
TransactionIdcutoff_xid,MultiXactIdcutoff_multi,
63616362
uint16*flags)
63626363
{
@@ -6383,16 +6384,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
63836384
*flags |=FRM_INVALIDATE_XMAX;
63846385
returnInvalidTransactionId;
63856386
}
6387+
elseif (MultiXactIdPrecedes(multi,relminmxid))
6388+
ereport(ERROR,
6389+
(errcode(ERRCODE_DATA_CORRUPTED),
6390+
errmsg_internal("found multixact %u from before relminmxid %u",
6391+
multi,relminmxid)));
63866392
elseif (MultiXactIdPrecedes(multi,cutoff_multi))
63876393
{
63886394
/*
6389-
* This old multi cannot possibly have members still running. If it
6390-
* was a locker only, it can be removed without any further
6391-
* consideration; but if it contained an update, we might need to
6392-
* preserve it.
6395+
* This old multi cannot possibly have members still running, but
6396+
*verify just in case. If itwas a locker only, it can be removed
6397+
*without any furtherconsideration; but if it contained an update, we
6398+
*might need topreserve it.
63936399
*/
6394-
Assert(!MultiXactIdIsRunning(multi,
6395-
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)));
6400+
if (MultiXactIdIsRunning(multi,
6401+
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6402+
ereport(ERROR,
6403+
(errcode(ERRCODE_DATA_CORRUPTED),
6404+
errmsg_internal("multixact %u from before cutoff %u found to be still running",
6405+
multi,cutoff_multi)));
6406+
63966407
if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
63976408
{
63986409
*flags |=FRM_INVALIDATE_XMAX;
@@ -6406,13 +6417,22 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64066417
/* wasn't only a lock, xid needs to be valid */
64076418
Assert(TransactionIdIsValid(xid));
64086419

6420+
if (TransactionIdPrecedes(xid,relfrozenxid))
6421+
ereport(ERROR,
6422+
(errcode(ERRCODE_DATA_CORRUPTED),
6423+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6424+
xid,relfrozenxid)));
6425+
64096426
/*
64106427
* If the xid is older than the cutoff, it has to have aborted,
64116428
* otherwise the tuple would have gotten pruned away.
64126429
*/
64136430
if (TransactionIdPrecedes(xid,cutoff_xid))
64146431
{
6415-
Assert(!TransactionIdDidCommit(xid));
6432+
if (TransactionIdDidCommit(xid))
6433+
ereport(ERROR,
6434+
(errcode(ERRCODE_DATA_CORRUPTED),
6435+
errmsg_internal("cannot freeze committed update xid %u",xid)));
64166436
*flags |=FRM_INVALIDATE_XMAX;
64176437
xid=InvalidTransactionId;/* not strictly necessary */
64186438
}
@@ -6484,6 +6504,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64846504
{
64856505
TransactionIdxid=members[i].xid;
64866506

6507+
Assert(TransactionIdIsValid(xid));
6508+
if (TransactionIdPrecedes(xid,relfrozenxid))
6509+
ereport(ERROR,
6510+
(errcode(ERRCODE_DATA_CORRUPTED),
6511+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6512+
xid,relfrozenxid)));
6513+
64876514
/*
64886515
* It's an update; should we keep it? If the transaction is known
64896516
* aborted or crashed then it's okay to ignore it, otherwise not.
@@ -6512,18 +6539,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
65126539
update_committed= true;
65136540
update_xid=xid;
65146541
}
6515-
6516-
/*
6517-
* Not in progress, not committed -- must be aborted or crashed;
6518-
* we can ignore it.
6519-
*/
6542+
else
6543+
{
6544+
/*
6545+
* Not in progress, not committed -- must be aborted or crashed;
6546+
* we can ignore it.
6547+
*/
6548+
}
65206549

65216550
/*
65226551
* Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6523-
* update Xid cannot possibly be older than the xid cutoff.
6552+
* update Xid cannot possibly be older than the xid cutoff. The
6553+
* presence of such a tuple would cause corruption, so be paranoid
6554+
* and check.
65246555
*/
6525-
Assert(!TransactionIdIsValid(update_xid)||
6526-
!TransactionIdPrecedes(update_xid,cutoff_xid));
6556+
if (TransactionIdIsValid(update_xid)&&
6557+
TransactionIdPrecedes(update_xid,cutoff_xid))
6558+
ereport(ERROR,
6559+
(errcode(ERRCODE_DATA_CORRUPTED),
6560+
errmsg_internal("found update xid %u from before xid cutoff %u",
6561+
update_xid,cutoff_xid)));
65276562

65286563
/*
65296564
* If we determined that it's an Xid corresponding to an update
@@ -6620,8 +6655,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
66206655
* recovery. We really need to remove old xids.
66216656
*/
66226657
bool
6623-
heap_prepare_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6624-
TransactionIdcutoff_multi,
6658+
heap_prepare_freeze_tuple(HeapTupleHeadertuple,
6659+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6660+
TransactionIdcutoff_xid,TransactionIdcutoff_multi,
66256661
xl_heap_freeze_tuple*frz,bool*totally_frozen_p)
66266662
{
66276663
boolchanged= false;
@@ -6638,8 +6674,20 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66386674
xid=HeapTupleHeaderGetXmin(tuple);
66396675
if (TransactionIdIsNormal(xid))
66406676
{
6677+
if (TransactionIdPrecedes(xid,relfrozenxid))
6678+
ereport(ERROR,
6679+
(errcode(ERRCODE_DATA_CORRUPTED),
6680+
errmsg_internal("found xmin %u from before relfrozenxid %u",
6681+
xid,relfrozenxid)));
6682+
66416683
if (TransactionIdPrecedes(xid,cutoff_xid))
66426684
{
6685+
if (!TransactionIdDidCommit(xid))
6686+
ereport(ERROR,
6687+
(errcode(ERRCODE_DATA_CORRUPTED),
6688+
errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen",
6689+
xid,cutoff_xid)));
6690+
66436691
frz->t_infomask |=HEAP_XMIN_FROZEN;
66446692
changed= true;
66456693
}
@@ -6664,6 +6712,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66646712
uint16flags;
66656713

66666714
newxmax=FreezeMultiXactId(xid,tuple->t_infomask,
6715+
relfrozenxid,relminmxid,
66676716
cutoff_xid,cutoff_multi,&flags);
66686717

66696718
if (flags&FRM_INVALIDATE_XMAX)
@@ -6713,8 +6762,28 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
67136762
}
67146763
elseif (TransactionIdIsNormal(xid))
67156764
{
6765+
if (TransactionIdPrecedes(xid,relfrozenxid))
6766+
ereport(ERROR,
6767+
(errcode(ERRCODE_DATA_CORRUPTED),
6768+
errmsg_internal("found xmax %u from before relfrozenxid %u",
6769+
xid,relfrozenxid)));
6770+
67166771
if (TransactionIdPrecedes(xid,cutoff_xid))
6772+
{
6773+
/*
6774+
* If we freeze xmax, make absolutely sure that it's not an XID
6775+
* that is important. (Note, a lock-only xmax can be removed
6776+
* independent of committedness, since a committed lock holder has
6777+
* released the lock).
6778+
*/
6779+
if (!(tuple->t_infomask&HEAP_XMAX_LOCK_ONLY)&&
6780+
TransactionIdDidCommit(xid))
6781+
ereport(ERROR,
6782+
(errcode(ERRCODE_DATA_CORRUPTED),
6783+
errmsg_internal("cannot freeze committed xmax %u",
6784+
xid)));
67176785
freeze_xmax= true;
6786+
}
67186787
else
67196788
totally_frozen= false;
67206789
}
@@ -6819,14 +6888,17 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
68196888
* Useful for callers like CLUSTER that perform their own WAL logging.
68206889
*/
68216890
bool
6822-
heap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6823-
TransactionIdcutoff_multi)
6891+
heap_freeze_tuple(HeapTupleHeadertuple,
6892+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6893+
TransactionIdcutoff_xid,TransactionIdcutoff_multi)
68246894
{
68256895
xl_heap_freeze_tuplefrz;
68266896
booldo_freeze;
68276897
booltuple_totally_frozen;
68286898

6829-
do_freeze=heap_prepare_freeze_tuple(tuple,cutoff_xid,cutoff_multi,
6899+
do_freeze=heap_prepare_freeze_tuple(tuple,
6900+
relfrozenxid,relminmxid,
6901+
cutoff_xid,cutoff_multi,
68306902
&frz,&tuple_totally_frozen);
68316903

68326904
/*

‎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
@@ -467,6 +467,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
467467
blkno;
468468
HeapTupleDatatuple;
469469
char*relname;
470+
TransactionIdrelfrozenxid=onerel->rd_rel->relfrozenxid;
471+
TransactionIdrelminmxid=onerel->rd_rel->relminmxid;
470472
BlockNumberempty_pages,
471473
vacuumed_pages;
472474
doublenum_tuples,
@@ -1004,6 +1006,13 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
10041006
* tuple, we choose to keep it, because it'll be a lot
10051007
* cheaper to get rid of it in the next pruning pass than
10061008
* to treat it like an indexed tuple.
1009+
*
1010+
* If this were to happen for a tuple that actually needed
1011+
* to be deleted, we'd be in trouble, because it'd
1012+
* possibly leave a tuple below the relation's xmin
1013+
* horizon alive. heap_prepare_freeze_tuple() is prepared
1014+
* to detect that case and abort the transaction,
1015+
* preventing corruption.
10071016
*/
10081017
if (HeapTupleIsHotUpdated(&tuple)||
10091018
HeapTupleIsHeapOnly(&tuple))
@@ -1095,8 +1104,10 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
10951104
* Each non-removable tuple must be checked to see if it needs
10961105
* freezing. Note we already have exclusive buffer lock.
10971106
*/
1098-
if (heap_prepare_freeze_tuple(tuple.t_data,FreezeLimit,
1099-
MultiXactCutoff,&frozen[nfrozen],
1107+
if (heap_prepare_freeze_tuple(tuple.t_data,
1108+
relfrozenxid,relminmxid,
1109+
FreezeLimit,MultiXactCutoff,
1110+
&frozen[nfrozen],
11001111
&tuple_totally_frozen))
11011112
frozen[nfrozen++].offset=offnum;
11021113

‎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