mirror of
https://github.com/EnterpriseDB/repmgr.git
synced 2026-03-22 22:56:29 +00:00
"standby clone": perform clone operations
This commit is contained in:
105
dbutils.c
105
dbutils.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
@@ -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
|
||||
|
||||
125
repmgr-client.c
125
repmgr-client.c
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user