"standby clone": perform clone operations

This commit is contained in:
Ian Barwick
2017-05-02 09:58:17 +09:00
parent 8f74d1b946
commit a960ed9d49
6 changed files with 1308 additions and 9 deletions

105
dbutils.c
View File

@@ -1142,6 +1142,7 @@ get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_i
int result;
initPQExpBuffer(&query);
appendPQExpBuffer(&query,
"SELECT node_id, type, upstream_node_id, node_name, conninfo, slot_name, priority, active"
" FROM repmgr.nodes "
@@ -1152,6 +1153,8 @@ get_node_record_by_name(PGconn *conn, const char *node_name, t_node_info *node_i
result = _get_node_record(conn, query.data, node_info);
termPQExpBuffer(&query);
if (result == 0)
{
log_verbose(LOG_DEBUG, "get_node_record(): no record found for node %s",
@@ -1670,3 +1673,105 @@ get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record)
return 1;
}
/* ================ */
/* backup functions */
/* ================ */
// XXX is first_wal_segment actually used anywhere?
bool
start_backup(PGconn *conn, char *first_wal_segment, bool fast_checkpoint, int server_version_num)
{
PQExpBufferData query;
PGresult *res;
initPQExpBuffer(&query);
if (server_version_num >= 100000)
{
appendPQExpBuffer(&query,
"SELECT pg_catalog.pg_walfile_name(pg_catalog.pg_start_backup('repmgr_standby_clone_%ld', %s))",
time(NULL),
fast_checkpoint ? "TRUE" : "FALSE");
}
else
{
appendPQExpBuffer(&query,
"SELECT pg_catalog.pg_xlogfile_name(pg_catalog.pg_start_backup('repmgr_standby_clone_%ld', %s))",
time(NULL),
fast_checkpoint ? "TRUE" : "FALSE");
}
log_verbose(LOG_DEBUG, "start_backup():\n %s", query.data);
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to start backup:\n %s"), PQerrorMessage(conn));
PQclear(res);
return false;
}
if (first_wal_segment != NULL)
{
char *first_wal_seg_pq = PQgetvalue(res, 0, 0);
size_t buf_sz = strlen(first_wal_seg_pq);
first_wal_segment = pg_malloc0(buf_sz + 1);
snprintf(first_wal_segment, buf_sz + 1, "%s", first_wal_seg_pq);
}
PQclear(res);
return true;
}
bool
stop_backup(PGconn *conn, char *last_wal_segment, int server_version_num)
{
PQExpBufferData query;
PGresult *res;
initPQExpBuffer(&query);
if (server_version_num >= 100000)
{
appendPQExpBuffer(&query,
"SELECT pg_catalog.pg_walfile_name(pg_catalog.pg_stop_backup())");
}
else
{
appendPQExpBuffer(&query,
"SELECT pg_catalog.pg_xlogfile_name(pg_catalog.pg_stop_backup())");
}
res = PQexec(conn, query.data);
termPQExpBuffer(&query);
if (PQresultStatus(res) != PGRES_TUPLES_OK)
{
log_error(_("unable to stop backup:\n %s"), PQerrorMessage(conn));
PQclear(res);
return false;
}
if (last_wal_segment != NULL)
{
char *last_wal_seg_pq = PQgetvalue(res, 0, 0);
size_t buf_sz = strlen(last_wal_seg_pq);
last_wal_segment = pg_malloc0(buf_sz + 1);
snprintf(last_wal_segment, buf_sz + 1, "%s", last_wal_seg_pq);
}
PQclear(res);
return true;
}

View File

@@ -184,5 +184,9 @@ bool create_replication_slot(PGconn *conn, char *slot_name, int server_version_
int get_slot_record(PGconn *conn, char *slot_name, t_replication_slot *record);
/* backup functions */
bool start_backup(PGconn *conn, char *first_wal_segment, bool fast_checkpoint, int server_version_num);
bool stop_backup(PGconn *conn, char *last_wal_segment, int server_version_num);
#endif

View File

@@ -26,6 +26,7 @@
#define ERR_SWITCHOVER_FAIL 18
#define ERR_BARMAN 19
#define ERR_REGISTRATION_SYNC 20
#define ERR_OUT_OF_MEMORY 21
#endif /* _ERRCODE_H_ */

File diff suppressed because it is too large Load Diff

View File

@@ -109,6 +109,11 @@ extern bool local_command(const char *command, PQExpBufferData *outputbuf);
extern bool check_upstream_config(PGconn *conn, int server_version_num, bool exit_on_error);
extern standy_clone_mode get_standby_clone_mode(void);
extern int copy_remote_files(char *host, char *remote_user, char *remote_path,
char *local_path, bool is_directory, int server_version_num);
extern void print_error_list(ItemList *error_list, int log_level);
extern char * make_pg_path(char *file);
#endif

View File

@@ -17,6 +17,7 @@
#include <unistd.h>
#include "repmgr.h"
#include "repmgr-client.h"
#include "repmgr-client-global.h"
@@ -24,6 +25,8 @@
#include "repmgr-action-standby.h"
#include "repmgr-action-cluster.h"
#include <storage/fd.h> /* for PG_TEMP_FILE_PREFIX */
/* globally available variables *
* ============================ */
@@ -40,6 +43,8 @@ char pg_bindir[MAXLEN] = "";
char repmgr_slot_name[MAXLEN] = "";
char *repmgr_slot_name_ptr = NULL;
char path_buf[MAXLEN] = "";
/*
* if --node-id/--node-name provided, place that node's record here
* for later use
@@ -1580,3 +1585,123 @@ get_standby_clone_mode(void)
return mode;
}
char *
make_pg_path(char *file)
{
maxlen_snprintf(path_buf, "%s%s", pg_bindir, file);
return path_buf;
}
int
copy_remote_files(char *host, char *remote_user, char *remote_path,
char *local_path, bool is_directory, int server_version_num)
{
PQExpBufferData rsync_flags;
char script[MAXLEN];
char host_string[MAXLEN];
int r;
initPQExpBuffer(&rsync_flags);
if (*config_file_options.rsync_options == '\0')
{
appendPQExpBuffer(&rsync_flags, "%s",
"--archive --checksum --compress --progress --rsh=ssh");
}
else
{
appendPQExpBuffer(&rsync_flags, "%s",
config_file_options.rsync_options);
}
if (runtime_options.force)
{
appendPQExpBuffer(&rsync_flags, "%s",
" --delete --checksum");
}
if (!remote_user[0])
{
maxlen_snprintf(host_string, "%s", host);
}
else
{
maxlen_snprintf(host_string, "%s@%s", remote_user, host);
}
/*
* When copying the main PGDATA directory, certain files and contents
* of certain directories need to be excluded.
*
* See function 'sendDir()' in 'src/backend/replication/basebackup.c' -
* we're basically simulating what pg_basebackup does, but with rsync rather
* than the BASEBACKUP replication protocol command.
*
* *However* currently we'll always copy the contents of the 'pg_replslot'
* directory and delete later if appropriate.
*/
if (is_directory)
{
/* Files which we don't want */
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=postmaster.pid --exclude=postmaster.opts --exclude=global/pg_control");
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=recovery.conf --exclude=recovery.done");
if (server_version_num >= 90400)
{
/*
* Ideally we'd use PG_AUTOCONF_FILENAME from utils/guc.h, but
* that has too many dependencies for a mere client program.
*/
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=postgresql.auto.conf.tmp");
}
/* Temporary files which we don't want, if they exist */
appendPQExpBuffer(&rsync_flags, " --exclude=%s*",
PG_TEMP_FILE_PREFIX);
/* Directories which we don't want */
if (server_version_num >= 100000)
{
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=pg_wal/*");
}
else
{
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=pg_xlog/*");
}
appendPQExpBuffer(&rsync_flags, "%s",
" --exclude=pg_log/* --exclude=pg_stat_tmp/*");
maxlen_snprintf(script, "rsync %s %s:%s/* %s",
rsync_flags.data, host_string, remote_path, local_path);
}
else
{
maxlen_snprintf(script, "rsync %s %s:%s %s",
rsync_flags.data, host_string, remote_path, local_path);
}
log_info(_("rsync command line: '%s'"), script);
r = system(script);
log_debug("copy_remote_files(): r = %i; WIFEXITED: %i; WEXITSTATUS: %i", r, WIFEXITED(r), WEXITSTATUS(r));
/* exit code 24 indicates vanished files, which isn't a problem for us */
if (WIFEXITED(r) && WEXITSTATUS(r) && WEXITSTATUS(r) != 24)
log_verbose(LOG_WARNING, "copy_remote_files(): rsync returned unexpected exit status %i", WEXITSTATUS(r));
return r;
}