Michael Paquier wrote: > > In that vein, I propose a function pg_promote() to promote > > physical standby servers. > > No fundamental issues from me regarding the concept of being able to > trigger a promotion remotely, so +1. Do we want this capability as well > for fallback_promote? My gut tells me no, and that we ought to drop > this option at some point in the future, still that's worth mentioning. > > You may want to move PROMOTE_SIGNAL_FILE in a position where xlogfuncs.c > could use it.
Good, idea; updated patch attached. Yours, Laurenz Albe
From 63ba6c6f8088bea138e924b4180a08086d339eb5 Mon Sep 17 00:00:00 2001 From: Laurenz Albe <laurenz.a...@cybertec.at> Date: Thu, 4 Oct 2018 13:24:03 +0200 Subject: [PATCH] Add pg_promote() to promote standby servers --- doc/src/sgml/func.sgml | 20 +++++++++++ doc/src/sgml/high-availability.sgml | 2 +- doc/src/sgml/recovery-config.sgml | 3 +- src/backend/access/transam/xlog.c | 2 -- src/backend/access/transam/xlogfuncs.c | 48 ++++++++++++++++++++++++++ src/include/access/xlog.h | 4 +++ src/include/catalog/pg_proc.dat | 4 +++ 7 files changed, 79 insertions(+), 4 deletions(-) diff --git a/doc/src/sgml/func.sgml b/doc/src/sgml/func.sgml index 4331bebc96..7beeaeacde 100644 --- a/doc/src/sgml/func.sgml +++ b/doc/src/sgml/func.sgml @@ -18596,6 +18596,9 @@ SELECT set_config('log_statement_stats', 'off', false); <indexterm> <primary>pg_terminate_backend</primary> </indexterm> + <indexterm> + <primary>pg_promote</primary> + </indexterm> <indexterm> <primary>signal</primary> @@ -18655,6 +18658,16 @@ SELECT set_config('log_statement_stats', 'off', false); however only superusers can terminate superuser backends. </entry> </row> + <row> + <entry> + <literal><function>pg_promote()</function></literal> + </entry> + <entry><type>boolean</type></entry> + <entry>Promote a physical standby server. This function can only be + called by superusers and will only have an effect when run on + a standby server. + </entry> + </row> </tbody> </tgroup> </table> @@ -18692,6 +18705,13 @@ SELECT set_config('log_statement_stats', 'off', false); subprocess. </para> + <para> + <function>pg_promote()</function> sends a signal to the server that causes it + to leave standby mode. Since sending signals is by nature asynchronous, + successful execution of the function does not guarantee that the server has + already been promoted. + </para> + </sect2> <sect2 id="functions-admin-backup"> diff --git a/doc/src/sgml/high-availability.sgml b/doc/src/sgml/high-availability.sgml index 8cb77f85ec..6014817d9e 100644 --- a/doc/src/sgml/high-availability.sgml +++ b/doc/src/sgml/high-availability.sgml @@ -1472,7 +1472,7 @@ synchronous_standby_names = 'ANY 2 (s1, s2, s3)' <para> To trigger failover of a log-shipping standby server, - run <command>pg_ctl promote</command> or create a trigger + run <command>pg_ctl promote</command>, call <function>pg_promote()</function>, or create a trigger file with the file name and path specified by the <varname>trigger_file</varname> setting in <filename>recovery.conf</filename>. If you're planning to use <command>pg_ctl promote</command> to fail over, <varname>trigger_file</varname> is diff --git a/doc/src/sgml/recovery-config.sgml b/doc/src/sgml/recovery-config.sgml index 92825fdf19..d06cd0b08e 100644 --- a/doc/src/sgml/recovery-config.sgml +++ b/doc/src/sgml/recovery-config.sgml @@ -439,7 +439,8 @@ restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows <para> Specifies a trigger file whose presence ends recovery in the standby. Even if this value is not set, you can still promote - the standby using <command>pg_ctl promote</command>. + the standby using <command>pg_ctl promote</command> or calling + <function>pg_promote()</function>. This setting has no effect if <varname>standby_mode</varname> is <literal>off</literal>. </para> </listitem> diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 3025d0badb..bb422e9a13 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -81,8 +81,6 @@ extern uint32 bootstrap_data_checksum_version; /* File path names (all relative to $PGDATA) */ #define RECOVERY_COMMAND_FILE "recovery.conf" #define RECOVERY_COMMAND_DONE "recovery.done" -#define PROMOTE_SIGNAL_FILE "promote" -#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote" /* User-settable parameters */ diff --git a/src/backend/access/transam/xlogfuncs.c b/src/backend/access/transam/xlogfuncs.c index 9731742978..ab37b03dee 100644 --- a/src/backend/access/transam/xlogfuncs.c +++ b/src/backend/access/transam/xlogfuncs.c @@ -35,6 +35,7 @@ #include "storage/fd.h" #include "storage/ipc.h" +#include <unistd.h> /* * Store label file and tablespace map during non-exclusive backups. @@ -697,3 +698,50 @@ pg_backup_start_time(PG_FUNCTION_ARGS) PG_RETURN_DATUM(xtime); } + +/* + * Promote a standby server. + * + * A result of "true" means that promotion has been initiated. + */ +Datum +pg_promote(PG_FUNCTION_ARGS) +{ + FILE *promote_file; + + if (!superuser()) + ereport(ERROR, + (errcode(ERRCODE_INSUFFICIENT_PRIVILEGE), + errmsg("must be superuser to promote standby servers"))); + + if (!RecoveryInProgress() || !StandbyMode) + PG_RETURN_BOOL(false); + + /* create the promote signal file */ + promote_file = AllocateFile(PROMOTE_SIGNAL_FILE, "w"); + if (!promote_file) + { + ereport(WARNING, + (errmsg("could not create file \"%s\": %m", PROMOTE_SIGNAL_FILE))); + PG_RETURN_BOOL(false); + } + + if (FreeFile(promote_file)) + { + /* probably unreachable, but it is better to be safe */ + ereport(WARNING, + (errmsg("could not write to file \"%s\": %m", PROMOTE_SIGNAL_FILE))); + PG_RETURN_BOOL(false); + } + + /* signal the postmaster */ + if (kill(PostmasterPid, SIGUSR1) != 0) + { + ereport(WARNING, + (errmsg("failed to send signal to postmaster: %m"))); + (void) unlink(PROMOTE_SIGNAL_FILE); + PG_RETURN_BOOL(false); + } + + PG_RETURN_BOOL(true); +} diff --git a/src/include/access/xlog.h b/src/include/access/xlog.h index 421ba6d775..a5a3c59007 100644 --- a/src/include/access/xlog.h +++ b/src/include/access/xlog.h @@ -192,6 +192,10 @@ extern bool XLOG_DEBUG; #define XLOG_INCLUDE_ORIGIN 0x01 /* include the replication origin */ #define XLOG_MARK_UNIMPORTANT 0x02 /* record not important for durability */ +/* files to signal promotion to primary */ +#define PROMOTE_SIGNAL_FILE "promote" +#define FALLBACK_PROMOTE_SIGNAL_FILE "fallback_promote" + /* Checkpoint statistics */ typedef struct CheckpointStatsData diff --git a/src/include/catalog/pg_proc.dat b/src/include/catalog/pg_proc.dat index 860571440a..a26e5216da 100644 --- a/src/include/catalog/pg_proc.dat +++ b/src/include/catalog/pg_proc.dat @@ -5997,6 +5997,10 @@ proname => 'pg_backup_start_time', provolatile => 's', prorettype => 'timestamptz', proargtypes => '', prosrc => 'pg_backup_start_time' }, +{ oid => '3436', descr => 'promote standby server', + proname => 'pg_promote', provolatile => 'v', + prorettype => 'bool', proargtypes => '', + prosrc => 'pg_promote' }, { oid => '2848', descr => 'switch to new wal file', proname => 'pg_switch_wal', provolatile => 'v', prorettype => 'pg_lsn', proargtypes => '', prosrc => 'pg_switch_wal' }, -- 2.17.1