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)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy