From c979a1fefafcc83553bf218c7f2270cad77ea31d Mon Sep 17 00:00:00 2001 From: Magnus Hagander Date: Wed, 23 Apr 2008 13:44:59 +0000 Subject: [PATCH] Prevent shutdown in normal mode if online backup is running, and have pg_ctl warn about this. Cancel running online backups (by renaming the backup_label file, thus rendering the backup useless) when shutting down in fast mode. Laurenz Albe --- doc/src/sgml/ref/pg_ctl-ref.sgml | 9 ++--- doc/src/sgml/runtime.sgml | 7 ++-- src/backend/access/transam/xlog.c | 52 ++++++++++++++++++++++++++++- src/backend/postmaster/postmaster.c | 37 +++++++++++++++++--- src/bin/pg_ctl/pg_ctl.c | 18 +++++++++- src/include/miscadmin.h | 6 +++- 6 files changed, 115 insertions(+), 14 deletions(-) diff --git a/doc/src/sgml/ref/pg_ctl-ref.sgml b/doc/src/sgml/ref/pg_ctl-ref.sgml index f4200718c7..2d0b8a33ee 100644 --- a/doc/src/sgml/ref/pg_ctl-ref.sgml +++ b/doc/src/sgml/ref/pg_ctl-ref.sgml @@ -1,5 +1,5 @@ @@ -133,9 +133,10 @@ PostgreSQL documentation In mode, the server that is running in the specified data directory is shut down. Three different shutdown methods can be selected with the - option: Smart mode waits for all the clients to - disconnect. This is the default. Fast mode does - not wait for clients to disconnect. All active transactions are + option: Smart mode waits for online backup mode + to finish and all the clients to disconnect. This is the default. + Fast mode does not wait for clients to disconnect and + will terminate an online backup in progress. All active transactions are rolled back and clients are forcibly disconnected, then the server is shut down. Immediate mode will abort all server processes without a clean shutdown. This will lead to diff --git a/doc/src/sgml/runtime.sgml b/doc/src/sgml/runtime.sgml index 63259faff5..5c36f9fce0 100644 --- a/doc/src/sgml/runtime.sgml +++ b/doc/src/sgml/runtime.sgml @@ -1,4 +1,4 @@ - + Operating System Environment @@ -1307,6 +1307,7 @@ sysctl -w vm.overcommit_memory=2 After receiving SIGTERM, the server + waits until online backup mode is no longer active. It then disallows new connections, but lets existing sessions end their work normally. It shuts down only after all of the sessions terminate normally. This is the Smart @@ -1322,7 +1323,9 @@ sysctl -w vm.overcommit_memory=2 The server disallows new connections and sends all existing server processes SIGTERM, which will cause them to abort their current transactions and exit promptly. It then - waits for the server processes to exit and finally shuts down. This is the + waits for the server processes to exit and finally shuts down. + If the server is in online backup mode, backup mode will be + terminated, rendering the backup useless. This is the Fast Shutdown. diff --git a/src/backend/access/transam/xlog.c b/src/backend/access/transam/xlog.c index 33c912ebaa..d23fc9b561 100644 --- a/src/backend/access/transam/xlog.c +++ b/src/backend/access/transam/xlog.c @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.298 2008/04/21 00:26:44 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/access/transam/xlog.c,v 1.299 2008/04/23 13:44:58 mha Exp $ * *------------------------------------------------------------------------- */ @@ -6577,6 +6577,7 @@ pg_start_backup_callback(int code, Datum arg) * create a backup history file in pg_xlog (whence it will immediately be * archived). The backup history file contains the same info found in * the label file, plus the backup-end time and WAL location. + * Note: different from CancelBackup which just cancels online backup mode. */ Datum pg_stop_backup(PG_FUNCTION_ARGS) @@ -7063,3 +7064,52 @@ rm_redo_error_callback(void *arg) pfree(buf.data); } + +/* + * BackupInProgress: check if online backup mode is active + * + * This is done by checking for existence of the "backup_label" file. + */ +bool +BackupInProgress(void) +{ + struct stat stat_buf; + + return (stat(BACKUP_LABEL_FILE, &stat_buf) == 0); +} + +/* + * CancelBackup: rename the "backup_label" file to cancel backup mode + * + * If the "backup_label" file exists, it will be renamed to "backup_label.old". + * Note that this will render an online backup in progress useless. + * To correctly finish an online backup, pg_stop_backup must be called. + */ +void +CancelBackup(void) +{ + struct stat stat_buf; + + /* if the file is not there, return */ + if (stat(BACKUP_LABEL_FILE, &stat_buf) < 0) + return; + + /* remove leftover file from previously cancelled backup if it exists */ + unlink(BACKUP_LABEL_OLD); + + if (rename(BACKUP_LABEL_FILE, BACKUP_LABEL_OLD) == 0) + { + ereport(LOG, + (errmsg("online backup mode cancelled"), + errdetail("\"%s\" renamed to \"%s\"", + BACKUP_LABEL_FILE, BACKUP_LABEL_OLD))); + } + else + { + ereport(WARNING, + (errcode_for_file_access(), + errmsg("could not rename \"%s\" to \"%s\", backup mode not cancelled: %m", + BACKUP_LABEL_FILE, BACKUP_LABEL_OLD))); + } +} + diff --git a/src/backend/postmaster/postmaster.c b/src/backend/postmaster/postmaster.c index 7c6692b2a5..f3bcdd968c 100644 --- a/src/backend/postmaster/postmaster.c +++ b/src/backend/postmaster/postmaster.c @@ -37,7 +37,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.554 2008/03/31 02:43:14 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/postmaster/postmaster.c,v 1.555 2008/04/23 13:44:59 mha Exp $ * * NOTES * @@ -253,6 +253,7 @@ typedef enum PM_INIT, /* postmaster starting */ PM_STARTUP, /* waiting for startup subprocess */ PM_RUN, /* normal "database is alive" state */ + PM_WAIT_BACKUP, /* waiting for online backup mode to end */ PM_WAIT_BACKENDS, /* waiting for live backends to exit */ PM_SHUTDOWN, /* waiting for bgwriter to do shutdown ckpt */ PM_SHUTDOWN_2, /* waiting for archiver to finish */ @@ -1724,8 +1725,12 @@ processCancelRequest(Port *port, void *pkt) static enum CAC_state canAcceptConnections(void) { - /* Can't start backends when in startup/shutdown/recovery state. */ - if (pmState != PM_RUN) + /* + * Can't start backends when in startup/shutdown/recovery state. + * In state PM_WAIT_BACKUP we must allow connections so that + * a superuser can end online backup mode. + */ + if ((pmState != PM_RUN) && (pmState != PM_WAIT_BACKUP)) { if (Shutdown > NoShutdown) return CAC_SHUTDOWN; /* shutdown is pending */ @@ -1965,11 +1970,12 @@ pmdie(SIGNAL_ARGS) /* and the walwriter too */ if (WalWriterPID != 0) signal_child(WalWriterPID, SIGTERM); - pmState = PM_WAIT_BACKENDS; + pmState = PM_WAIT_BACKUP; } /* - * Now wait for backends to exit. If there are none, + * Now wait for online backup mode to end and + * backends to exit. If that is already the case, * PostmasterStateMachine will take the next step. */ PostmasterStateMachine(); @@ -2011,6 +2017,13 @@ pmdie(SIGNAL_ARGS) * PostmasterStateMachine will take the next step. */ PostmasterStateMachine(); + + /* + * Terminate backup mode to avoid recovery after a + * clean fast shutdown. + */ + CancelBackup(); + break; case SIGQUIT: @@ -2552,6 +2565,20 @@ LogChildExit(int lev, const char *procname, int pid, int exitstatus) static void PostmasterStateMachine(void) { + if (pmState == PM_WAIT_BACKUP) + { + /* + * PM_WAIT_BACKUP state ends when online backup mode is no longer + * active. In this state canAcceptConnections() will still allow + * client connections, which is necessary because a superuser + * has to call pg_stop_backup() to end online backup mode. + */ + if (!BackupInProgress()) + { + pmState = PM_WAIT_BACKENDS; + } + } + /* * If we are in a state-machine state that implies waiting for backends to * exit, see if they're all gone, and change state if so. diff --git a/src/bin/pg_ctl/pg_ctl.c b/src/bin/pg_ctl/pg_ctl.c index 89fc34d686..55319c6262 100644 --- a/src/bin/pg_ctl/pg_ctl.c +++ b/src/bin/pg_ctl/pg_ctl.c @@ -4,7 +4,7 @@ * * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * - * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.96 2008/02/29 23:31:20 adunstan Exp $ + * $PostgreSQL: pgsql/src/bin/pg_ctl/pg_ctl.c,v 1.97 2008/04/23 13:44:59 mha Exp $ * *------------------------------------------------------------------------- */ @@ -144,6 +144,7 @@ static char def_postopts_file[MAXPGPATH]; static char postopts_file[MAXPGPATH]; static char pid_file[MAXPGPATH]; static char conf_file[MAXPGPATH]; +static char backup_file[MAXPGPATH]; #if defined(HAVE_GETRLIMIT) && defined(RLIMIT_CORE) static void unlimit_core_size(void); @@ -731,6 +732,7 @@ do_stop(void) { int cnt; pgpid_t pid; + struct stat statbuf; pid = get_pgpid(); @@ -763,6 +765,12 @@ do_stop(void) } else { + if ((shutdown_mode == SMART_MODE) && (stat(backup_file, &statbuf) == 0)) + { + print_msg(_("WARNING: online backup mode is active; must be ended\n" + " with pg_stop_backup() for shutdown to complete\n\n")); + } + print_msg(_("waiting for server to shut down...")); for (cnt = 0; cnt < wait_seconds; cnt++) @@ -799,6 +807,7 @@ do_restart(void) { int cnt; pgpid_t pid; + struct stat statbuf; pid = get_pgpid(); @@ -833,6 +842,12 @@ do_restart(void) exit(1); } + if ((shutdown_mode == SMART_MODE) && (stat(backup_file, &statbuf) == 0)) + { + print_msg(_("WARNING: online backup mode is active; must be ended\n" + " with pg_stop_backup() for shutdown to complete\n\n")); + } + print_msg(_("waiting for server to shut down...")); /* always wait for restart */ @@ -1883,6 +1898,7 @@ main(int argc, char **argv) snprintf(postopts_file, MAXPGPATH, "%s/postmaster.opts", pg_data); snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data); snprintf(conf_file, MAXPGPATH, "%s/postgresql.conf", pg_data); + snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data); } switch (ctl_command) diff --git a/src/include/miscadmin.h b/src/include/miscadmin.h index d06b34be43..3d1511e58a 100644 --- a/src/include/miscadmin.h +++ b/src/include/miscadmin.h @@ -13,7 +13,7 @@ * Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.201 2008/02/20 22:46:24 tgl Exp $ + * $PostgreSQL: pgsql/src/include/miscadmin.h,v 1.202 2008/04/23 13:44:59 mha Exp $ * * NOTES * some of the information in this file should be moved to other files. @@ -330,4 +330,8 @@ extern void ValidatePgVersion(const char *path); extern void process_shared_preload_libraries(void); extern void process_local_preload_libraries(void); +/* in access/transam/xlog.c */ +extern bool BackupInProgress(void); +extern void CancelBackup(void); + #endif /* MISCADMIN_H */