>> >> Seems reasonable. Does the victim backend currently know why it has been
>> >> killed?
>> >
>> > I don't think so.
>> >
>> > One idea is postmaster sets a flag in the shared memory area
>> > indicating it rceived SIGTERM before forwarding the signal to
>> > backends.
>> >
>> > Backend check the flag and if it's not set, it knows that the signal
>> > has been sent by pg_terminate_backend(), not postmaster.
>> 
>> Or it could also be sent by some other user process, like the user
>> running "kill" from the shell.
> 
> No problem (at least for pgpool-II).
> 
> If the flag is not set, postgres returns the same code as the one
> killed by pg_terminate_backend(). The point is, backend is killed by
> postmaster or not. Because if backend was killed by postmaster,
> pgpool-II should not expect the PostgreSQL server is usable since
> postmaster decided to shutdown.

Here is the patch to implement the feature.

1) pg_terminate_backend() sends SIGUSR1 signal rather than SIGTERM to
   the target backend.
2) The infrastructure used for message passing is
   storage/ipc/procsignal.c The new message type for ProcSignalReason
   is "PROCSIG_TERMNINATE_BACKEND_INTERRUPT"
3) I assign new error code 57P04 which is returned from the backend
   killed by pg_terminate_backend().

#define ERRCODE_TERMINATE_BACKEND                       MAKE_SQLSTATE('5','7', 
'P','0','4')

Comments are welcome.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
*** a/src/backend/storage/ipc/procsignal.c
--- b/src/backend/storage/ipc/procsignal.c
***************
*** 279,284 **** procsignal_sigusr1_handler(SIGNAL_ARGS)
--- 279,287 ----
  	if (CheckProcSignal(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN))
  		RecoveryConflictInterrupt(PROCSIG_RECOVERY_CONFLICT_BUFFERPIN);
  
+ 	if (CheckProcSignal(PROCSIG_TERMNINATE_BACKEND_INTERRUPT))
+ 		HandleTerminateBackendInterrupt();
+ 
  	latch_sigusr1_handler();
  
  	errno = save_errno;
*** a/src/backend/tcop/postgres.c
--- b/src/backend/tcop/postgres.c
***************
*** 184,189 **** static bool RecoveryConflictPending = false;
--- 184,195 ----
  static bool RecoveryConflictRetryable = true;
  static ProcSignalReason RecoveryConflictReason;
  
+ /*
+  * True if backend is being killed by pg_terminate_backend().
+  * Set by HandleTerminateBackendInterrupt() upon received SIGUSR1.
+  */
+ static bool TerminateBackendRequest = false;
+ 
  /* ----------------------------------------------------------------
   *		decls for routines only used in this file
   * ----------------------------------------------------------------
***************
*** 2875,2880 **** RecoveryConflictInterrupt(ProcSignalReason reason)
--- 2881,2924 ----
  }
  
  /*
+  * HandleTerminateBackendInterrupt: out-of-line portion of terminate backend
+  * handling following receipt of SIGUSR1. Designed to be similar to die().
+  * Called only by a normal user backend.
+  */
+ void
+ HandleTerminateBackendInterrupt(void)
+ {
+ 	int			save_errno = errno;
+ 
+ 	/* Don't joggle the elbow of proc_exit */
+ 	if (!proc_exit_inprogress)
+ 	{
+ 		InterruptPending = true;
+ 		ProcDiePending = true;
+ 		TerminateBackendRequest = true;
+ 
+ 		/*
+ 		 * If it's safe to interrupt, and we're waiting for input or a lock,
+ 		 * service the interrupt immediately
+ 		 */
+ 		if (ImmediateInterruptOK && InterruptHoldoffCount == 0 &&
+ 			CritSectionCount == 0)
+ 		{
+ 			/* bump holdoff count to make ProcessInterrupts() a no-op */
+ 			/* until we are done getting ready for it */
+ 			InterruptHoldoffCount++;
+ 			LockWaitCancel();	/* prevent CheckDeadLock from running */
+ 			DisableNotifyInterrupt();
+ 			DisableCatchupInterrupt();
+ 			InterruptHoldoffCount--;
+ 			ProcessInterrupts();
+ 		}
+ 	}
+ 
+ 	errno = save_errno;
+ }
+ 
+ /*
   * ProcessInterrupts: out-of-line portion of CHECK_FOR_INTERRUPTS() macro
   *
   * If an interrupt condition is pending, and it's safe to service it,
***************
*** 2912,2917 **** ProcessInterrupts(void)
--- 2956,2966 ----
  					(errcode(ERRCODE_ADMIN_SHUTDOWN),
  			  errmsg("terminating connection due to conflict with recovery"),
  					 errdetail_recovery_conflict()));
+ 		else if (TerminateBackendRequest)
+ 			ereport(FATAL,
+ 					(errcode(ERRCODE_TERMINATE_BACKEND),
+ 					 errmsg("terminating connection due to pg_terminate_backend")));
+ 
  		else
  			ereport(FATAL,
  					(errcode(ERRCODE_ADMIN_SHUTDOWN),
*** a/src/backend/utils/adt/misc.c
--- b/src/backend/utils/adt/misc.c
***************
*** 114,120 **** pg_cancel_backend(PG_FUNCTION_ARGS)
  Datum
  pg_terminate_backend(PG_FUNCTION_ARGS)
  {
! 	PG_RETURN_BOOL(pg_signal_backend(PG_GETARG_INT32(0), SIGTERM));
  }
  
  Datum
--- 114,122 ----
  Datum
  pg_terminate_backend(PG_FUNCTION_ARGS)
  {
! 	PG_RETURN_BOOL(
! 		SendProcSignal(PG_GETARG_INT32(0), PROCSIG_TERMNINATE_BACKEND_INTERRUPT,
! 					   InvalidBackendId) == 0);
  }
  
  Datum
*** a/src/include/storage/procsignal.h
--- b/src/include/storage/procsignal.h
***************
*** 40,45 **** typedef enum
--- 40,47 ----
  	PROCSIG_RECOVERY_CONFLICT_BUFFERPIN,
  	PROCSIG_RECOVERY_CONFLICT_STARTUP_DEADLOCK,
  
+ 	PROCSIG_TERMNINATE_BACKEND_INTERRUPT,	/* terminate request from pg_terminate_backend() */
+ 
  	NUM_PROCSIGNALS				/* Must be last! */
  } ProcSignalReason;
  
***************
*** 55,58 **** extern int SendProcSignal(pid_t pid, ProcSignalReason reason,
--- 57,62 ----
  
  extern void procsignal_sigusr1_handler(SIGNAL_ARGS);
  
+ extern void HandleTerminateBackendInterrupt(void);
+ 
  #endif   /* PROCSIGNAL_H */
*** a/src/include/utils/errcodes.h
--- b/src/include/utils/errcodes.h
***************
*** 332,337 ****
--- 332,338 ----
  #define ERRCODE_ADMIN_SHUTDOWN				MAKE_SQLSTATE('5','7', 'P','0','1')
  #define ERRCODE_CRASH_SHUTDOWN				MAKE_SQLSTATE('5','7', 'P','0','2')
  #define ERRCODE_CANNOT_CONNECT_NOW			MAKE_SQLSTATE('5','7', 'P','0','3')
+ #define ERRCODE_TERMINATE_BACKEND			MAKE_SQLSTATE('5','7', 'P','0','4')
  
  /* Class 58 - System Error (class borrowed from DB2) */
  /* (we define this as errors external to PostgreSQL itself) */
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to