>> >> 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 ([email protected])
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers