Allow CREATE INDEX CONCURRENTLY to disregard transactions in other
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Sep 2007 00:58:57 +0000 (00:58 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 7 Sep 2007 00:58:57 +0000 (00:58 +0000)
databases, per gripe from hubert depesz lubaczewski.  Patch from
Simon Riggs.

doc/src/sgml/ref/create_index.sgml
src/backend/commands/indexcmds.c
src/backend/storage/ipc/procarray.c
src/include/storage/procarray.h

index 23eec80c1ec8e14f7a1308b8f7af665d74ece932..c341db255a7fee037b0bd3125860a1b3018dc18d 100644 (file)
@@ -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
index cf564a50a123df1e4a830450ea85a939b12434a8..d918d839316c20315ec3e17670f039ab77419999 100644 (file)
@@ -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))
        {
index 821bdf4ca223b2ec695ffeec92d16bf04f64203b..19a2f56a5528aa6be4db6970dc2581bac817b604 100644 (file)
@@ -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;
+
+                       /*
+                        * 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;
+                               GET_VXID_FROM_PGPROC(vxid, *proc);
+                               if (VirtualTransactionIdIsValid(vxid))
+                                       vxids[count++] = vxid;
+                       }
                }
        }
 
index 08e2d1f03205ac85c22f94ec8f84cc457b863f6f..12e7a40bf1ad69fdc7f2e67b0043d2e96950921a 100644 (file)
@@ -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);