summaryrefslogtreecommitdiff
path: root/src/backend/commands
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2013-04-25 16:58:19 -0400
committerTom Lane <tgl@sss.pgh.pa.us>2013-04-25 16:58:19 -0400
commit0dcff7560a2f6c70313447b948c35f94193bc656 (patch)
tree78c8c0a0475496b81457b173cb4ad573e5b6a95f /src/backend/commands
parentfe1d8c1fe705a8a881bc98feeca1b52a26e9475b (diff)
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.
Diffstat (limited to 'src/backend/commands')
-rw-r--r--src/backend/commands/indexcmds.c23
1 files changed, 15 insertions, 8 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index d2169f029ac..441b99fa243 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -141,6 +141,7 @@ DefineIndex(RangeVar *heapRelation,
int16 *coloptions;
IndexInfo *indexInfo;
int numberOfAttributes;
+ TransactionId limitXmin;
VirtualTransactionId *old_lockholders;
VirtualTransactionId *old_snapshots;
int n_old_snapshots;
@@ -641,6 +642,18 @@ DefineIndex(RangeVar *heapRelation,
validate_index(relationId, indexRelationId, snapshot);
/*
+ * Drop the reference snapshot. We must do this before waiting out other
+ * snapshot holders, else we will deadlock against other processes also
+ * 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().
+ */
+ limitXmin = snapshot->xmin;
+
+ PopActiveSnapshot();
+ UnregisterSnapshot(snapshot);
+
+ /*
* The index is now valid in the sense that it contains all currently
* interesting tuples. But since it might not contain tuples deleted just
* before the reference snap was taken, we have to wait out any
@@ -672,7 +685,7 @@ DefineIndex(RangeVar *heapRelation,
* GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
* doesn't show up in the output, we know we can forget about it.
*/
- old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false,
+ old_snapshots = GetCurrentVirtualXIDs(limitXmin, true, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
&n_old_snapshots);
@@ -689,7 +702,7 @@ DefineIndex(RangeVar *heapRelation,
int j;
int k;
- newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin,
+ newer_snapshots = GetCurrentVirtualXIDs(limitXmin,
true, false,
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
&n_newer_snapshots);
@@ -728,12 +741,6 @@ DefineIndex(RangeVar *heapRelation,
*/
CacheInvalidateRelcacheByRelid(heaprelid.relId);
- /* we can now do away with our active snapshot */
- PopActiveSnapshot();
-
- /* And we can remove the validating snapshot too */
- UnregisterSnapshot(snapshot);
-
/*
* Last thing to do is release the session-level lock on the parent table.
*/