*** a/doc/src/sgml/func.sgml
--- b/doc/src/sgml/func.sgml
***************
*** 13602,13607 **** postgres=# SELECT * FROM pg_xlogfile_name_offset(pg_stop_backup());
--- 13602,13622 ----
the function returns NULL.
+
+
+ pg_trigger_failover()
+
+ bool
+ Request the standby to end recovery and become the master.
+ Even if is not specified, this triggers
+ failover. But it's important to specify trigger_file>
+ to enable failover even when the server is not in Hot Standby mode and
+ the function is not allowed to run. The function returns
+ false> if the server is not running recovery,
+ true> otherwise. Note that this cannot bring up the standby
+ which uses pg_standby>.
+
+
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 610,621 **** protocol to make nodes agree on a serializable transactional order.
later disconnected, the standby goes back to step 1 and tries to
restore the file from the archive again. This loop of retries from the
archive, pg_xlog>, and via streaming replication goes on until the server
! is stopped or failover is triggered by a trigger file.
Standby mode is exited and the server switches to normal operation,
! when a trigger file is found (trigger_file>). Before failover,
any WAL immediately available in the archive or in pg_xlog> will be
restored, but no attempt is made to connect to the master.
--- 610,623 ----
later disconnected, the standby goes back to step 1 and tries to
restore the file from the archive again. This loop of retries from the
archive, pg_xlog>, and via streaming replication goes on until the server
! is stopped or failover is triggered by a trigger file or
! pg_trigger_failover>.
Standby mode is exited and the server switches to normal operation,
! when a trigger file is found (trigger_file>) or
! pg_trigger_failover> is called. Before failover,
any WAL immediately available in the archive or in pg_xlog> will be
restored, but no attempt is made to connect to the master.
***************
*** 694,699 **** protocol to make nodes agree on a serializable transactional order.
--- 696,706 ----
If you're setting up the standby server for reporting
purposes, with no plans to fail over to it, trigger_file>
is not required.
+ Even if trigger_file> is not specified, you can trigger
+ failover by using pg_trigger_failover>. But it's important
+ to specify trigger_file> to enable failover even when
+ the server is not in Hot Standby mode and the function is not allowed
+ to run.
***************
*** 927,934 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
To trigger failover of a log-shipping standby server, create a trigger
file with the filename and path specified by the trigger_file>
! setting in recovery.conf>. If trigger_file> is
! not given, there is no way to exit recovery in the standby and promote
it to a master. That can be useful for e.g reporting servers that are
only used to offload read-only queries from the primary, not for high
availability purposes.
--- 934,942 ----
To trigger failover of a log-shipping standby server, create a trigger
file with the filename and path specified by the trigger_file>
! setting in recovery.conf> or call pg_trigger_failover>.
! If trigger_file> is not given and hot_standby> is not
! enabled, there is no way to exit recovery in the standby and promote
it to a master. That can be useful for e.g reporting servers that are
only used to offload read-only queries from the primary, not for high
availability purposes.
*** a/doc/src/sgml/recovery-config.sgml
--- b/doc/src/sgml/recovery-config.sgml
***************
*** 288,295 **** restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
Specifies a trigger file whose presence ends recovery in the
! standby. If no trigger file is specified, the standby never exits
! recovery.
This setting has no effect if standby_mode> is off>.
--- 288,296 ----
Specifies a trigger file whose presence ends recovery in the
! standby. Even if no trigger file is specified, you can request the standby
! to exit recovery by using pg_trigger_failover> if hot standby
! is enabled.
This setting has no effect if standby_mode> is off>.
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 416,421 **** typedef struct XLogCtlData
--- 416,427 ----
/* timestamp of last COMMIT/ABORT record replayed (or being replayed) */
TimestampTz recoveryLastXTime;
+ /*
+ * failoverRequested indicates if failover has been requested via
+ * pg_trigger_failover. Protected by info_lck.
+ */
+ bool failoverRequested;
+
slock_t info_lck; /* locks shared variables shown above */
} XLogCtlData;
***************
*** 8869,8874 **** pg_last_xlog_replay_location(PG_FUNCTION_ARGS)
--- 8875,8909 ----
}
/*
+ * Promote the standby to the master by requesting startup process to
+ * end recovery.
+ *
+ * Even if trigger_file parameter is not specified in recovery.conf,
+ * this function triggers failover.
+ *
+ * Returns FALSE if there is no startup process that we request to
+ * end recovery, TRUE otherwise.
+ *
+ * XXX: Should this return FALSE if standby mode is not enabled too?
+ */
+ Datum
+ pg_trigger_failover(PG_FUNCTION_ARGS)
+ {
+ /* use volatile pointer to prevent code rearrangement */
+ volatile XLogCtlData *xlogctl = XLogCtl;
+
+ if (!RecoveryInProgress())
+ PG_RETURN_BOOL(false);
+
+ SpinLockAcquire(&xlogctl->info_lck);
+ xlogctl->failoverRequested = true;
+ SpinLockRelease(&xlogctl->info_lck);
+
+ WakeupRecovery();
+ PG_RETURN_BOOL(true);
+ }
+
+ /*
* Compute an xlog file name and decimal byte offset given a WAL location,
* such as is returned by pg_stop_backup() or pg_xlog_switch().
*
***************
*** 9516,9524 **** retry:
failedSources |= sources;
/*
! * Check to see if the trigger file exists. Note that we
! * do this only after failure, so when you create the
! * trigger file, we still finish replaying as much as we
* can from archive and pg_xlog before failover.
*/
if (CheckForStandbyTrigger())
--- 9551,9559 ----
failedSources |= sources;
/*
! * Check to see if failover has been requested. Note that
! * we do this only after failure, so when you request
! * failover, we still finish replaying as much as we
* can from archive and pg_xlog before failover.
*/
if (CheckForStandbyTrigger())
***************
*** 9690,9704 **** emode_for_corrupt_record(int emode, XLogRecPtr RecPtr)
}
/*
! * Check to see if the trigger file exists. If it does, request postmaster
! * to shut down walreceiver, wait for it to exit, remove the trigger
! * file, and return true.
*/
static bool
CheckForStandbyTrigger(void)
{
struct stat stat_buf;
if (TriggerFile == NULL)
return false;
--- 9725,9759 ----
}
/*
! * Check to see if failover has been requested. If it's been done,
! * request postmaster to shut down walreceiver, wait for it to exit,
! * remove the trigger file if the request has come via it,
! * and return true.
*/
static bool
CheckForStandbyTrigger(void)
{
+ /* use volatile pointer to prevent code rearrangement */
+ volatile XLogCtlData *xlogctl = XLogCtl;
+ bool failoverRequested = false;
struct stat stat_buf;
+ SpinLockAcquire(&xlogctl->info_lck);
+ failoverRequested = xlogctl->failoverRequested;
+
+ /*
+ * It's not strictly necessary to reset the flag since we will not re-enter
+ * the standby mode after failover, but let's do it for the sake of tidiness.
+ */
+ xlogctl->failoverRequested = false;
+ SpinLockRelease(&xlogctl->info_lck);
+
+ if (failoverRequested)
+ {
+ ShutdownWalRcv();
+ return true;
+ }
+
if (TriggerFile == NULL)
return false;
*** a/src/include/access/xlog_internal.h
--- b/src/include/access/xlog_internal.h
***************
*** 271,276 **** extern Datum pg_current_xlog_location(PG_FUNCTION_ARGS);
--- 271,277 ----
extern Datum pg_current_xlog_insert_location(PG_FUNCTION_ARGS);
extern Datum pg_last_xlog_receive_location(PG_FUNCTION_ARGS);
extern Datum pg_last_xlog_replay_location(PG_FUNCTION_ARGS);
+ extern Datum pg_trigger_failover(PG_FUNCTION_ARGS);
extern Datum pg_xlogfile_name_offset(PG_FUNCTION_ARGS);
extern Datum pg_xlogfile_name(PG_FUNCTION_ARGS);
extern Datum pg_is_in_recovery(PG_FUNCTION_ARGS);
*** a/src/include/catalog/pg_proc.h
--- b/src/include/catalog/pg_proc.h
***************
*** 3380,3385 **** DATA(insert OID = 3820 ( pg_last_xlog_receive_location PGNSP PGUID 12 1 0 0 f f
--- 3380,3387 ----
DESCR("current xlog flush location");
DATA(insert OID = 3821 ( pg_last_xlog_replay_location PGNSP PGUID 12 1 0 0 f f f t f v 0 0 25 "" _null_ _null_ _null_ _null_ pg_last_xlog_replay_location _null_ _null_ _null_ ));
DESCR("last xlog replay location");
+ DATA(insert OID = 3819 ( pg_trigger_failover PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_trigger_failover _null_ _null_ _null_ ));
+ DESCR("trigger failover");
DATA(insert OID = 2621 ( pg_reload_conf PGNSP PGUID 12 1 0 0 f f f t f v 0 0 16 "" _null_ _null_ _null_ _null_ pg_reload_conf _null_ _null_ _null_ ));
DESCR("reload configuration files");