#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"
 +