aboutsummaryrefslogtreecommitdiff
path: root/src/backend/access/gin/ginvacuum.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/access/gin/ginvacuum.c')
-rw-r--r--src/backend/access/gin/ginvacuum.c51
1 files changed, 22 insertions, 29 deletions
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index b84d3a30de3..e6241850e1f 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -237,6 +237,9 @@ ginVacuumPostingTreeLeaves(GinVacuumState *gvs, BlockNumber blkno, bool isRoot,
return hasVoidPage;
}
+/*
+ * Delete a posting tree page.
+ */
static void
ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkno,
BlockNumber parentBlkno, OffsetNumber myoff, bool isParentRoot)
@@ -246,39 +249,35 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
Buffer pBuffer;
Page page,
parentPage;
+ BlockNumber rightlink;
+ /*
+ * Lock the pages in the same order as an insertion would, to avoid
+ * deadlocks: left, then right, then parent.
+ */
+ lBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, leftBlkno,
+ RBM_NORMAL, gvs->strategy);
dBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, deleteBlkno,
RBM_NORMAL, gvs->strategy);
-
- if (leftBlkno != InvalidBlockNumber)
- lBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, leftBlkno,
- RBM_NORMAL, gvs->strategy);
- else
- lBuffer = InvalidBuffer;
-
pBuffer = ReadBufferExtended(gvs->index, MAIN_FORKNUM, parentBlkno,
RBM_NORMAL, gvs->strategy);
+ LockBuffer(lBuffer, GIN_EXCLUSIVE);
LockBuffer(dBuffer, GIN_EXCLUSIVE);
if (!isParentRoot) /* parent is already locked by
* LockBufferForCleanup() */
LockBuffer(pBuffer, GIN_EXCLUSIVE);
- if (leftBlkno != InvalidBlockNumber)
- LockBuffer(lBuffer, GIN_EXCLUSIVE);
START_CRIT_SECTION();
- if (leftBlkno != InvalidBlockNumber)
- {
- BlockNumber rightlink;
-
- page = BufferGetPage(dBuffer);
- rightlink = GinPageGetOpaque(page)->rightlink;
+ /* Unlink the page by changing left sibling's rightlink */
+ page = BufferGetPage(dBuffer);
+ rightlink = GinPageGetOpaque(page)->rightlink;
- page = BufferGetPage(lBuffer);
- GinPageGetOpaque(page)->rightlink = rightlink;
- }
+ page = BufferGetPage(lBuffer);
+ GinPageGetOpaque(page)->rightlink = rightlink;
+ /* Delete downlink from parent */
parentPage = BufferGetPage(pBuffer);
#ifdef USE_ASSERT_CHECKING
do
@@ -360,10 +359,7 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
if (!isParentRoot)
LockBuffer(pBuffer, GIN_UNLOCK);
ReleaseBuffer(pBuffer);
-
- if (leftBlkno != InvalidBlockNumber)
- UnlockReleaseBuffer(lBuffer);
-
+ UnlockReleaseBuffer(lBuffer);
UnlockReleaseBuffer(dBuffer);
END_CRIT_SECTION();
@@ -431,15 +427,12 @@ ginScanToDelete(GinVacuumState *gvs, BlockNumber blkno, bool isRoot, DataPageDel
if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
{
- if (!(me->leftBlkno == InvalidBlockNumber && GinPageRightMost(page)))
+ /* we never delete the left- or rightmost branch */
+ if (me->leftBlkno != InvalidBlockNumber && !GinPageRightMost(page))
{
- /* we never delete right most branch */
Assert(!isRoot);
- if (GinPageGetOpaque(page)->maxoff < FirstOffsetNumber)
- {
- ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);
- meDelete = TRUE;
- }
+ ginDeletePage(gvs, blkno, me->leftBlkno, me->parent->blkno, myoff, me->parent->isRoot);
+ meDelete = TRUE;
}
}