diff options
Diffstat (limited to 'src/backend/commands/indexcmds.c')
-rw-r--r-- | src/backend/commands/indexcmds.c | 67 |
1 files changed, 56 insertions, 11 deletions
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c index ab075090819..f2ff5b6da21 100644 --- a/src/backend/commands/indexcmds.c +++ b/src/backend/commands/indexcmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.183 2009/03/31 22:12:47 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.184 2009/04/04 17:40:36 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -130,12 +130,14 @@ DefineIndex(RangeVar *heapRelation, int numberOfAttributes; VirtualTransactionId *old_lockholders; VirtualTransactionId *old_snapshots; + int n_old_snapshots; LockRelId heaprelid; LOCKTAG heaplocktag; Snapshot snapshot; Relation pg_index; HeapTuple indexTuple; Form_pg_index indexForm; + int i; /* * count attributes in index @@ -611,7 +613,7 @@ DefineIndex(RangeVar *heapRelation, * snapshot treats as committed. If such a recently-committed transaction * deleted tuples in the table, we will not include them in the index; yet * those transactions which see the deleting one as still-in-progress will - * expect them to be there once we mark the index as valid. + * expect such tuples to be there once we mark the index as valid. * * We solve this by waiting for all endangered transactions to exit before * we mark the index as valid. @@ -634,10 +636,13 @@ DefineIndex(RangeVar *heapRelation, * transactions that might have older snapshots. Obtain a list of VXIDs * of such transactions, and wait for them individually. * - * We can exclude any running transactions that have xmin >= the xmax of - * our reference snapshot, since they are clearly not interested in any - * missing older tuples. Transactions in other DBs aren't a problem - * either, since they'll never even be able to see this index. + * We can exclude any running transactions that have xmin > the xmin of + * our reference snapshot; their oldest snapshot must be newer than ours. + * We can also exclude any transactions that have xmin = zero, since they + * evidently have no live snapshot at all (and any one they might be + * in process of taking is certainly newer than ours). Transactions in + * other DBs can be ignored too, since they'll never even be able to see + * this index. * * We can also exclude autovacuum processes and processes running manual * lazy VACUUMs, because they won't be fazed by missing index entries @@ -647,14 +652,54 @@ DefineIndex(RangeVar *heapRelation, * * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not * check for that. + * + * If a process goes idle-in-transaction with xmin zero, we do not need + * to wait for it anymore, per the above argument. We do not have the + * infrastructure right now to stop waiting if that happens, but we can + * at least avoid the folly of waiting when it is idle at the time we + * would begin to wait. We do this by repeatedly rechecking the output of + * 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->xmax, false, - PROC_IS_AUTOVACUUM | PROC_IN_VACUUM); + old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + &n_old_snapshots); - while (VirtualTransactionIdIsValid(*old_snapshots)) + for (i = 0; i < n_old_snapshots; i++) { - VirtualXactLockTableWait(*old_snapshots); - old_snapshots++; + if (!VirtualTransactionIdIsValid(old_snapshots[i])) + continue; /* found uninteresting in previous cycle */ + + if (i > 0) + { + /* see if anything's changed ... */ + VirtualTransactionId *newer_snapshots; + int n_newer_snapshots; + int j; + int k; + + newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, + true, false, + PROC_IS_AUTOVACUUM | PROC_IN_VACUUM, + &n_newer_snapshots); + for (j = i; j < n_old_snapshots; j++) + { + if (!VirtualTransactionIdIsValid(old_snapshots[j])) + continue; /* found uninteresting in previous cycle */ + for (k = 0; k < n_newer_snapshots; k++) + { + if (VirtualTransactionIdEquals(old_snapshots[j], + newer_snapshots[k])) + break; + } + if (k >= n_newer_snapshots) /* not there anymore */ + SetInvalidVirtualTransactionId(old_snapshots[j]); + } + pfree(newer_snapshots); + } + + if (VirtualTransactionIdIsValid(old_snapshots[i])) + VirtualXactLockTableWait(old_snapshots[i]); } /* |