Commit ea0382e3 authored by Tom Lane's avatar Tom Lane

Code review for recent patch to terminate online backup during shutdown:

do CancelBackup at a sane place, fix some oversights in the state transitions,
allow only superusers to connect while we are waiting for backup mode to end.
parent b6e2fab9
<!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.415 2008/04/23 13:44:58 mha Exp $ --> <!-- $PostgreSQL: pgsql/doc/src/sgml/runtime.sgml,v 1.416 2008/04/26 22:47:40 tgl Exp $ -->
<chapter Id="runtime"> <chapter Id="runtime">
<title>Operating System Environment</title> <title>Operating System Environment</title>
...@@ -1306,12 +1306,15 @@ sysctl -w vm.overcommit_memory=2 ...@@ -1306,12 +1306,15 @@ sysctl -w vm.overcommit_memory=2
<term><systemitem>SIGTERM</systemitem><indexterm><primary>SIGTERM</></></term> <term><systemitem>SIGTERM</systemitem><indexterm><primary>SIGTERM</></></term>
<listitem> <listitem>
<para> <para>
This is the <firstterm>Smart Shutdown</firstterm> mode.
After receiving <systemitem>SIGTERM</systemitem>, the server After receiving <systemitem>SIGTERM</systemitem>, the server
waits until online backup mode is no longer active. It then
disallows new connections, but lets existing sessions end their disallows new connections, but lets existing sessions end their
work normally. It shuts down only after all of the sessions work normally. It shuts down only after all of the sessions terminate.
terminate normally. This is the <firstterm>Smart If the server is in online backup mode, it additionally waits
Shutdown</firstterm>. until online backup mode is no longer active. While backup mode is
active, new connections will still be allowed, but only to superusers
(this exception allows a superuser to connect to terminate
online backup mode).
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1320,13 +1323,13 @@ sysctl -w vm.overcommit_memory=2 ...@@ -1320,13 +1323,13 @@ sysctl -w vm.overcommit_memory=2
<term><systemitem>SIGINT</systemitem><indexterm><primary>SIGINT</></></term> <term><systemitem>SIGINT</systemitem><indexterm><primary>SIGINT</></></term>
<listitem> <listitem>
<para> <para>
This is the <firstterm>Fast Shutdown</firstterm> mode.
The server disallows new connections and sends all existing The server disallows new connections and sends all existing
server processes <systemitem>SIGTERM</systemitem>, which will cause them server processes <systemitem>SIGTERM</systemitem>, which will cause them
to abort their current transactions and exit promptly. It then to abort their current transactions and exit promptly. It then
waits for the server processes to exit and finally shuts down. waits for the server processes to exit and finally shuts down.
If the server is in online backup mode, backup mode will be If the server is in online backup mode, backup mode will be
terminated, rendering the backup useless. This is the terminated, rendering the backup useless.
<firstterm>Fast Shutdown</firstterm>.
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
...@@ -1335,8 +1338,8 @@ sysctl -w vm.overcommit_memory=2 ...@@ -1335,8 +1338,8 @@ sysctl -w vm.overcommit_memory=2
<term><systemitem>SIGQUIT</systemitem><indexterm><primary>SIGQUIT</></></term> <term><systemitem>SIGQUIT</systemitem><indexterm><primary>SIGQUIT</></></term>
<listitem> <listitem>
<para> <para>
This is the <firstterm>Immediate Shutdown</firstterm>, which This is the <firstterm>Immediate Shutdown</firstterm> mode.
will cause the master <command>postgres</command> process to send a The master <command>postgres</command> process will send a
<systemitem>SIGQUIT</systemitem> to all child processes and exit <systemitem>SIGQUIT</systemitem> to all child processes and exit
immediately, without properly shutting itself down. The child processes immediately, without properly shutting itself down. The child processes
likewise exit immediately upon receiving likewise exit immediately upon receiving
...@@ -1377,8 +1380,8 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput ...@@ -1377,8 +1380,8 @@ $ <userinput>kill -INT `head -1 /usr/local/pgsql/data/postmaster.pid`</userinput
</important> </important>
<para> <para>
To terminate a session while allowing other sessions to continue, use To terminate an individual session while allowing other sessions to
<function>pg_terminate_backend()</> (<xref continue, use <function>pg_terminate_backend()</> (see <xref
linkend="functions-admin-signal-table">) or send a linkend="functions-admin-signal-table">) or send a
<systemitem>SIGTERM</> signal to the child process associated with <systemitem>SIGTERM</> signal to the child process associated with
the session. the session.
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.555 2008/04/23 13:44:59 mha Exp $ * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.556 2008/04/26 22:47:40 tgl Exp $
* *
* NOTES * NOTES
* *
...@@ -230,6 +230,7 @@ static bool FatalError = false; /* T if recovering from backend crash */ ...@@ -230,6 +230,7 @@ static bool FatalError = false; /* T if recovering from backend crash */
* crash recovery (which is rather like shutdown followed by startup). * crash recovery (which is rather like shutdown followed by startup).
* *
* Normal child backends can only be launched when we are in PM_RUN state. * Normal child backends can only be launched when we are in PM_RUN state.
* (We also allow it in PM_WAIT_BACKUP state, but only for superusers.)
* In other states we handle connection requests by launching "dead_end" * In other states we handle connection requests by launching "dead_end"
* child processes, which will simply send the client an error message and * child processes, which will simply send the client an error message and
* quit. (We track these in the BackendList so that we can know when they * quit. (We track these in the BackendList so that we can know when they
...@@ -242,9 +243,9 @@ static bool FatalError = false; /* T if recovering from backend crash */ ...@@ -242,9 +243,9 @@ static bool FatalError = false; /* T if recovering from backend crash */
* will not be very long). * will not be very long).
* *
* Notice that this state variable does not distinguish *why* we entered * Notice that this state variable does not distinguish *why* we entered
* PM_WAIT_BACKENDS or later states --- Shutdown and FatalError must be * states later than PM_RUN --- Shutdown and FatalError must be consulted
* consulted to find that out. FatalError is never true in PM_RUN state, nor * to find that out. FatalError is never true in PM_RUN state, nor in
* in PM_SHUTDOWN states (because we don't enter those states when trying to * PM_SHUTDOWN states (because we don't enter those states when trying to
* recover from a crash). It can be true in PM_STARTUP state, because we * recover from a crash). It can be true in PM_STARTUP state, because we
* don't clear it until we've successfully recovered. * don't clear it until we've successfully recovered.
*/ */
...@@ -1650,6 +1651,9 @@ retry1: ...@@ -1650,6 +1651,9 @@ retry1:
(errcode(ERRCODE_TOO_MANY_CONNECTIONS), (errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already"))); errmsg("sorry, too many clients already")));
break; break;
case CAC_WAITBACKUP:
/* OK for now, will check in InitPostgres */
break;
case CAC_OK: case CAC_OK:
break; break;
} }
...@@ -1727,11 +1731,15 @@ canAcceptConnections(void) ...@@ -1727,11 +1731,15 @@ canAcceptConnections(void)
{ {
/* /*
* Can't start backends when in startup/shutdown/recovery state. * Can't start backends when in startup/shutdown/recovery state.
* In state PM_WAIT_BACKUP we must allow connections so that *
* a superuser can end online backup mode. * In state PM_WAIT_BACKUP only superusers can connect (this must be
* allowed so that a superuser can end online backup mode); we return
* CAC_WAITBACKUP code to indicate that this must be checked later.
*/ */
if ((pmState != PM_RUN) && (pmState != PM_WAIT_BACKUP)) if (pmState != PM_RUN)
{ {
if (pmState == PM_WAIT_BACKUP)
return CAC_WAITBACKUP; /* allow superusers only */
if (Shutdown > NoShutdown) if (Shutdown > NoShutdown)
return CAC_SHUTDOWN; /* shutdown is pending */ return CAC_SHUTDOWN; /* shutdown is pending */
if (pmState == PM_STARTUP && !FatalError) if (pmState == PM_STARTUP && !FatalError)
...@@ -1997,7 +2005,7 @@ pmdie(SIGNAL_ARGS) ...@@ -1997,7 +2005,7 @@ pmdie(SIGNAL_ARGS)
if (StartupPID != 0) if (StartupPID != 0)
signal_child(StartupPID, SIGTERM); signal_child(StartupPID, SIGTERM);
if (pmState == PM_RUN) if (pmState == PM_RUN || pmState == PM_WAIT_BACKUP)
{ {
ereport(LOG, ereport(LOG,
(errmsg("aborting any active transactions"))); (errmsg("aborting any active transactions")));
...@@ -2017,13 +2025,6 @@ pmdie(SIGNAL_ARGS) ...@@ -2017,13 +2025,6 @@ pmdie(SIGNAL_ARGS)
* PostmasterStateMachine will take the next step. * PostmasterStateMachine will take the next step.
*/ */
PostmasterStateMachine(); PostmasterStateMachine();
/*
* Terminate backup mode to avoid recovery after a
* clean fast shutdown.
*/
CancelBackup();
break; break;
case SIGQUIT: case SIGQUIT:
...@@ -2499,7 +2500,9 @@ HandleChildCrash(int pid, int exitstatus, const char *procname) ...@@ -2499,7 +2500,9 @@ HandleChildCrash(int pid, int exitstatus, const char *procname)
FatalError = true; FatalError = true;
/* We now transit into a state of waiting for children to die */ /* We now transit into a state of waiting for children to die */
if (pmState == PM_RUN || pmState == PM_SHUTDOWN) if (pmState == PM_RUN ||
pmState == PM_WAIT_BACKUP ||
pmState == PM_SHUTDOWN)
pmState = PM_WAIT_BACKENDS; pmState = PM_WAIT_BACKENDS;
} }
...@@ -2568,15 +2571,10 @@ PostmasterStateMachine(void) ...@@ -2568,15 +2571,10 @@ PostmasterStateMachine(void)
if (pmState == PM_WAIT_BACKUP) if (pmState == PM_WAIT_BACKUP)
{ {
/* /*
* PM_WAIT_BACKUP state ends when online backup mode is no longer * PM_WAIT_BACKUP state ends when online backup mode is not active.
* active. In this state canAcceptConnections() will still allow
* client connections, which is necessary because a superuser
* has to call pg_stop_backup() to end online backup mode.
*/ */
if (!BackupInProgress()) if (!BackupInProgress())
{
pmState = PM_WAIT_BACKENDS; pmState = PM_WAIT_BACKENDS;
}
} }
/* /*
...@@ -2699,6 +2697,12 @@ PostmasterStateMachine(void) ...@@ -2699,6 +2697,12 @@ PostmasterStateMachine(void)
} }
else else
{ {
/*
* Terminate backup mode to avoid recovery after a
* clean fast shutdown.
*/
CancelBackup();
/* Normal exit from the postmaster is here */ /* Normal exit from the postmaster is here */
ExitPostmaster(0); ExitPostmaster(0);
} }
...@@ -2819,7 +2823,7 @@ BackendStartup(Port *port) ...@@ -2819,7 +2823,7 @@ BackendStartup(Port *port)
return STATUS_ERROR; return STATUS_ERROR;
} }
/* Pass down canAcceptConnections state (kluge for EXEC_BACKEND case) */ /* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections(); port->canAcceptConnections = canAcceptConnections();
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
...@@ -2880,7 +2884,8 @@ BackendStartup(Port *port) ...@@ -2880,7 +2884,8 @@ BackendStartup(Port *port)
bn->pid = pid; bn->pid = pid;
bn->cancel_key = MyCancelKey; bn->cancel_key = MyCancelKey;
bn->is_autovacuum = false; bn->is_autovacuum = false;
bn->dead_end = (port->canAcceptConnections != CAC_OK); bn->dead_end = (port->canAcceptConnections != CAC_OK &&
port->canAcceptConnections != CAC_WAITBACKUP);
DLAddHead(BackendList, DLNewElem(bn)); DLAddHead(BackendList, DLNewElem(bn));
#ifdef EXEC_BACKEND #ifdef EXEC_BACKEND
if (!bn->dead_end) if (!bn->dead_end)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * IDENTIFICATION
* $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.182 2008/03/26 21:10:39 alvherre Exp $ * $PostgreSQL: pgsql/src/backend/utils/init/postinit.c,v 1.183 2008/04/26 22:47:40 tgl Exp $
* *
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "catalog/pg_database.h" #include "catalog/pg_database.h"
#include "catalog/pg_tablespace.h" #include "catalog/pg_tablespace.h"
#include "libpq/hba.h" #include "libpq/hba.h"
#include "libpq/libpq-be.h"
#include "mb/pg_wchar.h" #include "mb/pg_wchar.h"
#include "miscadmin.h" #include "miscadmin.h"
#include "pgstat.h" #include "pgstat.h"
...@@ -577,6 +578,16 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username, ...@@ -577,6 +578,16 @@ InitPostgres(const char *in_dbname, Oid dboid, const char *username,
if (!bootstrap) if (!bootstrap)
CheckMyDatabase(dbname, am_superuser); CheckMyDatabase(dbname, am_superuser);
/*
* If we're trying to shut down, only superusers can connect.
*/
if (!am_superuser &&
MyProcPort != NULL &&
MyProcPort->canAcceptConnections == CAC_WAITBACKUP)
ereport(FATAL,
(errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
errmsg("must be superuser to connect during database shutdown")));
/* /*
* Check a normal user hasn't connected to a superuser reserved slot. * Check a normal user hasn't connected to a superuser reserved slot.
*/ */
......
...@@ -11,7 +11,7 @@ ...@@ -11,7 +11,7 @@
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * Portions Copyright (c) 1994, Regents of the University of California
* *
* $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.65 2008/01/01 19:45:58 momjian Exp $ * $PostgreSQL: pgsql/src/include/libpq/libpq-be.h,v 1.66 2008/04/26 22:47:40 tgl Exp $
* *
*------------------------------------------------------------------------- *-------------------------------------------------------------------------
*/ */
...@@ -69,7 +69,8 @@ typedef struct ...@@ -69,7 +69,8 @@ typedef struct
typedef enum CAC_state typedef enum CAC_state
{ {
CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY,
CAC_WAITBACKUP
} CAC_state; } CAC_state;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment