Fix CREATE INDEX CONCURRENTLY to not deadlock against an automatic or manual
authorTom Lane <tgl@sss.pgh.pa.us>
Wed, 9 Jan 2008 21:52:36 +0000 (21:52 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Wed, 9 Jan 2008 21:52:36 +0000 (21:52 +0000)
VACUUM that is blocked waiting to get lock on the table being indexed.
Per report and fix suggestion from Greg Stark.

src/backend/commands/indexcmds.c
src/backend/storage/ipc/procarray.c
src/include/storage/procarray.h

index 6d6a6d0e1ae808123050669522a9977697f0ae03..e9d64b22f3eed30dad4ba214df3ea074b6fcc35f 100644 (file)
@@ -38,6 +38,7 @@
 #include "parser/parse_expr.h"
 #include "parser/parse_func.h"
 #include "parser/parsetree.h"
+#include "storage/proc.h"
 #include "storage/procarray.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -630,11 +631,19 @@ 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.  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.
+        * either, 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
+        * either.  (Manual ANALYZEs, however, can't be excluded because they
+        * might be within transactions that are going to do arbitrary operations
+        * later.)
+        *
+        * Also, GetCurrentVirtualXIDs never reports our own vxid, so we need not
+        * check for that.
         */
-       old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax, false);
+       old_snapshots = GetCurrentVirtualXIDs(ActiveSnapshot->xmax, false,
+                                                                                 PROC_IS_AUTOVACUUM | PROC_IN_VACUUM);
 
        while (VirtualTransactionIdIsValid(*old_snapshots))
        {
index c19638b61f66731c431f12fada485275cdc69a71..69bb1614d43dabf20b8e17ff915cc3cbf690056f 100644 (file)
@@ -1006,10 +1006,12 @@ IsBackendPid(int pid)
  *
  * If limitXmin is not InvalidTransactionId, we skip any backends
  * with xmin >= limitXmin.     If allDbs is false, we skip backends attached
- * to other databases. Also, our own process is always skipped.
+ * to other databases.  If excludeVacuum isn't zero, we skip processes for
+ * which (excludeVacuum & vacuumFlags) is not zero.  Also, our own process
+ * is always skipped.
  */
 VirtualTransactionId *
-GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs)
+GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs, int excludeVacuum)
 {
        VirtualTransactionId *vxids;
        ProcArrayStruct *arrayP = procArray;
@@ -1029,6 +1031,9 @@ GetCurrentVirtualXIDs(TransactionId limitXmin, bool allDbs)
                if (proc == MyProc)
                        continue;
 
+               if (excludeVacuum & proc->vacuumFlags)
+                       continue;
+
                if (allDbs || proc->databaseId == MyDatabaseId)
                {
                        /* Fetch xmin just once - might change on us? */
index 405e046fa82baf3e4edda49ba56c957fd5ba40a8..567ea6465440fdd8c7b84761e84bfb73e9f8bbea 100644 (file)
@@ -37,7 +37,7 @@ extern int    BackendXidGetPid(TransactionId xid);
 extern bool IsBackendPid(int pid);
 
 extern VirtualTransactionId *GetCurrentVirtualXIDs(TransactionId limitXmin,
-                                         bool allDbs);
+                                         bool allDbs, int excludeVacuum);
 extern int     CountActiveBackends(void);
 extern int     CountDBBackends(Oid databaseid);
 extern int     CountUserBackends(Oid roleid);