mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-23 15:16:29 +00:00
The repmgr3 implementation required the promotion candidate (standby) to directly work with the demotion candidate's data directory, directly execute server control commands etc. Here we delegated a lot more of that work to the repmgr on the demotion candidate, which reduces the amount of back-and-forth over SSH and generally makes things cleaner and smoother. In particular the repmgr on the demotion candidate will carry out a thorough check that the node is shut down and report the last checkpoint LSN to the promotion candidate; this can then be used to determine whether pg_rewind needs to be executed on the demoted primary before reintegrating it back into the cluster (todo). Also implement "--dry-run" for this action, which will sanity-check the nodes as far as possible without executing the switchover. Additionally some of the new repmgr node commands (or command options) introduced for this can be also executed by the user to obtain additional information about the status of each node.
129 lines
3.1 KiB
C
129 lines
3.1 KiB
C
/*
|
|
* controldata.c
|
|
* Copyright (c) 2ndQuadrant, 2010-2017
|
|
*
|
|
* Portions Copyright (c) 1996-2016, PostgreSQL Global Development Group
|
|
* Portions Copyright (c) 1994, Regents of the University of California
|
|
*/
|
|
|
|
#include <unistd.h>
|
|
#include <sys/stat.h>
|
|
#include <fcntl.h>
|
|
|
|
#include "postgres_fe.h"
|
|
|
|
#include "repmgr.h"
|
|
#include "controldata.h"
|
|
|
|
static ControlFileInfo *get_controlfile(char *DataDir);
|
|
|
|
DBState
|
|
get_db_state(char *data_directory)
|
|
{
|
|
ControlFileInfo *control_file_info;
|
|
DBState state;
|
|
|
|
control_file_info = get_controlfile(data_directory);
|
|
|
|
if (control_file_info->control_file_processed == true)
|
|
state = control_file_info->control_file->state;
|
|
else
|
|
/* if we were unable to parse the control file, assume DB is shut down */
|
|
state = DB_SHUTDOWNED;
|
|
|
|
pfree(control_file_info->control_file);
|
|
pfree(control_file_info);
|
|
return state;
|
|
}
|
|
|
|
|
|
XLogRecPtr
|
|
get_latest_checkpoint_location(char *data_directory)
|
|
{
|
|
ControlFileInfo *control_file_info;
|
|
XLogRecPtr checkPoint;
|
|
|
|
control_file_info = get_controlfile(data_directory);
|
|
|
|
if (control_file_info->control_file_processed == false)
|
|
return InvalidXLogRecPtr;
|
|
|
|
checkPoint = control_file_info->control_file->checkPoint;
|
|
|
|
pfree(control_file_info->control_file);
|
|
pfree(control_file_info);
|
|
|
|
return checkPoint;
|
|
}
|
|
|
|
|
|
const char *
|
|
describe_db_state(DBState state)
|
|
{
|
|
switch (state)
|
|
{
|
|
case DB_STARTUP:
|
|
return _("starting up");
|
|
case DB_SHUTDOWNED:
|
|
return _("shut down");
|
|
case DB_SHUTDOWNED_IN_RECOVERY:
|
|
return _("shut down in recovery");
|
|
case DB_SHUTDOWNING:
|
|
return _("shutting down");
|
|
case DB_IN_CRASH_RECOVERY:
|
|
return _("in crash recovery");
|
|
case DB_IN_ARCHIVE_RECOVERY:
|
|
return _("in archive recovery");
|
|
case DB_IN_PRODUCTION:
|
|
return _("in production");
|
|
}
|
|
return _("unrecognized status code");
|
|
}
|
|
|
|
|
|
/*
|
|
* we maintain our own version of get_controlfile() as we need cross-version
|
|
* compatibility, and also don't care if the file isn't readable.
|
|
*/
|
|
static ControlFileInfo *
|
|
get_controlfile(char *DataDir)
|
|
{
|
|
ControlFileInfo *control_file_info;
|
|
int fd;
|
|
char ControlFilePath[MAXPGPATH];
|
|
|
|
control_file_info = palloc0(sizeof(ControlFileInfo));
|
|
control_file_info->control_file_processed = false;
|
|
control_file_info->control_file = palloc0(sizeof(ControlFileData));
|
|
|
|
snprintf(ControlFilePath, MAXPGPATH, "%s/global/pg_control", DataDir);
|
|
|
|
if ((fd = open(ControlFilePath, O_RDONLY | PG_BINARY, 0)) == -1)
|
|
{
|
|
log_debug("could not open file \"%s\" for reading: %s",
|
|
ControlFilePath, strerror(errno));
|
|
return control_file_info;
|
|
}
|
|
|
|
if (read(fd, control_file_info->control_file, sizeof(ControlFileData)) != sizeof(ControlFileData))
|
|
{
|
|
log_debug("could not read file \"%s\": %s",
|
|
ControlFilePath, strerror(errno));
|
|
return control_file_info;
|
|
}
|
|
|
|
close(fd);
|
|
|
|
control_file_info->control_file_processed = true;
|
|
|
|
/*
|
|
* We don't check the CRC here as we're potentially checking a pg_control
|
|
* file from a different PostgreSQL version to the one repmgr was compiled
|
|
* against. However we're only interested in the first few fields, which
|
|
* should be constant across supported versions
|
|
*
|
|
*/
|
|
|
|
return control_file_info;
|
|
}
|