mirror of
https://github.com/postgres/postgres.git
synced 2025-08-24 09:27:52 +03:00
A session that does not have any live snapshots does not have to be waited for
when we are waiting for old snapshots to go away during a concurrent index build. In particular, this rule lets us avoid waiting for idle-in-transaction sessions. This logic could be improved further if we had some way to wake up when the session we are currently waiting for goes idle-in-transaction. However that would be a significantly more complex/invasive patch, so it'll have to wait for some other day. Simon Riggs, with some improvements by Tom.
This commit is contained in:
@@ -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]);
|
||||
}
|
||||
|
||||
/*
|
||||
|
Reference in New Issue
Block a user