Hi, To be reviewed easily, I'm splitting Synch Rep patch into some pieces. Attached is a patch of signal handling changes for Synch Rep.
http://archives.postgresql.org/pgsql-hackers/2008-09/msg00950.php Though I've posted the WIP patch previously, this is a finished one. Please feel free to comment on it. Regards, -- Fujii Masao NIPPON TELEGRAPH AND TELEPHONE CORPORATION NTT Open Source Software Center
Index: src/backend/access/transam/twophase.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/access/transam/twophase.c,v retrieving revision 1.46 diff -c -r1.46 twophase.c *** src/backend/access/transam/twophase.c 20 Oct 2008 19:18:18 -0000 1.46 --- src/backend/access/transam/twophase.c 27 Oct 2008 01:59:57 -0000 *************** *** 285,290 **** --- 285,291 ---- gxact->proc.databaseId = databaseid; gxact->proc.roleId = owner; gxact->proc.inCommit = false; + gxact->proc.signalFlags = 0; gxact->proc.vacuumFlags = 0; gxact->proc.lwWaiting = false; gxact->proc.lwExclusive = false; Index: src/backend/commands/async.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/commands/async.c,v retrieving revision 1.141 diff -c -r1.141 async.c *** src/backend/commands/async.c 30 Aug 2008 01:39:13 -0000 1.141 --- src/backend/commands/async.c 27 Oct 2008 01:59:57 -0000 *************** *** 915,923 **** * a frontend command. Signal handler execution of inbound notifies * is disabled until the next EnableNotifyInterrupt call. * ! * The SIGUSR1 signal handler also needs to call this, so as to ! * prevent conflicts if one signal interrupts the other. So we ! * must return the previous state of the flag. */ bool DisableNotifyInterrupt(void) --- 915,924 ---- * a frontend command. Signal handler execution of inbound notifies * is disabled until the next EnableNotifyInterrupt call. * ! * This also needs to be called when SIGUSR1 with ! * PROCSIGNAL_CATCHUP_INTERRUPT is received, so as to prevent conflicts ! * if one signal interrupts the other. So we must return the previous ! * state of the flag. */ bool DisableNotifyInterrupt(void) *************** *** 954,960 **** nulls[Natts_pg_listener]; bool catchup_enabled; ! /* Must prevent SIGUSR1 interrupt while I am running */ catchup_enabled = DisableCatchupInterrupt(); if (Trace_notify) --- 955,961 ---- nulls[Natts_pg_listener]; bool catchup_enabled; ! /* Must prevent catchup interrupt while I am running */ catchup_enabled = DisableCatchupInterrupt(); if (Trace_notify) Index: src/backend/postmaster/autovacuum.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/postmaster/autovacuum.c,v retrieving revision 1.84 diff -c -r1.84 autovacuum.c *** src/backend/postmaster/autovacuum.c 13 Aug 2008 00:07:50 -0000 1.84 --- src/backend/postmaster/autovacuum.c 27 Oct 2008 01:59:57 -0000 *************** *** 1480,1486 **** pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, CatchupInterruptHandler); /* We don't listen for async notifies */ pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); --- 1480,1486 ---- pqsignal(SIGALRM, handle_sig_alarm); pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, proc_sigusr1_handler); /* We don't listen for async notifies */ pqsignal(SIGUSR2, SIG_IGN); pqsignal(SIGFPE, FloatExceptionHandler); Index: src/backend/storage/ipc/sinval.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/storage/ipc/sinval.c,v retrieving revision 1.86 diff -c -r1.86 sinval.c *** src/backend/storage/ipc/sinval.c 19 Jun 2008 21:32:56 -0000 1.86 --- src/backend/storage/ipc/sinval.c 27 Oct 2008 01:59:57 -0000 *************** *** 27,33 **** * need a way to give an idle backend a swift kick in the rear and make * it catch up before the sinval queue overflows and forces it to go * through a cache reset exercise. This is done by sending SIGUSR1 ! * to any backend that gets too far behind. * * State for catchup events consists of two flags: one saying whether * the signal handler is currently allowed to call ProcessCatchupEvent --- 27,34 ---- * need a way to give an idle backend a swift kick in the rear and make * it catch up before the sinval queue overflows and forces it to go * through a cache reset exercise. This is done by sending SIGUSR1 ! * with PROCSIGNAL_CATCHUP_INTERRUPT to any backend that gets too far ! * behind. * * State for catchup events consists of two flags: one saying whether * the signal handler is currently allowed to call ProcessCatchupEvent *************** *** 144,152 **** /* ! * CatchupInterruptHandler * ! * This is the signal handler for SIGUSR1. * * If we are idle (catchupInterruptEnabled is set), we can safely * invoke ProcessCatchupEvent directly. Otherwise, just set a flag --- 145,154 ---- /* ! * HandleCatchupInterrupt * ! * This is called when SIGUSR1 with PROCSIGNAL_CATCHUP_INTERRUPT is ! * received. * * If we are idle (catchupInterruptEnabled is set), we can safely * invoke ProcessCatchupEvent directly. Otherwise, just set a flag *************** *** 156,168 **** * since there's no longer any reason to do anything.) */ void ! CatchupInterruptHandler(SIGNAL_ARGS) { - int save_errno = errno; - /* ! * Note: this is a SIGNAL HANDLER. You must be very wary what you do ! * here. */ /* Don't joggle the elbow of proc_exit */ --- 158,168 ---- * since there's no longer any reason to do anything.) */ void ! HandleCatchupInterrupt(void) { /* ! * Note: this is called by a SIGNAL HANDLER. ! * You must be very wary what you do here. */ /* Don't joggle the elbow of proc_exit */ *************** *** 216,223 **** */ catchupInterruptOccurred = 1; } - - errno = save_errno; } /* --- 216,221 ---- *************** *** 289,295 **** /* * ProcessCatchupEvent * ! * Respond to a catchup event (SIGUSR1) from another backend. * * This is called either directly from the SIGUSR1 signal handler, * or the next time control reaches the outer idle loop (assuming --- 287,294 ---- /* * ProcessCatchupEvent * ! * Respond to a catchup event (SIGUSR1 with PROCSIGNAL_CATCHUP_INTERRUPT) ! * from another backend. * * This is called either directly from the SIGUSR1 signal handler, * or the next time control reaches the outer idle loop (assuming Index: src/backend/storage/ipc/sinvaladt.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/storage/ipc/sinvaladt.c,v retrieving revision 1.74 diff -c -r1.74 sinvaladt.c *** src/backend/storage/ipc/sinvaladt.c 18 Jul 2008 14:45:48 -0000 1.74 --- src/backend/storage/ipc/sinvaladt.c 27 Oct 2008 01:59:57 -0000 *************** *** 655,661 **** LWLockRelease(SInvalReadLock); LWLockRelease(SInvalWriteLock); elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid); ! kill(his_pid, SIGUSR1); if (callerHasWriteLock) LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); } --- 655,661 ---- LWLockRelease(SInvalReadLock); LWLockRelease(SInvalWriteLock); elog(DEBUG4, "sending sinval catchup signal to PID %d", (int) his_pid); ! SendProcSignal(his_pid, PROCSIGNAL_CATCHUP_INTERRUPT); if (callerHasWriteLock) LWLockAcquire(SInvalWriteLock, LW_EXCLUSIVE); } Index: src/backend/storage/lmgr/proc.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/storage/lmgr/proc.c,v retrieving revision 1.201 diff -c -r1.201 proc.c *** src/backend/storage/lmgr/proc.c 9 Jun 2008 18:23:05 -0000 1.201 --- src/backend/storage/lmgr/proc.c 27 Oct 2008 01:59:58 -0000 *************** *** 88,93 **** --- 88,95 ---- static void AuxiliaryProcKill(int code, Datum arg); static bool CheckStatementTimeout(void); + static PGPROC *AuxiliaryPidGetProc(int pid); + /* * Report shared-memory space needed by InitProcGlobal. *************** *** 291,296 **** --- 293,299 ---- MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inCommit = false; + MyProc->signalFlags = 0; MyProc->vacuumFlags = 0; if (IsAutoVacuumWorkerProcess()) MyProc->vacuumFlags |= PROC_IS_AUTOVACUUM; *************** *** 430,435 **** --- 433,439 ---- MyProc->databaseId = InvalidOid; MyProc->roleId = InvalidOid; MyProc->inCommit = false; + MyProc->signalFlags = 0; /* we don't set the "is autovacuum" flag in the launcher */ MyProc->vacuumFlags = 0; MyProc->lwWaiting = false; *************** *** 1281,1286 **** --- 1285,1377 ---- PGSemaphoreUnlock(&proc->sem); } + /* + * SendProcSignal - send a signal with a reason to a process + * (such as backend, autovacuum worker and auxiliary process) + * identified by PID. + */ + void + SendProcSignal(int pid, uint8 reason) + { + PGPROC *proc = NULL; + + /* + * If a given pid is not for a backend or an auxiliary process, + * do nothing. + */ + if ((proc = BackendPidGetProc(pid)) == NULL + && (proc = AuxiliaryPidGetProc(pid)) == NULL) + return; + + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + + proc->signalFlags |= reason; + + LWLockRelease(ProcArrayLock); + + /* Send SIGUSR1 to a process */ + kill(pid, SIGUSR1); + } + + /* + * CheckProcSignal - check to see if a particular reason has been + * signaled, and clear the signal flag. Should be called after + * receiving SIGUSR1. + */ + bool + CheckProcSignal(uint8 reason) + { + LWLockAcquire(ProcArrayLock, LW_EXCLUSIVE); + + /* Careful here --- don't clear flag if we haven't seen it set */ + if (MyProc->signalFlags & reason) + { + MyProc->signalFlags &= ~reason; + LWLockRelease(ProcArrayLock); + return true; + } + + LWLockRelease(ProcArrayLock); + + return false; + } + + /* + * AuxiliaryPidGetProc - get an auxiliary process's PGPROC given its PID + * + * Returns NULL if not found. Note that it is up to the caller to be + * sure that the question remains meaningful for long enough for the + * answer to be used ... + */ + static PGPROC * + AuxiliaryPidGetProc(int pid) + { + PGPROC *result = NULL; + int proctype; + + if (pid == 0) + return NULL; + + LWLockAcquire(ProcArrayLock, LW_SHARED); + + for (proctype = 0; proctype < NUM_AUXILIARY_PROCS; proctype++) + { + PGPROC *proc = &AuxiliaryProcs[proctype]; + + if (proc->pid == 0) + break; + + if (proc->pid == pid) + { + result = proc; + break; + } + } + + LWLockRelease(ProcArrayLock); + + return result; + } /***************************************************************************** * SIGALRM interrupt support Index: src/backend/tcop/postgres.c =================================================================== RCS file: /projects/cvsroot/pgsql/src/backend/tcop/postgres.c,v retrieving revision 1.557 diff -c -r1.557 postgres.c *** src/backend/tcop/postgres.c 30 Sep 2008 10:52:13 -0000 1.557 --- src/backend/tcop/postgres.c 27 Oct 2008 01:59:58 -0000 *************** *** 2433,2438 **** --- 2433,2457 ---- */ /* + * proc_sigusr1_handler - handle signal conditions. + */ + void + proc_sigusr1_handler(SIGNAL_ARGS) + { + int save_errno = errno; + + if (CheckProcSignal(PROCSIGNAL_CATCHUP_INTERRUPT)) + { + /* + * Catchup interrupt has been sent. + */ + HandleCatchupInterrupt(); + } + + errno = save_errno; + } + + /* * quickdie() occurs when signalled SIGQUIT by the postmaster. * * Some backend has bought the farm, *************** *** 3176,3182 **** * of output during who-knows-what operation... */ pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, CatchupInterruptHandler); pqsignal(SIGUSR2, NotifyInterruptHandler); pqsignal(SIGFPE, FloatExceptionHandler); --- 3195,3201 ---- * of output during who-knows-what operation... */ pqsignal(SIGPIPE, SIG_IGN); ! pqsignal(SIGUSR1, proc_sigusr1_handler); pqsignal(SIGUSR2, NotifyInterruptHandler); pqsignal(SIGFPE, FloatExceptionHandler); Index: src/include/storage/proc.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/storage/proc.h,v retrieving revision 1.106 diff -c -r1.106 proc.h *** src/include/storage/proc.h 15 Apr 2008 20:28:47 -0000 1.106 --- src/include/storage/proc.h 27 Oct 2008 01:59:58 -0000 *************** *** 38,43 **** --- 38,46 ---- TransactionId xids[PGPROC_MAX_CACHED_SUBXIDS]; }; + /* Flags for PGPROC->signalFlags */ + #define PROCSIGNAL_CATCHUP_INTERRUPT 0x01 /* catchup interrupt */ + /* Flags for PGPROC->vacuumFlags */ #define PROC_IS_AUTOVACUUM 0x01 /* is it an autovac worker? */ #define PROC_IN_VACUUM 0x02 /* currently running lazy vacuum */ *************** *** 91,96 **** --- 94,100 ---- bool inCommit; /* true if within commit critical section */ + uint8 signalFlags; /* signal-related flags, see above */ uint8 vacuumFlags; /* vacuum-related flags, see above */ /* Info about LWLock the process is currently waiting for, if any. */ *************** *** 171,176 **** --- 175,183 ---- extern void ProcWaitForSignal(void); extern void ProcSendSignal(int pid); + extern void SendProcSignal(int pid, uint8 reason); + extern bool CheckProcSignal(uint8 reason); + extern bool enable_sig_alarm(int delayms, bool is_statement_timeout); extern bool disable_sig_alarm(bool is_statement_timeout); extern void handle_sig_alarm(SIGNAL_ARGS); Index: src/include/storage/sinval.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/storage/sinval.h,v retrieving revision 1.48 diff -c -r1.48 sinval.h *** src/include/storage/sinval.h 19 Jun 2008 21:32:56 -0000 1.48 --- src/include/storage/sinval.h 27 Oct 2008 01:59:58 -0000 *************** *** 90,96 **** void (*resetFunction) (void)); /* signal handler for catchup events (SIGUSR1) */ ! extern void CatchupInterruptHandler(SIGNAL_ARGS); /* * enable/disable processing of catchup events directly from signal handler. --- 90,96 ---- void (*resetFunction) (void)); /* signal handler for catchup events (SIGUSR1) */ ! extern void HandleCatchupInterrupt(void); /* * enable/disable processing of catchup events directly from signal handler. Index: src/include/tcop/tcopprot.h =================================================================== RCS file: /projects/cvsroot/pgsql/src/include/tcop/tcopprot.h,v retrieving revision 1.93 diff -c -r1.93 tcopprot.h *** src/include/tcop/tcopprot.h 10 Mar 2008 12:55:13 -0000 1.93 --- src/include/tcop/tcopprot.h 27 Oct 2008 01:59:58 -0000 *************** *** 56,61 **** --- 56,62 ---- extern bool assign_max_stack_depth(int newval, bool doit, GucSource source); + extern void proc_sigusr1_handler(SIGNAL_ARGS); extern void die(SIGNAL_ARGS); extern void quickdie(SIGNAL_ARGS); extern void authdie(SIGNAL_ARGS);
-- Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org) To make changes to your subscription: http://www.postgresql.org/mailpref/pgsql-hackers