Predicate-locking-in-gin-index.patch
application/octet-stream
Filename: Predicate-locking-in-gin-index.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Subject: Predicate locking in gin index
| File | + | − |
|---|---|---|
| src/backend/access/gin/ginbtree.c | 14 | 0 |
| src/backend/access/gin/ginget.c | 38 | 0 |
| src/backend/access/gin/gininsert.c | 5 | 0 |
| src/backend/access/gin/ginutil.c | 1 | 1 |
| src/backend/access/gin/ginvacuum.c | 9 | 2 |
| src/backend/storage/lmgr/README-SSI | 5 | 0 |
| src/test/isolation/expected/predicate-gin-2.out | 321 | 0 |
| src/test/isolation/expected/predicate-gin.out | 339 | 0 |
| src/test/isolation/isolation_schedule | 2 | 0 |
| src/test/isolation/specs/predicate-gin-2.spec | 41 | 0 |
| src/test/isolation/specs/predicate-gin.spec | 41 | 0 |
From 6172639a104785f051cb4aa0d511c58f2bae65a6 Mon Sep 17 00:00:00 2001
From: shubhambaraiss <you@example.com>
Date: Tue, 11 Jul 2017 05:26:52 +0530
Subject: [PATCH] Predicate locking in gin index
---
src/backend/access/gin/ginbtree.c | 14 +
src/backend/access/gin/ginget.c | 38 +++
src/backend/access/gin/gininsert.c | 5 +
src/backend/access/gin/ginutil.c | 2 +-
src/backend/access/gin/ginvacuum.c | 11 +-
src/backend/storage/lmgr/README-SSI | 5 +
src/test/isolation/expected/predicate-gin-2.out | 321 ++++++++++++++++++++++
src/test/isolation/expected/predicate-gin.out | 339 ++++++++++++++++++++++++
src/test/isolation/isolation_schedule | 2 +
src/test/isolation/specs/predicate-gin-2.spec | 41 +++
src/test/isolation/specs/predicate-gin.spec | 41 +++
11 files changed, 816 insertions(+), 3 deletions(-)
create mode 100644 src/test/isolation/expected/predicate-gin-2.out
create mode 100644 src/test/isolation/expected/predicate-gin.out
create mode 100644 src/test/isolation/specs/predicate-gin-2.spec
create mode 100644 src/test/isolation/specs/predicate-gin.spec
diff --git a/src/backend/access/gin/ginbtree.c b/src/backend/access/gin/ginbtree.c
index b02cb8a..22ef7e0 100644
--- a/src/backend/access/gin/ginbtree.c
+++ b/src/backend/access/gin/ginbtree.c
@@ -17,6 +17,7 @@
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
+#include "storage/predicate.h"
#include "miscadmin.h"
#include "utils/memutils.h"
#include "utils/rel.h"
@@ -515,6 +516,15 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
btree->fillRoot(btree, newrootpg,
BufferGetBlockNumber(lbuffer), newlpage,
BufferGetBlockNumber(rbuffer), newrpage);
+
+ PredicateLockPageSplit(btree->index,
+ BufferGetBlockNumber(stack->buffer),
+ BufferGetBlockNumber(lbuffer));
+
+ PredicateLockPageSplit(btree->index,
+ BufferGetBlockNumber(stack->buffer),
+ BufferGetBlockNumber(rbuffer));
+
}
else
{
@@ -524,6 +534,10 @@ ginPlaceToPage(GinBtree btree, GinBtreeStack *stack,
GinPageGetOpaque(newrpage)->rightlink = savedRightLink;
GinPageGetOpaque(newlpage)->flags |= GIN_INCOMPLETE_SPLIT;
GinPageGetOpaque(newlpage)->rightlink = BufferGetBlockNumber(rbuffer);
+
+ PredicateLockPageSplit(btree->index,
+ BufferGetBlockNumber(stack->buffer),
+ BufferGetBlockNumber(rbuffer));
}
/*
diff --git a/src/backend/access/gin/ginget.c b/src/backend/access/gin/ginget.c
index 56a5bf4..63691c5 100644
--- a/src/backend/access/gin/ginget.c
+++ b/src/backend/access/gin/ginget.c
@@ -16,9 +16,11 @@
#include "access/gin_private.h"
#include "access/relscan.h"
+#include "storage/predicate.h"
#include "miscadmin.h"
#include "utils/datum.h"
#include "utils/memutils.h"
+#include "utils/rel.h"
/* GUC parameter */
int GinFuzzySearchLimit = 0;
@@ -73,6 +75,10 @@ scanPostingTree(Relation index, GinScanEntry scanEntry,
/* Descend to the leftmost leaf page */
stack = ginScanBeginPostingTree(&btree, index, rootPostingTree, snapshot);
buffer = stack->buffer;
+
+ if (!GinGetUseFastUpdate(index))
+ PredicateLockPage(index, BufferGetBlockNumber(buffer), snapshot);
+
IncrBufferRefCount(buffer); /* prevent unpin in freeGinBtreeStack */
freeGinBtreeStack(stack);
@@ -94,6 +100,9 @@ scanPostingTree(Relation index, GinScanEntry scanEntry,
break; /* no more pages */
buffer = ginStepRight(buffer, index, GIN_SHARE);
+
+ if (!GinGetUseFastUpdate(index))
+ PredicateLockPage(index, BufferGetBlockNumber(buffer), snapshot);
}
UnlockReleaseBuffer(buffer);
@@ -323,6 +332,17 @@ restartScanEntry:
ginstate);
stackEntry = ginFindLeafPage(&btreeEntry, true, snapshot);
page = BufferGetPage(stackEntry->buffer);
+
+ /*
+ * If fast update is enabled, we acquire a predicate lock on the entire
+ * relation as fast update postpones the insertion of tuples into index
+ * structure due to which we can't detect rw conflicts.
+ */
+ if (GinGetUseFastUpdate(ginstate->index))
+ PredicateLockRelation(ginstate->index, snapshot);
+ else
+ PredicateLockPage(ginstate->index, BufferGetBlockNumber(stackEntry->buffer), snapshot);
+
/* ginFindLeafPage() will have already checked snapshot age. */
needUnlock = TRUE;
@@ -391,6 +411,9 @@ restartScanEntry:
rootPostingTree, snapshot);
entry->buffer = stack->buffer;
+ if (!GinGetUseFastUpdate(ginstate->index))
+ PredicateLockPage(ginstate->index, BufferGetBlockNumber(entry->buffer), snapshot);
+
/*
* We keep buffer pinned because we need to prevent deletion of
* page during scan. See GIN's vacuum implementation. RefCount is
@@ -633,6 +656,9 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
entry->btree.fullScan = false;
stack = ginFindLeafPage(&entry->btree, true, snapshot);
+ if (!GinGetUseFastUpdate(ginstate->index))
+ PredicateLockPage(ginstate->index, BufferGetBlockNumber(stack->buffer), snapshot);
+
/* we don't need the stack, just the buffer. */
entry->buffer = stack->buffer;
IncrBufferRefCount(entry->buffer);
@@ -677,6 +703,11 @@ entryLoadMoreItems(GinState *ginstate, GinScanEntry entry,
entry->buffer = ginStepRight(entry->buffer,
ginstate->index,
GIN_SHARE);
+
+ if (!GinGetUseFastUpdate(ginstate->index))
+ PredicateLockPage(ginstate->index, BufferGetBlockNumber(entry->buffer), snapshot);
+
+
page = BufferGetPage(entry->buffer);
}
stepright = true;
@@ -1733,6 +1764,13 @@ scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
return;
}
+ /*
+ * If fast update is disabled, but some items still exist in the pending
+ * list, then a predicate lock on the entire relation is required.
+ */
+ if (!GinGetUseFastUpdate(scan->indexRelation))
+ PredicateLockRelation(scan->indexRelation, scan->xs_snapshot);
+
pos.pendingBuffer = ReadBuffer(scan->indexRelation, blkno);
LockBuffer(pos.pendingBuffer, GIN_SHARE);
pos.firstOffset = FirstOffsetNumber;
diff --git a/src/backend/access/gin/gininsert.c b/src/backend/access/gin/gininsert.c
index 5378011..f9b661f 100644
--- a/src/backend/access/gin/gininsert.c
+++ b/src/backend/access/gin/gininsert.c
@@ -17,6 +17,7 @@
#include "access/gin_private.h"
#include "access/ginxlog.h"
#include "access/xloginsert.h"
+#include "storage/predicate.h"
#include "catalog/index.h"
#include "miscadmin.h"
#include "storage/bufmgr.h"
@@ -196,6 +197,8 @@ ginEntryInsert(GinState *ginstate,
stack = ginFindLeafPage(&btree, false, NULL);
page = BufferGetPage(stack->buffer);
+ CheckForSerializableConflictIn(btree.index, NULL, stack->buffer);
+
if (btree.findItem(&btree, stack))
{
/* found pre-existing entry */
@@ -513,6 +516,8 @@ gininsert(Relation index, Datum *values, bool *isnull,
memset(&collector, 0, sizeof(GinTupleCollector));
+ CheckForSerializableConflictIn(index, NULL, NULL);
+
for (i = 0; i < ginstate->origTupdesc->natts; i++)
ginHeapTupleFastCollect(ginstate, &collector,
(OffsetNumber) (i + 1),
diff --git a/src/backend/access/gin/ginutil.c b/src/backend/access/gin/ginutil.c
index 91e4a8c..5cfb45d 100644
--- a/src/backend/access/gin/ginutil.c
+++ b/src/backend/access/gin/ginutil.c
@@ -49,7 +49,7 @@ ginhandler(PG_FUNCTION_ARGS)
amroutine->amsearchnulls = false;
amroutine->amstorage = true;
amroutine->amclusterable = false;
- amroutine->ampredlocks = false;
+ amroutine->ampredlocks = true;
amroutine->amcanparallel = false;
amroutine->amkeytype = InvalidOid;
diff --git a/src/backend/access/gin/ginvacuum.c b/src/backend/access/gin/ginvacuum.c
index 31425e9..9b97fd9 100644
--- a/src/backend/access/gin/ginvacuum.c
+++ b/src/backend/access/gin/ginvacuum.c
@@ -153,11 +153,18 @@ ginDeletePage(GinVacuumState *gvs, BlockNumber deleteBlkno, BlockNumber leftBlkn
LockBuffer(lBuffer, GIN_EXCLUSIVE);
+ page = BufferGetPage(dBuffer);
+ rightlink = GinPageGetOpaque(page)->rightlink;
+
+ /*
+ * Any insert which would have gone on the leaf block will now go to its
+ * right sibling.
+ */
+ PredicateLockPageCombine(gvs->index, deleteBlkno, rightlink);
+
START_CRIT_SECTION();
/* Unlink the page by changing left sibling's rightlink */
- page = BufferGetPage(dBuffer);
- rightlink = GinPageGetOpaque(page)->rightlink;
page = BufferGetPage(lBuffer);
GinPageGetOpaque(page)->rightlink = rightlink;
diff --git a/src/backend/storage/lmgr/README-SSI b/src/backend/storage/lmgr/README-SSI
index a9dc01f..37c360c 100644
--- a/src/backend/storage/lmgr/README-SSI
+++ b/src/backend/storage/lmgr/README-SSI
@@ -379,6 +379,11 @@ level during a GiST search. An index insert at the leaf level can
then be trusted to ripple up to all levels and locations where
conflicting predicate locks may exist.
+ * Gin searches acquire predicate locks only on the leaf pages.
+If, however, fast update is enabled, a predicate lock on the index
+relation is required. During a page split, a predicate lock is copied
+from the original page to the new page.
+
* The effects of page splits, overflows, consolidations, and
removals must be carefully reviewed to ensure that predicate locks
aren't "lost" during those operations, or kept with pages which could
diff --git a/src/test/isolation/expected/predicate-gin-2.out b/src/test/isolation/expected/predicate-gin-2.out
new file mode 100644
index 0000000..b347bce
--- /dev/null
+++ b/src/test/isolation/expected/predicate-gin-2.out
@@ -0,0 +1,321 @@
+Parsed test spec with 2 sessions
+
+starting permutation: rxy1 wx1 c1 rxy2 wy2 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+
+starting permutation: rxy1 wx1 rxy2 c1 wy2 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+
+starting permutation: rxy1 wx1 rxy2 wy2 c1 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy1 wx1 rxy2 wy2 c2 c1
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy1 rxy2 wx1 c1 wy2 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+
+starting permutation: rxy1 rxy2 wx1 wy2 c1 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy1 rxy2 wx1 wy2 c2 c1
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy1 rxy2 wy2 wx1 c1 c2
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy1 rxy2 wy2 wx1 c2 c1
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy1 rxy2 wy2 c2 wx1 c1
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+
+starting permutation: rxy2 rxy1 wx1 c1 wy2 c2
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+
+starting permutation: rxy2 rxy1 wx1 wy2 c1 c2
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy2 rxy1 wx1 wy2 c2 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy2 rxy1 wy2 wx1 c1 c2
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy2 rxy1 wy2 wx1 c2 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy2 rxy1 wy2 c2 wx1 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+
+starting permutation: rxy2 wy2 rxy1 wx1 c1 c2
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+step c2: COMMIT;
+
+starting permutation: rxy2 wy2 rxy1 wx1 c2 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c2: COMMIT;
+step c1: COMMIT;
+
+starting permutation: rxy2 wy2 rxy1 c2 wx1 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
+
+starting permutation: rxy2 wy2 c2 rxy1 wx1 c1
+step rxy2: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4];
+sum
+
+1007820
+step wy2: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g;
+step c2: COMMIT;
+step rxy1: select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2];
+sum
+
+1003860
+step wx1: insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;
+step c1: COMMIT;
diff --git a/src/test/isolation/expected/predicate-gin.out b/src/test/isolation/expected/predicate-gin.out
new file mode 100644
index 0000000..ab293f6
--- /dev/null
+++ b/src/test/isolation/expected/predicate-gin.out
@@ -0,0 +1,339 @@
+Parsed test spec with 2 sessions
+
+starting permutation: rxy1 wx1 c1 rxy2 wy2 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+1004
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+
+starting permutation: rxy1 wx1 rxy2 c1 wy2 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c2: COMMIT;
+
+starting permutation: rxy1 wx1 rxy2 wy2 c1 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 wx1 rxy2 wy2 c2 c1
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 rxy2 wx1 c1 wy2 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c2: COMMIT;
+
+starting permutation: rxy1 rxy2 wx1 wy2 c1 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 rxy2 wx1 wy2 c2 c1
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 rxy2 wy2 wx1 c1 c2
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 rxy2 wy2 wx1 c2 c1
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy1 rxy2 wy2 c2 wx1 c1
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c1: COMMIT;
+
+starting permutation: rxy2 rxy1 wx1 c1 wy2 c2
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c2: COMMIT;
+
+starting permutation: rxy2 rxy1 wx1 wy2 c1 c2
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 rxy1 wx1 wy2 c2 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 rxy1 wy2 wx1 c1 c2
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 rxy1 wy2 wx1 c2 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 rxy1 wy2 c2 wx1 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c1: COMMIT;
+
+starting permutation: rxy2 wy2 rxy1 wx1 c1 c2
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
+step c2: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 wy2 rxy1 wx1 c2 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step c1: COMMIT;
+ERROR: could not serialize access due to read/write dependencies among transactions
+
+starting permutation: rxy2 wy2 rxy1 c2 wx1 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+400
+step c2: COMMIT;
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c1: COMMIT;
+
+starting permutation: rxy2 wy2 c2 rxy1 wx1 c1
+step rxy2: select sum(p[2]) from gin_tbl where p @> array[3,4];
+sum
+
+800
+step wy2: insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g;
+step c2: COMMIT;
+step rxy1: select sum(p[2]) from gin_tbl where p @> array[1,2];
+sum
+
+502
+step wx1: insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;
+step c1: COMMIT;
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 32c965b..3099d8b 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -62,3 +62,5 @@ test: sequence-ddl
test: async-notify
test: vacuum-reltuples
test: timeouts
+test: predicate-gin
+test: predicate-gin-2
diff --git a/src/test/isolation/specs/predicate-gin-2.spec b/src/test/isolation/specs/predicate-gin-2.spec
new file mode 100644
index 0000000..baac108
--- /dev/null
+++ b/src/test/isolation/specs/predicate-gin-2.spec
@@ -0,0 +1,41 @@
+# Test for page level predicate locking in gin
+#
+# Test to check reduced false positives.
+#
+# Queries are written in such a way that an index scan(from one transaction) and an index insert(from another transaction) will try to access different parts(sub-tree) of the index.
+
+
+setup
+{
+ create table gin_tbl(id int4, p int4[]);
+ create index ginidx on gin_tbl using gin(p) with
+ (fastupdate = off);
+ insert into gin_tbl select g, array[1, g*2, 2] from generate_series(11, 1000) g;
+ insert into gin_tbl select g, array[3, g*2, 4] from generate_series(11, 1000) g;
+}
+
+teardown
+{
+ DROP TABLE gin_tbl;
+}
+
+session "s1"
+setup {
+ BEGIN ISOLATION LEVEL SERIALIZABLE;
+ set enable_seqscan=off;
+ }
+step "rxy1" { select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[1,2]; }
+step "wx1" { insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(3000, 3100) g;}
+step "c1" { COMMIT; }
+
+session "s2"
+setup {
+ BEGIN ISOLATION LEVEL SERIALIZABLE;
+ set enable_seqscan=off;
+ }
+
+step "rxy2" { select sum(p[1]+p[2]+p[3]) from gin_tbl where p @> array[3,4]; }
+step "wy2" { insert into gin_tbl select g, array[g, g*2, g*3]
+ from generate_series(4000, 4100) g; }
+step "c2" { COMMIT; }
diff --git a/src/test/isolation/specs/predicate-gin.spec b/src/test/isolation/specs/predicate-gin.spec
new file mode 100644
index 0000000..7d9f446
--- /dev/null
+++ b/src/test/isolation/specs/predicate-gin.spec
@@ -0,0 +1,41 @@
+# Test for page level predicate locking in gin
+#
+# Test to verify serialization failures
+#
+# Queries are written in such a way that an index scan(from one transaction) and an index insert(from another transaction) will try to access the same part(sub-tree) of the index.
+
+
+setup
+{
+ create table gin_tbl(id int4, p int4[]);
+ create index ginidx on gin_tbl using gin(p) with
+ (fastupdate = off);
+ insert into gin_tbl select g, array[1, 2, g*2] from generate_series(1, 200) g;
+ insert into gin_tbl select g, array[3, 4, g*3] from generate_series(1, 200) g;
+}
+
+teardown
+{
+ DROP TABLE gin_tbl;
+}
+
+session "s1"
+setup {
+ BEGIN ISOLATION LEVEL SERIALIZABLE;
+ set enable_seqscan=off;
+ }
+step "rxy1" { select sum(p[2]) from gin_tbl where p @> array[1,2]; }
+step "wx1" { insert into gin_tbl select g, array[3, 4, g*3]
+ from generate_series(200, 250) g;}
+step "c1" { COMMIT; }
+
+session "s2"
+setup {
+ BEGIN ISOLATION LEVEL SERIALIZABLE;
+ set enable_seqscan=off;
+ }
+
+step "rxy2" { select sum(p[2]) from gin_tbl where p @> array[3,4]; }
+step "wy2" { insert into gin_tbl select g, array[1, 2, g*2]
+ from generate_series(200, 250) g; }
+step "c2" { COMMIT; }
--
1.9.1