Skip to content

Commit 1365d75

Browse files
author
shubhambaraiss
committed
Predicate locking in gin index
1 parent 119fdd8 commit 1365d75

File tree

10 files changed

+798
-3
lines changed

10 files changed

+798
-3
lines changed

src/backend/access/gin/ginbtree.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/gin_private.h"
1818
#include "access/ginxlog.h"
1919
#include "access/xloginsert.h"
20+
#include "storage/predicate.h"
2021
#include "miscadmin.h"
2122
#include "utils/memutils.h"
2223
#include "utils/rel.h"
@@ -524,6 +525,10 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
524525
GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
525526
GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
526527
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
528+
529+
PredicateLockPageSplit(btree->index,
530+
BufferGetBlockNumber(stack->buffer),
531+
BufferGetBlockNumber(rbuffer));
527532
}
528533

529534
/*

src/backend/access/gin/ginget.c

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,11 @@
1616

1717
#include "access/gin_private.h"
1818
#include "access/relscan.h"
19+
#include "storage/predicate.h"
1920
#include "miscadmin.h"
2021
#include "utils/datum.h"
2122
#include "utils/memutils.h"
23+
#include "utils/rel.h"
2224

2325
/* GUC parameter */
2426
int GinFuzzySearchLimit = 0;
@@ -73,6 +75,10 @@ scanPostingTree(Relation index, GinScanEntry scanEntry,
7375
/* Descend to the leftmost leaf page */
7476
stack = ginScanBeginPostingTree(&btree, index, rootPostingTree, snapshot);
7577
buffer = stack->buffer;
78+
79+
if (!GinGetUseFastUpdate(index))
80+
PredicateLockPage(index, BufferGetBlockNumber(buffer), snapshot);
81+
7682
IncrBufferRefCount(buffer); /* prevent unpin in freeGinBtreeStack */
7783

7884
freeGinBtreeStack(stack);
@@ -94,6 +100,9 @@ scanPostingTree(Relation index, GinScanEntry scanEntry,
94100
break; /* no more pages */
95101

96102
buffer = ginStepRight(buffer, index, GIN_SHARE);
103+
104+
if (!GinGetUseFastUpdate(index))
105+
PredicateLockPage(index, BufferGetBlockNumber(buffer), snapshot);
97106
}
98107

99108
UnlockReleaseBuffer(buffer);
@@ -323,6 +332,17 @@ startScanEntry(GinState *ginstate, GinScanEntry entry, Snapshot snapshot)
323332
ginstate);
324333
stackEntry = ginFindLeafPage(&btreeEntry, true, snapshot);
325334
page = BufferGetPage(stackEntry->buffer);
335+
336+
/*
337+
* If fast update is enabled, we acquire a predicate lock on the entire
338+
* relation as fast update postpones the insertion of tuples into index
339+
* structure due to which we can't detect rw conflicts.
340+
*/
341+
if (GinGetUseFastUpdate(ginstate->index))
342+
PredicateLockRelation(ginstate->index, snapshot);
343+
else
344+
PredicateLockPage(ginstate->index, BufferGetBlockNumber(stackEntry->buffer), snapshot);
345+
326346
/* ginFindLeafPage() will have already checked snapshot age. */
327347
needUnlock = TRUE;
328348

@@ -391,6 +411,9 @@ startScanEntry(GinState *ginstate, GinScanEntry entry, Snapshot snapshot)
391411
rootPostingTree, snapshot);
392412
entry->buffer = stack->buffer;
393413

414+
if (!GinGetUseFastUpdate(ginstate->index))
415+
PredicateLockPage(ginstate->index, BufferGetBlockNumber(entry->buffer), snapshot);
416+
394417
/*
395418
* We keep buffer pinned because we need to prevent deletion of
396419
* page during scan. See GIN's vacuum implementation. RefCount is
@@ -633,6 +656,9 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
633656
entry->btree.fullScan = false;
634657
stack = ginFindLeafPage(&entry->btree, true, snapshot);
635658

659+
if (!GinGetUseFastUpdate(ginstate->index))
660+
PredicateLockPage(ginstate->index, BufferGetBlockNumber(stack->buffer), snapshot);
661+
636662
/* we don't need the stack, just the buffer. */
637663
entry->buffer = stack->buffer;
638664
IncrBufferRefCount(entry->buffer);
@@ -677,6 +703,11 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
677703
entry->buffer = ginStepRight(entry->buffer,
678704
ginstate->index,
679705
GIN_SHARE);
706+
707+
if (!GinGetUseFastUpdate(ginstate->index))
708+
PredicateLockPage(ginstate->index, BufferGetBlockNumber(entry->buffer), snapshot);
709+
710+
680711
page = BufferGetPage(entry->buffer);
681712
}
682713
stepright = true;

src/backend/access/gin/gininsert.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#include "access/gin_private.h"
1818
#include "access/ginxlog.h"
1919
#include "access/xloginsert.h"
20+
#include "storage/predicate.h"
2021
#include "catalog/index.h"
2122
#include "miscadmin.h"
2223
#include "storage/bufmgr.h"
@@ -196,6 +197,8 @@ ginEntryInsert(GinState *ginstate,
196197
stack = ginFindLeafPage(&btree, false, NULL);
197198
page = BufferGetPage(stack->buffer);
198199

200+
CheckForSerializableConflictIn(btree.index, NULL, stack->buffer);
201+
199202
if (btree.findItem(&btree, stack))
200203
{
201204
/* found pre-existing entry */
@@ -513,6 +516,8 @@ gininsert(Relation index, Datum *values, bool *isnull,
513516

514517
memset(&collector, 0, sizeof(GinTupleCollector));
515518

519+
CheckForSerializableConflictIn(index, NULL, NULL);
520+
516521
for (i = 0; i < ginstate->origTupdesc->natts; i++)
517522
ginHeapTupleFastCollect(ginstate, &collector,
518523
(OffsetNumber) (i + 1),

src/backend/access/gin/ginutil.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,7 +49,7 @@ ginhandler(PG_FUNCTION_ARGS)
4949
amroutine->amsearchnulls = false;
5050
amroutine->amstorage = true;
5151
amroutine->amclusterable = false;
52-
amroutine->ampredlocks = false;
52+
amroutine->ampredlocks = true;
5353
amroutine->amcanparallel = false;
5454
amroutine->amkeytype = InvalidOid;
5555

src/backend/access/gin/ginvacuum.c

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -153,11 +153,18 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
153153

154154
LockBuffer(lBuffer, GIN_EXCLUSIVE);
155155

156+
page = BufferGetPage(dBuffer);
157+
rightlink = GinPageGetOpaque(page)->rightlink;
158+
159+
/*
160+
* Any insert which would have gone on the leaf block will now go to its
161+
* right sibling.
162+
*/
163+
PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
164+
156165
START_CRIT_SECTION();
157166

158167
/* Unlink the page by changing left sibling's rightlink */
159-
page = BufferGetPage(dBuffer);
160-
rightlink = GinPageGetOpaque(page)->rightlink;
161168

162169
page = BufferGetPage(lBuffer);
163170
GinPageGetOpaque(page)->rightlink = rightlink;

src/backend/storage/lmgr/README-SSI

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,11 @@ level during a GiST search. An index insert at the leaf level can
379379
then be trusted to ripple up to all levels and locations where
380380
conflicting predicate locks may exist.
381381

382+
* Gin searches acquire predicate locks only on the leaf pages.
383+
If, however, fast update is enabled, a predicate lock on the index
384+
relation is required. During a page split, a predicate lock is copied
385+
from the original page to the new page.
386+
382387
* The effects of page splits, overflows, consolidations, and
383388
removals must be carefully reviewed to ensure that predicate locks
384389
aren't "lost" during those operations, or kept with pages which could

0 commit comments

Comments
 (0)