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; @@ -640,6 +641,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 @@ -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. */