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

Reply via email to