>From 770b75a5037f28e691c3e4f311d83e4dfa0b4ed2 Mon Sep 17 00:00:00 2001
From: Andres Freund <andres@anarazel.de>
Date: Fri, 23 Nov 2012 13:13:20 +0100
Subject: [PATCH 2/2] Add isolationtester tests for CREATE/DROP INDEX
 CONCURRENTLY interactions

---
 .../expected/create-index-concurrently-hot.out     | 34 ++++++++++++++
 .../expected/drop-index-concurrently-1.out         | 40 ----------------
 .../expected/drop-index-concurrently-block.out     | 38 +++++++++++++++
 .../expected/drop-index-concurrently-write.out     | 40 ++++++++++++++++
 src/test/isolation/isolation_schedule              |  4 +-
 .../specs/create-index-concurrently-hot.spec       | 40 ++++++++++++++++
 .../isolation/specs/drop-index-concurrently-1.spec | 38 ---------------
 .../specs/drop-index-concurrently-block.spec       | 54 ++++++++++++++++++++++
 .../specs/drop-index-concurrently-write.spec       | 38 +++++++++++++++
 9 files changed, 247 insertions(+), 79 deletions(-)
 create mode 100644 src/test/isolation/expected/create-index-concurrently-hot.out
 delete mode 100644 src/test/isolation/expected/drop-index-concurrently-1.out
 create mode 100644 src/test/isolation/expected/drop-index-concurrently-block.out
 create mode 100644 src/test/isolation/expected/drop-index-concurrently-write.out
 create mode 100644 src/test/isolation/specs/create-index-concurrently-hot.spec
 delete mode 100644 src/test/isolation/specs/drop-index-concurrently-1.spec
 create mode 100644 src/test/isolation/specs/drop-index-concurrently-block.spec
 create mode 100644 src/test/isolation/specs/drop-index-concurrently-write.spec

diff --git a/src/test/isolation/expected/create-index-concurrently-hot.out b/src/test/isolation/expected/create-index-concurrently-hot.out
new file mode 100644
index 0000000..af9eab6
--- /dev/null
+++ b/src/test/isolation/expected/create-index-concurrently-hot.out
@@ -0,0 +1,34 @@
+Parsed test spec with 4 sessions
+
+starting permutation: begin insert cic s4_begin s4_lock commit up s4_commit sel sel_s sel_d sel_i_e sel_i
+step begin: BEGIN;
+step insert: INSERT INTO t1 VALUES (2, 2, 2);
+step cic: CREATE INDEX CONCURRENTLY idx_conc_t1 ON t1(c2); <waiting ...>
+step s4_begin: BEGIN;
+step s4_lock: SELECT indrelid::regclass FROM pg_index WHERE indrelid = 't1'::regclass FOR UPDATE;
+indrelid       
+
+t1             
+step commit: COMMIT;
+step up: UPDATE t1 SET c2=5 WHERE c1=1;
+step s4_commit: COMMIT;
+step cic: <... completed>
+step sel: SELECT * FROM t1
+c1             c2             c3             
+
+2              2              2              
+1              5              3              
+step sel_s: SELECT * FROM t1 WHERE c2=5;
+c1             c2             c3             
+
+1              5              3              
+step sel_d: SET enable_seqscan = false;
+step sel_i_e: EXPLAIN (COSTS off) SELECT * FROM t1 WHERE c2=5;
+QUERY PLAN     
+
+Index Scan using idx_conc_t1 on t1
+  Index Cond: (c2 = 5)
+step sel_i: SELECT * FROM t1 WHERE c2=5;
+c1             c2             c3             
+
+1              5              3              
diff --git a/src/test/isolation/expected/drop-index-concurrently-1.out b/src/test/isolation/expected/drop-index-concurrently-1.out
deleted file mode 100644
index 8bedf13..0000000
--- a/src/test/isolation/expected/drop-index-concurrently-1.out
+++ /dev/null
@@ -1,40 +0,0 @@
-Parsed test spec with 3 sessions
-
-starting permutation: noseq prepi preps begin explaini explains select2 drop insert2 end2 selecti selects end
-step noseq: SET enable_seqscan = false;
-step prepi: PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data;
-step preps: PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data;
-step begin: BEGIN;
-step explaini: EXPLAIN (COSTS OFF) EXECUTE getrow_idx;
-QUERY PLAN     
-
-Sort           
-  Sort Key: id 
-  ->  Index Scan using test_dc_data on test_dc
-        Index Cond: (data = 34)
-step explains: EXPLAIN (COSTS OFF) EXECUTE getrow_seq;
-QUERY PLAN     
-
-Sort           
-  Sort Key: id, data
-  ->  Seq Scan on test_dc
-        Filter: ((data)::text = '34'::text)
-step select2: SELECT * FROM test_dc WHERE data=34 ORDER BY id,data;
-id             data           
-
-34             34             
-step drop: DROP INDEX CONCURRENTLY test_dc_data; <waiting ...>
-step insert2: INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100);
-step end2: COMMIT;
-step selecti: EXECUTE getrow_idx;
-id             data           
-
-34             34             
-134            34             
-step selects: EXECUTE getrow_seq;
-id             data           
-
-34             34             
-134            34             
-step end: COMMIT;
-step drop: <... completed>
diff --git a/src/test/isolation/expected/drop-index-concurrently-block.out b/src/test/isolation/expected/drop-index-concurrently-block.out
new file mode 100644
index 0000000..b630e70
--- /dev/null
+++ b/src/test/isolation/expected/drop-index-concurrently-block.out
@@ -0,0 +1,38 @@
+Parsed test spec with 6 sessions
+
+starting permutation: s1_begin s1_ds s1_sel s5_drop s2_begin s2_ds s2_sel s1_commit s3_begin s3_ds s3_sel s4_begin s4_ds s4_sel s2_commit s3_up s3_commit s6_up s4_commit
+step s1_begin: BEGIN;
+step s1_ds: SET enable_seqscan = false;
+step s1_sel: SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;
+c1             c2             c3             
+
+step s5_drop: DROP INDEX CONCURRENTLY idx_conc_t1; <waiting ...>
+step s2_begin: BEGIN;
+step s2_ds: SET enable_seqscan = false;
+step s2_sel: SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;
+c1             c2             c3             
+
+step s1_commit: COMMIT;
+step s3_begin: BEGIN;
+step s3_ds: SET enable_seqscan = false;
+step s3_sel: SELECT * FROM t1 WHERE c2 = 1 FOR UPDATE;
+c1             c2             c3             
+
+1              1              1              
+step s4_begin: BEGIN;
+step s4_ds: SET enable_seqscan = false;
+step s4_sel: SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;
+c1             c2             c3             
+
+step s2_commit: COMMIT;
+step s5_drop: <... completed>
+step s3_up: UPDATE t1 SET c3 = 3 WHERE c2 = 1 RETURNING *;
+c1             c2             c3             
+
+1              1              3              
+step s3_commit: COMMIT;
+step s6_up: UPDATE t1 SET c3 = 3 WHERE c2 = 2 RETURNING *;
+c1             c2             c3             
+
+2              2              3              
+step s4_commit: COMMIT;
diff --git a/src/test/isolation/expected/drop-index-concurrently-write.out b/src/test/isolation/expected/drop-index-concurrently-write.out
new file mode 100644
index 0000000..8bedf13
--- /dev/null
+++ b/src/test/isolation/expected/drop-index-concurrently-write.out
@@ -0,0 +1,40 @@
+Parsed test spec with 3 sessions
+
+starting permutation: noseq prepi preps begin explaini explains select2 drop insert2 end2 selecti selects end
+step noseq: SET enable_seqscan = false;
+step prepi: PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data;
+step preps: PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data;
+step begin: BEGIN;
+step explaini: EXPLAIN (COSTS OFF) EXECUTE getrow_idx;
+QUERY PLAN     
+
+Sort           
+  Sort Key: id 
+  ->  Index Scan using test_dc_data on test_dc
+        Index Cond: (data = 34)
+step explains: EXPLAIN (COSTS OFF) EXECUTE getrow_seq;
+QUERY PLAN     
+
+Sort           
+  Sort Key: id, data
+  ->  Seq Scan on test_dc
+        Filter: ((data)::text = '34'::text)
+step select2: SELECT * FROM test_dc WHERE data=34 ORDER BY id,data;
+id             data           
+
+34             34             
+step drop: DROP INDEX CONCURRENTLY test_dc_data; <waiting ...>
+step insert2: INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100);
+step end2: COMMIT;
+step selecti: EXECUTE getrow_idx;
+id             data           
+
+34             34             
+134            34             
+step selects: EXECUTE getrow_seq;
+id             data           
+
+34             34             
+134            34             
+step end: COMMIT;
+step drop: <... completed>
diff --git a/src/test/isolation/isolation_schedule b/src/test/isolation/isolation_schedule
index 1d0770c..ce62c36 100644
--- a/src/test/isolation/isolation_schedule
+++ b/src/test/isolation/isolation_schedule
@@ -14,4 +14,6 @@ test: fk-contention
 test: fk-deadlock
 test: fk-deadlock2
 test: eval-plan-qual
-test: drop-index-concurrently-1
+test: drop-index-concurrently-write
+test: drop-index-concurrently-block
+test: create-index-concurrently-hot
diff --git a/src/test/isolation/specs/create-index-concurrently-hot.spec b/src/test/isolation/specs/create-index-concurrently-hot.spec
new file mode 100644
index 0000000..3d31cdd
--- /dev/null
+++ b/src/test/isolation/specs/create-index-concurrently-hot.spec
@@ -0,0 +1,40 @@
+# Verify that HOT Updates work correctly during CREATE INDEX CONCURRENTLY.
+#
+# We schedule sessions in a way we block each phase of CIC individually so we
+# can fire an UPDATE in the problematic moment.
+
+setup
+{
+    CREATE TABLE t1(c1 int, c2 int, c3 int);
+	INSERT INTO t1(c1, c2, c3) VALUES(1,2,3);
+}
+
+teardown
+{
+    DROP TABLE t1;
+}
+
+session "s1"
+step "begin" { BEGIN; }
+step "insert" { INSERT INTO t1 VALUES (2, 2, 2); }
+step "commit" { COMMIT; }
+
+session "s2"
+step "cic" { CREATE INDEX CONCURRENTLY idx_conc_t1 ON t1(c2); }
+
+session "s3"
+step "up" { UPDATE t1 SET c2=5 WHERE c1=1; }
+step "sel" { SELECT * FROM t1 }
+step "sel_s" { SELECT * FROM t1 WHERE c2=5;}
+step "sel_d" { SET enable_seqscan = false;}
+step "sel_i_e" { EXPLAIN (COSTS off) SELECT * FROM t1 WHERE c2=5;}
+step "sel_i" { SELECT * FROM t1 WHERE c2=5;}
+
+session "s4"
+step "s4_begin" {BEGIN;}
+# lock pg_index row so inisread=true cannot be written to the heap, so we stop
+# in the right place for s3's "up" step.
+step "s4_lock" {SELECT indrelid::regclass FROM pg_index WHERE indrelid = 't1'::regclass FOR UPDATE;}
+step "s4_commit" {COMMIT;}
+
+permutation "begin" "insert" "cic" "s4_begin" "s4_lock" "commit" "up" "s4_commit" "sel" "sel_s" "sel_d" "sel_i_e" "sel_i"
diff --git a/src/test/isolation/specs/drop-index-concurrently-1.spec b/src/test/isolation/specs/drop-index-concurrently-1.spec
deleted file mode 100644
index 8ebe5e6..0000000
--- a/src/test/isolation/specs/drop-index-concurrently-1.spec
+++ /dev/null
@@ -1,38 +0,0 @@
-# DROP INDEX CONCURRENTLY
-#
-# This test shows that the concurrent write behaviour works correctly
-# with the expected output being 2 rows.
-#
-setup
-{
-	CREATE TABLE test_dc(id serial primary key, data int);
-	INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100);
-	CREATE INDEX test_dc_data ON test_dc(data);
-}
-
-teardown
-{
-	DROP TABLE test_dc;
-}
-
-session "s1"
-step "noseq" { SET enable_seqscan = false; }
-step "prepi" { PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
-step "preps" { PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data; }
-step "begin" { BEGIN; }
-step "explaini" { EXPLAIN (COSTS OFF) EXECUTE getrow_idx; }
-step "explains" { EXPLAIN (COSTS OFF) EXECUTE getrow_seq; }
-step "selecti" { EXECUTE getrow_idx; }
-step "selects" { EXECUTE getrow_seq; }
-step "end" { COMMIT; }
-
-session "s2"
-setup { BEGIN; }
-step "select2" { SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
-step "insert2" { INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100); }
-step "end2" { COMMIT; }
-
-session "s3"
-step "drop" { DROP INDEX CONCURRENTLY test_dc_data; }
-
-permutation "noseq" "prepi" "preps" "begin" "explaini" "explains" "select2" "drop" "insert2" "end2" "selecti" "selects" "end"
diff --git a/src/test/isolation/specs/drop-index-concurrently-block.spec b/src/test/isolation/specs/drop-index-concurrently-block.spec
new file mode 100644
index 0000000..c41fc8d
--- /dev/null
+++ b/src/test/isolation/specs/drop-index-concurrently-block.spec
@@ -0,0 +1,54 @@
+# Test whether DROP INDEX CONCURRENTLY actually works without block concurrent
+# changes to tables.
+#
+# FIXME: Unfortunately this blocks indefinitely if "s6_up" is blocked because
+# isolationtester currently can't wait for two sessions at the same time and we
+# are already waiting for "s5_drop".
+
+setup
+{
+    CREATE TABLE t1(c1 int, c2 int, c3 int);
+	INSERT INTO t1(c1, c2, c3) VALUES(1,1,1);
+	INSERT INTO t1(c1, c2, c3) VALUES(2,2,2);
+	INSERT INTO t1(c1, c2, c3) VALUES(3,3,3);
+	CREATE INDEX idx_conc_t1 ON t1(c1);
+	CREATE INDEX idx_conc_t2 ON t1(c2);
+}
+
+teardown
+{
+    DROP TABLE t1;
+}
+
+session "s1"
+step "s1_begin" { BEGIN; }
+step "s1_ds" { SET enable_seqscan = false;}
+step "s1_sel" { SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;}
+step "s1_commit" { COMMIT; }
+
+session "s2"
+step "s2_begin" { BEGIN; }
+step "s2_ds" { SET enable_seqscan = false;}
+step "s2_sel" { SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;}
+step "s2_commit" { COMMIT; }
+
+session "s3"
+step "s3_begin" { BEGIN; }
+step "s3_ds" { SET enable_seqscan = false;}
+step "s3_sel" { SELECT * FROM t1 WHERE c2 = 1 FOR UPDATE;}
+step "s3_up" { UPDATE t1 SET c3 = 3 WHERE c2 = 1 RETURNING *;}
+step "s3_commit" { COMMIT; }
+
+session "s4"
+step "s4_begin" { BEGIN; }
+step "s4_ds" { SET enable_seqscan = false;}
+step "s4_sel" { SELECT * FROM t1 WHERE c2 = -1 FOR UPDATE;}
+step "s4_commit" { COMMIT; }
+
+session "s5"
+step "s5_drop" { DROP INDEX CONCURRENTLY idx_conc_t1; }
+
+session "s6"
+step "s6_up" { UPDATE t1 SET c3 = 3 WHERE c2 = 2 RETURNING *;}
+
+permutation "s1_begin" "s1_ds" "s1_sel" "s5_drop" "s2_begin" "s2_ds" "s2_sel" "s1_commit" "s3_begin" "s3_ds" "s3_sel" "s4_begin" "s4_ds" "s4_sel" "s2_commit" "s3_up" "s3_commit" "s6_up""s4_commit"
diff --git a/src/test/isolation/specs/drop-index-concurrently-write.spec b/src/test/isolation/specs/drop-index-concurrently-write.spec
new file mode 100644
index 0000000..8ebe5e6
--- /dev/null
+++ b/src/test/isolation/specs/drop-index-concurrently-write.spec
@@ -0,0 +1,38 @@
+# DROP INDEX CONCURRENTLY
+#
+# This test shows that the concurrent write behaviour works correctly
+# with the expected output being 2 rows.
+#
+setup
+{
+	CREATE TABLE test_dc(id serial primary key, data int);
+	INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100);
+	CREATE INDEX test_dc_data ON test_dc(data);
+}
+
+teardown
+{
+	DROP TABLE test_dc;
+}
+
+session "s1"
+step "noseq" { SET enable_seqscan = false; }
+step "prepi" { PREPARE getrow_idx AS SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
+step "preps" { PREPARE getrow_seq AS SELECT * FROM test_dc WHERE data::text=34::text ORDER BY id,data; }
+step "begin" { BEGIN; }
+step "explaini" { EXPLAIN (COSTS OFF) EXECUTE getrow_idx; }
+step "explains" { EXPLAIN (COSTS OFF) EXECUTE getrow_seq; }
+step "selecti" { EXECUTE getrow_idx; }
+step "selects" { EXECUTE getrow_seq; }
+step "end" { COMMIT; }
+
+session "s2"
+setup { BEGIN; }
+step "select2" { SELECT * FROM test_dc WHERE data=34 ORDER BY id,data; }
+step "insert2" { INSERT INTO test_dc(data) SELECT * FROM generate_series(1, 100); }
+step "end2" { COMMIT; }
+
+session "s3"
+step "drop" { DROP INDEX CONCURRENTLY test_dc_data; }
+
+permutation "noseq" "prepi" "preps" "begin" "explaini" "explains" "select2" "drop" "insert2" "end2" "selecti" "selects" "end"
-- 
1.7.12.289.g0ce9864.dirty

