]> granicus.if.org Git - postgresql/commitdiff
Fix deadlock hazard in CREATE INDEX CONCURRENTLY
authorAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 2 Jan 2018 22:16:16 +0000 (19:16 -0300)
committerAlvaro Herrera <alvherre@alvh.no-ip.org>
Tue, 2 Jan 2018 22:16:16 +0000 (19:16 -0300)
Multiple sessions doing CREATE INDEX CONCURRENTLY simultaneously are
supposed to be able to work in parallel, as evidenced by fixes in commit
c3d09b3bd23f specifically to support this case.  In reality, one of the
sessions would be aborted by a misterious "deadlock detected" error.

Jeff Janes diagnosed that this is because of leftover snapshots used for
system catalog scans -- this was broken by 8aa3e47510b9 keeping track of
(registering) the catalog snapshot.  To fix the deadlocks, it's enough
to de-register that snapshot prior to waiting.

Backpatch to 9.4, which introduced MVCC catalog scans.

Include an isolationtester spec that 8 out of 10 times reproduces the
deadlock with the unpatched code for me (Álvaro).

Author: Jeff Janes
Diagnosed-by: Jeff Janes
Reported-by: Jeremy Finzel
Discussion: https://postgr.es/m/CAMa1XUhHjCv8Qkx0WOr1Mpm_R4qxN26EibwCrj0Oor2YBUFUTg%40mail.gmail.com

src/backend/commands/indexcmds.c
src/test/isolation/expected/multiple-cic.out [new file with mode: 0644]
src/test/isolation/isolation_schedule
src/test/isolation/specs/multiple-cic.spec [new file with mode: 0644]

index 97091dd9fbd98b079aecc9a986d039420e9a0dd8..ffa99aec16d35f712d8e5e28961b1938c28f17d0 100644 (file)
@@ -856,11 +856,14 @@ DefineIndex(Oid relationId,
         * doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
         * they must wait for.  But first, save the snapshot's xmin to use as
         * limitXmin for GetCurrentVirtualXIDs().
+        *
+        * Our catalog snapshot could have the same effect, so drop that one too.
         */
        limitXmin = snapshot->xmin;
 
        PopActiveSnapshot();
        UnregisterSnapshot(snapshot);
+       InvalidateCatalogSnapshot();
 
        /*
         * The index is now valid in the sense that it contains all currently
diff --git a/src/test/isolation/expected/multiple-cic.out b/src/test/isolation/expected/multiple-cic.out
new file mode 100644 (file)
index 0000000..cc57940
--- /dev/null
@@ -0,0 +1,19 @@
+Parsed test spec with 2 sessions
+
+starting permutation: s2l s1i s2i
+step s2l: SELECT pg_advisory_lock(281457);
+pg_advisory_lock
+
+               
+step s1i: 
+               CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id)
+               WHERE lck_shr(281457);
+ <waiting ...>
+step s2i: 
+               CREATE INDEX CONCURRENTLY mcic_two_pkey ON mcic_two (id)
+               WHERE unlck();
+
+step s1i: <... completed>
+s1             
+
+               
index eb566ebb6c13afc3be57f995c219b16f363252b0..befe6768160e0782ef82df0e167d7a8817663ad3 100644 (file)
@@ -55,6 +55,7 @@ test: skip-locked-2
 test: skip-locked-3
 test: skip-locked-4
 test: drop-index-concurrently-1
+test: multiple-cic
 test: alter-table-1
 test: alter-table-2
 test: alter-table-3
diff --git a/src/test/isolation/specs/multiple-cic.spec b/src/test/isolation/specs/multiple-cic.spec
new file mode 100644 (file)
index 0000000..a7ba4eb
--- /dev/null
@@ -0,0 +1,40 @@
+# Test multiple CREATE INDEX CONCURRENTLY working simultaneously
+
+setup
+{
+  CREATE TABLE mcic_one (
+       id int
+  );
+  CREATE TABLE mcic_two (
+       id int
+  );
+  CREATE FUNCTION lck_shr(bigint) RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$
+     BEGIN PERFORM pg_advisory_lock_shared($1); RETURN true; END;
+  $$;
+  CREATE FUNCTION unlck() RETURNS bool IMMUTABLE LANGUAGE plpgsql AS $$
+     BEGIN PERFORM pg_advisory_unlock_all(); RETURN true; END;
+  $$;
+}
+teardown
+{
+  DROP TABLE mcic_one, mcic_two;
+  DROP FUNCTION lck_shr(bigint);
+  DROP FUNCTION unlck();
+}
+
+session "s1"
+step "s1i"     {
+               CREATE INDEX CONCURRENTLY mcic_one_pkey ON mcic_one (id)
+               WHERE lck_shr(281457);
+       }
+teardown       { SELECT pg_advisory_unlock_all() AS "s1"; }
+
+
+session "s2"
+step "s2l"  { SELECT pg_advisory_lock(281457); }
+step "s2i"     {
+               CREATE INDEX CONCURRENTLY mcic_two_pkey ON mcic_two (id)
+               WHERE unlck();
+       }
+
+permutation "s2l" "s1i" "s2i"