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

Commit986a915

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 parent937494c commit986a915

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
@@ -6364,6 +6364,7 @@ heap_inplace_update(Relation relation, HeapTuple tuple)
63646364
*/
63656365
staticTransactionId
63666366
FreezeMultiXactId(MultiXactIdmulti,uint16t_infomask,
6367+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
63676368
TransactionIdcutoff_xid,MultiXactIdcutoff_multi,
63686369
uint16*flags)
63696370
{
@@ -6390,16 +6391,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
63906391
*flags |=FRM_INVALIDATE_XMAX;
63916392
returnInvalidTransactionId;
63926393
}
6394+
elseif (MultiXactIdPrecedes(multi,relminmxid))
6395+
ereport(ERROR,
6396+
(errcode(ERRCODE_DATA_CORRUPTED),
6397+
errmsg_internal("found multixact %u from before relminmxid %u",
6398+
multi,relminmxid)));
63936399
elseif (MultiXactIdPrecedes(multi,cutoff_multi))
63946400
{
63956401
/*
6396-
* This old multi cannot possibly have members still running. If it
6397-
* was a locker only, it can be removed without any further
6398-
* consideration; but if it contained an update, we might need to
6399-
* preserve it.
6402+
* This old multi cannot possibly have members still running, but
6403+
*verify just in case. If itwas a locker only, it can be removed
6404+
*without any furtherconsideration; but if it contained an update, we
6405+
*might need topreserve it.
64006406
*/
6401-
Assert(!MultiXactIdIsRunning(multi,
6402-
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)));
6407+
if (MultiXactIdIsRunning(multi,
6408+
HEAP_XMAX_IS_LOCKED_ONLY(t_infomask)))
6409+
ereport(ERROR,
6410+
(errcode(ERRCODE_DATA_CORRUPTED),
6411+
errmsg_internal("multixact %u from before cutoff %u found to be still running",
6412+
multi,cutoff_multi)));
6413+
64036414
if (HEAP_XMAX_IS_LOCKED_ONLY(t_infomask))
64046415
{
64056416
*flags |=FRM_INVALIDATE_XMAX;
@@ -6413,13 +6424,22 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64136424
/* wasn't only a lock, xid needs to be valid */
64146425
Assert(TransactionIdIsValid(xid));
64156426

6427+
if (TransactionIdPrecedes(xid,relfrozenxid))
6428+
ereport(ERROR,
6429+
(errcode(ERRCODE_DATA_CORRUPTED),
6430+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6431+
xid,relfrozenxid)));
6432+
64166433
/*
64176434
* If the xid is older than the cutoff, it has to have aborted,
64186435
* otherwise the tuple would have gotten pruned away.
64196436
*/
64206437
if (TransactionIdPrecedes(xid,cutoff_xid))
64216438
{
6422-
Assert(!TransactionIdDidCommit(xid));
6439+
if (TransactionIdDidCommit(xid))
6440+
ereport(ERROR,
6441+
(errcode(ERRCODE_DATA_CORRUPTED),
6442+
errmsg_internal("cannot freeze committed update xid %u",xid)));
64236443
*flags |=FRM_INVALIDATE_XMAX;
64246444
xid=InvalidTransactionId;/* not strictly necessary */
64256445
}
@@ -6491,6 +6511,13 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
64916511
{
64926512
TransactionIdxid=members[i].xid;
64936513

6514+
Assert(TransactionIdIsValid(xid));
6515+
if (TransactionIdPrecedes(xid,relfrozenxid))
6516+
ereport(ERROR,
6517+
(errcode(ERRCODE_DATA_CORRUPTED),
6518+
errmsg_internal("found update xid %u from before relfrozenxid %u",
6519+
xid,relfrozenxid)));
6520+
64946521
/*
64956522
* It's an update; should we keep it? If the transaction is known
64966523
* aborted or crashed then it's okay to ignore it, otherwise not.
@@ -6519,18 +6546,26 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
65196546
update_committed= true;
65206547
update_xid=xid;
65216548
}
6522-
6523-
/*
6524-
* Not in progress, not committed -- must be aborted or crashed;
6525-
* we can ignore it.
6526-
*/
6549+
else
6550+
{
6551+
/*
6552+
* Not in progress, not committed -- must be aborted or crashed;
6553+
* we can ignore it.
6554+
*/
6555+
}
65276556

65286557
/*
65296558
* Since the tuple wasn't marked HEAPTUPLE_DEAD by vacuum, the
6530-
* update Xid cannot possibly be older than the xid cutoff.
6559+
* update Xid cannot possibly be older than the xid cutoff. The
6560+
* presence of such a tuple would cause corruption, so be paranoid
6561+
* and check.
65316562
*/
6532-
Assert(!TransactionIdIsValid(update_xid)||
6533-
!TransactionIdPrecedes(update_xid,cutoff_xid));
6563+
if (TransactionIdIsValid(update_xid)&&
6564+
TransactionIdPrecedes(update_xid,cutoff_xid))
6565+
ereport(ERROR,
6566+
(errcode(ERRCODE_DATA_CORRUPTED),
6567+
errmsg_internal("found update xid %u from before xid cutoff %u",
6568+
update_xid,cutoff_xid)));
65346569

65356570
/*
65366571
* If we determined that it's an Xid corresponding to an update
@@ -6627,8 +6662,9 @@ FreezeMultiXactId(MultiXactId multi, uint16 t_infomask,
66276662
* recovery. We really need to remove old xids.
66286663
*/
66296664
bool
6630-
heap_prepare_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6631-
TransactionIdcutoff_multi,
6665+
heap_prepare_freeze_tuple(HeapTupleHeadertuple,
6666+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6667+
TransactionIdcutoff_xid,TransactionIdcutoff_multi,
66326668
xl_heap_freeze_tuple*frz,bool*totally_frozen_p)
66336669
{
66346670
boolchanged= false;
@@ -6645,8 +6681,20 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66456681
xid=HeapTupleHeaderGetXmin(tuple);
66466682
if (TransactionIdIsNormal(xid))
66476683
{
6684+
if (TransactionIdPrecedes(xid,relfrozenxid))
6685+
ereport(ERROR,
6686+
(errcode(ERRCODE_DATA_CORRUPTED),
6687+
errmsg_internal("found xmin %u from before relfrozenxid %u",
6688+
xid,relfrozenxid)));
6689+
66486690
if (TransactionIdPrecedes(xid,cutoff_xid))
66496691
{
6692+
if (!TransactionIdDidCommit(xid))
6693+
ereport(ERROR,
6694+
(errcode(ERRCODE_DATA_CORRUPTED),
6695+
errmsg_internal("uncommitted xmin %u from before xid cutoff %u needs to be frozen",
6696+
xid,cutoff_xid)));
6697+
66506698
frz->t_infomask |=HEAP_XMIN_FROZEN;
66516699
changed= true;
66526700
}
@@ -6671,6 +6719,7 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
66716719
uint16flags;
66726720

66736721
newxmax=FreezeMultiXactId(xid,tuple->t_infomask,
6722+
relfrozenxid,relminmxid,
66746723
cutoff_xid,cutoff_multi,&flags);
66756724

66766725
if (flags&FRM_INVALIDATE_XMAX)
@@ -6720,8 +6769,28 @@ heap_prepare_freeze_tuple(HeapTupleHeader tuple, TransactionId cutoff_xid,
67206769
}
67216770
elseif (TransactionIdIsNormal(xid))
67226771
{
6772+
if (TransactionIdPrecedes(xid,relfrozenxid))
6773+
ereport(ERROR,
6774+
(errcode(ERRCODE_DATA_CORRUPTED),
6775+
errmsg_internal("found xmax %u from before relfrozenxid %u",
6776+
xid,relfrozenxid)));
6777+
67236778
if (TransactionIdPrecedes(xid,cutoff_xid))
6779+
{
6780+
/*
6781+
* If we freeze xmax, make absolutely sure that it's not an XID
6782+
* that is important. (Note, a lock-only xmax can be removed
6783+
* independent of committedness, since a committed lock holder has
6784+
* released the lock).
6785+
*/
6786+
if (!(tuple->t_infomask&HEAP_XMAX_LOCK_ONLY)&&
6787+
TransactionIdDidCommit(xid))
6788+
ereport(ERROR,
6789+
(errcode(ERRCODE_DATA_CORRUPTED),
6790+
errmsg_internal("cannot freeze committed xmax %u",
6791+
xid)));
67246792
freeze_xmax= true;
6793+
}
67256794
else
67266795
totally_frozen= false;
67276796
}
@@ -6826,14 +6895,17 @@ heap_execute_freeze_tuple(HeapTupleHeader tuple, xl_heap_freeze_tuple *frz)
68266895
* Useful for callers like CLUSTER that perform their own WAL logging.
68276896
*/
68286897
bool
6829-
heap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
6830-
TransactionIdcutoff_multi)
6898+
heap_freeze_tuple(HeapTupleHeadertuple,
6899+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
6900+
TransactionIdcutoff_xid,TransactionIdcutoff_multi)
68316901
{
68326902
xl_heap_freeze_tuplefrz;
68336903
booldo_freeze;
68346904
booltuple_totally_frozen;
68356905

6836-
do_freeze=heap_prepare_freeze_tuple(tuple,cutoff_xid,cutoff_multi,
6906+
do_freeze=heap_prepare_freeze_tuple(tuple,
6907+
relfrozenxid,relminmxid,
6908+
cutoff_xid,cutoff_multi,
68376909
&frz,&tuple_totally_frozen);
68386910

68396911
/*

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

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

411414
/*

‎src/backend/commands/vacuumlazy.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -456,6 +456,8 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
456456
blkno;
457457
HeapTupleDatatuple;
458458
char*relname;
459+
TransactionIdrelfrozenxid=onerel->rd_rel->relfrozenxid;
460+
TransactionIdrelminmxid=onerel->rd_rel->relminmxid;
459461
BlockNumberempty_pages,
460462
vacuumed_pages;
461463
doublenum_tuples,
@@ -987,6 +989,13 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
987989
* tuple, we choose to keep it, because it'll be a lot
988990
* cheaper to get rid of it in the next pruning pass than
989991
* to treat it like an indexed tuple.
992+
*
993+
* If this were to happen for a tuple that actually needed
994+
* to be deleted, we'd be in trouble, because it'd
995+
* possibly leave a tuple below the relation's xmin
996+
* horizon alive. heap_prepare_freeze_tuple() is prepared
997+
* to detect that case and abort the transaction,
998+
* preventing corruption.
990999
*/
9911000
if (HeapTupleIsHotUpdated(&tuple)||
9921001
HeapTupleIsHeapOnly(&tuple))
@@ -1078,8 +1087,10 @@ lazy_scan_heap(Relation onerel, int options, LVRelStats *vacrelstats,
10781087
* Each non-removable tuple must be checked to see if it needs
10791088
* freezing. Note we already have exclusive buffer lock.
10801089
*/
1081-
if (heap_prepare_freeze_tuple(tuple.t_data,FreezeLimit,
1082-
MultiXactCutoff,&frozen[nfrozen],
1090+
if (heap_prepare_freeze_tuple(tuple.t_data,
1091+
relfrozenxid,relminmxid,
1092+
FreezeLimit,MultiXactCutoff,
1093+
&frozen[nfrozen],
10831094
&tuple_totally_frozen))
10841095
frozen[nfrozen++].offset=offnum;
10851096

‎src/include/access/heapam.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -166,8 +166,9 @@ extern HTSU_Result heap_lock_tuple(Relation relation, HeapTuple tuple,
166166
boolfollow_update,
167167
Buffer*buffer,HeapUpdateFailureData*hufd);
168168
externvoidheap_inplace_update(Relationrelation,HeapTupletuple);
169-
externboolheap_freeze_tuple(HeapTupleHeadertuple,TransactionIdcutoff_xid,
170-
TransactionIdcutoff_multi);
169+
externboolheap_freeze_tuple(HeapTupleHeadertuple,
170+
TransactionIdrelfrozenxid,TransactionIdrelminmxid,
171+
TransactionIdcutoff_xid,TransactionIdcutoff_multi);
171172
externboolheap_tuple_needs_freeze(HeapTupleHeadertuple,TransactionIdcutoff_xid,
172173
MultiXactIdcutoff_multi,Bufferbuf);
173174
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
@@ -383,6 +383,8 @@ extern XLogRecPtr log_heap_freeze(Relation reln, Buffer buffer,
383383
TransactionIdcutoff_xid,xl_heap_freeze_tuple*tuples,
384384
intntuples);
385385
externboolheap_prepare_freeze_tuple(HeapTupleHeadertuple,
386+
TransactionIdrelfrozenxid,
387+
TransactionIdrelminmxid,
386388
TransactionIdcutoff_xid,
387389
TransactionIdcutoff_multi,
388390
xl_heap_freeze_tuple*frz,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp