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

Commit962e0cc

Browse files
committed
Fix race conditions associated with SPGiST redirection tuples.
The correct test for whether a redirection tuple is removable is whethertuple's xid < RecentGlobalXmin, not OldestXmin; the previous codingfailed to protect index searches being done in concurrent transactions thathave no XID. This mirrors the recent fix in btree's page recycling logicmade in commitd3abbbe.Also, WAL-log the newest XID of any removed redirection tuple on an indexpage, and apply ResolveRecoveryConflictWithSnapshot during InHotStandby WALreplay. This protects against concurrent Hot Standby transactions possiblyneeding to see the redirection tuple(s).Per my query of 2012-03-12 and subsequent discussion.
1 parent7719ed0 commit962e0cc

File tree

4 files changed

+27
-12
lines changed

4 files changed

+27
-12
lines changed

‎src/backend/access/spgist/spgutils.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -722,6 +722,7 @@ spgFormDeadTuple(SpGistState *state, int tupstate,
722722
if (tupstate==SPGIST_REDIRECT)
723723
{
724724
ItemPointerSet(&tuple->pointer,blkno,offnum);
725+
Assert(TransactionIdIsValid(state->myXid));
725726
tuple->xid=state->myXid;
726727
}
727728
else

‎src/backend/access/spgist/spgvacuum.c

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
#include"storage/bufmgr.h"
2525
#include"storage/indexfsm.h"
2626
#include"storage/lmgr.h"
27-
#include"storage/procarray.h"
2827
#include"utils/snapmgr.h"
2928

3029

@@ -49,7 +48,6 @@ typedef struct spgBulkDeleteState
4948
SpGistStatespgstate;/* for SPGiST operations that need one */
5049
spgVacPendingItem*pendingList;/* TIDs we need to (re)visit */
5150
TransactionIdmyXmin;/* for detecting newly-added redirects */
52-
TransactionIdOldestXmin;/* for deciding a redirect is obsolete */
5351
BlockNumberlastFilledBlock;/* last non-deletable block */
5452
}spgBulkDeleteState;
5553

@@ -491,8 +489,7 @@ vacuumLeafRoot(spgBulkDeleteState *bds, Relation index, Buffer buffer)
491489
* Unlike the routines above, this works on both leaf and inner pages.
492490
*/
493491
staticvoid
494-
vacuumRedirectAndPlaceholder(Relationindex,Bufferbuffer,
495-
TransactionIdOldestXmin)
492+
vacuumRedirectAndPlaceholder(Relationindex,Bufferbuffer)
496493
{
497494
Pagepage=BufferGetPage(buffer);
498495
SpGistPageOpaqueopaque=SpGistPageGetOpaque(page);
@@ -509,6 +506,7 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer,
509506
xlrec.node=index->rd_node;
510507
xlrec.blkno=BufferGetBlockNumber(buffer);
511508
xlrec.nToPlaceholder=0;
509+
xlrec.newestRedirectXid=InvalidTransactionId;
512510

513511
START_CRIT_SECTION();
514512

@@ -526,13 +524,18 @@ vacuumRedirectAndPlaceholder(Relation index, Buffer buffer,
526524
dt= (SpGistDeadTuple)PageGetItem(page,PageGetItemId(page,i));
527525

528526
if (dt->tupstate==SPGIST_REDIRECT&&
529-
TransactionIdPrecedes(dt->xid,OldestXmin))
527+
TransactionIdPrecedes(dt->xid,RecentGlobalXmin))
530528
{
531529
dt->tupstate=SPGIST_PLACEHOLDER;
532530
Assert(opaque->nRedirection>0);
533531
opaque->nRedirection--;
534532
opaque->nPlaceholder++;
535533

534+
/* remember newest XID among the removed redirects */
535+
if (!TransactionIdIsValid(xlrec.newestRedirectXid)||
536+
TransactionIdPrecedes(xlrec.newestRedirectXid,dt->xid))
537+
xlrec.newestRedirectXid=dt->xid;
538+
536539
ItemPointerSetInvalid(&dt->pointer);
537540

538541
itemToPlaceholder[xlrec.nToPlaceholder]=i;
@@ -640,13 +643,13 @@ spgvacuumpage(spgBulkDeleteState *bds, BlockNumber blkno)
640643
else
641644
{
642645
vacuumLeafPage(bds,index,buffer, false);
643-
vacuumRedirectAndPlaceholder(index,buffer,bds->OldestXmin);
646+
vacuumRedirectAndPlaceholder(index,buffer);
644647
}
645648
}
646649
else
647650
{
648651
/* inner page */
649-
vacuumRedirectAndPlaceholder(index,buffer,bds->OldestXmin);
652+
vacuumRedirectAndPlaceholder(index,buffer);
650653
}
651654

652655
/*
@@ -723,7 +726,7 @@ spgprocesspending(spgBulkDeleteState *bds)
723726
/* deal with any deletable tuples */
724727
vacuumLeafPage(bds,index,buffer, true);
725728
/* might as well do this while we are here */
726-
vacuumRedirectAndPlaceholder(index,buffer,bds->OldestXmin);
729+
vacuumRedirectAndPlaceholder(index,buffer);
727730

728731
SpGistSetLastUsedPage(index,buffer);
729732

@@ -806,7 +809,6 @@ spgvacuumscan(spgBulkDeleteState *bds)
806809
initSpGistState(&bds->spgstate,index);
807810
bds->pendingList=NULL;
808811
bds->myXmin=GetActiveSnapshot()->xmin;
809-
bds->OldestXmin=GetOldestXmin(true, false);
810812
bds->lastFilledBlock=SPGIST_LAST_FIXED_BLKNO;
811813

812814
/*

‎src/backend/access/spgist/spgxlog.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,9 @@
1515
#include"postgres.h"
1616

1717
#include"access/spgist_private.h"
18+
#include"access/transam.h"
1819
#include"access/xlogutils.h"
19-
#include"storage/bufmgr.h"
20+
#include"storage/standby.h"
2021
#include"utils/memutils.h"
2122

2223

@@ -888,6 +889,15 @@ spgRedoVacuumRedirect(XLogRecPtr lsn, XLogRecord *record)
888889
ptr+=sizeof(spgxlogVacuumRedirect);
889890
itemToPlaceholder= (OffsetNumber*)ptr;
890891

892+
/*
893+
* If any redirection tuples are being removed, make sure there are no
894+
* live Hot Standby transactions that might need to see them. This code
895+
* behaves similarly to btree's XLOG_BTREE_REUSE_PAGE case.
896+
*/
897+
if (InHotStandby&&TransactionIdIsValid(xldata->newestRedirectXid))
898+
ResolveRecoveryConflictWithSnapshot(xldata->newestRedirectXid,
899+
xldata->node);
900+
891901
if (!(record->xl_info&XLR_BKP_BLOCK_1))
892902
{
893903
buffer=XLogReadBuffer(xldata->node,xldata->blkno, false);
@@ -1060,8 +1070,9 @@ spg_desc(StringInfo buf, uint8 xl_info, char *rec)
10601070
break;
10611071
caseXLOG_SPGIST_VACUUM_REDIRECT:
10621072
out_target(buf, ((spgxlogVacuumRedirect*)rec)->node);
1063-
appendStringInfo(buf,"vacuum redirect tuples on page %u",
1064-
((spgxlogVacuumRedirect*)rec)->blkno);
1073+
appendStringInfo(buf,"vacuum redirect tuples on page %u, newest XID %u",
1074+
((spgxlogVacuumRedirect*)rec)->blkno,
1075+
((spgxlogVacuumRedirect*)rec)->newestRedirectXid);
10651076
break;
10661077
default:
10671078
appendStringInfo(buf,"unknown spgist op code %u",info);

‎src/include/access/spgist_private.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,7 @@ typedef struct spgxlogVacuumRedirect
591591
BlockNumberblkno;/* block number to clean */
592592
uint16nToPlaceholder;/* number of redirects to make placeholders */
593593
OffsetNumberfirstPlaceholder;/* first placeholder tuple to remove */
594+
TransactionIdnewestRedirectXid;/* newest XID of removed redirects */
594595

595596
/* offsets of redirect tuples to make placeholders follow */
596597
}spgxlogVacuumRedirect;

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp