From 8ccfad5af8291d5279bf0dffe240856143d5993c Mon Sep 17 00:00:00 2001
From: shubhambaraiss <you@example.com>
Date: Mon, 25 Sep 2017 17:31:52 +0530
Subject: [PATCH] Predicate locking in hash index

---
 src/backend/access/hash/hash.c                   |   2 +-
 src/backend/access/hash/hashinsert.c             |   3 +
 src/backend/access/hash/hashpage.c               |   9 +
 src/backend/access/hash/hashsearch.c             |   2 +
 src/backend/storage/lmgr/README-SSI              |   4 +
 src/test/isolation/expected/predicate-hash-2.out | 321 +++++++++++++++++++++
 src/test/isolation/expected/predicate-hash.out   | 339 +++++++++++++++++++++++
 src/test/isolation/isolation_schedule            |   2 +
 src/test/isolation/specs/predicate-hash-2.spec   |  51 ++++
 src/test/isolation/specs/predicate-hash.spec     |  51 ++++
 10 files changed, 783 insertions(+), 1 deletion(-)
 create mode 100644 src/test/isolation/expected/predicate-hash-2.out
 create mode 100644 src/test/isolation/expected/predicate-hash.out
 create mode 100644 src/test/isolation/specs/predicate-hash-2.spec
 create mode 100644 src/test/isolation/specs/predicate-hash.spec

diff --git a/src/backend/access/hash/hash.c b/src/backend/access/hash/hash.c
index d89c192..fa4d4d6 100644
--- a/src/backend/access/hash/hash.c
+++ b/src/backend/access/hash/hash.c
@@ -68,7 +68,7 @@ hashhandler(PG_FUNCTION_ARGS)
 	amroutine->amsearchnulls = false;
 	amroutine->amstorage = false;
 	amroutine->amclusterable = false;
-	amroutine->ampredlocks = false;
+	amroutine->ampredlocks = true;
 	amroutine->amcanparallel = false;
 	amroutine->amkeytype = INT4OID;
 
diff --git a/src/backend/access/hash/hashinsert.c b/src/backend/access/hash/hashinsert.c
index dc08db9..c8005eb 100644
--- a/src/backend/access/hash/hashinsert.c
+++ b/src/backend/access/hash/hashinsert.c
@@ -22,6 +22,7 @@
 #include "utils/rel.h"
 #include "storage/lwlock.h"
 #include "storage/buf_internals.h"
+#include "storage/predicate.h"
 
 static void _hash_vacuum_one_page(Relation rel, Buffer metabuf, Buffer buf,
 					  RelFileNode hnode);
@@ -88,6 +89,8 @@ restart_insert:
 										  &usedmetap);
 	Assert(usedmetap != NULL);
 
+	CheckForSerializableConflictIn(rel, NULL, buf);
+
 	/* remember the primary bucket buffer to release the pin on it at end. */
 	bucket_buf = buf;
 
diff --git a/src/backend/access/hash/hashpage.c b/src/backend/access/hash/hashpage.c
index 1cb18a7..2a950e1 100644
--- a/src/backend/access/hash/hashpage.c
+++ b/src/backend/access/hash/hashpage.c
@@ -33,6 +33,7 @@
 #include "miscadmin.h"
 #include "storage/lmgr.h"
 #include "storage/smgr.h"
+#include "storage/predicate.h"
 
 
 static bool _hash_alloc_buckets(Relation rel, BlockNumber firstblock,
@@ -947,6 +948,10 @@ restart_expand:
 					  buf_oblkno, buf_nblkno, NULL,
 					  maxbucket, highmask, lowmask);
 
+	PredicateLockPageSplit(rel,
+				BufferGetBlockNumber(buf_oblkno),
+				BufferGetBlockNumber(buf_nblkno));
+
 	/* all done, now release the locks and pins on primary buckets. */
 	_hash_relbuf(rel, buf_oblkno);
 	_hash_relbuf(rel, buf_nblkno);
@@ -1425,6 +1430,10 @@ _hash_finish_split(Relation rel, Buffer metabuf, Buffer obuf, Bucket obucket,
 					  nbucket, obuf, bucket_nbuf, tidhtab,
 					  maxbucket, highmask, lowmask);
 
+	PredicateLockPageSplit(rel,
+				BufferGetBlockNumber(obuf),
+				BufferGetBlockNumber(bucket_nbuf));
+
 	_hash_relbuf(rel, bucket_nbuf);
 	LockBuffer(obuf, BUFFER_LOCK_UNLOCK);
 	hash_destroy(tidhtab);
diff --git a/src/backend/access/hash/hashsearch.c b/src/backend/access/hash/hashsearch.c
index 3e461ad..dfde237 100644
--- a/src/backend/access/hash/hashsearch.c
+++ b/src/backend/access/hash/hashsearch.c
@@ -19,6 +19,7 @@
 #include "miscadmin.h"
 #include "pgstat.h"
 #include "utils/rel.h"
+#include "storage/predicate.h"
 
 
 /*
@@ -284,6 +285,7 @@ _hash_first(IndexScanDesc scan, ScanDirection dir)
 	so->hashso_sk_hash = hashkey;
 
 	buf = _hash_getbucketbuf_from_hashkey(rel, hashkey, HASH_READ, NULL);
+	PredicateLockPage(rel, BufferGetBlockNumber(buf), scan->xs_snapshot);
 	page = BufferGetPage(buf);
 	TestForOldSnapshot(scan->xs_snapshot, rel, page);
 	opaque = (HashPageOpaque) PageGetSpecialPointer(page);
diff --git a/src/backend/storage/lmgr/README-SSI b/src/backend/storage/lmgr/README-SSI
index a9dc01f..6e9cbba 100644
--- a/src/backend/storage/lmgr/README-SSI
+++ b/src/backend/storage/lmgr/README-SSI
@@ -379,6 +379,10 @@ 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.
 
+    * Hash index searches acquire predicate locks on the primary
+page of a bucket. During a bucket split, a predicate lock is copied from
+the primary page of an old bucket to the primary page of a new bucket.
+
     * 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-hash-2.out b/src/test/isolation/expected/predicate-hash-2.out
new file mode 100644
index 0000000..78312d0
--- /dev/null
+++ b/src/test/isolation/expected/predicate-hash-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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+
+starting permutation: rxy1 wx1 rxy2 c1 wy2 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+
+starting permutation: rxy1 wx1 rxy2 wy2 c1 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy1 wx1 rxy2 wy2 c2 c1
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy1 rxy2 wx1 c1 wy2 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+
+starting permutation: rxy1 rxy2 wx1 wy2 c1 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy1 rxy2 wx1 wy2 c2 c1
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy1 rxy2 wy2 wx1 c1 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy1 rxy2 wy2 wx1 c2 c1
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy1 rxy2 wy2 c2 wx1 c1
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+
+starting permutation: rxy2 rxy1 wx1 c1 wy2 c2
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+
+starting permutation: rxy2 rxy1 wx1 wy2 c1 c2
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy2 rxy1 wx1 wy2 c2 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy2 rxy1 wy2 wx1 c1 c2
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy2 rxy1 wy2 wx1 c2 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy2 rxy1 wy2 c2 wx1 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+
+starting permutation: rxy2 wy2 rxy1 wx1 c1 c2
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+step c2: commit;
+
+starting permutation: rxy2 wy2 rxy1 wx1 c2 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c2: commit;
+step c1: commit;
+
+starting permutation: rxy2 wy2 rxy1 c2 wx1 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
+
+starting permutation: rxy2 wy2 c2 rxy1 wx1 c1
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g;
+step c2: commit;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g;
+step c1: commit;
diff --git a/src/test/isolation/expected/predicate-hash.out b/src/test/isolation/expected/predicate-hash.out
new file mode 100644
index 0000000..272cb2e
--- /dev/null
+++ b/src/test/isolation/expected/predicate-hash.out
@@ -0,0 +1,339 @@
+Parsed test spec with 2 sessions
+
+starting permutation: rxy1 wx1 c1 rxy2 wy2 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step c1: commit;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+600            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step c2: commit;
+
+starting permutation: rxy1 wx1 rxy2 c1 wy2 c2
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=20;
+sum            
+
+200            
+step rxy2: select sum(p) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step c1: commit;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+200            
+step c2: commit;
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) 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) from hash_point_tbl where p=30;
+sum            
+
+300            
+step wy2: insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g;
+step c2: commit;
+step rxy1: select sum(p) from hash_point_tbl where p=20;
+sum            
+
+400            
+step wx1: insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g;
+step c1: commit;
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 32c965b..284b87a 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-hash
+test: predicate-hash-2
diff --git a/src/test/isolation/specs/predicate-hash-2.spec b/src/test/isolation/specs/predicate-hash-2.spec
new file mode 100644
index 0000000..09d424d
--- /dev/null
+++ b/src/test/isolation/specs/predicate-hash-2.spec
@@ -0,0 +1,51 @@
+# Test for predicate locking in hash index
+#
+# Test to check 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 buckets of the index.
+
+
+setup
+{
+ create table hash_point_tbl(id int4, p integer);
+ create index hash_pointidx on hash_point_tbl using hash(p);
+ insert into hash_point_tbl (id, p)
+ select g, 10 from generate_series(1, 10) g;
+ insert into hash_point_tbl (id, p)
+ select g, 20 from generate_series(11, 20) g;
+ insert into hash_point_tbl (id, p)
+ select g, 30 from generate_series(21, 30) g;
+ insert into hash_point_tbl (id, p)
+ select g, 40 from generate_series(31, 40) g;
+}
+
+teardown
+{
+ DROP TABLE hash_point_tbl;
+}
+
+
+session "s1"
+setup		{
+		  BEGIN ISOLATION LEVEL SERIALIZABLE;
+		  set enable_seqscan=off;
+		  set enable_bitmapscan=off;
+		  set enable_indexonlyscan=on;
+		}
+step "rxy1"	{ select sum(p) from hash_point_tbl where p=20; }
+step "wx1"	{ insert into hash_point_tbl (id, p)
+                  select g, 50 from generate_series(41, 50) g; }
+step "c1"	{ commit; }
+
+
+session "s2"
+setup		{
+		  BEGIN ISOLATION LEVEL SERIALIZABLE;
+		  set enable_seqscan=off;
+		  set enable_bitmapscan=off;
+		  set enable_indexonlyscan=on;
+		}
+step "rxy2"	{ select sum(p) from hash_point_tbl where p=30; }
+step "wy2"	{ insert into hash_point_tbl (id, p)
+                  select g, 60 from generate_series(51, 60) g; }
+step "c2"	{ commit; }
diff --git a/src/test/isolation/specs/predicate-hash.spec b/src/test/isolation/specs/predicate-hash.spec
new file mode 100644
index 0000000..5bb2e52
--- /dev/null
+++ b/src/test/isolation/specs/predicate-hash.spec
@@ -0,0 +1,51 @@
+# Test for predicate locking in hash index
+#
+# 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 bucket of the index.
+
+
+setup
+{
+ create table hash_point_tbl(id int4, p integer);
+ create index hash_pointidx on hash_point_tbl using hash(p);
+ insert into hash_point_tbl (id, p)
+ select g, 10 from generate_series(1, 10) g;
+ insert into hash_point_tbl (id, p)
+ select g, 20 from generate_series(11, 20) g;
+ insert into hash_point_tbl (id, p)
+ select g, 30 from generate_series(21, 30) g;
+ insert into hash_point_tbl (id, p)
+ select g, 40 from generate_series(31, 40) g;
+}
+
+teardown
+{
+ DROP TABLE hash_point_tbl;
+}
+
+
+session "s1"
+setup		{
+		  BEGIN ISOLATION LEVEL SERIALIZABLE;
+		  set enable_seqscan=off;
+		  set enable_bitmapscan=off;
+		  set enable_indexonlyscan=on;
+		}
+step "rxy1"	{ select sum(p) from hash_point_tbl where p=20; }
+step "wx1"	{ insert into hash_point_tbl (id, p)
+                  select g, 30 from generate_series(41, 50) g; }
+step "c1"	{ commit; }
+
+
+session "s2"
+setup		{
+		  BEGIN ISOLATION LEVEL SERIALIZABLE;
+		  set enable_seqscan=off;
+		  set enable_bitmapscan=off;
+		  set enable_indexonlyscan=on;
+		}
+step "rxy2"	{ select sum(p) from hash_point_tbl where p=30; }
+step "wy2"	{ insert into hash_point_tbl (id, p)
+                  select g, 20 from generate_series(51, 60) g; }
+step "c2"	{ commit; }
-- 
1.9.1

