Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit c973051

Browse files
committed
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.
1 parent 1c2d408 commit c973051

File tree

4 files changed

+101
-32
lines changed

4 files changed

+101
-32
lines changed

src/backend/commands/indexcmds.c

Lines changed: 56 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.183 2009/03/31 22:12:47 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.184 2009/04/04 17:40:36 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -130,12 +130,14 @@ DefineIndex(RangeVar *heapRelation,
130130
int numberOfAttributes;
131131
VirtualTransactionId *old_lockholders;
132132
VirtualTransactionId *old_snapshots;
133+
int n_old_snapshots;
133134
LockRelId heaprelid;
134135
LOCKTAG heaplocktag;
135136
Snapshot snapshot;
136137
Relation pg_index;
137138
HeapTuple indexTuple;
138139
Form_pg_index indexForm;
140+
int i;
139141

140142
/*
141143
* count attributes in index
@@ -611,7 +613,7 @@ DefineIndex(RangeVar *heapRelation,
611613
* snapshot treats as committed. If such a recently-committed transaction
612614
* deleted tuples in the table, we will not include them in the index; yet
613615
* those transactions which see the deleting one as still-in-progress will
614-
* expect them to be there once we mark the index as valid.
616+
* expect such tuples to be there once we mark the index as valid.
615617
*
616618
* We solve this by waiting for all endangered transactions to exit before
617619
* we mark the index as valid.
@@ -634,10 +636,13 @@ DefineIndex(RangeVar *heapRelation,
634636
* transactions that might have older snapshots. Obtain a list of VXIDs
635637
* of such transactions, and wait for them individually.
636638
*
637-
* We can exclude any running transactions that have xmin >= the xmax of
638-
* our reference snapshot, since they are clearly not interested in any
639-
* missing older tuples. Transactions in other DBs aren't a problem
640-
* either, since they'll never even be able to see this index.
639+
* We can exclude any running transactions that have xmin > the xmin of
640+
* our reference snapshot; their oldest snapshot must be newer than ours.
641+
* We can also exclude any transactions that have xmin = zero, since they
642+
* evidently have no live snapshot at all (and any one they might be
643+
* in process of taking is certainly newer than ours). Transactions in
644+
* other DBs can be ignored too, since they'll never even be able to see
645+
* this index.
641646
*
642647
* We can also exclude autovacuum processes and processes running manual
643648
* lazy VACUUMs, because they won't be fazed by missing index entries
@@ -647,14 +652,54 @@ DefineIndex(RangeVar *heapRelation,
647652
*
648653
* Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
649654
* check for that.
655+
*
656+
* If a process goes idle-in-transaction with xmin zero, we do not need
657+
* to wait for it anymore, per the above argument. We do not have the
658+
* infrastructure right now to stop waiting if that happens, but we can
659+
* at least avoid the folly of waiting when it is idle at the time we
660+
* would begin to wait. We do this by repeatedly rechecking the output of
661+
* GetCurrentVirtualXIDs. If, during any iteration, a particular vxid
662+
* doesn't show up in the output, we know we can forget about it.
650663
*/
651-
old_snapshots = GetCurrentVirtualXIDs(snapshot->xmax, false,
652-
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM);
664+
old_snapshots = GetCurrentVirtualXIDs(snapshot->xmin, true, false,
665+
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
666+
&n_old_snapshots);
653667

654-
while (VirtualTransactionIdIsValid(*old_snapshots))
668+
for (i = 0; i < n_old_snapshots; i++)
655669
{
656-
VirtualXactLockTableWait(*old_snapshots);
657-
old_snapshots++;
670+
if (!VirtualTransactionIdIsValid(old_snapshots[i]))
671+
continue; /* found uninteresting in previous cycle */
672+
673+
if (i > 0)
674+
{
675+
/* see if anything's changed ... */
676+
VirtualTransactionId *newer_snapshots;
677+
int n_newer_snapshots;
678+
int j;
679+
int k;
680+
681+
newer_snapshots = GetCurrentVirtualXIDs(snapshot->xmin,
682+
true, false,
683+
PROC_IS_AUTOVACUUM | PROC_IN_VACUUM,
684+
&n_newer_snapshots);
685+
for (j = i; j < n_old_snapshots; j++)
686+
{
687+
if (!VirtualTransactionIdIsValid(old_snapshots[j]))
688+
continue; /* found uninteresting in previous cycle */
689+
for (k = 0; k < n_newer_snapshots; k++)
690+
{
691+
if (VirtualTransactionIdEquals(old_snapshots[j],
692+
newer_snapshots[k]))
693+
break;
694+
}
695+
if (k >= n_newer_snapshots) /* not there anymore */
696+
SetInvalidVirtualTransactionId(old_snapshots[j]);
697+
}
698+
pfree(newer_snapshots);
699+
}
700+
701+
if (VirtualTransactionIdIsValid(old_snapshots[i]))
702+
VirtualXactLockTableWait(old_snapshots[i]);
658703
}
659704

660705
/*

src/backend/storage/ipc/procarray.c

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
*
2424
*
2525
* IDENTIFICATION
26-
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.48 2009/03/31 05:18:33 heikki Exp $
26+
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.49 2009/04/04 17:40:36 tgl Exp $
2727
*
2828
*-------------------------------------------------------------------------
2929
*/
@@ -1022,25 +1022,42 @@ IsBackendPid(int pid)
10221022
/*
10231023
* GetCurrentVirtualXIDs -- returns an array of currently active VXIDs.
10241024
*
1025-
* The array is palloc'd and is terminated with an invalid VXID.
1025+
* The array is palloc'd. The number of valid entries is returned into *nvxids.
10261026
*
1027-
* If limitXmin is not InvalidTransactionId, we skip any backends
1028-
* with xmin >= limitXmin. If allDbs is false, we skip backends attached
1029-
* to other databases. If excludeVacuum isn't zero, we skip processes for
1030-
* which (excludeVacuum & vacuumFlags) is not zero. Also, our own process
1031-
* is always skipped.
1027+
* The arguments allow filtering the set of VXIDs returned. Our own process
1028+
* is always skipped. In addition:
1029+
* If limitXmin is not InvalidTransactionId, skip processes with
1030+
* xmin > limitXmin.
1031+
* If excludeXmin0 is true, skip processes with xmin = 0.
1032+
* If allDbs is false, skip processes attached to other databases.
1033+
* If excludeVacuum isn't zero, skip processes for which
1034+
* (vacuumFlags & excludeVacuum) is not zero.
1035+
*
1036+
* Note: the purpose of the limitXmin and excludeXmin0 parameters is to
1037+
* allow skipping backends whose oldest live snapshot is no older than
1038+
* some snapshot we have. Since we examine the procarray with only shared
1039+
* lock, there are race conditions: a backend could set its xmin just after
1040+
* we look. Indeed, on multiprocessors with weak memory ordering, the
1041+
* other backend could have set its xmin *before* we look. We know however
1042+
* that such a backend must have held shared ProcArrayLock overlapping our
1043+
* own hold of ProcArrayLock, else we would see its xmin update. Therefore,
1044+
* any snapshot the other backend is taking concurrently with our scan cannot
1045+
* consider any transactions as still running that we think are committed
1046+
* (since backends must hold ProcArrayLock exclusive to commit).
10321047
*/
10331048
VirtualTransactionId *
1034-
GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs, int excludeVacuum)
1049+
GetCurrentVirtualXIDs(TransactionId limitXmin, bool excludeXmin0,
1050+
bool allDbs, int excludeVacuum,
1051+
int *nvxids)
10351052
{
10361053
VirtualTransactionId *vxids;
10371054
ProcArrayStruct *arrayP = procArray;
10381055
int count = 0;
10391056
int index;
10401057

1041-
/* allocate result space with room for a terminator */
1058+
/* allocate what's certainly enough result space */
10421059
vxids = (VirtualTransactionId *)
1043-
palloc(sizeof(VirtualTransactionId) * (arrayP->maxProcs + 1));
1060+
palloc(sizeof(VirtualTransactionId) * arrayP->maxProcs);
10441061

10451062
LWLockAcquire(ProcArrayLock, LW_SHARED);
10461063

@@ -1056,15 +1073,18 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs, int excludeVacuum)
10561073

10571074
if (allDbs || proc->databaseId == MyDatabaseId)
10581075
{
1059-
/* Fetch xmin just once - might change on us? */
1076+
/* Fetch xmin just once - might change on us */
10601077
TransactionId pxmin = proc->xmin;
10611078

1079+
if (excludeXmin0 && !TransactionIdIsValid(pxmin))
1080+
continue;
1081+
10621082
/*
1063-
* Note that InvalidTransactionId precedes all other XIDs, so a
1064-
* proc that hasn't set xmin yet will always be included.
1083+
* InvalidTransactionId precedes all other XIDs, so a proc that
1084+
* hasn't set xmin yet will not be rejected by this test.
10651085
*/
10661086
if (!TransactionIdIsValid(limitXmin) ||
1067-
TransactionIdPrecedes(pxmin, limitXmin))
1087+
TransactionIdPrecedesOrEquals(pxmin, limitXmin))
10681088
{
10691089
VirtualTransactionId vxid;
10701090

@@ -1077,10 +1097,7 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs, int excludeVacuum)
10771097

10781098
LWLockRelease(ProcArrayLock);
10791099

1080-
/* add the terminator */
1081-
vxids[count].backendId = InvalidBackendId;
1082-
vxids[count].localTransactionId = InvalidLocalTransactionId;
1083-
1100+
*nvxids = count;
10841101
return vxids;
10851102
}
10861103

src/include/storage/lock.h

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.115 2009/01/01 17:24:01 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/lock.h,v 1.116 2009/04/04 17:40:36 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -67,6 +67,12 @@ typedef struct
6767
#define VirtualTransactionIdIsValid(vxid) \
6868
(((vxid).backendId != InvalidBackendId) && \
6969
LocalTransactionIdIsValid((vxid).localTransactionId))
70+
#define VirtualTransactionIdEquals(vxid1, vxid2) \
71+
((vxid1).backendId == (vxid2).backendId && \
72+
(vxid1).localTransactionId == (vxid2).localTransactionId)
73+
#define SetInvalidVirtualTransactionId(vxid) \
74+
((vxid).backendId = InvalidBackendId, \
75+
(vxid).localTransactionId = InvalidLocalTransactionId)
7076
#define GET_VXID_FROM_PGPROC(vxid, proc) \
7177
((vxid).backendId = (proc).backendId, \
7278
(vxid).localTransactionId = (proc).lxid)

src/include/storage/procarray.h

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.24 2009/01/01 17:24:01 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.25 2009/04/04 17:40:36 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -40,7 +40,8 @@ extern int BackendXidGetPid(TransactionId xid);
4040
extern bool IsBackendPid(int pid);
4141

4242
extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
43-
bool allDbs, int excludeVacuum);
43+
bool excludeXmin0, bool allDbs, int excludeVacuum,
44+
int *nvxids);
4445
extern int CountActiveBackends(void);
4546
extern int CountDBBackends(Oid databaseid);
4647
extern int CountUserBackends(Oid roleid);

0 commit comments

Comments
 (0)