summaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginvacuum.c
diff options
context:
space:
mode:
authorAlexander Korotkov <akorotkov@postgresql.org>2018-12-13 06:12:31 +0300
committerAlexander Korotkov <akorotkov@postgresql.org>2018-12-13 06:52:26 +0300
commit1cf175c74f103e9f0905c41d761940282c3d21f1 (patch)
tree6dde7ded4d8e2df171942802b502c13263935c14 /src/backend/access/gin/ginvacuum.c
parent19cf52e6cc33b9e126775f28269ccccb6ddf7e30 (diff)
Prevent GIN deleted pages from being reclaimed too early
When GIN vacuum deletes a posting tree page, it assumes that no concurrent searchers can access it, thanks to ginStepRight() locking two pages at once. However, since 9.4 searches can skip parts of posting trees descending from the root. That leads to the risk that page is deleted and reclaimed before concurrent search can access it. This commit prevents the risk of above by waiting for every transaction, which might wait to reference this page, to finish. Due to binary compatibility we 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.com Author: Andrey Borodin, Alexander Korotkov Reviewed-by: Alexander Korotkov Backpatch-through: 9.4
Diffstat (limited to 'src/backend/access/gin/ginvacuum.c')
-rw-r--r--src/backend/access/gin/ginvacuum.c6
1 files changed, 5 insertions, 1 deletions
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index cc440d93547..aed60cb7ae5 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -261,6 +261,9 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
page = BufferGetPage(dBuffer);
rightlink = GinPageGetOpaque(page)->rightlink;
+ /* For deleted page remember last xid which could knew its address */
+ GinPageSetDeleteXid(page, ReadNewTransactionId());
+
page = BufferGetPage(lBuffer);
GinPageGetOpaque(page)->rightlink = rightlink;
@@ -300,6 +303,7 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
data.parentOffset = myoff;
data.leftBlkno = leftBlkno;
data.rightLink = GinPageGetOpaque(page)->rightlink;
+ data.deleteXid = GinPageGetDeleteXid(page);
/*
* We can't pass buffer_std = TRUE, because we didn't set pd_lower on
@@ -777,7 +781,7 @@ ginvacuumcleanup(PG_FUNCTION_ARGS)
LockBuffer(buffer, GIN_SHARE);
page = (Page) BufferGetPage(buffer);
- if (PageIsNew(page) || GinPageIsDeleted(page))
+ if (GinPageIsRecyclable(page))
{
Assert(blkno != GIN_ROOT_BLKNO);
RecordFreeIndexPage(index, blkno);