Allow CREATE INDEX CONCURRENTLY to disregard transactions in other

databases, per gripe from hubert depesz lubaczewski.  Patch from
Simon Riggs.
This commit is contained in:
Tom Lane 2007-09-07 00:58:57 +00:00
parent f8942f4a15
commit cd1aae5864
4 changed files with 33 additions and 24 deletions

View File

@ -1,5 +1,5 @@
<!--
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.63 2007/06/03 17:05:53 tgl Exp $
$PostgreSQL: pgsql/doc/src/sgml/ref/create_index.sgml,v 1.64 2007/09/07 00:58:56 tgl Exp $
PostgreSQL documentation
-->
@ -308,7 +308,7 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] <replaceable class="parameter">name</re
table. Other transactions can still read the table, but if they try to
insert, update, or delete rows in the table they will block until the
index build is finished. This could have a severe effect if the system is
a live production database. Large tables can take many hours to be
a live production database. Very large tables can take many hours to be
indexed, and even for smaller tables, an index build can lock out writers
for periods that are unacceptably long for a production system.
</para>
@ -319,7 +319,8 @@ CREATE [ UNIQUE ] INDEX [ CONCURRENTLY ] <replaceable class="parameter">name</re
<literal>CONCURRENTLY</> option of <command>CREATE INDEX</>.
When this option is used,
<productname>PostgreSQL</> must perform two scans of the table, and in
addition it must wait for all existing transactions to terminate. Thus
addition it must wait for all existing transactions that could potentially
use the index to terminate. Thus
this method requires more total work than a standard index build and takes
significantly longer to complete. However, since it allows normal
operations to continue while the index is built, this method is useful for

View File

@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.163 2007/09/05 18:10:47 tgl Exp $
* $PostgreSQL: pgsql/src/backend/commands/indexcmds.c,v 1.164 2007/09/07 00:58:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -535,10 +535,12 @@ DefineIndex(RangeVar *heapRelation,
*
* 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. Also, GetCurrentVirtualXIDs never reports our
* own vxid, so we need not check for that.
* missing older tuples. Transactions in other DBs aren't a problem
* either, since they'll never even be able to see this index.
* Also, GetCurrentVirtualXIDs never reports our own vxid, so we
* need not check for that.
*/
old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax);
old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax, false);
while (VirtualTransactionIdIsValid(*old_snapshots))
{

View File

@ -23,7 +23,7 @@
*
*
* IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.30 2007/09/05 21:11:19 tgl Exp $
* $PostgreSQL: pgsql/src/backend/storage/ipc/procarray.c,v 1.31 2007/09/07 00:58:56 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -891,10 +891,11 @@ IsBackendPid(int pid)
* The array is palloc'd and is terminated with an invalid VXID.
*
* If limitXmin is not InvalidTransactionId, we skip any backends
* with xmin >= limitXmin. Also, our own process is always skipped.
* with xmin >= limitXmin. If allDbs is false, we skip backends attached
* to other databases. Also, our own process is always skipped.
*/
VirtualTransactionId *
GetCurrentVirtualXIDs(TransactionId limitXmin)
GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs)
{
VirtualTransactionId *vxids;
ProcArrayStruct *arrayP = procArray;
@ -910,24 +911,28 @@ GetCurrentVirtualXIDs(TransactionId limitXmin)
for (index = 0; index < arrayP->numProcs; index++)
{
volatile PGPROC *proc = arrayP->procs[index];
/* Fetch xmin just once - might change on us? */
TransactionId pxmin = proc->xmin;
if (proc == MyProc)
continue;
/*
* Note that InvalidTransactionId precedes all other XIDs, so a
* proc that hasn't set xmin yet will always be included.
*/
if (!TransactionIdIsValid(limitXmin) ||
TransactionIdPrecedes(pxmin, limitXmin))
if (allDbs || proc->databaseId == MyDatabaseId)
{
VirtualTransactionId vxid;
/* Fetch xmin just once - might change on us? */
TransactionId pxmin = proc->xmin;
GET_VXID_FROM_PGPROC(vxid, *proc);
if (VirtualTransactionIdIsValid(vxid))
vxids[count++] = vxid;
/*
* Note that InvalidTransactionId precedes all other XIDs, so a
* proc that hasn't set xmin yet will always be included.
*/
if (!TransactionIdIsValid(limitXmin) ||
TransactionIdPrecedes(pxmin, limitXmin))
{
VirtualTransactionId vxid;
GET_VXID_FROM_PGPROC(vxid, *proc);
if (VirtualTransactionIdIsValid(vxid))
vxids[count++] = vxid;
}
}
}

View File

@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
* $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.15 2007/09/05 18:10:48 tgl Exp $
* $PostgreSQL: pgsql/src/include/storage/procarray.h,v 1.16 2007/09/07 00:58:57 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@ -33,7 +33,8 @@ extern PGPROC *BackendPidGetProc(int pid);
extern int BackendXidGetPid(TransactionId xid);
extern bool IsBackendPid(int pid);
extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin);
extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
bool allDbs);
extern int CountActiveBackends(void);
extern int CountDBBackends(Oid databaseid);
extern int CountUserBackends(Oid roleid);