Skip to content

Commit 32ad1d6

Browse files
committed
Avoid deadlock between concurrent CREATE INDEX CONCURRENTLY commands.
There was a high probability of two or more concurrent C.I.C. commands deadlocking just before completion, because each would wait for the others to release their reference snapshots. Fix by releasing the snapshot before waiting for other snapshots to go away. Per report from Paul Hinze. Back-patch to all active branches.
1 parent ae76795 commit 32ad1d6

File tree

1 file changed

+15
-8
lines changed

1 file changed

+15
-8
lines changed

src/backend/commands/indexcmds.c

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ DefineIndex(RangeVar *heapRelation,
142142
int16 *coloptions;
143143
IndexInfo *indexInfo;
144144
int numberOfAttributes;
145+
TransactionId limitXmin;
145146
VirtualTransactionId *old_lockholders;
146147
VirtualTransactionId *old_snapshots;
147148
int n_old_snapshots;
@@ -576,6 +577,18 @@ DefineIndex(RangeVar *heapRelation,
576577
*/
577578
validate_index(relationId, indexRelationId, snapshot);
578579

580+
/*
581+
* Drop the reference snapshot. We must do this before waiting out other
582+
* snapshot holders, else we will deadlock against other processes also
583+
* doing CREATE INDEX CONCURRENTLY, which would see our snapshot as one
584+
* they must wait for. But first, save the snapshot's xmin to use as
585+
* limitXmin for GetCurrentVirtualXIDs().
586+
*/
587+
limitXmin = snapshot->xmin;
588+
589+
PopActiveSnapshot();
590+
UnregisterSnapshot(snapshot);
591+
579592
/*
580593
* The index is now valid in the sense that it contains all currently
581594
* interesting tuples. But since it might not contain tuples deleted just
@@ -608,7 +621,7 @@ DefineIndex(RangeVar *heapRelation,
608621
* GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
609622
* doesn't show up in the output, we know we can forget about it.
610623
*/
611-
old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false,
624+
old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
612625
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
613626
&n_old_snapshots);
614627

@@ -625,7 +638,7 @@ DefineIndex(RangeVar *heapRelation,
625638
int j;
626639
int k;
627640

628-
newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin,
641+
newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
629642
true, false,
630643
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
631644
&n_newer_snapshots);
@@ -664,12 +677,6 @@ DefineIndex(RangeVar *heapRelation,
664677
*/
665678
CacheInvalidateRelcacheByRelid(heaprelid.relId);
666679

667-
/* we can now do away with our active snapshot */
668-
PopActiveSnapshot();
669-
670-
/* And we can remove the validating snapshot too */
671-
UnregisterSnapshot(snapshot);
672-
673680
/*
674681
* Last thing to do is release the session-level lock on the parent table.
675682
*/

0 commit comments

Comments
 (0)