*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 959,964 **** synchronous_replication = on
--- 959,970 ----
+ When a smart shutdown is requested, new replication connections are
+ allowed in order to transfer all outstanding WAL records to standby
+ servers and wake up backends waiting for synchronous replication.
+
+
+
Users will stop waiting if a fast shutdown is requested, though the
server does not fully shutdown until all outstanding WAL records are
transferred to standby servers.
*** a/doc/src/sgml/runtime.sgml
--- b/doc/src/sgml/runtime.sgml
***************
*** 1386,1392 **** echo -17 > /proc/self/oom_adj
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). If the server is in recovery when a smart
shutdown is requested, recovery and streaming replication will be
stopped only after all regular sessions have terminated.
--- 1386,1396 ----
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). While regular sessions are open, new replication
! connections will still be allowed (this exception allows WAL sender
! process to send all outstanding WAL records to standby servers and
! wake up backends waiting for synchronous replication).
! If the server is in recovery when a smart
shutdown is requested, recovery and streaming replication will be
stopped only after all regular sessions have terminated.
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 248,254 **** static bool RecoveryError = false; /* T if WAL recovery failed */
*
* Normal child backends can only be launched when we are in PM_RUN or
* PM_HOT_STANDBY state. (We also allow launch of normal
! * child backends in PM_WAIT_BACKUP state, but only for superusers.)
* In other states we handle connection requests by launching "dead_end"
* 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
--- 248,255 ----
*
* Normal child backends can only be launched when we are in PM_RUN or
* PM_HOT_STANDBY state. (We also allow launch of normal
! * child backends in PM_WAIT_BACKUP_AND_SYNCREP state, but only for
! * superusers and walsenders.)
* In other states we handle connection requests by launching "dead_end"
* 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
***************
*** 276,282 **** typedef enum
PM_RECOVERY, /* in archive recovery mode */
PM_HOT_STANDBY, /* in hot standby mode */
PM_RUN, /* normal "database is alive" state */
! PM_WAIT_BACKUP, /* waiting for online backup mode to end */
PM_WAIT_READONLY, /* waiting for read only backends to exit */
PM_WAIT_BACKENDS, /* waiting for live backends to exit */
PM_SHUTDOWN, /* waiting for bgwriter to do shutdown ckpt */
--- 277,284 ----
PM_RECOVERY, /* in archive recovery mode */
PM_HOT_STANDBY, /* in hot standby mode */
PM_RUN, /* normal "database is alive" state */
! PM_WAIT_BACKUP_AND_SYNCREP, /* waiting for online backup mode and regular
! * backends (waiting for sync rep) to end */
PM_WAIT_READONLY, /* waiting for read only backends to exit */
PM_WAIT_BACKENDS, /* waiting for live backends to exit */
PM_SHUTDOWN, /* waiting for bgwriter to do shutdown ckpt */
***************
*** 1850,1856 **** retry1:
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
break;
! case CAC_WAITBACKUP:
/* OK for now, will check in InitPostgres */
break;
case CAC_OK:
--- 1852,1858 ----
(errcode(ERRCODE_TOO_MANY_CONNECTIONS),
errmsg("sorry, too many clients already")));
break;
! case CAC_WAIT_BACKUP_AND_SYNCREP:
/* OK for now, will check in InitPostgres */
break;
case CAC_OK:
***************
*** 1934,1949 **** canAcceptConnections(void)
* Can't start backends when in startup/shutdown/inconsistent recovery
* state.
*
! * 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.
! * Note that neither CAC_OK nor CAC_WAITBACKUP can safely be returned
! * until we have checked for too many children.
*/
if (pmState != PM_RUN)
{
! if (pmState == PM_WAIT_BACKUP)
! result = CAC_WAITBACKUP; /* allow superusers only */
else if (Shutdown > NoShutdown)
return CAC_SHUTDOWN; /* shutdown is pending */
else if (!FatalError &&
--- 1936,1952 ----
* Can't start backends when in startup/shutdown/inconsistent recovery
* state.
*
! * In PM_WAIT_BACKUP_AND_SYNCREP state only superusers and standby servers
! * can connect (this must be allowed so that a superuser can end online
! * backup mode and walsender can wake up backends waiting for sync rep);
! * we return CAC_WAIT_BACKUP_AND_SYNCREP code to indicate that this must
! * be checked later. Note that neither CAC_OK nor CAC_WAIT_BACKUP_AND_SYNCREP
! * can safely be returned until we have checked for too many children.
*/
if (pmState != PM_RUN)
{
! if (pmState == PM_WAIT_BACKUP_AND_SYNCREP)
! result = CAC_WAIT_BACKUP_AND_SYNCREP; /* allow superusers and walsenders only */
else if (Shutdown > NoShutdown)
return CAC_SHUTDOWN; /* shutdown is pending */
else if (!FatalError &&
***************
*** 2214,2220 **** pmdie(SIGNAL_ARGS)
* and walreceiver processes.
*/
pmState = (pmState == PM_RUN) ?
! PM_WAIT_BACKUP : PM_WAIT_READONLY;
}
/*
--- 2217,2223 ----
* and walreceiver processes.
*/
pmState = (pmState == PM_RUN) ?
! PM_WAIT_BACKUP_AND_SYNCREP : PM_WAIT_READONLY;
}
/*
***************
*** 2249,2255 **** pmdie(SIGNAL_ARGS)
pmState = PM_WAIT_BACKENDS;
}
else if (pmState == PM_RUN ||
! pmState == PM_WAIT_BACKUP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_WAIT_BACKENDS ||
pmState == PM_HOT_STANDBY)
--- 2252,2258 ----
pmState = PM_WAIT_BACKENDS;
}
else if (pmState == PM_RUN ||
! pmState == PM_WAIT_BACKUP_AND_SYNCREP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_WAIT_BACKENDS ||
pmState == PM_HOT_STANDBY)
***************
*** 2828,2834 **** HandleChildCrash(int pid, int exitstatus, const char *procname)
if (pmState == PM_RECOVERY ||
pmState == PM_HOT_STANDBY ||
pmState == PM_RUN ||
! pmState == PM_WAIT_BACKUP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_SHUTDOWN)
pmState = PM_WAIT_BACKENDS;
--- 2831,2837 ----
if (pmState == PM_RECOVERY ||
pmState == PM_HOT_STANDBY ||
pmState == PM_RUN ||
! pmState == PM_WAIT_BACKUP_AND_SYNCREP ||
pmState == PM_WAIT_READONLY ||
pmState == PM_SHUTDOWN)
pmState = PM_WAIT_BACKENDS;
***************
*** 2896,2907 **** LogChildExit(int lev, const char *procname, int pid, int exitstatus)
static void
PostmasterStateMachine(void)
{
! if (pmState == PM_WAIT_BACKUP)
{
/*
! * PM_WAIT_BACKUP state ends when online backup mode is not active.
*/
! if (!BackupInProgress())
pmState = PM_WAIT_BACKENDS;
}
--- 2899,2911 ----
static void
PostmasterStateMachine(void)
{
! if (pmState == PM_WAIT_BACKUP_AND_SYNCREP)
{
/*
! * PM_WAIT_BACKUP_AND_SYNCREP state ends when online backup mode is
! * not active and there is no regular backend waiting for sync rep.
*/
! if (!BackupInProgress() && CountChildren(BACKEND_TYPE_NORMAL) == 0)
pmState = PM_WAIT_BACKENDS;
}
***************
*** 3233,3239 **** BackendStartup(Port *port)
/* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections();
bn->dead_end = (port->canAcceptConnections != CAC_OK &&
! port->canAcceptConnections != CAC_WAITBACKUP);
/*
* Unless it's a dead_end child, assign it a child slot number
--- 3237,3243 ----
/* Pass down canAcceptConnections state */
port->canAcceptConnections = canAcceptConnections();
bn->dead_end = (port->canAcceptConnections != CAC_OK &&
! port->canAcceptConnections != CAC_WAIT_BACKUP_AND_SYNCREP);
/*
* Unless it's a dead_end child, assign it a child slot number
*** a/src/backend/utils/init/postinit.c
--- b/src/backend/utils/init/postinit.c
***************
*** 608,628 **** InitPostgres(const char *in_dbname, Oid dboid, const char *username,
}
/*
! * If we're trying to shut down, only superusers can connect, and new
! * replication connections are not allowed.
*/
! if ((!am_superuser || am_walsender) &&
MyProcPort != NULL &&
! MyProcPort->canAcceptConnections == CAC_WAITBACKUP)
{
! if (am_walsender)
! ereport(FATAL,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("new replication connections are not allowed during database shutdown")));
! else
! ereport(FATAL,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser to connect during database shutdown")));
}
/*
--- 608,624 ----
}
/*
! * If we're trying to shut down, only superusers and standby servers
! * can connect.
*/
! if (!am_superuser &&
! !am_walsender &&
MyProcPort != NULL &&
! MyProcPort->canAcceptConnections == CAC_WAIT_BACKUP_AND_SYNCREP)
{
! ereport(FATAL,
! (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE),
! errmsg("must be superuser or standby server to connect during database shutdown")));
}
/*
*** a/src/include/libpq/libpq-be.h
--- b/src/include/libpq/libpq-be.h
***************
*** 73,79 **** typedef struct
typedef enum CAC_state
{
CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY,
! CAC_WAITBACKUP
} CAC_state;
--- 73,79 ----
typedef enum CAC_state
{
CAC_OK, CAC_STARTUP, CAC_SHUTDOWN, CAC_RECOVERY, CAC_TOOMANY,
! CAC_WAIT_BACKUP_AND_SYNCREP
} CAC_state;