probackup备机备份

This commit is contained in:
mujinqiang 2021-03-27 22:16:31 +08:00
parent 28934bcdfa
commit f4686aa3c9
20 changed files with 377 additions and 72 deletions

View File

@ -39,6 +39,8 @@ static uint32 stream_stop_timeout = 0;
/* Time in which we started to wait for streaming end */
static time_t stream_stop_begin = 0;
static const uint32 archive_timeout_deno = 5;
//const char *progname = "pg_probackup";
/* list of files contained in backup */
@ -63,6 +65,7 @@ typedef struct
XLogRecPtr startpos;
TimeLineID starttli;
bool renamepartial;
} StreamThreadArg;
static pthread_t stream_thread;
@ -268,6 +271,12 @@ static void start_stream_wal(const char *database_path, PGconn *backup_conn)
stream_thread_arg.starttli = current.tli;
thread_interrupted = false;
if (current.from_replica) {
stream_thread_arg.renamepartial = true;
} else {
stream_thread_arg.renamepartial = false;
}
pthread_create(&stream_thread, NULL, StreamLog, &stream_thread_arg);
}
@ -442,6 +451,27 @@ static void sync_files(parray *database_map, const char *database_path, parray *
{
time_t start_time, end_time;
char pretty_time[20];
/* In case of backup from replica >= 9.6 we must fix minRecPoint,
* First we must find pg_control in backup_files_list.
*/
if (current.from_replica && !exclusive_backup)
{
pgFile *pg_control = NULL;
for (int i = 0; i < parray_num(backup_files_list); i++)
{
pgFile *tmp_file = (pgFile *)parray_get(backup_files_list, (size_t)i);
if (tmp_file->external_dir_num == 0 &&
(strcmp(tmp_file->rel_path, XLOG_CONTROL_FILE) == 0))
{
pg_control = tmp_file;
break;
}
}
if (!pg_control)
elog(ERROR, "Failed to find file \"%s\" in backup filelist.", XLOG_CONTROL_FILE);
set_min_recovery_point(pg_control, database_path, current.stop_lsn);
}
/* close and sync page header map */
if (current.hdr_map.fp)
@ -735,7 +765,6 @@ PGconn *
pgdata_basic_setup(const ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
{
PGconn *cur_conn;
bool from_replica;
errno_t rc = 0;
/* Create connection for PostgreSQL */
@ -743,11 +772,6 @@ pgdata_basic_setup(const ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
conn_opt.pgdatabase,
conn_opt.pguser);
from_replica = pg_is_in_recovery(cur_conn);
if (from_replica) {
elog(ERROR, "gs_probackup is not supported on standby\n");
}
/* Confirm data block size and xlog block size are compatible */
confirm_block_size(cur_conn, "block_size", BLCKSZ);
confirm_block_size(cur_conn, "wal_block_size", XLOG_BLCKSZ);
@ -755,10 +779,12 @@ pgdata_basic_setup(const ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
nodeInfo->wal_block_size = XLOG_BLCKSZ;
nodeInfo->pgpro_support = pgpro_support(cur_conn);
current.from_replica = pg_is_in_recovery(cur_conn);
nodeInfo->server_version = PQserverVersion(conn);
exclusive_backup = true;
if (!current.from_replica) {
exclusive_backup = true;
}
current.checksum_version = 0;
@ -868,6 +894,10 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
*/
backup_conn = pgdata_basic_setup(instance_config.conn_opt, &nodeInfo);
if (current.from_replica) {
elog(INFO, "Backup %s is going to be taken from standby", base36enc((unsigned long int)start_time));
}
/*
* Ensure that backup directory was initialized for the same PostgreSQL
* instance we opened connection to. And that target backup database PGDATA
@ -1186,6 +1216,20 @@ bool inform_user_wal_seg_absent(bool is_start_lsn, uint32 *try_count, bool segme
return true;
}
/* Try to find compressed WAL file */
void tryToFindCompressedWALFile(bool *file_exists, char *gz_wal_segment_path, char *wal_segment_path)
{
if (!(*file_exists)) {
#ifdef HAVE_LIBZ
*file_exists = fileExists(gz_wal_segment_path, FIO_BACKUP_HOST);
if (*file_exists)
elog(LOG, "Found compressed WAL segment: %s", wal_segment_path);
#endif
} else {
elog(LOG, "Found WAL segment: %s", wal_segment_path);
}
}
/*
* Wait for target LSN or WAL segment, containing target LSN.
*
@ -1259,10 +1303,7 @@ wait_wal_lsn(XLogRecPtr target_lsn, bool is_start_lsn, TimeLineID tli,
}
/* TODO: remove this in 3.0 (it is a cludge against some old bug with archive_timeout) */
if (instance_config.archive_timeout > 0)
timeout = instance_config.archive_timeout;
else
timeout = ARCHIVE_TIMEOUT_DEFAULT;
timeout = (instance_config.archive_timeout > 0) ? instance_config.archive_timeout : ARCHIVE_TIMEOUT_DEFAULT;
if (segment_only)
elog(LOG, "Looking for segment: %s", wal_segment);
@ -1282,20 +1323,9 @@ wait_wal_lsn(XLogRecPtr target_lsn, bool is_start_lsn, TimeLineID tli,
if (!file_exists)
{
file_exists = fileExists(wal_segment_path, FIO_BACKUP_HOST);
/* Try to find compressed WAL file */
if (!file_exists)
{
#ifdef HAVE_LIBZ
file_exists = fileExists(gz_wal_segment_path, FIO_BACKUP_HOST);
if (file_exists)
elog(LOG, "Found compressed WAL segment: %s", wal_segment_path);
#endif
}
else
elog(LOG, "Found WAL segment: %s", wal_segment_path);
}
tryToFindCompressedWALFile(&file_exists, gz_wal_segment_path, wal_segment_path);
}
if (file_exists)
{
/* Do not check for target LSN */
@ -1313,6 +1343,32 @@ wait_wal_lsn(XLogRecPtr target_lsn, bool is_start_lsn, TimeLineID tli,
elog(LOG, "Found LSN: %X/%X", (uint32) (target_lsn >> 32), (uint32) target_lsn);
return target_lsn;
}
/*
* If we failed to get target LSN in a reasonable time, try
* to get LSN of last valid record prior to the target LSN. But only
* in case of a backup from a replica.
* Note, that with NullXRecOff target_lsn we do not wait
* for 'timeout / 5' seconds before going for previous record,
* because such LSN cannot be delivered at all.
*
* There are two cases for this:
* 1. Replica returned readpoint LSN which just do not exists. We want to look
* for previous record in the same(!) WAL segment which endpoint points to this LSN.
* 2. Replica returened endpoint LSN with NullXRecOff. We want to look
* for previous record which endpoint points greater or equal LSN in previous WAL segment.
*/
if (current.from_replica &&
(XRecOffIsNull(target_lsn) || try_count > timeout / archive_timeout_deno)) {
XLogRecPtr res = get_prior_record_lsn(wal_segment_dir, current.start_lsn, target_lsn, tli,
in_prev_segment, instance_config.xlog_seg_size);
if (!XLogRecPtrIsInvalid(res)) {
/* LSN of the prior record was found */
elog(LOG, "Found prior LSN: %X/%X",
(uint32) (res >> 32), (uint32) res);
return res;
}
}
}
sleep(1);
@ -1392,9 +1448,11 @@ static void get_valid_stop_lsn(pgBackup *backup, bool *stop_lsn_exists, XLogRecP
!XRecOffIsValid(lsn_tmp) ||
lsn_tmp < stop_backup_lsn_tmp)
{
elog(ERROR, "Failed to get next WAL record after %X/%X",
(uint32) (stop_backup_lsn_tmp >> 32),
(uint32) (stop_backup_lsn_tmp));
/* Backup from master should error out here */
if (!backup->from_replica)
elog(ERROR, "Failed to get next WAL record after %X/%X",
(uint32)(stop_backup_lsn_tmp >> 32),
(uint32)(stop_backup_lsn_tmp));
/* No luck, falling back to looking up for previous record */
elog(WARNING, "Failed to get next WAL record after %X/%X, "
@ -1666,8 +1724,10 @@ pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn,
res = pgut_execute(conn, "SET datestyle = 'ISO, DMY';", 0, NULL);
PQclear(res);
/* Create restore point */
if (backup != NULL)
/* Create restore point
* Only if backup is from master.
*/
if (backup != nullptr && !backup->from_replica)
{
create_restore_point(backup, conn);
}
@ -1686,22 +1746,7 @@ pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn,
* wait for pg_stop_backup() forever.
*/
PgStopBackupSent(conn, &stop_backup_query);
if (!pg_stop_backup_is_sent)
{
bool sent = false;
stop_backup_query = "SELECT"
" pg_catalog.txid_snapshot_xmax(pg_catalog.txid_current_snapshot()),"
" current_timestamp(0)::timestamptz,"
" pg_catalog.pg_stop_backup() as lsn";
sent = pgut_send(conn, stop_backup_query, 0, NULL, WARNING);
pg_stop_backup_is_sent = true;
if (!sent)
elog(ERROR, "Failed to send pg_stop_backup query");
}
/* After we have sent pg_stop_backup, we don't need this callback anymore */
pgut_atexit_pop(backup_stopbackup_callback, pg_startbackup_conn);
@ -1769,9 +1814,13 @@ pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn,
* If replica returned valid STOP_LSN of not actually existing record,
* look for previous record with endpoint >= STOP_LSN.
*/
if (!stop_lsn_exists)
if (!stop_lsn_exists) {
if (backup->from_replica) {
stop_backup_lsn = stop_backup_lsn_tmp;
}
stop_backup_lsn = wait_wal_lsn(stop_backup_lsn_tmp, false, backup->tli,
false, false, ERROR, stream_wal);
}
if (stream_wal)
{
@ -2068,16 +2117,14 @@ parse_filelist_filenames(parray *files, const char *root)
while (unlogged_file_num >= 0 &&
(unlogged_file_reloid != 0) &&
(unlogged_file->relOid == unlogged_file_reloid))
{
(unlogged_file->relOid == unlogged_file_reloid)) {
pgFileFree(unlogged_file);
parray_remove(files, unlogged_file_num);
unlogged_file_num--;
i--;
unlogged_file = (pgFile *) parray_get(files,
unlogged_file_num);
unlogged_file = (pgFile *) parray_get(files, unlogged_file_num);
}
}
}
@ -2220,8 +2267,7 @@ stop_streaming(XLogRecPtr xlogpos, uint32 timeline, bool segment_finished)
if (!XLogRecPtrIsInvalid(stop_backup_lsn))
{
if (xlogpos >= stop_backup_lsn)
{
if (xlogpos >= stop_backup_lsn) {
stop_stream_lsn = xlogpos;
return true;
}
@ -2324,12 +2370,12 @@ StreamLog(void *arg)
#else
if(ReceiveXlogStream(stream_arg->conn, stream_arg->startpos, stream_arg->starttli,
NULL, (const char *) stream_arg->basedir, stop_streaming,
standby_message_timeout_local, false) == false)
standby_message_timeout_local, stream_arg->renamepartial) == false)
elog(ERROR, "Problem in receivexlog");
#endif
elog(LOG, "finished streaming WAL at %X/%X (timeline %u)",
(uint32) (stop_stream_lsn >> 32), (uint32) stop_stream_lsn, stream_arg->starttli);
(uint32) (stop_stream_lsn >> 32), (uint32) stop_stream_lsn, stream_arg->starttli);
stream_arg->ret = 0;
PQfinish(stream_arg->conn);

View File

@ -1472,7 +1472,14 @@ void anchor_lsn_keep_segments_timelines(InstanceConfig *instance, parray *timeli
interval->begin_segno = segno;
GetXLogSegNo(backup->stop_lsn, segno, instance->xlog_seg_size);
interval->end_segno = segno;
/*
* On replica it is possible to get STOP_LSN pointing to contrecord,
* so set end_segno to the next segment after STOP_LSN just to be safe.
*/
if (backup->from_replica)
interval->end_segno = segno + 1;
else
interval->end_segno = segno;
GetXLogFileName(begin_segno_str, tlinfo->tli, interval->begin_segno, instance->xlog_seg_size);
GetXLogFileName(end_segno_str, tlinfo->tli, interval->end_segno, instance->xlog_seg_size);
@ -1808,6 +1815,7 @@ pgBackupWriteControl(FILE *out, pgBackup *backup)
fio_fprintf(out, "compress-alg = %s\n",
deparse_compress_alg(backup->compress_alg));
fio_fprintf(out, "compress-level = %d\n", backup->compress_level);
fio_fprintf(out, "from-replica = %s\n", backup->from_replica ? "true" : "false");
fio_fprintf(out, "\n#Compatibility\n");
fio_fprintf(out, "block-size = %u\n", backup->block_size);
@ -2055,7 +2063,6 @@ write_backup_filelist(pgBackup *backup, parray *files, const char *root,
len += nRet;
}
if (file->linked)
{
nRet = snprintf_s(line+len, remainLen - len,remainLen - len - 1,",\"linked\":\"%s\"", file->linked);
@ -2063,7 +2070,6 @@ write_backup_filelist(pgBackup *backup, parray *files, const char *root,
len += nRet;
}
if (file->n_blocks > 0)
{
nRet = snprintf_s(line+len,remainLen - len,remainLen - len - 1, ",\"n_blocks\":\"%i\"", file->n_blocks);
@ -2089,6 +2095,7 @@ write_backup_filelist(pgBackup *backup, parray *files, const char *root,
nRet = snprintf_s(line+len,remainLen - len,remainLen - len - 1, "}\n");
securec_check_ss_c(nRet, "\0", "\0");
len += nRet;
if (sync)
COMP_FILE_CRC32(true, backup->content_crc, line, strlen(line));
@ -2191,6 +2198,7 @@ readBackupControlFile(const char *path)
{'s', 0, "merge-dest-id", &merge_dest_backup, SOURCE_FILE_STRICT},
{'s', 0, "compress-alg", &compress_alg, SOURCE_FILE_STRICT},
{'u', 0, "compress-level", &backup->compress_level, SOURCE_FILE_STRICT},
{'b', 0, "from-replica", &backup->from_replica, SOURCE_FILE_STRICT},
{'s', 0, "external-dirs", &backup->external_dir_str, SOURCE_FILE_STRICT},
{'s', 0, "note", &backup->note, SOURCE_FILE_STRICT},
{'s', 0, "recovery-name", &recovery_name, SOURCE_FILE_STRICT},
@ -2424,6 +2432,7 @@ pgBackupInit(pgBackup *backup)
backup->checksum_version = 0;
backup->stream = false;
backup->from_replica = false;
backup->parent_backup = INVALID_BACKUP_ID;
backup->merge_dest_backup = INVALID_BACKUP_ID;
backup->parent_backup_link = NULL;

View File

@ -882,6 +882,7 @@ static void threads_handle(pgBackup *dest_backup,
full_backup->recovery_time = dest_backup->recovery_time;
full_backup->recovery_xid = dest_backup->recovery_xid;
full_backup->tli = dest_backup->tli;
full_backup->from_replica = dest_backup->from_replica;
pfree(full_backup->external_dir_str);
full_backup->external_dir_str = pgut_strdup(dest_backup->external_dir_str);

View File

@ -634,9 +634,10 @@ wal_contains_lsn(const char *archivedir, XLogRecPtr target_lsn,
res = XLogReadRecord(xlogreader, target_lsn, &errormsg) != NULL;
/* Didn't find 'target_lsn' and there is no error, return false */
if (errormsg)
elog(WARNING, "Could not read WAL record at %X/%X: %s",
(uint32) (target_lsn >> 32), (uint32) (target_lsn), errormsg);
if (!current.from_replica)
if (errormsg)
elog(WARNING, "Could not read WAL record at %X/%X: %s",
(uint32) (target_lsn >> 32), (uint32) (target_lsn), errormsg);
CleanupXLogPageRead(xlogreader);
XLogReaderFree(xlogreader);
@ -1459,7 +1460,7 @@ XLogThreadWorker(void *arg)
* Usually SimpleXLogPageRead_local() does it by itself. But here we need
* to do it manually to support threads.
*/
if (reader_data->need_switch && errormsg == NULL)
if (reader_data->need_switch)
{
if (SwitchThreadToNextWal(xlogreader, thread_arg))
continue;

View File

@ -254,6 +254,7 @@ struct pgBackup
bool stream; /* Was this backup taken in stream mode?
* i.e. does it include all needed WAL files? */
bool from_replica; /* Was this backup taken from replica */
time_t parent_backup; /* Identifier of the previous backup.
* Which is basic backup for this
* incremental backup. */

View File

@ -69,8 +69,10 @@ pg_ptrack_get_pagemapset(PGconn *backup_conn, XLogRecPtr lsn)
securec_check_ss_c(rc, "\0", "\0");
params[0] = gs_pstrdup(start_lsn);
res = pgut_execute(backup_conn, "CHECKPOINT;", 0, NULL);
PQclear(res);
if (!current.from_replica) {
res = pgut_execute(backup_conn, "CHECKPOINT;", 0, NULL);
PQclear(res);
}
res = pgut_execute(backup_conn, "SELECT pg_cbm_tracked_location()", 0, NULL);
if (PQnfields(res) != 1) {
@ -94,8 +96,7 @@ pg_ptrack_get_pagemapset(PGconn *backup_conn, XLogRecPtr lsn)
pagemap.bitmapsize = 0;
/* Construct database map */
for (i = 0; i < PQntuples(res); i++)
{
for (i = 0; i < PQntuples(res); i++) {
page_map_entry *pm_entry = (page_map_entry *) pgut_malloc(sizeof(page_map_entry));
/* get path */

View File

@ -373,6 +373,10 @@ print_backup_json_object(PQExpBuffer buf, pgBackup *backup)
json_add_key(buf, "compress-level", json_level);
appendPQExpBuffer(buf, "%d", backup->compress_level);
json_add_value(buf, "from-replica",
backup->from_replica ? "true" : "false", json_level,
true);
json_add_key(buf, "block-size", json_level);
appendPQExpBuffer(buf, "%u", backup->block_size);

View File

@ -7127,8 +7127,9 @@
AddBuiltinFunc(_0(2626), _1("pg_sleep"), _2(1), _3(true), _4(false), _5(pg_sleep), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1, 701), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_sleep"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'))
),
AddFuncGroup(
"pg_start_backup", 1,
AddBuiltinFunc(_0(2172), _1("pg_start_backup"), _2(2), _3(true), _4(false), _5(pg_start_backup), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(1), _20(2, 25, 16), _21(NULL), _22(NULL), _23(2, "label", "fast"), _24("({CONST :consttype 16 :consttypmod -1 :constcollid 0 :constlen 1 :constbyval true :constisnull false :ismaxvalue false :location 72803 :constvalue 1 [ 0 0 0 0 0 0 0 0 ] :cursor_data :row_count 0 :cur_dno 0 :is_open false :found false :not_found false :null_open false :null_fetch false})"), _25("pg_start_backup"), _26(NULL), _27(NULL), _28(NULL), _29(1, 1), _30(false), _31(false), _32(false), _33(NULL), _34('f'))
"pg_start_backup", 2,
AddBuiltinFunc(_0(2172), _1("pg_start_backup"), _2(2), _3(true), _4(false), _5(pg_start_backup), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(1), _20(2, 25, 16), _21(NULL), _22(NULL), _23(2, "label", "fast"), _24("({CONST :consttype 16 :consttypmod -1 :constcollid 0 :constlen 1 :constbyval true :constisnull false :ismaxvalue false :location 72803 :constvalue 1 [ 0 0 0 0 0 0 0 0 ] :cursor_data :row_count 0 :cur_dno 0 :is_open false :found false :not_found false :null_open false :null_fetch false})"), _25("pg_start_backup"), _26(NULL), _27(NULL), _28(NULL), _29(1, 1), _30(false), _31(false), _32(false), _33(NULL), _34('f')),
AddBuiltinFunc(_0(6203), _1("pg_start_backup"), _2(3), _3(true), _4(false), _5(pg_start_backup_v2), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(3, 25, 16, 16), _21(NULL), _22(NULL), _23(3, "label", "fast", "exclusive"), _24(NULL), _25("pg_start_backup_v2"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(false), _32(false), _33(NULL), _34('f'))
),
AddFuncGroup(
"pg_stat_bad_block", 1,
@ -7693,8 +7694,9 @@
AddBuiltinFunc(_0(5601), _1("pg_stat_set_last_data_changed_time"), _2(1), _3(true), _4(false), _5(pg_stat_set_last_data_changed_time), _6(2278), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('s'), _19(0), _20(1, 26), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_stat_set_last_data_changed_time"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'))
),
AddFuncGroup(
"pg_stop_backup", 1,
AddBuiltinFunc(_0(2173), _1("pg_stop_backup"), _2(0), _3(true), _4(false), _5(pg_stop_backup), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_stop_backup"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'))
"pg_stop_backup", 2,
AddBuiltinFunc(_0(2173), _1("pg_stop_backup"), _2(0), _3(true), _4(false), _5(pg_stop_backup), _6(25), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(0), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(0), _21(NULL), _22(NULL), _23(NULL), _24(NULL), _25("pg_stop_backup"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f')),
AddBuiltinFunc(_0(6204), _1("pg_stop_backup"), _2(1), _3(true), _4(true), _5(pg_stop_backup_v2), _6(2249), _7(PG_CATALOG_NAMESPACE), _8(BOOTSTRAP_SUPERUSERID), _9(INTERNALlanguageId), _10(1), _11(1), _12(0), _13(0), _14(false), _15(false), _16(false), _17(false), _18('v'), _19(0), _20(1,16), _21(4, 16, 25, 25, 25), _22(4, 'i', 'o', 'o', 'o'), _23(4, "exclusive", "lsn","labelfile", "spcmapfile"), _24(NULL), _25("pg_stop_backup_v2"), _26(NULL), _27(NULL), _28(NULL), _29(0), _30(false), _31(NULL), _32(false), _33(NULL), _34('f'))
),
AddFuncGroup(
"pg_switch_xlog", 1,

View File

@ -500,6 +500,10 @@ static void knl_u_proc_init(knl_u_proc_context* proc_cxt)
proc_cxt->clientIsGsroach = false;
proc_cxt->IsBinaryUpgrade = false;
proc_cxt->IsWLMWhiteList = false;
proc_cxt->sessionBackupState = SESSION_BACKUP_NONE;
proc_cxt->LabelFile = NULL;
proc_cxt->TblspcMapFile = NULL;
proc_cxt->registerAbortBackupHandlerdone = false;
proc_cxt->gsRewindAddCount = false;
proc_cxt->PassConnLimit = false;
proc_cxt->sessionBackupState = SESSION_BACKUP_NONE;

View File

@ -156,11 +156,13 @@ Datum pg_cbm_get_changed_block(PG_FUNCTION_ARGS)
text *start_lsn_arg = PG_GETARG_TEXT_P(0);
text *end_lsn_arg = PG_GETARG_TEXT_P(1);
#ifdef ENABLE_MULTIPLE_NODES
/* At present, we only allow merging CBM files on master */
if (RecoveryInProgress())
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE), errmsg("recovery is in progress"),
errhint("pg_cbm_get_changed_block() cannot be executed"
"during recovery.")));
#endif
char *start_lsn_str = text_to_cstring(start_lsn_arg);
char *end_lsn_str = text_to_cstring(end_lsn_arg);

View File

@ -13334,6 +13334,17 @@ XLogRecPtr do_pg_stop_backup(char *labelfile, bool waitforarchive)
}
u_sess->proc_cxt.sessionBackupState = SESSION_BACKUP_NONE;
StopSuspendWalInsert(lastlrc);
/*
* Clean up session-level lock.
*
* You might think that WALInsertLockRelease() can be called before
* cleaning up session-level lock because session-level lock doesn't need
* to be protected with WAL insertion lock. But since
* CHECK_FOR_INTERRUPTS() can occur in it, session-level lock must be
* cleaned up before it.
*/
u_sess->proc_cxt.sessionBackupState = SESSION_BACKUP_NONE;
if (exclusive) {
/*
@ -13642,6 +13653,13 @@ void do_pg_abort_backup(void)
int32 lastlrc = 0;
StartSuspendWalInsert(&lastlrc);
/*
* Quick exit if session is not keeping around a non-exclusive backup
* already started.
*/
if (u_sess->proc_cxt.sessionBackupState != SESSION_BACKUP_NON_EXCLUSIVE)
return;
Assert(t_thrd.shemem_ptr_cxt.XLogCtl->Insert.nonExclusiveBackups > 0);
t_thrd.shemem_ptr_cxt.XLogCtl->Insert.nonExclusiveBackups--;
@ -13652,6 +13670,7 @@ void do_pg_abort_backup(void)
u_sess->proc_cxt.sessionBackupState = SESSION_BACKUP_NONE;
StopSuspendWalInsert(lastlrc);
u_sess->proc_cxt.sessionBackupState = SESSION_BACKUP_NONE;
}
/*

View File

@ -75,6 +75,13 @@ Datum pg_start_backup(PG_FUNCTION_ARGS)
char startxlogstr[MAXFNAMELEN];
errno_t errorno = EOK;
SessionBackupState status = u_sess->proc_cxt.sessionBackupState;
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a non-exclusive backup is already in progress in this session")));
backupidstr = text_to_cstring(backupid);
dir = AllocateDir("pg_tblspc");
if (!dir) {
@ -114,6 +121,13 @@ Datum pg_stop_backup(PG_FUNCTION_ARGS)
char stopxlogstr[MAXFNAMELEN];
errno_t errorno = EOK;
SessionBackupState status = u_sess->proc_cxt.sessionBackupState;
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
ereport(ERROR,
(errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a non-exclusive backup is already in progress in this session")));
/* when delay xlog recycle is true, we do not copy xlog from archive */
stoppoint = do_pg_stop_backup(NULL, !GetDelayXlogRecycle());
@ -124,6 +138,156 @@ Datum pg_stop_backup(PG_FUNCTION_ARGS)
PG_RETURN_TEXT_P(cstring_to_text(stopxlogstr));
}
/*
* pg_start_backup_v2: set up for taking an on-line backup dump
*
*/
Datum pg_start_backup_v2(PG_FUNCTION_ARGS)
{
text* backupid = PG_GETARG_TEXT_P(0);
bool fast = PG_GETARG_BOOL(1);
bool exclusive = PG_GETARG_BOOL(2);
char* backupidstr = NULL;
char* labelfile = NULL;
char* tblspcmapfile = NULL;
XLogRecPtr startpoint;
DIR *dir;
char startxlogstr[MAXFNAMELEN];
errno_t errorno = EOK;
MemoryContext oldContext;
u_sess->probackup_context = AllocSetContextCreate(u_sess->top_mem_cxt, "probackup context",
ALLOCSET_DEFAULT_MINSIZE, ALLOCSET_DEFAULT_INITSIZE,
ALLOCSET_DEFAULT_MAXSIZE);
oldContext = MemoryContextSwitchTo(u_sess->probackup_context);
SessionBackupState status = u_sess->proc_cxt.sessionBackupState;
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a non-exclusive backup is already in progress in this session")));
backupidstr = text_to_cstring(backupid);
dir = AllocateDir("pg_tblspc");
if (!dir) {
ereport(ERROR, (errmsg("could not open directory \"%s\": %m", "pg_tblspc")));
}
if (exclusive) {
startpoint = do_pg_start_backup(backupidstr, fast, NULL, dir, NULL, NULL, false, true);
} else {
if (status == SESSION_BACKUP_EXCLUSIVE)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("a backup is already in progress in this session")));
startpoint = do_pg_start_backup(backupidstr, fast, &labelfile,dir, &tblspcmapfile, NULL,false,true);
u_sess->proc_cxt.LabelFile = MemoryContextStrdup(u_sess->probackup_context, labelfile);
if (tblspcmapfile != NULL) {
u_sess->proc_cxt.TblspcMapFile = MemoryContextStrdup(u_sess->probackup_context, tblspcmapfile);
} else {
u_sess->proc_cxt.TblspcMapFile = NULL;
}
}
errorno = snprintf_s(startxlogstr, sizeof(startxlogstr), sizeof(startxlogstr) - 1, "%X/%X",
(uint32)(startpoint >> 32), (uint32)startpoint);
securec_check_ss(errorno, "", "");
PG_RETURN_TEXT_P(cstring_to_text(startxlogstr));
MemoryContextSwitchTo(oldContext);
}
/*
* pg_stop_backup_v2: finish taking an on-line backup dump
*
*/
Datum pg_stop_backup_v2(PG_FUNCTION_ARGS)
{
ReturnSetInfo *rsinfo = (ReturnSetInfo *)fcinfo->resultinfo;
TupleDesc tupdesc;
Tuplestorestate *tupstore;
MemoryContext perqueryctx, oldcontext, oldcontext2;
Datum values[3];
bool nulls[3];
XLogRecPtr stoppoint;
char stopxlogstr[MAXFNAMELEN];
errno_t errorno = EOK;
bool exclusive = PG_GETARG_BOOL(0);
errno_t rc;
SessionBackupState status = u_sess->proc_cxt.sessionBackupState;
oldcontext2 = MemoryContextSwitchTo(u_sess->probackup_context);
/* check to see if caller supports us returning a tuplestore */
if (rsinfo == NULL || !IsA(rsinfo, ReturnSetInfo))
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("set-valued function called in context that cannot accept a set")));
if (!(rsinfo->allowedModes & SFRM_Materialize))
ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
errmsg("materialize mode required, but it is not allowed in this context")));
/* Build a tuple descriptor for our result type */
if (get_call_result_type(fcinfo, NULL, &tupdesc) != TYPEFUNC_COMPOSITE)
ereport(ERROR, (errcode(ERRCODE_DATATYPE_MISMATCH), errmsg("return type must be a row type")));
perqueryctx = rsinfo->econtext->ecxt_per_query_memory;
oldcontext = MemoryContextSwitchTo(perqueryctx);
tupstore = tuplestore_begin_heap(true, false, u_sess->attr.attr_memory.work_mem);
rsinfo->returnMode = SFRM_Materialize;
rsinfo->setResult = tupstore;
rsinfo->setDesc = tupdesc;
MemoryContextSwitchTo(oldcontext);
rc = memset_s(values, sizeof(values), 0, sizeof(values));
securec_check(rc, "\0", "\0");
rc = memset_s(nulls, sizeof(nulls), false, sizeof(nulls));
securec_check(rc, "\0", "\0");
if (exclusive) {
if (status == SESSION_BACKUP_NON_EXCLUSIVE)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("non-exclusive backup in progress"), errhint("Did you mean to use pg_stop_backup('f')?")));
/* when delay xlog recycle is true, we do not copy xlog from archive */
stoppoint = do_pg_stop_backup(NULL, !GetDelayXlogRecycle());
nulls[1] = true;
nulls[2] = true;
} else {
if (status != SESSION_BACKUP_NON_EXCLUSIVE)
ereport(ERROR, (errcode(ERRCODE_OBJECT_NOT_IN_PREREQUISITE_STATE),
errmsg("non-exclusive backup is not in progress")));
stoppoint = do_pg_stop_backup(u_sess->proc_cxt.LabelFile, !GetDelayXlogRecycle());
values[1] = CStringGetTextDatum(u_sess->proc_cxt.LabelFile);
pfree(u_sess->proc_cxt.LabelFile);
u_sess->proc_cxt.LabelFile = NULL;
if (u_sess->proc_cxt.TblspcMapFile) {
values[2] = CStringGetTextDatum(u_sess->proc_cxt.TblspcMapFile);
pfree(u_sess->proc_cxt.TblspcMapFile);
u_sess->proc_cxt.TblspcMapFile = NULL;
} else {
nulls[2] = true;
}
}
errorno = snprintf_s(stopxlogstr, sizeof(stopxlogstr), sizeof(stopxlogstr) - 1, "%X/%X",
(uint32)(stoppoint >> 32), (uint32)stoppoint);
securec_check_ss(errorno, "", "");
values[0] = CStringGetTextDatum(stopxlogstr);
tuplestore_putvalues(tupstore, tupdesc, values, nulls);
tuplestore_donestoring(tupstore);
MemoryContextSwitchTo(oldcontext2);
return (Datum) 0;
}
/*
* gs_roach_stop_backup: stop roach backup with passed-in backup name
*

View File

@ -0,0 +1,2 @@
DROP FUNCTION IF EXISTS pg_catalog.pg_start_backup(IN backupid TEXT, IN fast BOOL, IN exclusive BOOL) CASCADE;
DROP FUNCTION IF EXISTS pg_catalog.pg_stop_backup(IN exclusive BOOL) CASCADE;

View File

@ -0,0 +1,2 @@
DROP FUNCTION IF EXISTS pg_catalog.pg_start_backup(IN BACKUPID TEXT, IN FAST BOOL, IN EXCLUSIVE BOOL) CASCADE;
DROP FUNCTION IF EXISTS pg_catalog.pg_stop_backup(IN EXCLUSIVE BOOL) CASCADE;

View File

@ -2360,3 +2360,21 @@ out system_identifier pg_catalog.int8,
out pg_control_last_modified pg_catalog.timestamptz)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_control_system';
DROP FUNCTION IF EXISTS pg_catalog.pg_start_backup(IN backupid TEXT, IN fast BOOL, IN exclusive BOOL) CASCADE;
DROP FUNCTION IF EXISTS pg_catalog.pg_stop_backup(IN exclusive BOOL) CASCADE;
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 6203;
CREATE OR REPLACE FUNCTION pg_catalog.pg_start_backup
(IN backupid pg_catalog.text,
IN fast pg_catalog.bool,
IN exclusive pg_catalog.bool)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_start_backup_v2';
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 6204;
CREATE OR REPLACE FUNCTION pg_catalog.pg_stop_backup
(IN exclusive pg_catalog.bool,
out lsn pg_catalog.text,
out labelfile pg_catalog.text,
out spcmapfile pg_catalog.text)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_stop_backup_v2';

View File

@ -2393,3 +2393,21 @@ out catalog_version_no pg_catalog.int4,
out system_identifier pg_catalog.int8,
out pg_control_last_modified pg_catalog.timestamptz)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_control_system';
DROP FUNCTION IF EXISTS pg_catalog.pg_start_backup(IN backupid TEXT, IN fast BOOL, IN exclusive BOOL) CASCADE;
DROP FUNCTION IF EXISTS pg_catalog.pg_stop_backup(IN exclusive BOOL) CASCADE;
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 6203;
CREATE OR REPLACE FUNCTION pg_catalog.pg_start_backup
(IN backupid pg_catalog.text,
IN fast pg_catalog.bool,
IN exclusive pg_catalog.bool)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_start_backup_v2';
SET LOCAL inplace_upgrade_next_system_object_oids = IUO_PROC, 6204;
CREATE OR REPLACE FUNCTION pg_catalog.pg_stop_backup
(IN exclusive pg_catalog.bool,
out lsn pg_catalog.text,
out labelfile pg_catalog.text,
out spcmapfile pg_catalog.text)
RETURNS SETOF record LANGUAGE INTERNAL VOLATILE STRICT as 'pg_stop_backup_v2';

View File

@ -994,7 +994,12 @@ typedef struct knl_u_proc_context {
* */
enum SessionBackupState sessionBackupState;
bool registerExclusiveHandlerdone;
/*
* Store label file and tablespace map during non-exclusive backups.
*/
char* LabelFile;
char* TblspcMapFile;
bool registerAbortBackupHandlerdone; /* unterminated backups handler flag */
} knl_u_proc_context;
/* maximum possible number of fields in a date string */
@ -2278,6 +2283,7 @@ typedef struct knl_session_context {
MemoryContext top_transaction_mem_cxt;
MemoryContext self_mem_cxt;
MemoryContext top_portal_cxt;
MemoryContext probackup_context;
MemoryContextGroup* mcxt_group;
/* temp_mem_cxt is a context which will be reset when the session attach to a thread */
MemoryContext temp_mem_cxt;

View File

@ -73,6 +73,7 @@ extern void proc_exit(int code);
extern void sess_exit(int code);
extern void shmem_exit(int code);
extern void on_proc_exit(pg_on_exit_callback function, Datum arg);
extern void before_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void on_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void cancel_shmem_exit(pg_on_exit_callback function, Datum arg);
extern void on_exit_reset(void);

View File

@ -2686,6 +2686,8 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
6116 | int1smaller
6117 | int1inc
6118 | set_hashbucket_info
6203 | pg_start_backup
6204 | pg_stop_backup
6224 | gs_get_next_xid_csn
6321 | pg_stat_file_recursive
7777 | sysdate

View File

@ -2773,6 +2773,8 @@ WHERE d.classoid IS NULL AND p1.oid <= 9999 order by 1;
6200 | mot_session_memory_detail
6201 | mot_global_memory_detail
6202 | mot_local_memory_detail
6203 | pg_start_backup
6204 | pg_stop_backup
6224 | gs_get_next_xid_csn
6321 | pg_stat_file_recursive
7777 | sysdate