Index: src/backend/storage/lmgr/deadlock.c =================================================================== RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/storage/lmgr/deadlock.c,v retrieving revision 1.48 diff -c -p -r1.48 deadlock.c *** src/backend/storage/lmgr/deadlock.c 19 Jun 2007 20:13:21 -0000 1.48 --- src/backend/storage/lmgr/deadlock.c 25 Oct 2007 20:06:36 -0000 *************** static int maxPossibleConstraints; *** 109,114 **** --- 109,117 ---- static DEADLOCK_INFO *deadlockDetails; static int nDeadlockDetails; + /* PGPROC pointer of any blocking av worker found */ + static PGPROC *blocking_autovacuum_proc = NULL; + /* * InitDeadLockChecking -- initialize deadlock checker during backend startup *************** DeadLockCheck(PGPROC *proc) *** 206,211 **** --- 209,217 ---- nPossibleConstraints = 0; nWaitOrders = 0; + /* Initialize to not blocked by an autovacuum worker */ + blocking_autovacuum_proc = NULL; + /* Search for deadlocks and possible fixes */ if (DeadLockCheckRecurse(proc)) { *************** DeadLockCheck(PGPROC *proc) *** 255,265 **** --- 261,289 ---- /* Return code tells caller if we had to escape a deadlock or not */ if (nWaitOrders > 0) return DS_SOFT_DEADLOCK; + else if (blocking_autovacuum_proc != NULL) + return DS_BLOCKED_BY_AUTOVACUUM; else return DS_NO_DEADLOCK; } /* + * Return the PGPROC of the autovacuum that's blocking a process. + * + * We reset the saved pointer as soon as we pass it back. + */ + PGPROC * + GetBlockingAutoVacuumPgproc(void) + { + PGPROC *ptr; + + ptr = blocking_autovacuum_proc; + blocking_autovacuum_proc = NULL; + + return ptr; + } + + /* * DeadLockCheckRecurse -- recursively search for valid orderings * * curConstraints[] holds the current set of constraints being considered *************** FindLockCycleRecurse(PGPROC *checkProc, *** 497,502 **** --- 521,534 ---- if ((proclock->holdMask & LOCKBIT_ON(lm)) && (conflictMask & LOCKBIT_ON(lm))) { + /* + * Look for a blocking autovacuum. There will only ever + * be one, since the autovacuum workers are careful + * not to operate concurrently on the same table. + */ + if (proc->vacuumFlags & PROC_IS_AUTOVACUUM) + blocking_autovacuum_proc = proc; + /* This proc hard-blocks checkProc */ if (FindLockCycleRecurse(proc, depth + 1, softEdges, nSoftEdges)) Index: src/backend/storage/lmgr/proc.c =================================================================== RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/storage/lmgr/proc.c,v retrieving revision 1.195 diff -c -p -r1.195 proc.c *** src/backend/storage/lmgr/proc.c 24 Oct 2007 20:55:36 -0000 1.195 --- src/backend/storage/lmgr/proc.c 25 Oct 2007 20:03:58 -0000 *************** ProcSleep(LOCALLOCK *locallock, LockMeth *** 734,739 **** --- 734,740 ---- PROC_QUEUE *waitQueue = &(lock->waitProcs); LOCKMASK myHeldLocks = MyProc->heldLocks; bool early_deadlock = false; + bool allow_autovacuum_cancel = true; int myWaitStatus; PGPROC *proc; int i; *************** ProcSleep(LOCALLOCK *locallock, LockMeth *** 894,899 **** --- 895,949 ---- myWaitStatus = MyProc->waitStatus; /* + * If we are not deadlocked, but are waiting on an autovacuum-induced + * task, send a signal to interrupt it. + */ + if (deadlock_state == DS_BLOCKED_BY_AUTOVACUUM && allow_autovacuum_cancel) + { + PGPROC *autovac = GetBlockingAutoVacuumPgproc(); + + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + + /* + * only do it if the worker is not working to protect against Xid + * wraparound + */ + if ((autovac != NULL) && + !(autovac->vacuumFlags & PROC_VACUUM_FOR_WRAPAROUND)) + { + int pid = autovac->pid; + + elog(DEBUG2, "sending cancel to blocking autovacuum pid = %d", + pid); + + /* don't hold the lock across the kill() syscall */ + LWLockRelease(ProcArrayLock); + + /* + * Send the autovacuum worker Back to Old Kent Road + * + * If we have setsid(), signal the backend's whole process group + */ + #ifdef HAVE_SETSID + if (kill(-pid, SIGINT)) + #else + if (kill(pid, SIGINT)) + #endif + { + /* Just a warning to allow multiple callers */ + ereport(WARNING, + (errmsg("could not send signal to process %d: %m", + pid))); + } + } + else + LWLockRelease(ProcArrayLock); + + /* prevent signal from being resent more than once */ + allow_autovacuum_cancel = false; + } + + /* * If awoken after the deadlock check interrupt has run, and * log_lock_waits is on, then report about the wait. */ *************** CheckDeadLock(void) *** 1189,1201 **** * RemoveFromWaitQueue took care of waking up any such processes. */ } ! else if (log_lock_waits) { /* * Unlock my semaphore so that the interrupted ProcSleep() call can * print the log message (we daren't do it here because we are inside * a signal handler). It will then sleep again until someone * releases the lock. */ PGSemaphoreUnlock(&MyProc->sem); } --- 1239,1254 ---- * RemoveFromWaitQueue took care of waking up any such processes. */ } ! else if (log_lock_waits || deadlock_state == DS_BLOCKED_BY_AUTOVACUUM) { /* * Unlock my semaphore so that the interrupted ProcSleep() call can * print the log message (we daren't do it here because we are inside * a signal handler). It will then sleep again until someone * releases the lock. + * + * If blocked by autovacuum, this wakeup will enable ProcSleep to send + * the cancelling signal to the autovacuum worker. */ PGSemaphoreUnlock(&MyProc->sem); } Index: src/include/storage/lock.h =================================================================== RCS file: /home/alvherre/Code/cvs/pgsql/src/include/storage/lock.h,v retrieving revision 1.107 diff -c -p -r1.107 lock.h *** src/include/storage/lock.h 5 Sep 2007 18:10:48 -0000 1.107 --- src/include/storage/lock.h 25 Oct 2007 17:11:02 -0000 *************** typedef enum *** 442,448 **** DS_NOT_YET_CHECKED, /* no deadlock check has run yet */ DS_NO_DEADLOCK, /* no deadlock detected */ DS_SOFT_DEADLOCK, /* deadlock avoided by queue rearrangement */ ! DS_HARD_DEADLOCK /* deadlock, no way out but ERROR */ } DeadLockState; --- 442,449 ---- DS_NOT_YET_CHECKED, /* no deadlock check has run yet */ DS_NO_DEADLOCK, /* no deadlock detected */ DS_SOFT_DEADLOCK, /* deadlock avoided by queue rearrangement */ ! DS_HARD_DEADLOCK, /* deadlock, no way out but ERROR */ ! DS_BLOCKED_BY_AUTOVACUUM /* queue blocked by autovacuum worker */ } DeadLockState; *************** extern void lock_twophase_postabort(Tran *** 495,500 **** --- 496,502 ---- void *recdata, uint32 len); extern DeadLockState DeadLockCheck(PGPROC *proc); + extern PGPROC *GetBlockingAutoVacuumPgproc(void); extern void DeadLockReport(void); extern void RememberSimpleDeadLock(PGPROC *proc1, LOCKMODE lockmode,