pg_ctl: Detect current standby state from pg_control
pg_ctl used to determine whether a server was in standby mode by looking for a recovery.conf file. With this change, it instead looks into pg_control, which is potentially more accurate. There are also occasional discussions about removing recovery.conf, so this removes one dependency. Reviewed-by: Michael Paquier <michael.paquier@gmail.com>
This commit is contained in:
parent
eb5089a05b
commit
c1dc51d484
|
@ -52,6 +52,9 @@ pg_control_system(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* read the control file */
|
/* read the control file */
|
||||||
ControlFile = get_controlfile(DataDir, NULL);
|
ControlFile = get_controlfile(DataDir, NULL);
|
||||||
|
if (!ControlFile)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("calculated CRC checksum does not match value stored in file")));
|
||||||
|
|
||||||
values[0] = Int32GetDatum(ControlFile->pg_control_version);
|
values[0] = Int32GetDatum(ControlFile->pg_control_version);
|
||||||
nulls[0] = false;
|
nulls[0] = false;
|
||||||
|
@ -128,6 +131,9 @@ pg_control_checkpoint(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* Read the control file. */
|
/* Read the control file. */
|
||||||
ControlFile = get_controlfile(DataDir, NULL);
|
ControlFile = get_controlfile(DataDir, NULL);
|
||||||
|
if (!ControlFile)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("calculated CRC checksum does not match value stored in file")));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Calculate name of the WAL file containing the latest checkpoint's REDO
|
* Calculate name of the WAL file containing the latest checkpoint's REDO
|
||||||
|
@ -230,6 +236,9 @@ pg_control_recovery(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* read the control file */
|
/* read the control file */
|
||||||
ControlFile = get_controlfile(DataDir, NULL);
|
ControlFile = get_controlfile(DataDir, NULL);
|
||||||
|
if (!ControlFile)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("calculated CRC checksum does not match value stored in file")));
|
||||||
|
|
||||||
values[0] = LSNGetDatum(ControlFile->minRecoveryPoint);
|
values[0] = LSNGetDatum(ControlFile->minRecoveryPoint);
|
||||||
nulls[0] = false;
|
nulls[0] = false;
|
||||||
|
@ -295,6 +304,9 @@ pg_control_init(PG_FUNCTION_ARGS)
|
||||||
|
|
||||||
/* read the control file */
|
/* read the control file */
|
||||||
ControlFile = get_controlfile(DataDir, NULL);
|
ControlFile = get_controlfile(DataDir, NULL);
|
||||||
|
if (!ControlFile)
|
||||||
|
ereport(ERROR,
|
||||||
|
(errmsg("calculated CRC checksum does not match value stored in file")));
|
||||||
|
|
||||||
values[0] = Int32GetDatum(ControlFile->maxAlign);
|
values[0] = Int32GetDatum(ControlFile->maxAlign);
|
||||||
nulls[0] = false;
|
nulls[0] = false;
|
||||||
|
|
|
@ -156,6 +156,10 @@ main(int argc, char *argv[])
|
||||||
|
|
||||||
/* get a copy of the control file */
|
/* get a copy of the control file */
|
||||||
ControlFile = get_controlfile(DataDir, progname);
|
ControlFile = get_controlfile(DataDir, progname);
|
||||||
|
if (!ControlFile)
|
||||||
|
printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
|
||||||
|
"Either the file is corrupt, or it has a different layout than this program\n"
|
||||||
|
"is expecting. The results below are untrustworthy.\n\n"));
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This slightly-chintzy coding will work as long as the control file
|
* This slightly-chintzy coding will work as long as the control file
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
|
|
||||||
#include "postgres_fe.h"
|
#include "postgres_fe.h"
|
||||||
|
|
||||||
|
#include "catalog/pg_control.h"
|
||||||
|
#include "common/controldata_utils.h"
|
||||||
#include "libpq-fe.h"
|
#include "libpq-fe.h"
|
||||||
#include "pqexpbuffer.h"
|
#include "pqexpbuffer.h"
|
||||||
|
|
||||||
|
@ -96,7 +98,6 @@ static char postopts_file[MAXPGPATH];
|
||||||
static char version_file[MAXPGPATH];
|
static char version_file[MAXPGPATH];
|
||||||
static char pid_file[MAXPGPATH];
|
static char pid_file[MAXPGPATH];
|
||||||
static char backup_file[MAXPGPATH];
|
static char backup_file[MAXPGPATH];
|
||||||
static char recovery_file[MAXPGPATH];
|
|
||||||
static char promote_file[MAXPGPATH];
|
static char promote_file[MAXPGPATH];
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -158,6 +159,8 @@ static bool postmaster_is_alive(pid_t pid);
|
||||||
static void unlimit_core_size(void);
|
static void unlimit_core_size(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static DBState get_control_dbstate(void);
|
||||||
|
|
||||||
|
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
static void
|
static void
|
||||||
|
@ -988,12 +991,12 @@ do_stop(void)
|
||||||
/*
|
/*
|
||||||
* If backup_label exists, an online backup is running. Warn the user
|
* If backup_label exists, an online backup is running. Warn the user
|
||||||
* that smart shutdown will wait for it to finish. However, if
|
* that smart shutdown will wait for it to finish. However, if
|
||||||
* recovery.conf is also present, we're recovering from an online
|
* the server is in archive recovery, we're recovering from an online
|
||||||
* backup instead of performing one.
|
* backup instead of performing one.
|
||||||
*/
|
*/
|
||||||
if (shutdown_mode == SMART_MODE &&
|
if (shutdown_mode == SMART_MODE &&
|
||||||
stat(backup_file, &statbuf) == 0 &&
|
stat(backup_file, &statbuf) == 0 &&
|
||||||
stat(recovery_file, &statbuf) != 0)
|
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
|
||||||
{
|
{
|
||||||
print_msg(_("WARNING: online backup mode is active\n"
|
print_msg(_("WARNING: online backup mode is active\n"
|
||||||
"Shutdown will not complete until pg_stop_backup() is called.\n\n"));
|
"Shutdown will not complete until pg_stop_backup() is called.\n\n"));
|
||||||
|
@ -1076,12 +1079,12 @@ do_restart(void)
|
||||||
/*
|
/*
|
||||||
* If backup_label exists, an online backup is running. Warn the user
|
* If backup_label exists, an online backup is running. Warn the user
|
||||||
* that smart shutdown will wait for it to finish. However, if
|
* that smart shutdown will wait for it to finish. However, if
|
||||||
* recovery.conf is also present, we're recovering from an online
|
* the server is in archive recovery, we're recovering from an online
|
||||||
* backup instead of performing one.
|
* backup instead of performing one.
|
||||||
*/
|
*/
|
||||||
if (shutdown_mode == SMART_MODE &&
|
if (shutdown_mode == SMART_MODE &&
|
||||||
stat(backup_file, &statbuf) == 0 &&
|
stat(backup_file, &statbuf) == 0 &&
|
||||||
stat(recovery_file, &statbuf) != 0)
|
get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
|
||||||
{
|
{
|
||||||
print_msg(_("WARNING: online backup mode is active\n"
|
print_msg(_("WARNING: online backup mode is active\n"
|
||||||
"Shutdown will not complete until pg_stop_backup() is called.\n\n"));
|
"Shutdown will not complete until pg_stop_backup() is called.\n\n"));
|
||||||
|
@ -1168,7 +1171,6 @@ do_promote(void)
|
||||||
{
|
{
|
||||||
FILE *prmfile;
|
FILE *prmfile;
|
||||||
pgpid_t pid;
|
pgpid_t pid;
|
||||||
struct stat statbuf;
|
|
||||||
|
|
||||||
pid = get_pgpid(false);
|
pid = get_pgpid(false);
|
||||||
|
|
||||||
|
@ -1187,8 +1189,7 @@ do_promote(void)
|
||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* If recovery.conf doesn't exist, the server is not in standby mode */
|
if (get_control_dbstate() != DB_IN_ARCHIVE_RECOVERY)
|
||||||
if (stat(recovery_file, &statbuf) != 0)
|
|
||||||
{
|
{
|
||||||
write_stderr(_("%s: cannot promote server; "
|
write_stderr(_("%s: cannot promote server; "
|
||||||
"server is not in standby mode\n"),
|
"server is not in standby mode\n"),
|
||||||
|
@ -2115,6 +2116,35 @@ adjust_data_dir(void)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static DBState
|
||||||
|
get_control_dbstate(void)
|
||||||
|
{
|
||||||
|
DBState ret;
|
||||||
|
|
||||||
|
for (;;)
|
||||||
|
{
|
||||||
|
ControlFileData *control_file_data = get_controlfile(pg_data, progname);
|
||||||
|
|
||||||
|
if (control_file_data)
|
||||||
|
{
|
||||||
|
ret = control_file_data->state;
|
||||||
|
pfree(control_file_data);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (wait_seconds > 0)
|
||||||
|
{
|
||||||
|
pg_usleep(1000000); /* 1 sec */
|
||||||
|
wait_seconds--;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_stderr(_("%s: control file appears to be corrupt\n"), progname);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
int
|
int
|
||||||
main(int argc, char **argv)
|
main(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -2401,7 +2431,6 @@ main(int argc, char **argv)
|
||||||
snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
|
snprintf(version_file, MAXPGPATH, "%s/PG_VERSION", pg_data);
|
||||||
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
|
snprintf(pid_file, MAXPGPATH, "%s/postmaster.pid", pg_data);
|
||||||
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
|
snprintf(backup_file, MAXPGPATH, "%s/backup_label", pg_data);
|
||||||
snprintf(recovery_file, MAXPGPATH, "%s/recovery.conf", pg_data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
switch (ctl_command)
|
switch (ctl_command)
|
||||||
|
|
|
@ -33,9 +33,11 @@
|
||||||
*
|
*
|
||||||
* Get controlfile values. The caller is responsible
|
* Get controlfile values. The caller is responsible
|
||||||
* for pfreeing the result.
|
* for pfreeing the result.
|
||||||
|
*
|
||||||
|
* Returns NULL if the CRC did not match.
|
||||||
*/
|
*/
|
||||||
ControlFileData *
|
ControlFileData *
|
||||||
get_controlfile(char *DataDir, const char *progname)
|
get_controlfile(const char *DataDir, const char *progname)
|
||||||
{
|
{
|
||||||
ControlFileData *ControlFile;
|
ControlFileData *ControlFile;
|
||||||
int fd;
|
int fd;
|
||||||
|
@ -82,13 +84,10 @@ get_controlfile(char *DataDir, const char *progname)
|
||||||
FIN_CRC32C(crc);
|
FIN_CRC32C(crc);
|
||||||
|
|
||||||
if (!EQ_CRC32C(crc, ControlFile->crc))
|
if (!EQ_CRC32C(crc, ControlFile->crc))
|
||||||
#ifndef FRONTEND
|
{
|
||||||
elog(ERROR, _("calculated CRC checksum does not match value stored in file"));
|
pfree(ControlFile);
|
||||||
#else
|
return NULL;
|
||||||
printf(_("WARNING: Calculated CRC checksum does not match value stored in file.\n"
|
}
|
||||||
"Either the file is corrupt, or it has a different layout than this program\n"
|
|
||||||
"is expecting. The results below are untrustworthy.\n\n"));
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* Make sure the control file is valid byte order. */
|
/* Make sure the control file is valid byte order. */
|
||||||
if (ControlFile->pg_control_version % 65536 == 0 &&
|
if (ControlFile->pg_control_version % 65536 == 0 &&
|
||||||
|
|
|
@ -12,6 +12,6 @@
|
||||||
|
|
||||||
#include "catalog/pg_control.h"
|
#include "catalog/pg_control.h"
|
||||||
|
|
||||||
extern ControlFileData *get_controlfile(char *DataDir, const char *progname);
|
extern ControlFileData *get_controlfile(const char *DataDir, const char *progname);
|
||||||
|
|
||||||
#endif /* COMMON_CONTROLDATA_UTILS_H */
|
#endif /* COMMON_CONTROLDATA_UTILS_H */
|
||||||
|
|
Loading…
Reference in New Issue