Re: How to know killed by pg_terminate_backend - Mailing list pgsql-hackers

From Tatsuo Ishii
Subject Re: How to know killed by pg_terminate_backend
Date
Msg-id 20110102.225628.641421216238674108.t-ishii@sraoss.co.jp
Whole thread Raw
In response to Re: How to know killed by pg_terminate_backend  (Tatsuo Ishii <ishii@postgresql.org>)
Responses Re: How to know killed by pg_terminate_backend
List pgsql-hackers
>> >> 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
bypg_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
dueto 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
borrowedfrom DB2) */ /* (we define this as errors external to PostgreSQL itself) */ 

pgsql-hackers by date:

Previous
From: "Kevin Grittner"
Date:
Subject: Re: SSI SLRU low-level functions first cut
Next
From: Tatsuo Ishii
Date:
Subject: Re: How to know killed by pg_terminate_backend