Tom Lane wrote:
> Alvaro Herrera <[EMAIL PROTECTED]> writes:
> > Note that currently there's no way for a backend to know whether another
> > backend is autovacuum or not.  I thought about adding a flag to PGPROC,
> > but eventually considered it ugly,
> 
> No, that was exactly the way I thought we'd do it.  One thing to note is
> that to avoid race conditions, the PGPROC entry has to be marked as
> autovac from the instant it's inserted into the array --- with a
> separate area I think you'd have difficulty avoiding the race condition.

Here it is.

I have run the regression tests many times and they pass.  I added some
debug printouts (not in the patch) to make sure the kill code path was
being invoked, and while it seldom shows, it certainly does.

Note that I used the same DatabaseHasActiveBackends() function to do the
kill.  I had first added a different one to kill autovacuum, but then
noticed that this one has no callers that don't want the side effect, so
I merged them.  It seems a bit ugly to me to have a function named like
this and still have the side effect, but on the other hand it's quite
useless to have a version without the side effect that will never get
called.

Another point to make is that it only kills autovacuum, and only if no
other process is found.  So if there are two processes and autovacuum is
one of them, it will be allowed to continue.

I feel that changing the DROP DATABASE behavior with respect to killing
other backends is beyond the scope of this patch.  It seems easy enough
to do if somebody feels so inclined.

-- 
Alvaro Herrera                                http://www.CommandPrompt.com/
The PostgreSQL Company - Command Prompt, Inc.
Index: src/backend/access/transam/twophase.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/access/transam/twophase.c,v
retrieving revision 1.26
diff -c -p -r1.26 twophase.c
*** src/backend/access/transam/twophase.c	5 Jan 2007 22:19:23 -0000	1.26
--- src/backend/access/transam/twophase.c	15 Jan 2007 19:11:15 -0000
*************** MarkAsPreparing(TransactionId xid, const
*** 280,285 ****
--- 280,286 ----
  	gxact->proc.databaseId = databaseid;
  	gxact->proc.roleId = owner;
  	gxact->proc.inVacuum = false;
+ 	gxact->proc.isAutovacuum = false;
  	gxact->proc.lwWaiting = false;
  	gxact->proc.lwExclusive = false;
  	gxact->proc.lwWaitLink = NULL;
Index: src/backend/bootstrap/bootstrap.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/bootstrap/bootstrap.c,v
retrieving revision 1.228
diff -c -p -r1.228 bootstrap.c
*** src/backend/bootstrap/bootstrap.c	5 Jan 2007 22:19:24 -0000	1.228
--- src/backend/bootstrap/bootstrap.c	15 Jan 2007 19:08:47 -0000
*************** BootstrapMain(int argc, char *argv[])
*** 446,452 ****
  	/*
  	 * Do backend-like initialization for bootstrap mode
  	 */
! 	InitProcess();
  	(void) InitPostgres(dbname, NULL);
  
  	/*
--- 446,452 ----
  	/*
  	 * Do backend-like initialization for bootstrap mode
  	 */
! 	InitProcess(false);
  	(void) InitPostgres(dbname, NULL);
  
  	/*
Index: src/backend/postmaster/autovacuum.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/autovacuum.c,v
retrieving revision 1.30
diff -c -p -r1.30 autovacuum.c
*** src/backend/postmaster/autovacuum.c	5 Jan 2007 22:19:36 -0000	1.30
--- src/backend/postmaster/autovacuum.c	15 Jan 2007 20:20:28 -0000
*************** AutoVacMain(int argc, char *argv[])
*** 290,296 ****
  	 * had to do some stuff with LWLocks).
  	 */
  #ifndef EXEC_BACKEND
! 	InitProcess();
  #endif
  
  	/*
--- 290,296 ----
  	 * had to do some stuff with LWLocks).
  	 */
  #ifndef EXEC_BACKEND
! 	InitProcess(true);
  #endif
  
  	/*
*************** AutoVacMain(int argc, char *argv[])
*** 307,313 ****
  		EmitErrorReport();
  
  		/*
! 		 * We can now go away.	Note that because we'll call InitProcess, a
  		 * callback will be registered to do ProcKill, which will clean up
  		 * necessary state.
  		 */
--- 307,313 ----
  		EmitErrorReport();
  
  		/*
! 		 * We can now go away.	Note that because we called InitProcess, a
  		 * callback will be registered to do ProcKill, which will clean up
  		 * necessary state.
  		 */
Index: src/backend/postmaster/postmaster.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/postmaster/postmaster.c,v
retrieving revision 1.507
diff -c -p -r1.507 postmaster.c
*** src/backend/postmaster/postmaster.c	5 Jan 2007 22:19:36 -0000	1.507
--- src/backend/postmaster/postmaster.c	15 Jan 2007 19:09:29 -0000
*************** SubPostmasterMain(int argc, char *argv[]
*** 3347,3353 ****
  		InitShmemAccess(UsedShmemSegAddr);
  
  		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
! 		InitProcess();
  
  		/*
  		 * Attach process to shared data structures.  If testing EXEC_BACKEND
--- 3347,3353 ----
  		InitShmemAccess(UsedShmemSegAddr);
  
  		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
! 		InitProcess(false);
  
  		/*
  		 * Attach process to shared data structures.  If testing EXEC_BACKEND
*************** SubPostmasterMain(int argc, char *argv[]
*** 3391,3397 ****
  		InitShmemAccess(UsedShmemSegAddr);
  
  		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
! 		InitProcess();
  
  		/* Attach process to shared data structures */
  		CreateSharedMemoryAndSemaphores(false, 0);
--- 3391,3397 ----
  		InitShmemAccess(UsedShmemSegAddr);
  
  		/* Need a PGPROC to run CreateSharedMemoryAndSemaphores */
! 		InitProcess(true);
  
  		/* Attach process to shared data structures */
  		CreateSharedMemoryAndSemaphores(false, 0);
Index: src/backend/storage/ipc/procarray.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/storage/ipc/procarray.c,v
retrieving revision 1.20
diff -c -p -r1.20 procarray.c
*** src/backend/storage/ipc/procarray.c	5 Jan 2007 22:19:38 -0000	1.20
--- src/backend/storage/ipc/procarray.c	15 Jan 2007 20:21:41 -0000
***************
*** 29,34 ****
--- 29,36 ----
   */
  #include "postgres.h"
  
+ #include <signal.h>
+ 
  #include "access/subtrans.h"
  #include "access/transam.h"
  #include "access/xact.h"
*************** GetSnapshotData(Snapshot snapshot, bool 
*** 679,684 ****
--- 681,687 ----
  
  /*
   * DatabaseHasActiveBackends -- are there any backends running in the given DB
+  * If the only process running on the database is autovacuum, try to kill it.
   *
   * If 'ignoreMyself' is TRUE, ignore this particular backend while checking
   * for backends in the target database.
*************** GetSnapshotData(Snapshot snapshot, bool 
*** 693,701 ****
  bool
  DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
  {
! 	bool		result = false;
  	ProcArrayStruct *arrayP = procArray;
  	int			index;
  
  	LWLockAcquire(ProcArrayLock, LW_SHARED);
  
--- 696,711 ----
  bool
  DatabaseHasActiveBackends(Oid databaseId, bool ignoreMyself)
  {
! 	bool		result;
  	ProcArrayStruct *arrayP = procArray;
  	int			index;
+ 	int			num;
+ 	pid_t		autovacPid;
+ 
+ restart:
+ 	num = 0;
+ 	autovacPid = 0;
+ 	result = false;
  
  	LWLockAcquire(ProcArrayLock, LW_SHARED);
  
*************** DatabaseHasActiveBackends(Oid databaseId
*** 708,718 ****
  			if (ignoreMyself && proc == MyProc)
  				continue;
  
! 			result = true;
! 			break;
  		}
  	}
  
  	LWLockRelease(ProcArrayLock);
  
  	return result;
--- 718,755 ----
  			if (ignoreMyself && proc == MyProc)
  				continue;
  
! 			/*
! 			 * We can't hope that only autovacuum is running if there's more than
! 			 * one process.
! 			 */
! 			if (++num > 1)
! 				break;
! 
! 			if (proc->isAutovacuum)
! 			{
! 				Assert(autovacPid == 0);
! 				autovacPid = proc->pid;
! 			}
  		}
  	}
  
+ 	if (num == 0)
+ 	{
+ 		/* yipee, there's nobody here */
+ 		result = false;
+ 	}
+ 	else if (num == 1 && autovacPid != 0)
+ 	{
+ 		/* good, there's only an autovacuum -- kill it */
+ 		kill(autovacPid, SIGINT);
+ 		LWLockRelease(ProcArrayLock);
+ 		pg_usleep(100 * 1000);		/* 100ms */
+ 		goto restart;
+ 	}
+ 	else
+ 		/* no luck; there's a different backend */
+ 		result = true;
+ 
  	LWLockRelease(ProcArrayLock);
  
  	return result;
Index: src/backend/storage/lmgr/proc.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/storage/lmgr/proc.c,v
retrieving revision 1.182
diff -c -p -r1.182 proc.c
*** src/backend/storage/lmgr/proc.c	5 Jan 2007 22:19:38 -0000	1.182
--- src/backend/storage/lmgr/proc.c	15 Jan 2007 19:59:44 -0000
*************** InitProcGlobal(void)
*** 194,202 ****
  
  /*
   * InitProcess -- initialize a per-process data structure for this backend
   */
  void
! InitProcess(void)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile PROC_HDR *procglobal = ProcGlobal;
--- 194,204 ----
  
  /*
   * InitProcess -- initialize a per-process data structure for this backend
+  *
+  * "autovac" is used to initialize the "isAutovacuum" PGPROC member.
   */
  void
! InitProcess(bool autovac)
  {
  	/* use volatile pointer to prevent code rearrangement */
  	volatile PROC_HDR *procglobal = ProcGlobal;
*************** InitProcess(void)
*** 258,263 ****
--- 260,266 ----
  	MyProc->databaseId = InvalidOid;
  	MyProc->roleId = InvalidOid;
  	MyProc->inVacuum = false;
+ 	MyProc->isAutovacuum = autovac;
  	MyProc->lwWaiting = false;
  	MyProc->lwExclusive = false;
  	MyProc->lwWaitLink = NULL;
*************** InitDummyProcess(void)
*** 390,395 ****
--- 393,399 ----
  	MyProc->databaseId = InvalidOid;
  	MyProc->roleId = InvalidOid;
  	MyProc->inVacuum = false;
+ 	MyProc->isAutovacuum = false;
  	MyProc->lwWaiting = false;
  	MyProc->lwExclusive = false;
  	MyProc->lwWaitLink = NULL;
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/backend/tcop/postgres.c,v
retrieving revision 1.521
diff -c -p -r1.521 postgres.c
*** src/backend/tcop/postgres.c	5 Jan 2007 22:19:39 -0000	1.521
--- src/backend/tcop/postgres.c	15 Jan 2007 19:10:28 -0000
*************** PostgresMain(int argc, char *argv[], con
*** 3125,3133 ****
  	 */
  #ifdef EXEC_BACKEND
  	if (!IsUnderPostmaster)
! 		InitProcess();
  #else
! 	InitProcess();
  #endif
  
  	/*
--- 3125,3133 ----
  	 */
  #ifdef EXEC_BACKEND
  	if (!IsUnderPostmaster)
! 		InitProcess(false);
  #else
! 	InitProcess(false);
  #endif
  
  	/*
Index: src/include/storage/proc.h
===================================================================
RCS file: /home/alvherre/Code/cvs/pgsql/src/include/storage/proc.h,v
retrieving revision 1.92
diff -c -p -r1.92 proc.h
*** src/include/storage/proc.h	5 Jan 2007 22:19:58 -0000	1.92
--- src/include/storage/proc.h	15 Jan 2007 19:12:12 -0000
*************** struct PGPROC
*** 75,80 ****
--- 75,81 ----
  	Oid			roleId;			/* OID of role using this backend */
  
  	bool		inVacuum;		/* true if current xact is a LAZY VACUUM */
+ 	bool		isAutovacuum;	/* true if it's autovacuum */
  
  	/* Info about LWLock the process is currently waiting for, if any. */
  	bool		lwWaiting;		/* true if waiting for an LW lock */
*************** extern volatile bool cancel_from_timeout
*** 136,142 ****
  extern int	ProcGlobalSemas(void);
  extern Size ProcGlobalShmemSize(void);
  extern void InitProcGlobal(void);
! extern void InitProcess(void);
  extern void InitProcessPhase2(void);
  extern void InitDummyProcess(void);
  extern bool HaveNFreeProcs(int n);
--- 137,143 ----
  extern int	ProcGlobalSemas(void);
  extern Size ProcGlobalShmemSize(void);
  extern void InitProcGlobal(void);
! extern void InitProcess(bool autovac);
  extern void InitProcessPhase2(void);
  extern void InitDummyProcess(void);
  extern bool HaveNFreeProcs(int n);
---------------------------(end of broadcast)---------------------------
TIP 2: Don't 'kill -9' the postmaster

Reply via email to