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

Commitd3ff180

Browse files
committed
Fix a longstanding bug in VACUUM FULL's handling of update chains. The code
did not expect that a DEAD tuple could follow a RECENTLY_DEAD tuple in anupdate chain, but because the OldestXmin rule for determining deadness is asimplification of reality, it is possible for this situation to occur(implying that the RECENTLY_DEAD tuple is in fact dead to all observers,but this patch does not attempt to exploit that). The code would follow achain forward all the way, but then stop before a DEAD tuple when backingup, meaning that not all of the chain got moved. This could lead to copyingthe chain multiple times (resulting in duplicate copies of the live tuple atits end), or leaving dangling index entries behind (which, aside fromgenerating warnings from later vacuums, creates a risk of wrong queryresults or bogus duplicate-key errors once the heap slot the index entrypoints to is repopulated).The fix is to recheck HeapTupleSatisfiesVacuum while following a chainforward, and to stop if a DEAD tuple is reached. Each contiguous groupof RECENTLY_DEAD tuples will therefore be copied as a separate chain.The patch also adds a couple of extra sanity checks to verify correctbehavior.Per report and test case from Pavan Deolasee.
1 parent0169c35 commitd3ff180

File tree

1 file changed

+44
-2
lines changed

1 file changed

+44
-2
lines changed

‎src/backend/commands/vacuum.c

Lines changed: 44 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
*
1414
*
1515
* IDENTIFICATION
16-
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.348 2007/03/13 00:33:40 tgl Exp $
16+
* $PostgreSQL: pgsql/src/backend/commands/vacuum.c,v 1.349 2007/03/14 18:48:55 tgl Exp $
1717
*
1818
*-------------------------------------------------------------------------
1919
*/
@@ -1880,6 +1880,15 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
18801880
* To be on the safe side, we abandon the repair_frag process if
18811881
* we cannot find the parent tuple in vtlinks.This may be overly
18821882
* conservative; AFAICS it would be safe to move the chain.
1883+
*
1884+
* Also, because we distinguish DEAD and RECENTLY_DEAD tuples
1885+
* using OldestXmin, which is a rather coarse test, it is quite
1886+
* possible to have an update chain in which a tuple we think is
1887+
* RECENTLY_DEAD links forward to one that is definitely DEAD.
1888+
* In such a case the RECENTLY_DEAD tuple must actually be dead,
1889+
* but it seems too complicated to try to make VACUUM remove it.
1890+
* We treat each contiguous set of RECENTLY_DEAD tuples as a
1891+
* separately movable chain, ignoring any intervening DEAD ones.
18831892
*/
18841893
if (((tuple.t_data->t_infomask&HEAP_UPDATED)&&
18851894
!TransactionIdPrecedes(HeapTupleHeaderGetXmin(tuple.t_data),
@@ -1892,6 +1901,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
18921901
BufferCbuf=buf;
18931902
boolfreeCbuf= false;
18941903
boolchain_move_failed= false;
1904+
boolmoved_target= false;
18951905
ItemPointerDataCtid;
18961906
HeapTupleDatatp=tuple;
18971907
Sizetlen=tuple_len;
@@ -1919,7 +1929,13 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
19191929
* If this tuple is in the begin/middle of the chain then we
19201930
* have to move to the end of chain. As with any t_ctid
19211931
* chase, we have to verify that each new tuple is really the
1922-
* descendant of the tuple we came from.
1932+
* descendant of the tuple we came from; however, here we
1933+
* need even more than the normal amount of paranoia.
1934+
* If t_ctid links forward to a tuple determined to be DEAD,
1935+
* then depending on where that tuple is, it might already
1936+
* have been removed, and perhaps even replaced by a MOVED_IN
1937+
* tuple. We don't want to include any DEAD tuples in the
1938+
* chain, so we have to recheck HeapTupleSatisfiesVacuum.
19231939
*/
19241940
while (!(tp.t_data->t_infomask& (HEAP_XMAX_INVALID |
19251941
HEAP_IS_LOCKED))&&
@@ -1933,6 +1949,7 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
19331949
OffsetNumbernextOffnum;
19341950
ItemIdnextItemid;
19351951
HeapTupleHeadernextTdata;
1952+
HTSV_ResultnextTstatus;
19361953

19371954
nextTid=tp.t_data->t_ctid;
19381955
priorXmax=HeapTupleHeaderGetXmax(tp.t_data);
@@ -1963,6 +1980,19 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
19631980
ReleaseBuffer(nextBuf);
19641981
break;
19651982
}
1983+
/* must check for DEAD or MOVED_IN tuple, too */
1984+
nextTstatus=HeapTupleSatisfiesVacuum(nextTdata,
1985+
OldestXmin,
1986+
nextBuf);
1987+
if (nextTstatus==HEAPTUPLE_DEAD||
1988+
nextTstatus==HEAPTUPLE_INSERT_IN_PROGRESS)
1989+
{
1990+
ReleaseBuffer(nextBuf);
1991+
break;
1992+
}
1993+
/* if it's MOVED_OFF we shoulda moved this one with it */
1994+
if (nextTstatus==HEAPTUPLE_DELETE_IN_PROGRESS)
1995+
elog(ERROR,"updated tuple is already HEAP_MOVED_OFF");
19661996
/* OK, switch our attention to the next tuple in chain */
19671997
tp.t_data=nextTdata;
19681998
tp.t_self=nextTid;
@@ -2034,6 +2064,11 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
20342064
free_vtmove--;
20352065
num_vtmove++;
20362066

2067+
/* Remember if we reached the original target tuple */
2068+
if (ItemPointerGetBlockNumber(&tp.t_self)==blkno&&
2069+
ItemPointerGetOffsetNumber(&tp.t_self)==offnum)
2070+
moved_target= true;
2071+
20372072
/* Done if at beginning of chain */
20382073
if (!(tp.t_data->t_infomask&HEAP_UPDATED)||
20392074
TransactionIdPrecedes(HeapTupleHeaderGetXmin(tp.t_data),
@@ -2102,6 +2137,13 @@ repair_frag(VRelStats *vacrelstats, Relation onerel,
21022137
ReleaseBuffer(Cbuf);
21032138
freeCbuf= false;
21042139

2140+
/* Double-check that we will move the current target tuple */
2141+
if (!moved_target&& !chain_move_failed)
2142+
{
2143+
elog(DEBUG2,"failed to chain back to target --- cannot continue repair_frag");
2144+
chain_move_failed= true;
2145+
}
2146+
21052147
if (chain_move_failed)
21062148
{
21072149
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp