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

Commitcd24b4e

Browse files
committed
Prevent GIN deleted pages from being reclaimed too early
When GIN vacuum deletes a posting tree page, it assumes that no concurrentsearchers can access it, thanks to ginStepRight() locking two pages at once.However, since 9.4 searches can skip parts of posting trees descending from theroot. That leads to the risk that page is deleted and reclaimed beforeconcurrent search can access it.This commit prevents the risk of above by waiting for every transaction, whichmight wait to reference this page, to finish. Due to binary compatibilitywe can't change GinPageOpaqueData to store corresponding transaction id.Instead we reuse page header pd_prune_xid field, which is unused in index pages.Discussion:https://postgr.es/m/31a702a.14dd.166c1366ac1.Coremail.chjischj%40163.comAuthor: Andrey Borodin, Alexander KorotkovReviewed-by: Alexander KorotkovBackpatch-through: 9.4
1 parent80d4d8d commitcd24b4e

File tree

5 files changed

+22
-13
lines changed

5 files changed

+22
-13
lines changed

‎src/backend/access/gin/README

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -304,12 +304,10 @@ the lock on next page has been acquired.
304304
The downlink is more tricky. A search descending the tree must release the
305305
lock on the parent page before locking the child, or it could deadlock with
306306
a concurrent split of the child page; a page split locks the parent, while
307-
already holding a lock on the child page. However, posting trees are only
308-
fully searched from left to right, starting from the leftmost leaf. (The
309-
tree-structure is only needed by insertions, to quickly find the correct
310-
insert location). So as long as we don't delete the leftmost page on each
311-
level, a search can never follow a downlink to page that's about to be
312-
deleted.
307+
already holding a lock on the child page. So, deleted page cannot be reclaimed
308+
immediately. Instead, we have to wait for every transaction, which might wait
309+
to reference this page, to finish. Corresponding processes must observe that
310+
the page is marked deleted and recover accordingly.
313311

314312
The previous paragraph's reasoning only applies to searches, and only to
315313
posting trees. To protect from inserters following a downlink to a deleted

‎src/backend/access/gin/ginutil.c

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -274,12 +274,7 @@ GinNewBuffer(Relation index)
274274
*/
275275
if (ConditionalLockBuffer(buffer))
276276
{
277-
Pagepage=BufferGetPage(buffer);
278-
279-
if (PageIsNew(page))
280-
returnbuffer;/* OK to use, if never initialized */
281-
282-
if (GinPageIsDeleted(page))
277+
if (GinPageIsRecyclable(BufferGetPage(buffer)))
283278
returnbuffer;/* OK to use */
284279

285280
LockBuffer(buffer,GIN_UNLOCK);

‎src/backend/access/gin/ginvacuum.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -215,6 +215,9 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
215215
page=BufferGetPage(dBuffer);
216216
rightlink=GinPageGetOpaque(page)->rightlink;
217217

218+
/* For deleted page remember last xid which could knew its address */
219+
GinPageSetDeleteXid(page,ReadNewTransactionId());
220+
218221
page=BufferGetPage(lBuffer);
219222
GinPageGetOpaque(page)->rightlink=rightlink;
220223

@@ -262,6 +265,7 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
262265

263266
data.parentOffset=myoff;
264267
data.rightLink=GinPageGetOpaque(page)->rightlink;
268+
data.deleteXid=GinPageGetDeleteXid(page);
265269

266270
XLogRegisterData((char*)&data,sizeof(ginxlogDeletePage));
267271

@@ -708,7 +712,7 @@ ginvacuumcleanup(IndexVacuumInfo *info, IndexBulkDeleteResult *stats)
708712
LockBuffer(buffer,GIN_SHARE);
709713
page= (Page)BufferGetPage(buffer);
710714

711-
if (PageIsNew(page)||GinPageIsDeleted(page))
715+
if (GinPageIsRecyclable(page))
712716
{
713717
Assert(blkno!=GIN_ROOT_BLKNO);
714718
RecordFreeIndexPage(index,blkno);

‎src/backend/access/gin/ginxlog.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,7 @@ ginRedoDeletePage(XLogReaderState *record)
529529
page=BufferGetPage(dbuffer);
530530
Assert(GinPageIsData(page));
531531
GinPageGetOpaque(page)->flags=GIN_DELETED;
532+
GinPageSetDeleteXid(page,data->deleteXid);
532533
PageSetLSN(page,lsn);
533534
MarkBufferDirty(dbuffer);
534535
}

‎src/include/access/gin_private.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
#include"access/amapi.h"
1414
#include"access/gin.h"
1515
#include"access/itup.h"
16+
#include"access/transam.h"
1617
#include"fmgr.h"
1718
#include"storage/bufmgr.h"
1819
#include"lib/rbtree.h"
@@ -131,6 +132,15 @@ typedef struct GinMetaPageData
131132

132133
#defineGinPageRightMost(page) ( GinPageGetOpaque(page)->rightlink == InvalidBlockNumber)
133134

135+
/*
136+
* We should reclaim deleted page only once every transaction started before
137+
* its deletion is over.
138+
*/
139+
#defineGinPageGetDeleteXid(page) ( ((PageHeader) (page))->pd_prune_xid )
140+
#defineGinPageSetDeleteXid(page,xid) ( ((PageHeader) (page))->pd_prune_xid = xid)
141+
#defineGinPageIsRecyclable(page) ( PageIsNew(page) || (GinPageIsDeleted(page) \
142+
&& TransactionIdPrecedes(GinPageGetDeleteXid(page), RecentGlobalXmin)))
143+
134144
/*
135145
* We use our own ItemPointerGet(BlockNumber|OffsetNumber)
136146
* to avoid Asserts, since sometimes the ip_posid isn't "valid"
@@ -540,6 +550,7 @@ typedef struct ginxlogDeletePage
540550
{
541551
OffsetNumberparentOffset;
542552
BlockNumberrightLink;
553+
TransactionIddeleteXid;/* last Xid which could see this page in scan */
543554
}ginxlogDeletePage;
544555

545556
#defineXLOG_GIN_UPDATE_META_PAGE 0x60

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp