pg_ctl failover Re: Latches, signals, and waiting
On Wed, Sep 15, 2010 at 11:14 PM, Heikki Linnakangas
<heikki.linnakangas@enterprisedb.com> wrote:
On 15/09/10 16:55, Tom Lane wrote:
So I'm wondering if we couldn't eliminate the five-second sleep
requirement here too. It's problematic anyhow, since somebody looking
for energy efficiency will still feel it's too short, while somebody
concerned about fast failover will feel it's too long.Yep.
Could the
standby triggering protocol be modified so that it involves sending a
signal, not just creating a file?Seems reasonable, at least if we still provide an option for more frequent
polling and no need to send signal.(One issue is that it's not clear what that'd translate to on Windows.)
pg_ctl failover ? At the moment, the location of the trigger file is
configurable, but if we accept a constant location like "$PGDATA/failover"
pg_ctl could do the whole thing, create the file and send signal. pg_ctl on
Window already knows how to send the "signal" via the named pipe signal
emulation.
The attached patch implements the above-mentioned pg_ctl failover.
Comments? Objections?
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
Attachments:
pg_ctl_failover_v1.patchapplication/octet-stream; name=pg_ctl_failover_v1.patchDownload
*** a/doc/src/sgml/ref/pg_ctl-ref.sgml
--- b/doc/src/sgml/ref/pg_ctl-ref.sgml
***************
*** 77,82 **** PostgreSQL documentation
--- 77,89 ----
<cmdsynopsis>
<command>pg_ctl</command>
+ <arg choice="plain">failover</arg>
+ <arg>-s</arg>
+ <arg>-D <replaceable>datadir</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>pg_ctl</command>
<arg choice="plain">reload</arg>
<arg>-s</arg>
<arg>-D <replaceable>datadir</replaceable></arg>
***************
*** 184,189 **** PostgreSQL documentation
--- 191,201 ----
</para>
<para>
+ In <option>failover</option> mode, the standby server that is
+ running in the specified data directory is promoted to the primary.
+ </para>
+
+ <para>
<option>reload</option> mode simply sends the
<command>postgres</command> process a <systemitem>SIGHUP</>
signal, causing it to reread its configuration files
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 64,69 ****
--- 64,70 ----
#define BACKUP_LABEL_OLD "backup_label.old"
#define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done"
+ #define FAILOVER_SIGNAL_FILE "failover"
/* User-settable parameters */
***************
*** 546,551 **** typedef struct xl_parameter_change
--- 547,553 ----
*/
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;
+ static volatile sig_atomic_t standby_triggered = false;
/*
* Flag set when executing a restore command, to tell SIGTERM signal handler
***************
*** 9196,9201 **** StartupProcSigUsr1Handler(SIGNAL_ARGS)
--- 9198,9211 ----
latch_sigusr1_handler();
}
+ /* SIGUSR2: set flag to finish recovery */
+ static void
+ StartupProcTriggerHandler(SIGNAL_ARGS)
+ {
+ standby_triggered = true;
+ WakeupRecovery();
+ }
+
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
StartupProcSigHupHandler(SIGNAL_ARGS)
***************
*** 9273,9279 **** StartupProcessMain(void)
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, SIG_IGN);
/*
* Reset some signals that are accepted by postmaster but not here
--- 9283,9289 ----
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, StartupProcTriggerHandler);
/*
* Reset some signals that are accepted by postmaster but not here
***************
*** 9719,9733 **** 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;
--- 9729,9753 ----
}
/*
! * Check to see if the user-specified trigger file exists and
! * if a failover has been requested by pg_ctl. If either does,
! * request postmaster to shut down walreceiver, wait for it to exit,
! * and return true.
*/
static bool
CheckForStandbyTrigger(void)
{
struct stat stat_buf;
+ if (standby_triggered)
+ {
+ ereport(LOG,
+ (errmsg("failover requested")));
+ ShutdownWalRcv();
+ standby_triggered = false;
+ return true;
+ }
+
if (TriggerFile == NULL)
return false;
***************
*** 9743,9748 **** CheckForStandbyTrigger(void)
--- 9763,9789 ----
}
/*
+ * Check to see if a failover has been requested by pg_ctl. Should be
+ * called by postmaster after receiving SIGUSR1.
+ */
+ bool
+ CheckFailoverSignal(void)
+ {
+ struct stat stat_buf;
+
+ if (stat(FAILOVER_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ /*
+ * Since we are in a signal handler, it's not safe
+ * to elog. We silently ignore the error of unlink.
+ */
+ unlink(FAILOVER_SIGNAL_FILE);
+ return true;
+ }
+ return false;
+ }
+
+ /*
* Wake up startup process to replay newly arrived WAL, or to notice that
* failover has been requested.
*/
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 4271,4276 **** sigusr1_handler(SIGNAL_ARGS)
--- 4271,4284 ----
WalReceiverPID = StartWalReceiver();
}
+ if (CheckFailoverSignal() && StartupPID != 0 &&
+ (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
+ pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
+ {
+ /* Tell startup process to finish recovery */
+ signal_child(StartupPID, SIGUSR2);
+ }
+
PG_SETMASK(&UnBlockSig);
errno = save_errno;
*** a/src/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
***************
*** 63,68 **** typedef enum
--- 63,69 ----
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
+ FAILOVER_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND,
***************
*** 107,112 **** static void do_init(void);
--- 108,114 ----
static void do_start(void);
static void do_stop(void);
static void do_restart(void);
+ static void do_failover(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(pgpid_t pid);
***************
*** 146,151 **** static char postopts_file[MAXPGPATH];
--- 148,154 ----
static char pid_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH];
+ static char failover_file[MAXPGPATH];
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
static void unlimit_core_size(void);
***************
*** 871,877 **** do_stop(void)
/*
! * restart/reload routines
*/
static void
--- 874,880 ----
/*
! * restart/failover/reload routines
*/
static void
***************
*** 964,969 **** do_restart(void)
--- 967,1029 ----
do_start();
}
+ static void
+ do_failover(void)
+ {
+ FILE *fofile;
+ pgpid_t pid;
+ struct stat statbuf;
+
+ pid = get_pgpid();
+
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot request failover; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ exit(1);
+ }
+
+ /* If recovery.conf doesn't exist, the server is not in standby mode */
+ if (stat(recovery_file, &statbuf) != 0)
+ {
+ write_stderr(_("%s: cannot request failover; "
+ "server is not in standby mode\n"),
+ progname);
+ exit(1);
+ }
+
+ if ((fofile = fopen(failover_file, "w")) == NULL)
+ {
+ write_stderr(_("%s: could not create failover signal file \"%s\": %s\n"),
+ progname, failover_file, strerror(errno));
+ exit(1);
+ }
+ if (fclose(fofile))
+ {
+ write_stderr(_("%s: could not write failover signal file \"%s\": %s\n"),
+ progname, failover_file, strerror(errno));
+ exit(1);
+ }
+
+ sig = SIGUSR1;
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send failover signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("failover requested\n"));
+ }
+
static void
do_reload(void)
***************
*** 1616,1632 **** do_advice(void)
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s start [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
! printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
! " [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
! printf(_(" %s status [-D DATADIR]\n"), progname);
! printf(_(" %s kill SIGNALNAME PID\n"), progname);
#if defined(WIN32) || defined(__CYGWIN__)
printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
" [-S START-TYPE] [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);
--- 1676,1693 ----
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, failover, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s start [-w] [-t SECS] [-D DATADIR] [-s] [-l FILENAME] [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
! printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
! " [-o \"OPTIONS\"]\n"), progname);
! printf(_(" %s failover [-D DATADIR] [-s]\n"), progname);
! printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
! printf(_(" %s status [-D DATADIR]\n"), progname);
! printf(_(" %s kill SIGNALNAME PID\n"), progname);
#if defined(WIN32) || defined(__CYGWIN__)
printf(_(" %s register [-N SERVICENAME] [-U USERNAME] [-P PASSWORD] [-D DATADIR]\n"
" [-S START-TYPE] [-w] [-t SECS] [-o \"OPTIONS\"]\n"), progname);
***************
*** 1949,1954 **** main(int argc, char **argv)
--- 2010,2017 ----
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
+ else if (strcmp(argv[optind], "failover") == 0)
+ ctl_command = FAILOVER_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
***************
*** 2035,2040 **** main(int argc, char **argv)
--- 2098,2104 ----
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(failover_file, MAXPGPATH, "%s/failover", pg_data);
}
switch (ctl_command)
***************
*** 2054,2059 **** main(int argc, char **argv)
--- 2118,2126 ----
case RESTART_COMMAND:
do_restart();
break;
+ case FAILOVER_COMMAND:
+ do_failover();
+ break;
case RELOAD_COMMAND:
do_reload();
break;
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 310,315 **** extern TimeLineID GetRecoveryTargetTLI(void);
--- 310,316 ----
extern void HandleStartupProcInterrupts(void);
extern void StartupProcessMain(void);
+ extern bool CheckFailoverSignal(void);
extern void WakeupRecovery(void);
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast);
On Thu, Jan 13, 2011 at 00:14, Fujii Masao <masao.fujii@gmail.com> wrote:
pg_ctl failover ? At the moment, the location of the trigger file is
configurable, but if we accept a constant location like "$PGDATA/failover"
pg_ctl could do the whole thing, create the file and send signal. pg_ctl on
Window already knows how to send the "signal" via the named pipe signal
emulation.The attached patch implements the above-mentioned pg_ctl failover.
I have three comments:
- Will we call it "failover"? We will use the command also in "switchover"
operations. "pg_ctl promote" might be more neutral, but users might be
hard to imagine replication feature from "promote".
- pg_ctl should unlink failover_files when it failed to send failover signals.
- "standby_triggered" variable might be renamed to "failover_triggered" or so.
--
Itagaki Takahiro
On Thu, Jan 13, 2011 at 11:29 AM, Itagaki Takahiro
<itagaki.takahiro@gmail.com> wrote:
On Thu, Jan 13, 2011 at 00:14, Fujii Masao <masao.fujii@gmail.com> wrote:
pg_ctl failover ? At the moment, the location of the trigger file is
configurable, but if we accept a constant location like "$PGDATA/failover"
pg_ctl could do the whole thing, create the file and send signal. pg_ctl on
Window already knows how to send the "signal" via the named pipe signal
emulation.The attached patch implements the above-mentioned pg_ctl failover.
I have three comments:
Thanks for the review!
- Will we call it "failover"? We will use the command also in "switchover"
operations. "pg_ctl promote" might be more neutral, but users might be
hard to imagine replication feature from "promote".
OK. Similarly, I should also change the word "failover" used in function and
variable names to the "promote"? For example,
#define PROMOTE_SIGNAL_FILE "promote" rather than
#define FAILOVER_SIGNAL_FILE "failover"?
- pg_ctl should unlink failover_files when it failed to send failover signals.
Good catch.
- "standby_triggered" variable might be renamed to "failover_triggered" or so.
Furthermore, "failover_triggered" should be renamed to "promote_triggered"?
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
On 13.01.2011 04:29, Itagaki Takahiro wrote:
On Thu, Jan 13, 2011 at 00:14, Fujii Masao<masao.fujii@gmail.com> wrote:
pg_ctl failover ? At the moment, the location of the trigger file is
configurable, but if we accept a constant location like "$PGDATA/failover"
pg_ctl could do the whole thing, create the file and send signal. pg_ctl on
Window already knows how to send the "signal" via the named pipe signal
emulation.The attached patch implements the above-mentioned pg_ctl failover.
I have three comments:
- Will we call it "failover"? We will use the command also in "switchover"
operations. "pg_ctl promote" might be more neutral, but users might be
hard to imagine replication feature from "promote".
I agree that "failover" or even "switchover" is too specific. You might
want promote a server even if you keep the old master still running, if
you're creating a temporary copy of the master repository for testing
purposes etc.
+1 for "promote". People unfamiliar with the replication stuff might not
immediately understand that it's related to replication, but they
wouldn't have any use for the option anyway. It should be clear to
anyone who needs it.
--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com
On Thu, Jan 13, 2011 at 5:00 AM, Heikki Linnakangas
<heikki.linnakangas@enterprisedb.com> wrote:
On 13.01.2011 04:29, Itagaki Takahiro wrote:
On Thu, Jan 13, 2011 at 00:14, Fujii Masao<masao.fujii@gmail.com> wrote:
pg_ctl failover ? At the moment, the location of the trigger file is
configurable, but if we accept a constant location like
"$PGDATA/failover"
pg_ctl could do the whole thing, create the file and send signal. pg_ctl
on
Window already knows how to send the "signal" via the named pipe signal
emulation.The attached patch implements the above-mentioned pg_ctl failover.
I have three comments:
- Will we call it "failover"? We will use the command also in "switchover"
operations. "pg_ctl promote" might be more neutral, but users might be
hard to imagine replication feature from "promote".I agree that "failover" or even "switchover" is too specific. You might want
promote a server even if you keep the old master still running, if you're
creating a temporary copy of the master repository for testing purposes etc.+1 for "promote". People unfamiliar with the replication stuff might not
immediately understand that it's related to replication, but they wouldn't
have any use for the option anyway. It should be clear to anyone who needs
it.
I agree.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Thu, Jan 13, 2011 at 7:00 PM, Heikki Linnakangas
<heikki.linnakangas@enterprisedb.com> wrote:
+1 for "promote". People unfamiliar with the replication stuff might not
immediately understand that it's related to replication, but they wouldn't
have any use for the option anyway. It should be clear to anyone who needs
it.
I did s/failover/promote. Here is the updated patch.
- pg_ctl should unlink failover_files when it failed to send failover signals.
Done.
And, I changed some descriptions about trigger in high-availability.sgml
and recovery-config.sgml.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
Attachments:
pg_ctl_failover_v2.patchapplication/octet-stream; name=pg_ctl_failover_v2.patchDownload
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 615,621 **** protocol to make nodes agree on a serializable transactional order.
<para>
Standby mode is exited and the server switches to normal operation,
! when a trigger file is found (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
--- 615,622 ----
<para>
Standby mode is exited and the server switches to normal operation,
! when <command>pg_ctl promote</> is run or a trigger file is found
! (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
***************
*** 684,694 **** protocol to make nodes agree on a serializable transactional order.
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. You will also need to set <varname>trigger_file</> to make
! it possible to fail over.
! If you're setting up the standby server for reporting
! purposes, with no plans to fail over to it, <varname>trigger_file</>
! is not required.
</para>
<para>
--- 685,692 ----
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. If you're planning to use <command>pg_ctl promote</> to
! fail over, <varname>trigger_file</> is not required.
</para>
<para>
***************
*** 709,715 **** protocol to make nodes agree on a serializable transactional order.
standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
restore_command = 'cp /path/to/archive/%f %p'
- trigger_file = '/path/to/trigger_file'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
</programlisting>
</para>
--- 707,712 ----
***************
*** 948,960 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
</para>
<para>
! To trigger failover of a log-shipping standby server, create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If <varname>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.
</para>
</sect1>
--- 945,956 ----
</para>
<para>
! To trigger failover of a log-shipping standby server,
! run <command>pg_ctl promote</> or create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If you're planning to use
! <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
! not required.
</para>
</sect1>
*** a/doc/src/sgml/recovery-config.sgml
--- b/doc/src/sgml/recovery-config.sgml
***************
*** 298,305 **** restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
<listitem>
<para>
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 <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
--- 298,305 ----
<listitem>
<para>
Specifies a trigger file whose presence ends recovery in the
! standby. If you plan to use <command>pg_ctl promote</> to promote
! the standby, no trigger file needs to be specified.
This setting has no effect if <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
*** a/doc/src/sgml/ref/pg_ctl-ref.sgml
--- b/doc/src/sgml/ref/pg_ctl-ref.sgml
***************
*** 77,82 **** PostgreSQL documentation
--- 77,89 ----
<cmdsynopsis>
<command>pg_ctl</command>
+ <arg choice="plain">promote</arg>
+ <arg>-s</arg>
+ <arg>-D <replaceable>datadir</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>pg_ctl</command>
<arg choice="plain">reload</arg>
<arg>-s</arg>
<arg>-D <replaceable>datadir</replaceable></arg>
***************
*** 184,189 **** PostgreSQL documentation
--- 191,201 ----
</para>
<para>
+ In <option>promote</option> mode, the standby server that is
+ running in the specified data directory is promoted to the primary.
+ </para>
+
+ <para>
<option>reload</option> mode simply sends the
<command>postgres</command> process a <systemitem>SIGHUP</>
signal, causing it to reread its configuration files
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 64,69 ****
--- 64,70 ----
#define BACKUP_LABEL_OLD "backup_label.old"
#define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done"
+ #define PROMOTE_SIGNAL_FILE "promote"
/* User-settable parameters */
***************
*** 546,551 **** typedef struct xl_parameter_change
--- 547,553 ----
*/
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;
+ static volatile sig_atomic_t promote_triggered = false;
/*
* Flag set when executing a restore command, to tell SIGTERM signal handler
***************
*** 9196,9201 **** StartupProcSigUsr1Handler(SIGNAL_ARGS)
--- 9198,9211 ----
latch_sigusr1_handler();
}
+ /* SIGUSR2: set flag to finish recovery */
+ static void
+ StartupProcTriggerHandler(SIGNAL_ARGS)
+ {
+ promote_triggered = true;
+ WakeupRecovery();
+ }
+
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
StartupProcSigHupHandler(SIGNAL_ARGS)
***************
*** 9273,9279 **** StartupProcessMain(void)
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, SIG_IGN);
/*
* Reset some signals that are accepted by postmaster but not here
--- 9283,9289 ----
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, StartupProcTriggerHandler);
/*
* Reset some signals that are accepted by postmaster but not here
***************
*** 9719,9733 **** 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;
--- 9729,9753 ----
}
/*
! * Check to see if the user-specified trigger file exists and
! * if a promote request has arrived. If either does,
! * request postmaster to shut down walreceiver, wait for it to exit,
! * and return true.
*/
static bool
CheckForStandbyTrigger(void)
{
struct stat stat_buf;
+ if (promote_triggered)
+ {
+ ereport(LOG,
+ (errmsg("received promote request")));
+ ShutdownWalRcv();
+ promote_triggered = false;
+ return true;
+ }
+
if (TriggerFile == NULL)
return false;
***************
*** 9743,9748 **** CheckForStandbyTrigger(void)
--- 9763,9789 ----
}
/*
+ * Check to see if a promote request has arrived. Should be
+ * called by postmaster after receiving SIGUSR1.
+ */
+ bool
+ CheckPromoteSignal(void)
+ {
+ struct stat stat_buf;
+
+ if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ /*
+ * Since we are in a signal handler, it's not safe
+ * to elog. We silently ignore the error of unlink.
+ */
+ unlink(PROMOTE_SIGNAL_FILE);
+ return true;
+ }
+ return false;
+ }
+
+ /*
* Wake up startup process to replay newly arrived WAL, or to notice that
* failover has been requested.
*/
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 4271,4276 **** sigusr1_handler(SIGNAL_ARGS)
--- 4271,4284 ----
WalReceiverPID = StartWalReceiver();
}
+ if (CheckPromoteSignal() && StartupPID != 0 &&
+ (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
+ pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
+ {
+ /* Tell startup process to finish recovery */
+ signal_child(StartupPID, SIGUSR2);
+ }
+
PG_SETMASK(&UnBlockSig);
errno = save_errno;
*** a/src/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
***************
*** 63,68 **** typedef enum
--- 63,69 ----
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
+ PROMOTE_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND,
***************
*** 107,112 **** static void do_init(void);
--- 108,114 ----
static void do_start(void);
static void do_stop(void);
static void do_restart(void);
+ static void do_promote(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(pgpid_t pid);
***************
*** 146,151 **** static char postopts_file[MAXPGPATH];
--- 148,154 ----
static char pid_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH];
+ static char promote_file[MAXPGPATH];
#if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE)
static void unlimit_core_size(void);
***************
*** 871,877 **** do_stop(void)
/*
! * restart/reload routines
*/
static void
--- 874,880 ----
/*
! * restart/promote/reload routines
*/
static void
***************
*** 964,969 **** do_restart(void)
--- 967,1032 ----
do_start();
}
+ static void
+ do_promote(void)
+ {
+ FILE *prmfile;
+ pgpid_t pid;
+ struct stat statbuf;
+
+ pid = get_pgpid();
+
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot promote server; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ exit(1);
+ }
+
+ /* If recovery.conf doesn't exist, the server is not in standby mode */
+ if (stat(recovery_file, &statbuf) != 0)
+ {
+ write_stderr(_("%s: cannot promote server; "
+ "server is not in standby mode\n"),
+ progname);
+ exit(1);
+ }
+
+ if ((prmfile = fopen(promote_file, "w")) == NULL)
+ {
+ write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+ if (fclose(prmfile))
+ {
+ write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ sig = SIGUSR1;
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ if (unlink(promote_file) != 0)
+ write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("server promoting\n"));
+ }
+
static void
do_reload(void)
***************
*** 1616,1622 **** do_advice(void)
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
--- 1679,1685 ----
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, promote, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
***************
*** 1624,1629 **** do_help(void)
--- 1687,1693 ----
printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
" [-o \"OPTIONS\"]\n"), progname);
+ printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
printf(_(" %s kill SIGNALNAME PID\n"), progname);
***************
*** 1949,1954 **** main(int argc, char **argv)
--- 2013,2020 ----
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
+ else if (strcmp(argv[optind], "promote") == 0)
+ ctl_command = PROMOTE_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
***************
*** 2035,2040 **** main(int argc, char **argv)
--- 2101,2107 ----
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
}
switch (ctl_command)
***************
*** 2054,2059 **** main(int argc, char **argv)
--- 2121,2129 ----
case RESTART_COMMAND:
do_restart();
break;
+ case PROMOTE_COMMAND:
+ do_promote();
+ break;
case RELOAD_COMMAND:
do_reload();
break;
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 310,315 **** extern TimeLineID GetRecoveryTargetTLI(void);
--- 310,316 ----
extern void HandleStartupProcInterrupts(void);
extern void StartupProcessMain(void);
+ extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast);
On Thu, Jan 13, 2011 at 9:08 PM, Fujii Masao <masao.fujii@gmail.com> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
Attachments:
pg_ctl_promote_v3.patchapplication/octet-stream; name=pg_ctl_promote_v3.patchDownload
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 615,621 **** protocol to make nodes agree on a serializable transactional order.
<para>
Standby mode is exited and the server switches to normal operation,
! when a trigger file is found (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
--- 615,622 ----
<para>
Standby mode is exited and the server switches to normal operation,
! when <command>pg_ctl promote</> is run or a trigger file is found
! (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
***************
*** 684,694 **** protocol to make nodes agree on a serializable transactional order.
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. You will also need to set <varname>trigger_file</> to make
! it possible to fail over.
! If you're setting up the standby server for reporting
! purposes, with no plans to fail over to it, <varname>trigger_file</>
! is not required.
</para>
<para>
--- 685,692 ----
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. If you're planning to use <command>pg_ctl promote</> to
! fail over, <varname>trigger_file</> is not required.
</para>
<para>
***************
*** 709,715 **** protocol to make nodes agree on a serializable transactional order.
standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
restore_command = 'cp /path/to/archive/%f %p'
- trigger_file = '/path/to/trigger_file'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
</programlisting>
</para>
--- 707,712 ----
***************
*** 948,960 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
</para>
<para>
! To trigger failover of a log-shipping standby server, create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If <varname>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.
</para>
</sect1>
--- 945,956 ----
</para>
<para>
! To trigger failover of a log-shipping standby server,
! run <command>pg_ctl promote</> or create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If you're planning to use
! <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
! not required.
</para>
</sect1>
*** a/doc/src/sgml/recovery-config.sgml
--- b/doc/src/sgml/recovery-config.sgml
***************
*** 298,305 **** restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
<listitem>
<para>
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 <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
--- 298,305 ----
<listitem>
<para>
Specifies a trigger file whose presence ends recovery in the
! standby. If you plan to use <command>pg_ctl promote</> to promote
! the standby, no trigger file needs to be specified.
This setting has no effect if <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
*** a/doc/src/sgml/ref/pg_ctl-ref.sgml
--- b/doc/src/sgml/ref/pg_ctl-ref.sgml
***************
*** 77,82 **** PostgreSQL documentation
--- 77,89 ----
<cmdsynopsis>
<command>pg_ctl</command>
+ <arg choice="plain">promote</arg>
+ <arg>-s</arg>
+ <arg>-D <replaceable>datadir</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>pg_ctl</command>
<arg choice="plain">reload</arg>
<arg>-s</arg>
<arg>-D <replaceable>datadir</replaceable></arg>
***************
*** 184,189 **** PostgreSQL documentation
--- 191,201 ----
</para>
<para>
+ In <option>promote</option> mode, the standby server that is
+ running in the specified data directory is promoted to the primary.
+ </para>
+
+ <para>
<option>reload</option> mode simply sends the
<command>postgres</command> process a <systemitem>SIGHUP</>
signal, causing it to reread its configuration files
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 64,69 ****
--- 64,70 ----
#define BACKUP_LABEL_OLD "backup_label.old"
#define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done"
+ #define PROMOTE_SIGNAL_FILE "promote"
/* User-settable parameters */
***************
*** 546,551 **** typedef struct xl_parameter_change
--- 547,553 ----
*/
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;
+ static volatile sig_atomic_t promote_triggered = false;
/*
* Flag set when executing a restore command, to tell SIGTERM signal handler
***************
*** 9196,9201 **** StartupProcSigUsr1Handler(SIGNAL_ARGS)
--- 9198,9211 ----
latch_sigusr1_handler();
}
+ /* SIGUSR2: set flag to finish recovery */
+ static void
+ StartupProcTriggerHandler(SIGNAL_ARGS)
+ {
+ promote_triggered = true;
+ WakeupRecovery();
+ }
+
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
StartupProcSigHupHandler(SIGNAL_ARGS)
***************
*** 9273,9279 **** StartupProcessMain(void)
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, SIG_IGN);
/*
* Reset some signals that are accepted by postmaster but not here
--- 9283,9289 ----
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, StartupProcTriggerHandler);
/*
* Reset some signals that are accepted by postmaster but not here
***************
*** 9719,9733 **** 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;
--- 9729,9753 ----
}
/*
! * Check to see if the user-specified trigger file exists and
! * if a promote request has arrived. If either does,
! * request postmaster to shut down walreceiver, wait for it to exit,
! * and return true.
*/
static bool
CheckForStandbyTrigger(void)
{
struct stat stat_buf;
+ if (promote_triggered)
+ {
+ ereport(LOG,
+ (errmsg("received promote request")));
+ ShutdownWalRcv();
+ promote_triggered = false;
+ return true;
+ }
+
if (TriggerFile == NULL)
return false;
***************
*** 9743,9748 **** CheckForStandbyTrigger(void)
--- 9763,9789 ----
}
/*
+ * Check to see if a promote request has arrived. Should be
+ * called by postmaster after receiving SIGUSR1.
+ */
+ bool
+ CheckPromoteSignal(void)
+ {
+ struct stat stat_buf;
+
+ if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ /*
+ * Since we are in a signal handler, it's not safe
+ * to elog. We silently ignore the error of unlink.
+ */
+ unlink(PROMOTE_SIGNAL_FILE);
+ return true;
+ }
+ return false;
+ }
+
+ /*
* Wake up startup process to replay newly arrived WAL, or to notice that
* failover has been requested.
*/
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 4272,4277 **** sigusr1_handler(SIGNAL_ARGS)
--- 4272,4285 ----
WalReceiverPID = StartWalReceiver();
}
+ if (CheckPromoteSignal() && StartupPID != 0 &&
+ (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
+ pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
+ {
+ /* Tell startup process to finish recovery */
+ signal_child(StartupPID, SIGUSR2);
+ }
+
PG_SETMASK(&UnBlockSig);
errno = save_errno;
*** a/src/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
***************
*** 62,67 **** typedef enum
--- 62,68 ----
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
+ PROMOTE_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND,
***************
*** 96,101 **** static char postopts_file[MAXPGPATH];
--- 97,103 ----
static char pid_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH];
+ static char promote_file[MAXPGPATH];
#if defined(WIN32) || defined(__CYGWIN__)
static DWORD pgctl_start_type = SERVICE_AUTO_START;
***************
*** 124,129 **** static void do_init(void);
--- 126,132 ----
static void do_start(void);
static void do_stop(void);
static void do_restart(void);
+ static void do_promote(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(pgpid_t pid);
***************
*** 872,878 **** do_stop(void)
/*
! * restart/reload routines
*/
static void
--- 875,881 ----
/*
! * restart/promote/reload routines
*/
static void
***************
*** 965,970 **** do_restart(void)
--- 968,1033 ----
do_start();
}
+ static void
+ do_promote(void)
+ {
+ FILE *prmfile;
+ pgpid_t pid;
+ struct stat statbuf;
+
+ pid = get_pgpid();
+
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot promote server; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ exit(1);
+ }
+
+ /* If recovery.conf doesn't exist, the server is not in standby mode */
+ if (stat(recovery_file, &statbuf) != 0)
+ {
+ write_stderr(_("%s: cannot promote server; "
+ "server is not in standby mode\n"),
+ progname);
+ exit(1);
+ }
+
+ if ((prmfile = fopen(promote_file, "w")) == NULL)
+ {
+ write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+ if (fclose(prmfile))
+ {
+ write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ sig = SIGUSR1;
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ if (unlink(promote_file) != 0)
+ write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("server promoting\n"));
+ }
+
static void
do_reload(void)
***************
*** 1617,1623 **** do_advice(void)
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
--- 1680,1686 ----
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, promote, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
***************
*** 1625,1630 **** do_help(void)
--- 1688,1694 ----
printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
" [-o \"OPTIONS\"]\n"), progname);
+ printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
printf(_(" %s kill SIGNALNAME PID\n"), progname);
***************
*** 1950,1955 **** main(int argc, char **argv)
--- 2014,2021 ----
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
+ else if (strcmp(argv[optind], "promote") == 0)
+ ctl_command = PROMOTE_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
***************
*** 2036,2041 **** main(int argc, char **argv)
--- 2102,2108 ----
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
}
switch (ctl_command)
***************
*** 2055,2060 **** main(int argc, char **argv)
--- 2122,2130 ----
case RESTART_COMMAND:
do_restart();
break;
+ case PROMOTE_COMMAND:
+ do_promote();
+ break;
case RELOAD_COMMAND:
do_reload();
break;
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 310,315 **** extern TimeLineID GetRecoveryTargetTLI(void);
--- 310,316 ----
extern void HandleStartupProcInterrupts(void);
extern void StartupProcessMain(void);
+ extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
extern XLogRecPtr do_pg_start_backup(const char *backupidstr, bool fast);
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.
If there's enough interest, I will propose such a function for next CF.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Fri, Jan 28, 2011 at 08:44, Tatsuo Ishii <ishii@postgresql.org> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.
I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.
If there's enough interest, I will propose such a function for next CF.
Just as a reminder, remember that next CF means 9.2.
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
On Fri, Jan 28, 2011 at 08:44, Tatsuo Ishii <ishii@postgresql.org> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.If there's enough interest, I will propose such a function for next CF.
Just as a reminder, remember that next CF means 9.2.
Oh, I meant current CF (has started in January)
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Fri, Jan 28, 2011 at 4:57 PM, Magnus Hagander <magnus@hagander.net> wrote:
On Fri, Jan 28, 2011 at 08:44, Tatsuo Ishii <ishii@postgresql.org> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.
Agreed. I submitted the patch before, but I forgot to update it
and add it to CF.
http://archives.postgresql.org/message-id/AANLkTimuHbxbuM+zLkaEX3aDqSeiMUE3xb4ww1QtsLmf@mail.gmail.com
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
On Fri, Jan 28, 2011 at 4:57 PM, Magnus Hagander <magnus@hagander.net> wrote:
On Fri, Jan 28, 2011 at 08:44, Tatsuo Ishii <ishii@postgresql.org> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.Agreed. I submitted the patch before, but I forgot to update it
and add it to CF.
http://archives.postgresql.org/message-id/AANLkTimuHbxbuM+zLkaEX3aDqSeiMUE3xb4ww1QtsLmf@mail.gmail.com
Great!
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Fri, Jan 28, 2011 at 3:40 AM, Tatsuo Ishii <ishii@postgresql.org> wrote:
On Fri, Jan 28, 2011 at 4:57 PM, Magnus Hagander <magnus@hagander.net> wrote:
On Fri, Jan 28, 2011 at 08:44, Tatsuo Ishii <ishii@postgresql.org> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.Agreed. I submitted the patch before, but I forgot to update it
and add it to CF.
http://archives.postgresql.org/message-id/AANLkTimuHbxbuM+zLkaEX3aDqSeiMUE3xb4ww1QtsLmf@mail.gmail.comGreat!
I hate to be a wet blanket, but the number of patches in this CF is
going the wrong direction.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
Robert Haas <robertmhaas@gmail.com> writes:
On Fri, Jan 28, 2011 at 3:40 AM, Tatsuo Ishii <ishii@postgresql.org> wrote:
Agreed. I submitted the patch before, but I forgot to update it
and add it to CF.
http://archives.postgresql.org/message-id/AANLkTimuHbxbuM+zLkaEX3aDqSeiMUE3xb4ww1QtsLmf@mail.gmail.comGreat!
I hate to be a wet blanket, but the number of patches in this CF is
going the wrong direction.
Yes. I'm not sure that the fact that something was discussed months ago
entitles the submitter to a free exemption from the requirement to meet
the CF submission deadline.
regards, tom lane
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
I'm thinking about implementing a function which does a promotion for
the standby. It will make pgpool lot easier to control the promotion
since it allow to fire the promotion operation (either creating a
trigger file or sending a signal) via SQL, not ssh etc.I agree that having this available via SQL would be useful in a number
of cases. pgpool or such being one, but also for example pgadmin.If there's enough interest, I will propose such a function for next CF.
Just as a reminder, remember that next CF means 9.2.
Ok. I will write a C user function and add to pgpool source tree. I
think it will be fairly easy to create a trigger file in the function.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Sat, Jan 29, 2011 at 1:11 AM, Tatsuo Ishii <ishii@postgresql.org> wrote:
Ok. I will write a C user function and add to pgpool source tree. I
think it will be fairly easy to create a trigger file in the function.
If the "pg_ctl promote" patch will have been committed, I recommend that
the C function should send the signal to the startup process rather than
creating the trigger file. Because the trigger file is checked every for 5s,
which would lengthen the failover time by an average 2.5s.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
On Mon, Jan 31, 2011 at 11:52, Fujii Masao <masao.fujii@gmail.com> wrote:
On Sat, Jan 29, 2011 at 1:11 AM, Tatsuo Ishii <ishii@postgresql.org> wrote:
Ok. I will write a C user function and add to pgpool source tree. I
think it will be fairly easy to create a trigger file in the function.If the "pg_ctl promote" patch will have been committed, I recommend that
the C function should send the signal to the startup process rather than
creating the trigger file.
The C function needs to create a trigger file in $PGDATA/promote
before sending signals, no? system("pg_ctl promote") seems
the easiest way if you use an external module.
--
Itagaki Takahiro
If the "pg_ctl promote" patch will have been committed, I recommend that
the C function should send the signal to the startup process rather than
creating the trigger file. Because the trigger file is checked every for 5s,
which would lengthen the failover time by an average 2.5s.
Ok, probably I could make the function smart enough to signal or not
by looking at the PostgreSQL version.
BTW is it possible to export following variable in xlog.c?
static char *TriggerFile = NULL;
That would make coding of the C function lot easier.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Mon, Jan 31, 2011 at 12:31 PM, Itagaki Takahiro
<itagaki.takahiro@gmail.com> wrote:
The C function needs to create a trigger file in $PGDATA/promote
before sending signals, no?
No. At least in the current patch, just receipt of SIGUSR2 causes the
startup process to end a recovery. The startup process doesn't check
the existence of $PGDATA/promote, though postmaster does.
system("pg_ctl promote") seems
the easiest way if you use an external module.
Yeah, that's true.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
On Mon, Jan 31, 2011 at 12:35 PM, Tatsuo Ishii <ishii@postgresql.org> wrote:
If the "pg_ctl promote" patch will have been committed, I recommend that
the C function should send the signal to the startup process rather than
creating the trigger file. Because the trigger file is checked every for 5s,
which would lengthen the failover time by an average 2.5s.Ok, probably I could make the function smart enough to signal or not
by looking at the PostgreSQL version.BTW is it possible to export following variable in xlog.c?
static char *TriggerFile = NULL;
That would make coding of the C function lot easier.
If you change the function so that it sends the signal or call
system("pg_ctl promote"), exporting that variable seems to
be unnecessary. Because pg_ctl promote can promote
the server even if trigger_file is not supplied. You don't need
to check whether trigger_file is set or not, in the C function.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
On Mon, Jan 31, 2011 at 12:35 PM, Tatsuo Ishii <ishii@postgresql.org> wrote:
If the "pg_ctl promote" patch will have been committed, I recommend that
the C function should send the signal to the startup process rather than
creating the trigger file. Because the trigger file is checked every for 5s,
which would lengthen the failover time by an average 2.5s.Ok, probably I could make the function smart enough to signal or not
by looking at the PostgreSQL version.BTW is it possible to export following variable in xlog.c?
static char *TriggerFile = NULL;
That would make coding of the C function lot easier.
If you change the function so that it sends the signal or call
system("pg_ctl promote"), exporting that variable seems to
be unnecessary. Because pg_ctl promote can promote
the server even if trigger_file is not supplied. You don't need
to check whether trigger_file is set or not, in the C function.
True.
BTW for 9.0, perhaps copy&paste parseRecoveryCommandFileLine() from
xlog.c into the C function is the only way to go.
--
Tatsuo Ishii
SRA OSS, Inc. Japan
English: http://www.sraoss.co.jp/index_en.php
Japanese: http://www.sraoss.co.jp
On Wed, Jan 19, 2011 at 1:01 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
On Thu, Jan 13, 2011 at 9:08 PM, Fujii Masao <masao.fujii@gmail.com> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
This patch looks fine to me. I will mark it Ready for Committer.
(Someone else please feel free to pick it up for the actual commit, if
you have cycles.)
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company
On Tue, Feb 8, 2011 at 05:24, Robert Haas <robertmhaas@gmail.com> wrote:
On Wed, Jan 19, 2011 at 1:01 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
On Thu, Jan 13, 2011 at 9:08 PM, Fujii Masao <masao.fujii@gmail.com> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
This patch looks fine to me. I will mark it Ready for Committer.
(Someone else please feel free to pick it up for the actual commit, if
you have cycles.)
I see that the docs part of the patch removes the mentioning of
reporting servers - is that intentional, or a mistake? Seems that
usecase still remains, no?
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
On Thu, Feb 10, 2011 at 15:25, Magnus Hagander <magnus@hagander.net> wrote:
On Tue, Feb 8, 2011 at 05:24, Robert Haas <robertmhaas@gmail.com> wrote:
On Wed, Jan 19, 2011 at 1:01 AM, Fujii Masao <masao.fujii@gmail.com> wrote:
On Thu, Jan 13, 2011 at 9:08 PM, Fujii Masao <masao.fujii@gmail.com> wrote:
I did s/failover/promote. Here is the updated patch.
I rebased the patch to current git master.
This patch looks fine to me. I will mark it Ready for Committer.
(Someone else please feel free to pick it up for the actual commit, if
you have cycles.)I see that the docs part of the patch removes the mentioning of
reporting servers - is that intentional, or a mistake? Seems that
usecase still remains, no?
Also, the patch no longer applies, since it conflicts with
faa0550572583f51dba25611ab0f1d1c31de559b.
Since you (Fujii-san) wrote both of them, feel like rebasing it
properly for current master?
--
Magnus Hagander
Me: http://www.hagander.net/
Work: http://www.redpill-linpro.com/
Thanks for the review!
On Thu, Feb 10, 2011 at 11:25 PM, Magnus Hagander <magnus@hagander.net> wrote:
I see that the docs part of the patch removes the mentioning of
reporting servers - is that intentional, or a mistake? Seems that
usecase still remains, no?
It was intentional, but I agree with you. I re-added the mention to
the reporting servers.
On Thu, Feb 10, 2011 at 11:30 PM, Magnus Hagander <magnus@hagander.net> wrote:
Also, the patch no longer applies, since it conflicts with
faa0550572583f51dba25611ab0f1d1c31de559b.Since you (Fujii-san) wrote both of them, feel like rebasing it
properly for current master?
Yeah, I rebased the patch to the current git master and attached it.
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
Attachments:
pg_ctl_promote_v4.patchapplication/octet-stream; name=pg_ctl_promote_v4.patchDownload
*** a/doc/src/sgml/high-availability.sgml
--- b/doc/src/sgml/high-availability.sgml
***************
*** 616,622 **** protocol to make nodes agree on a serializable transactional order.
<para>
Standby mode is exited and the server switches to normal operation,
! when a trigger file is found (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
--- 616,623 ----
<para>
Standby mode is exited and the server switches to normal operation,
! when <command>pg_ctl promote</> is run or a trigger file is found
! (<varname>trigger_file</>). Before failover,
any WAL immediately available in the archive or in <filename>pg_xlog</> will be
restored, but no attempt is made to connect to the master.
</para>
***************
*** 685,695 **** protocol to make nodes agree on a serializable transactional order.
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. You will also need to set <varname>trigger_file</> to make
! it possible to fail over.
If you're setting up the standby server for reporting
! purposes, with no plans to fail over to it, <varname>trigger_file</>
! is not required.
</para>
<para>
--- 686,697 ----
If you're setting up the standby server for high availability purposes,
set up WAL archiving, connections and authentication like the primary
server, because the standby server will work as a primary server after
! failover. If you're planning to use <command>pg_ctl promote</> to
! fail over, <varname>trigger_file</> is not required.
If you're setting up the standby server for reporting
! purposes, with no plans to fail over to it, neither
! <command>pg_ctl promote</> needs to be run nor <varname>trigger_file</>
! is required.
</para>
<para>
***************
*** 710,716 **** protocol to make nodes agree on a serializable transactional order.
standby_mode = 'on'
primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
restore_command = 'cp /path/to/archive/%f %p'
- trigger_file = '/path/to/trigger_file'
archive_cleanup_command = 'pg_archivecleanup /path/to/archive %r'
</programlisting>
</para>
--- 712,717 ----
***************
*** 949,961 **** primary_conninfo = 'host=192.168.1.50 port=5432 user=foo password=foopass'
</para>
<para>
! To trigger failover of a log-shipping standby server, create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If <varname>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.
</para>
</sect1>
--- 950,964 ----
</para>
<para>
! To trigger failover of a log-shipping standby server,
! run <command>pg_ctl promote</> or create a trigger
file with the filename and path specified by the <varname>trigger_file</>
! setting in <filename>recovery.conf</>. If you're planning to use
! <command>pg_ctl promote</> to fail over, <varname>trigger_file</> is
! not required. If you're setting up the reporting servers that are
only used to offload read-only queries from the primary, not for high
! availability purposes, you don't need to exit recovery in the standby
! and to promote it to a master.
</para>
</sect1>
*** a/doc/src/sgml/recovery-config.sgml
--- b/doc/src/sgml/recovery-config.sgml
***************
*** 343,350 **** restore_command = 'copy "C:\\server\\archivedir\\%f" "%p"' # Windows
<listitem>
<para>
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 <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
--- 343,350 ----
<listitem>
<para>
Specifies a trigger file whose presence ends recovery in the
! standby. If you plan to use <command>pg_ctl promote</> to promote
! the standby, no trigger file needs to be specified.
This setting has no effect if <varname>standby_mode</> is <literal>off</>.
</para>
</listitem>
*** a/doc/src/sgml/ref/pg_ctl-ref.sgml
--- b/doc/src/sgml/ref/pg_ctl-ref.sgml
***************
*** 77,82 **** PostgreSQL documentation
--- 77,89 ----
<cmdsynopsis>
<command>pg_ctl</command>
+ <arg choice="plain">promote</arg>
+ <arg>-s</arg>
+ <arg>-D <replaceable>datadir</replaceable></arg>
+ </cmdsynopsis>
+
+ <cmdsynopsis>
+ <command>pg_ctl</command>
<arg choice="plain">reload</arg>
<arg>-s</arg>
<arg>-D <replaceable>datadir</replaceable></arg>
***************
*** 184,189 **** PostgreSQL documentation
--- 191,201 ----
</para>
<para>
+ In <option>promote</option> mode, the standby server that is
+ running in the specified data directory is promoted to the primary.
+ </para>
+
+ <para>
<option>reload</option> mode simply sends the
<command>postgres</command> process a <systemitem>SIGHUP</>
signal, causing it to reread its configuration files
*** a/src/backend/access/transam/xlog.c
--- b/src/backend/access/transam/xlog.c
***************
*** 62,67 ****
--- 62,68 ----
/* File path names (all relative to $PGDATA) */
#define RECOVERY_COMMAND_FILE "recovery.conf"
#define RECOVERY_COMMAND_DONE "recovery.done"
+ #define PROMOTE_SIGNAL_FILE "promote"
/* User-settable parameters */
***************
*** 565,570 **** typedef struct xl_restore_point
--- 566,572 ----
*/
static volatile sig_atomic_t got_SIGHUP = false;
static volatile sig_atomic_t shutdown_requested = false;
+ static volatile sig_atomic_t promote_triggered = false;
/*
* Flag set when executing a restore command, to tell SIGTERM signal handler
***************
*** 9659,9664 **** StartupProcSigUsr1Handler(SIGNAL_ARGS)
--- 9661,9674 ----
latch_sigusr1_handler();
}
+ /* SIGUSR2: set flag to finish recovery */
+ static void
+ StartupProcTriggerHandler(SIGNAL_ARGS)
+ {
+ promote_triggered = true;
+ WakeupRecovery();
+ }
+
/* SIGHUP: set flag to re-read config file at next convenient time */
static void
StartupProcSigHupHandler(SIGNAL_ARGS)
***************
*** 9736,9742 **** StartupProcessMain(void)
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, SIG_IGN);
/*
* Reset some signals that are accepted by postmaster but not here
--- 9746,9752 ----
pqsignal(SIGALRM, SIG_IGN);
pqsignal(SIGPIPE, SIG_IGN);
pqsignal(SIGUSR1, StartupProcSigUsr1Handler);
! pqsignal(SIGUSR2, StartupProcTriggerHandler);
/*
* Reset some signals that are accepted by postmaster but not here
***************
*** 10182,10190 **** 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)
--- 10192,10201 ----
}
/*
! * Check to see if the user-specified trigger file exists and
! * if a promote request has arrived. If either does,
! * request postmaster to shut down walreceiver, wait for it to exit,
! * and return true.
*/
static bool
CheckForStandbyTrigger(void)
***************
*** 10195,10200 **** CheckForStandbyTrigger(void)
--- 10206,10221 ----
if (triggered)
return true;
+ if (promote_triggered)
+ {
+ ereport(LOG,
+ (errmsg("received promote request")));
+ ShutdownWalRcv();
+ promote_triggered = false;
+ triggered = true;
+ return true;
+ }
+
if (TriggerFile == NULL)
return false;
***************
*** 10211,10216 **** CheckForStandbyTrigger(void)
--- 10232,10258 ----
}
/*
+ * Check to see if a promote request has arrived. Should be
+ * called by postmaster after receiving SIGUSR1.
+ */
+ bool
+ CheckPromoteSignal(void)
+ {
+ struct stat stat_buf;
+
+ if (stat(PROMOTE_SIGNAL_FILE, &stat_buf) == 0)
+ {
+ /*
+ * Since we are in a signal handler, it's not safe
+ * to elog. We silently ignore the error of unlink.
+ */
+ unlink(PROMOTE_SIGNAL_FILE);
+ return true;
+ }
+ return false;
+ }
+
+ /*
* Wake up startup process to replay newly arrived WAL, or to notice that
* failover has been requested.
*/
*** a/src/backend/postmaster/postmaster.c
--- b/src/backend/postmaster/postmaster.c
***************
*** 4284,4289 **** sigusr1_handler(SIGNAL_ARGS)
--- 4284,4297 ----
WalReceiverPID = StartWalReceiver();
}
+ if (CheckPromoteSignal() && StartupPID != 0 &&
+ (pmState == PM_STARTUP || pmState == PM_RECOVERY ||
+ pmState == PM_HOT_STANDBY || pmState == PM_WAIT_READONLY))
+ {
+ /* Tell startup process to finish recovery */
+ signal_child(StartupPID, SIGUSR2);
+ }
+
PG_SETMASK(&UnBlockSig);
errno = save_errno;
*** a/src/bin/pg_ctl/pg_ctl.c
--- b/src/bin/pg_ctl/pg_ctl.c
***************
*** 62,67 **** typedef enum
--- 62,68 ----
START_COMMAND,
STOP_COMMAND,
RESTART_COMMAND,
+ PROMOTE_COMMAND,
RELOAD_COMMAND,
STATUS_COMMAND,
KILL_COMMAND,
***************
*** 96,101 **** static char postopts_file[MAXPGPATH];
--- 97,103 ----
static char pid_file[MAXPGPATH];
static char backup_file[MAXPGPATH];
static char recovery_file[MAXPGPATH];
+ static char promote_file[MAXPGPATH];
#if defined(WIN32) || defined(__CYGWIN__)
static DWORD pgctl_start_type = SERVICE_AUTO_START;
***************
*** 124,129 **** static void do_init(void);
--- 126,132 ----
static void do_start(void);
static void do_stop(void);
static void do_restart(void);
+ static void do_promote(void);
static void do_reload(void);
static void do_status(void);
static void do_kill(pgpid_t pid);
***************
*** 872,878 **** do_stop(void)
/*
! * restart/reload routines
*/
static void
--- 875,881 ----
/*
! * restart/promote/reload routines
*/
static void
***************
*** 965,970 **** do_restart(void)
--- 968,1033 ----
do_start();
}
+ static void
+ do_promote(void)
+ {
+ FILE *prmfile;
+ pgpid_t pid;
+ struct stat statbuf;
+
+ pid = get_pgpid();
+
+ if (pid == 0) /* no pid file */
+ {
+ write_stderr(_("%s: PID file \"%s\" does not exist\n"), progname, pid_file);
+ write_stderr(_("Is server running?\n"));
+ exit(1);
+ }
+ else if (pid < 0) /* standalone backend, not postmaster */
+ {
+ pid = -pid;
+ write_stderr(_("%s: cannot promote server; "
+ "single-user server is running (PID: %ld)\n"),
+ progname, pid);
+ exit(1);
+ }
+
+ /* If recovery.conf doesn't exist, the server is not in standby mode */
+ if (stat(recovery_file, &statbuf) != 0)
+ {
+ write_stderr(_("%s: cannot promote server; "
+ "server is not in standby mode\n"),
+ progname);
+ exit(1);
+ }
+
+ if ((prmfile = fopen(promote_file, "w")) == NULL)
+ {
+ write_stderr(_("%s: could not create promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+ if (fclose(prmfile))
+ {
+ write_stderr(_("%s: could not write promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ sig = SIGUSR1;
+ if (kill((pid_t) pid, sig) != 0)
+ {
+ write_stderr(_("%s: could not send promote signal (PID: %ld): %s\n"),
+ progname, pid, strerror(errno));
+ if (unlink(promote_file) != 0)
+ write_stderr(_("%s: could not remove promote signal file \"%s\": %s\n"),
+ progname, promote_file, strerror(errno));
+ exit(1);
+ }
+
+ print_msg(_("server promoting\n"));
+ }
+
static void
do_reload(void)
***************
*** 1617,1623 **** do_advice(void)
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
--- 1680,1686 ----
static void
do_help(void)
{
! printf(_("%s is a utility to start, stop, restart, promote, reload configuration files,\n"
"report the status of a PostgreSQL server, or signal a PostgreSQL process.\n\n"), progname);
printf(_("Usage:\n"));
printf(_(" %s init[db] [-D DATADIR] [-s] [-o \"OPTIONS\"]\n"), progname);
***************
*** 1625,1630 **** do_help(void)
--- 1688,1694 ----
printf(_(" %s stop [-W] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"), progname);
printf(_(" %s restart [-w] [-t SECS] [-D DATADIR] [-s] [-m SHUTDOWN-MODE]\n"
" [-o \"OPTIONS\"]\n"), progname);
+ printf(_(" %s promote [-D DATADIR] [-s]\n"), progname);
printf(_(" %s reload [-D DATADIR] [-s]\n"), progname);
printf(_(" %s status [-D DATADIR]\n"), progname);
printf(_(" %s kill SIGNALNAME PID\n"), progname);
***************
*** 1950,1955 **** main(int argc, char **argv)
--- 2014,2021 ----
ctl_command = STOP_COMMAND;
else if (strcmp(argv[optind], "restart") == 0)
ctl_command = RESTART_COMMAND;
+ else if (strcmp(argv[optind], "promote") == 0)
+ ctl_command = PROMOTE_COMMAND;
else if (strcmp(argv[optind], "reload") == 0)
ctl_command = RELOAD_COMMAND;
else if (strcmp(argv[optind], "status") == 0)
***************
*** 2036,2041 **** main(int argc, char **argv)
--- 2102,2108 ----
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
+ snprintf(promote_file, MAXPGPATH, "%s/promote", pg_data);
}
switch (ctl_command)
***************
*** 2055,2060 **** main(int argc, char **argv)
--- 2122,2130 ----
case RESTART_COMMAND:
do_restart();
break;
+ case PROMOTE_COMMAND:
+ do_promote();
+ break;
case RELOAD_COMMAND:
do_reload();
break;
*** a/src/include/access/xlog.h
--- b/src/include/access/xlog.h
***************
*** 313,318 **** extern TimeLineID GetRecoveryTargetTLI(void);
--- 313,319 ----
extern void HandleStartupProcInterrupts(void);
extern void StartupProcessMain(void);
+ extern bool CheckPromoteSignal(void);
extern void WakeupRecovery(void);
/*
Fujii,
* Fujii Masao (masao.fujii@gmail.com) wrote:
Yeah, I rebased the patch to the current git master and attached it.
Reviewing this, I just had a couple of comments and questions. Overall,
I think it looks good and hence will be marking it 'Ready for
Committer'.
* You removed trigger_file from the list in
doc/src/sgml/high-availability.sgml and I'm not sure I agree with
that. It's still perfectly valid and could be used by someone
instead of pg_ctl promote. I'd recommend two things:
- Adding comments into this recovery.conf snippet
- Adding a comment indicationg that trigger_file is only needed if
you're not using pg_ctl promote.
* I'm not happy that pg_ctl.c doesn't #include something which defines
all the file names which are used, couldn't we use a header which
makes sense and is pulled in by pg_ctl.c and xlog.c to #define all of
these? Still, that's not really the fault of this patch.
* I'm a bit worried that there's just only so many USR signals that we
can send and it looks like we're burning another one here. Should we
be considering a better way to do this?
Thanks,
Stephen
On Tue, Feb 15, 2011 at 2:10 AM, Stephen Frost <sfrost@snowman.net> wrote:
Fujii,
* Fujii Masao (masao.fujii@gmail.com) wrote:
Yeah, I rebased the patch to the current git master and attached it.
Reviewing this, I just had a couple of comments and questions. Overall,
I think it looks good and hence will be marking it 'Ready for
Committer'.
Thanks for the review!
* You removed trigger_file from the list in
doc/src/sgml/high-availability.sgml and I'm not sure I agree with
that. It's still perfectly valid and could be used by someone
instead of pg_ctl promote. I'd recommend two things:
- Adding comments into this recovery.conf snippet
Adding the following is enough?
+# NOTE that if you plan to use "pg_ctl promote" command to promote
+# the standby, no trigger file needs to be specified.
- Adding a comment indicationg that trigger_file is only needed if
you're not using pg_ctl promote.
Where should I add such a comment?
* I'm not happy that pg_ctl.c doesn't #include something which defines
all the file names which are used, couldn't we use a header which
makes sense and is pulled in by pg_ctl.c and xlog.c to #define all of
these? Still, that's not really the fault of this patch.
That would make sense. But I'm not sure that's possible. As a trial,
I added '#include "access/xlog.h"' into pg_ctl.c and compiled the source,
but I got many compilation errors. So probably hacking Makefiles is
required to do that. Do you know where should be changed?
* I'm a bit worried that there's just only so many USR signals that we
can send and it looks like we're burning another one here. Should we
be considering a better way to do this?
You're worried about the case where users wrongly send the SIGUSR2
to the startup process, and then the standby is brought up to the master
unexpectedly?
Regards,
--
Fujii Masao
NIPPON TELEGRAPH AND TELEPHONE CORPORATION
NTT Open Source Software Center
* Fujii Masao (masao.fujii@gmail.com) wrote:
On Tue, Feb 15, 2011 at 2:10 AM, Stephen Frost <sfrost@snowman.net> wrote:
* You removed trigger_file from the list in
doc/src/sgml/high-availability.sgml and I'm not sure I agree with
that. It's still perfectly valid and could be used by someone
instead of pg_ctl promote. I'd recommend two things:
- Adding comments into this recovery.conf snippetAdding the following is enough?
+# NOTE that if you plan to use "pg_ctl promote" command to promote +# the standby, no trigger file needs to be specified.
No.. I was thinking of having comments throughout the whole file,
similar to what we have for postgresql.conf.sample. I realize it's an
example in the docs, but people are likely to copy & paste it into their
own files.
- Adding a comment indicationg that trigger_file is only needed if
you're not using pg_ctl promote.Where should I add such a comment?
This was still in the example recovery.conf in high-availability.sgml.
* I'm not happy that pg_ctl.c doesn't #include something which defines
all the file names which are used, couldn't we use a header which
makes sense and is pulled in by pg_ctl.c and xlog.c to #define all of
these? Still, that's not really the fault of this patch.That would make sense. But I'm not sure that's possible. As a trial,
I added '#include "access/xlog.h"' into pg_ctl.c and compiled the source,
but I got many compilation errors. So probably hacking Makefiles is
required to do that. Do you know where should be changed?
No, I wouldn't expect that to work.. I would have thought something
that was already included in the necessary places, eg, miscadmin.h.
* I'm a bit worried that there's just only so many USR signals that we
can send and it looks like we're burning another one here. Should we
be considering a better way to do this?You're worried about the case where users wrongly send the SIGUSR2
to the startup process, and then the standby is brought up to the master
unexpectedly?
No.. My concern was that it looked like we were adding a meaning to
SIGUSR2 which might make it unavailable for other uses later, and at
least according to man 7 signal on my system, there's only 2
User-defined signals available (SIGUSR1 and SIGUSR2)..
I just wouldn't want to use up something which is a finite resource
without good cause, in case we have a need for it later. Now, perhaps
that's not happening and my concern is unfounded.
Thanks,
Stephen
On Sun, Feb 13, 2011 at 10:18 PM, Fujii Masao <masao.fujii@gmail.com> wrote:
Thanks for the review!
On Thu, Feb 10, 2011 at 11:25 PM, Magnus Hagander <magnus@hagander.net> wrote:
I see that the docs part of the patch removes the mentioning of
reporting servers - is that intentional, or a mistake? Seems that
usecase still remains, no?It was intentional, but I agree with you. I re-added the mention to
the reporting servers.On Thu, Feb 10, 2011 at 11:30 PM, Magnus Hagander <magnus@hagander.net> wrote:
Also, the patch no longer applies, since it conflicts with
faa0550572583f51dba25611ab0f1d1c31de559b.Since you (Fujii-san) wrote both of them, feel like rebasing it
properly for current master?Yeah, I rebased the patch to the current git master and attached it.
Committed with minor tweaks to comments and documentation.
--
Robert Haas
EnterpriseDB: http://www.enterprisedb.com
The Enterprise PostgreSQL Company