From 3e1bc6deb4a238dd0e5a56806b2f85490ff4b70e Mon Sep 17 00:00:00 2001 From: shubhambaraiss Date: Sun, 25 Jun 2017 04:44:41 +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 | 44 +++ src/test/isolation/specs/predicate-hash.spec | 44 +++ 10 files changed, 769 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..cb7fba5 100644 --- a/src/backend/access/hash/hashinsert.c +++ b/src/backend/access/hash/hashinsert.c @@ -17,6 +17,7 @@ #include "access/hash.h" #include "access/hash_xlog.h" +#include "storage/predicate.h" #include "access/heapam.h" #include "miscadmin.h" #include "utils/rel.h" @@ -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..3aef09d 100644 --- a/src/backend/access/hash/hashsearch.c +++ b/src/backend/access/hash/hashsearch.c @@ -16,6 +16,7 @@ #include "access/hash.h" #include "access/relscan.h" +#include "storage/predicate.h" #include "miscadmin.h" #include "pgstat.h" #include "utils/rel.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..2b08278 --- /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_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; + +starting permutation: rxy1 wx1 rxy2 c1 wy2 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; + +starting permutation: rxy1 wx1 rxy2 wy2 c1 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy1 wx1 rxy2 wy2 c2 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy1 rxy2 wx1 c1 wy2 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; + +starting permutation: rxy1 rxy2 wx1 wy2 c1 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy1 rxy2 wx1 wy2 c2 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy1 rxy2 wy2 wx1 c1 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy1 rxy2 wy2 wx1 c2 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy1 rxy2 wy2 c2 wx1 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; + +starting permutation: rxy2 rxy1 wx1 c1 wy2 c2 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; + +starting permutation: rxy2 rxy1 wx1 wy2 c1 c2 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy2 rxy1 wx1 wy2 c2 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy2 rxy1 wy2 wx1 c1 c2 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy2 rxy1 wy2 wx1 c2 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy2 rxy1 wy2 c2 wx1 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; + +starting permutation: rxy2 wy2 rxy1 wx1 c1 c2 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; +step c2: commit; + +starting permutation: rxy2 wy2 rxy1 wx1 c2 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c2: commit; +step c1: commit; + +starting permutation: rxy2 wy2 rxy1 c2 wx1 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) g; +step c1: commit; + +starting permutation: rxy2 wy2 c2 rxy1 wx1 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) g; +step c2: commit; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) 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..20c0874 --- /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_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step c1: commit; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +600 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step c2: commit; + +starting permutation: rxy1 wx1 rxy2 c1 wy2 c2 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 30 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 wy2 wx1 c2 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 30 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 c2 wx1 c1 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) 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_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step c1: commit; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) g; +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) 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_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 30 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 wy2 wx1 c2 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step wx1: insert into hash_tbl (id, p) + select g, 30 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 c2 wx1 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) 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_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 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 wy2 rxy1 wx1 c2 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step wx1: insert into hash_tbl (id, p) + select g, 30 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 wy2 rxy1 c2 wx1 c1 +step rxy2: select sum(p) from hash_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +200 +step c2: commit; +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) 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_tbl where p=30; +sum + +300 +step wy2: insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; +step c2: commit; +step rxy1: select sum(p) from hash_tbl where p=20; +sum + +400 +step wx1: insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) 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..51c4af6 --- /dev/null +++ b/src/test/isolation/specs/predicate-hash-2.spec @@ -0,0 +1,44 @@ +# 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_tbl as select g*10+i id, g*10 p + from generate_series(1,4)g, generate_series(1,10)i; + create index hash_pointidx on hash_tbl using hash(p); +} + +teardown +{ + DROP TABLE hash_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_tbl where p=20; } +step "wx1" { insert into hash_tbl (id, p) + select g, 50 from generate_series(51, 60) 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_tbl where p=30; } +step "wy2" { insert into hash_tbl (id, p) + select g, 60 from generate_series(61, 70) 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..7af4b3f --- /dev/null +++ b/src/test/isolation/specs/predicate-hash.spec @@ -0,0 +1,44 @@ +# 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_tbl as select g*10+i id, g*10 p + from generate_series(1,4)g, generate_series(1,10)i; + create index hash_pointidx on hash_tbl using hash(p); +} + +teardown +{ + DROP TABLE hash_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_tbl where p=20; } +step "wx1" { insert into hash_tbl (id, p) + select g, 30 from generate_series(51, 60) 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_tbl where p=30; } +step "wy2" { insert into hash_tbl (id, p) + select g, 20 from generate_series(61, 70) g; } +step "c2" { commit; } -- 1.9.1