#include "access/gin_private.h"
#include "access/relscan.h"
#include "miscadmin.h"
+#include "storage/predicate.h"
#include "utils/datum.h"
#include "utils/memutils.h"
+#include "utils/rel.h"
/* GUC parameter */
int GinFuzzySearchLimit = 0;
} pendingPosition;
+/*
+ * Place predicate lock on GIN page if needed.
+ */
+static void
+GinPredicateLockPage(Relation index, BlockNumber blkno, Snapshot snapshot)
+{
+ /*
+ * When fast update is on then no need in locking pages, because we
+ * anyway need to lock the whole index.
+ */
+ if (!GinGetUseFastUpdate(index))
+ PredicateLockPage(index, blkno, snapshot);
+}
+
/*
* Goes to the next page if current offset is outside of bounds
*/
static bool
-moveRightIfItNeeded(GinBtreeData *btree, GinBtreeStack *stack)
+moveRightIfItNeeded(GinBtreeData *btree, GinBtreeStack *stack, Snapshot snapshot)
{
Page page = BufferGetPage(stack->buffer);
stack->buffer = ginStepRight(stack->buffer, btree->index, GIN_SHARE);
stack->blkno = BufferGetBlockNumber(stack->buffer);
stack->off = FirstOffsetNumber;
+ GinPredicateLockPage(btree->index, stack->blkno, snapshot);
}
return true;
/* Descend to the leftmost leaf page */
stack = ginScanBeginPostingTree(&btree, index, rootPostingTree, snapshot);
buffer = stack->buffer;
+
IncrBufferRefCount(buffer); /* prevent unpin in freeGinBtreeStack */
freeGinBtreeStack(stack);
*/
for (;;)
{
+ /*
+ * Predicate lock each leaf page in posting tree
+ */
+ GinPredicateLockPage(index, BufferGetBlockNumber(buffer), snapshot);
+
page = BufferGetPage(buffer);
if ((GinPageGetOpaque(page)->flags & GIN_DELETED) == 0)
{
attnum = scanEntry->attnum;
attr = TupleDescAttr(btree->ginstate->origTupdesc, attnum - 1);
+ /*
+ * Predicate lock entry leaf page, following pages will be locked by
+ * moveRightIfItNeeded()
+ */
+ GinPredicateLockPage(btree->index, stack->buffer, snapshot);
+
for (;;)
{
Page page;
/*
* stack->off points to the interested entry, buffer is already locked
*/
- if (moveRightIfItNeeded(btree, stack) == false)
+ if (moveRightIfItNeeded(btree, stack, snapshot) == false)
return true;
page = BufferGetPage(stack->buffer);
Datum newDatum;
GinNullCategory newCategory;
- if (moveRightIfItNeeded(btree, stack) == false)
+ if (moveRightIfItNeeded(btree, stack, snapshot) == false)
elog(ERROR, "lost saved point in index"); /* must not happen !!! */
page = BufferGetPage(stack->buffer);
ginstate);
stackEntry = ginFindLeafPage(&btreeEntry, true, snapshot);
page = BufferGetPage(stackEntry->buffer);
+
/* ginFindLeafPage() will have already checked snapshot age. */
needUnlock = true;
{
IndexTuple itup = (IndexTuple) PageGetItem(page, PageGetItemId(page, stackEntry->off));
+ /* Predicate lock visited entry leaf page */
+ GinPredicateLockPage(ginstate->index,
+ BufferGetBlockNumber(stackEntry->buffer), snapshot);
+
if (GinIsPostingTree(itup))
{
BlockNumber rootPostingTree = GinGetPostingTree(itup);
rootPostingTree, snapshot);
entry->buffer = stack->buffer;
+ /*
+ * Predicate lock visited posting tree page, following pages
+ * will be locked by moveRightIfItNeeded or entryLoadMoreItems
+ */
+ GinPredicateLockPage(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
for (i = 0; i < key->nentries - 1; i++)
{
- /* Pass all entries <= i as FALSE, and the rest as MAYBE */
+ /* Pass all entries <= i as false, and the rest as MAYBE */
for (j = 0; j <= i; j++)
key->entryRes[entryIndexes[j]] = GIN_FALSE;
for (j = i + 1; j < key->nentries; j++)
entry->btree.fullScan = false;
stack = ginFindLeafPage(&entry->btree, true, snapshot);
+ GinPredicateLockPage(ginstate->index, BufferGetBlockNumber(stack->buffer), snapshot);
+
/* we don't need the stack, just the buffer. */
entry->buffer = stack->buffer;
IncrBufferRefCount(entry->buffer);
entry->buffer = ginStepRight(entry->buffer,
ginstate->index,
GIN_SHARE);
+
+ GinPredicateLockPage(ginstate->index, BufferGetBlockNumber(entry->buffer), snapshot);
+
+
page = BufferGetPage(entry->buffer);
}
stepright = true;
* lossy page even when none of the other entries match.
*
* Our strategy is to call the tri-state consistent function, with the
- * lossy-page entries set to MAYBE, and all the other entries FALSE. If it
- * returns FALSE, none of the lossy items alone are enough for a match, so
+ * lossy-page entries set to MAYBE, and all the other entries false. If it
+ * returns false, none of the lossy items alone are enough for a match, so
* we don't need to return a lossy-page pointer. Otherwise, return a
* lossy-page pointer to indicate that the whole heap page must be
* checked. (On subsequent calls, we'll do nothing until minItem is past
}
/*
- * Collect all matched rows from pending list into bitmap
+ * Collect all matched rows from pending list into bitmap. Also function
+ * takes PendingLockRelation if it's needed.
*/
static void
scanPendingInsert(IndexScanDesc scan, TIDBitmap *tbm, int64 *ntids)
{
/* No pending list, so proceed with normal scan */
UnlockReleaseBuffer(metabuffer);
+
+ /*
+ * 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(scan->indexRelation))
+ PredicateLockRelation(scan->indexRelation, scan->xs_snapshot);
+
return;
}
+ /*
+ * Pending list is not empty, we need to lock the index doesn't despite on
+ * fastupdate state
+ */
+ PredicateLockRelation(scan->indexRelation, scan->xs_snapshot);
+
pos.pendingBuffer = ReadBuffer(scan->indexRelation, blkno);
LockBuffer(pos.pendingBuffer, GIN_SHARE);
pos.firstOffset = FirstOffsetNumber;
--- /dev/null
+Parsed test spec with 2 sessions
+
+starting permutation: rxy1 wx1 c1 rxy2 wy2 c2
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10050
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step c2: commit;
+
+starting permutation: rxy2 wy2 c2 rxy1 wx1 c1
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step c2: commit;
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10050
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+
+starting permutation: rxy3 wx3 c1 rxy4 wy4 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+
+starting permutation: rxy4 wy4 c2 rxy3 wx3 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+
+starting permutation: rxy1 wx1 rxy2 c1 wy2 c2
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step c1: commit;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2: select count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step c2: commit;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step c2: commit;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) 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 count(*) from gin_tbl where p @> array[5,6];
+count
+
+10000
+step wy2: insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g;
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step c2: commit;
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c1: commit;
+
+starting permutation: rxy3 wx3 rxy4 c1 wy4 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step c1: commit;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+
+starting permutation: rxy3 wx3 rxy4 wy4 c1 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy3 wx3 rxy4 wy4 c2 c1
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy3 rxy4 wx3 c1 wy4 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+
+starting permutation: rxy3 rxy4 wx3 wy4 c1 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy3 rxy4 wx3 wy4 c2 c1
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy3 rxy4 wy4 wx3 c1 c2
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy3 rxy4 wy4 wx3 c2 c1
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy3 rxy4 wy4 c2 wx3 c1
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+
+starting permutation: rxy4 rxy3 wx3 c1 wy4 c2
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+
+starting permutation: rxy4 rxy3 wx3 wy4 c1 c2
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy4 rxy3 wx3 wy4 c2 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy4 rxy3 wy4 wx3 c1 c2
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy4 rxy3 wy4 wx3 c2 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy4 rxy3 wy4 c2 wx3 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step c2: commit;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+
+starting permutation: rxy4 wy4 rxy3 wx3 c1 c2
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy4 wy4 rxy3 wx3 c2 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy4 wy4 rxy3 c2 wx3 c1
+step rxy4: select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000];
+count
+
+4
+step wy4: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g;
+step rxy3: select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000];
+count
+
+4
+step c2: commit;
+step wx3: insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g;
+step c1: commit;
+
+starting permutation: rxy1 rxy2fu wx1 c1 wy2fu c2
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2fu: select count(*) from gin_tbl where p @> array[10000,10005];
+count
+
+0
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+step wy2fu: insert into gin_tbl select g, array[10000,10005] from
+ generate_series(20051, 20100) g;
+step c2: commit;
+
+starting permutation: fu1 rxy1 rxy2fu wx1 c1 wy2fu c2
+step fu1: alter index ginidx set (fastupdate = on);
+ commit;
+ begin isolation level serializable;
+ set enable_seqscan=off;
+step rxy1: select count(*) from gin_tbl where p @> array[4,5];
+count
+
+10000
+step rxy2fu: select count(*) from gin_tbl where p @> array[10000,10005];
+count
+
+0
+step wx1: insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g;
+step c1: commit;
+step wy2fu: insert into gin_tbl select g, array[10000,10005] from
+ generate_series(20051, 20100) g;
+ERROR: could not serialize access due to read/write dependencies among transactions
+step c2: commit;
--- /dev/null
+# Test for page level predicate locking in gin index
+#
+# Test to verify serialization failures and to check reduced false positives
+#
+# To verify serialization failures, queries and permutations 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
+# whereas to check reduced false positives, they will try to access different
+# parts (sub-tree) of the index.
+
+
+setup
+{
+ create table gin_tbl(id int4, p int4[]);
+ insert into gin_tbl select g, array[g, g*2,g*3] from generate_series(1, 10000) g;
+ insert into gin_tbl select g, array[4,5,6] from generate_series(10001, 20000) g;
+ create index ginidx on gin_tbl using gin(p) with (fastupdate = off);
+}
+
+teardown
+{
+ drop table gin_tbl;
+}
+
+session "s1"
+setup
+{
+ begin isolation level serializable;
+ set enable_seqscan=off;
+}
+
+# enable pending list for a small subset of tests
+step "fu1" { alter index ginidx set (fastupdate = on);
+ commit;
+ begin isolation level serializable;
+ set enable_seqscan=off; }
+
+step "rxy1" { select count(*) from gin_tbl where p @> array[4,5]; }
+step "wx1" { insert into gin_tbl select g, array[5,6] from generate_series
+ (20001, 20050) g; }
+step "rxy3" { select count(*) from gin_tbl where p @> array[1,2] or
+ p @> array[100,200] or p @> array[500,1000] or p @> array[1000,2000]; }
+step "wx3" { insert into gin_tbl select g, array[g,g*2] from generate_series
+ (1, 50) g; }
+step "c1" { commit; }
+
+session "s2"
+setup
+{
+ begin isolation level serializable;
+ set enable_seqscan=off;
+}
+
+step "rxy2" { select count(*) from gin_tbl where p @> array[5,6]; }
+step "rxy2fu" { select count(*) from gin_tbl where p @> array[10000,10005]; }
+step "wy2" { insert into gin_tbl select g, array[4,5] from
+ generate_series(20051, 20100) g; }
+step "wy2fu" { insert into gin_tbl select g, array[10000,10005] from
+ generate_series(20051, 20100) g; }
+step "rxy4" { select count(*) from gin_tbl where p @> array[4000,8000] or
+ p @> array[5000,10000] or p @> array[6000,12000] or
+ p @> array[8000,16000]; }
+step "wy4" { insert into gin_tbl select g, array[g,g*2] from generate_series
+ (10000, 10050) g; }
+step "c2" { commit; }
+
+
+# An index scan (from one transaction) and an index insert (from another transaction)
+# try to access the same part of the index but one transaction commits before other
+# transaction begins so no r-w conflict.
+
+permutation "rxy1" "wx1" "c1" "rxy2" "wy2" "c2"
+permutation "rxy2" "wy2" "c2" "rxy1" "wx1" "c1"
+
+# An index scan (from one transaction) and an index insert (from another transaction)
+# try to access different parts of the index and also one transaction commits before
+# other transaction begins, so no r-w conflict.
+
+permutation "rxy3" "wx3" "c1" "rxy4" "wy4" "c2"
+permutation "rxy4" "wy4" "c2" "rxy3" "wx3" "c1"
+
+
+# An index scan (from one transaction) and an index insert (from another transaction)
+# try to access the same part of the index and one transaction begins before other
+# transaction commits so there is a r-w conflict.
+
+permutation "rxy1" "wx1" "rxy2" "c1" "wy2" "c2"
+permutation "rxy1" "wx1" "rxy2" "wy2" "c1" "c2"
+permutation "rxy1" "wx1" "rxy2" "wy2" "c2" "c1"
+permutation "rxy1" "rxy2" "wx1" "c1" "wy2" "c2"
+permutation "rxy1" "rxy2" "wx1" "wy2" "c1" "c2"
+permutation "rxy1" "rxy2" "wx1" "wy2" "c2" "c1"
+permutation "rxy1" "rxy2" "wy2" "wx1" "c1" "c2"
+permutation "rxy1" "rxy2" "wy2" "wx1" "c2" "c1"
+permutation "rxy1" "rxy2" "wy2" "c2" "wx1" "c1"
+permutation "rxy2" "rxy1" "wx1" "c1" "wy2" "c2"
+permutation "rxy2" "rxy1" "wx1" "wy2" "c1" "c2"
+permutation "rxy2" "rxy1" "wx1" "wy2" "c2" "c1"
+permutation "rxy2" "rxy1" "wy2" "wx1" "c1" "c2"
+permutation "rxy2" "rxy1" "wy2" "wx1" "c2" "c1"
+permutation "rxy2" "rxy1" "wy2" "c2" "wx1" "c1"
+permutation "rxy2" "wy2" "rxy1" "wx1" "c1" "c2"
+permutation "rxy2" "wy2" "rxy1" "wx1" "c2" "c1"
+permutation "rxy2" "wy2" "rxy1" "c2" "wx1" "c1"
+
+# An index scan (from one transaction) and an index insert (from another transaction)
+# try to access different parts of the index so no r-w conflict.
+
+permutation "rxy3" "wx3" "rxy4" "c1" "wy4" "c2"
+permutation "rxy3" "wx3" "rxy4" "wy4" "c1" "c2"
+permutation "rxy3" "wx3" "rxy4" "wy4" "c2" "c1"
+permutation "rxy3" "rxy4" "wx3" "c1" "wy4" "c2"
+permutation "rxy3" "rxy4" "wx3" "wy4" "c1" "c2"
+permutation "rxy3" "rxy4" "wx3" "wy4" "c2" "c1"
+permutation "rxy3" "rxy4" "wy4" "wx3" "c1" "c2"
+permutation "rxy3" "rxy4" "wy4" "wx3" "c2" "c1"
+permutation "rxy3" "rxy4" "wy4" "c2" "wx3" "c1"
+permutation "rxy4" "rxy3" "wx3" "c1" "wy4" "c2"
+permutation "rxy4" "rxy3" "wx3" "wy4" "c1" "c2"
+permutation "rxy4" "rxy3" "wx3" "wy4" "c2" "c1"
+permutation "rxy4" "rxy3" "wy4" "wx3" "c1" "c2"
+permutation "rxy4" "rxy3" "wy4" "wx3" "c2" "c1"
+permutation "rxy4" "rxy3" "wy4" "c2" "wx3" "c1"
+permutation "rxy4" "wy4" "rxy3" "wx3" "c1" "c2"
+permutation "rxy4" "wy4" "rxy3" "wx3" "c2" "c1"
+permutation "rxy4" "wy4" "rxy3" "c2" "wx3" "c1"
+
+# Test fastupdate = on. First test should pass because fastupdate is off and
+# sessions touches different parts of index, second should fail because
+# with fastupdate on, then whole index should be under predicate lock.
+
+permutation "rxy1" "rxy2fu" "wx1" "c1" "wy2fu" "c2"
+permutation "fu1" "rxy1" "rxy2fu" "wx1" "c1" "wy2fu" "c2"
+