资源池化适配gs_probackup
This commit is contained in:
@ -263,7 +263,7 @@ static void run_backup_threads(char *external_prefix, char *database_path, char
|
||||
pfree(threads_args);
|
||||
}
|
||||
|
||||
static void start_stream_wal(const char *database_path, PGconn *backup_conn)
|
||||
static void start_stream_wal(const char *database_path, const char *dssdata_path, PGconn *backup_conn)
|
||||
{
|
||||
static char dst_backup_path[MAXPGPATH];
|
||||
|
||||
@ -271,7 +271,15 @@ static void start_stream_wal(const char *database_path, PGconn *backup_conn)
|
||||
stream_stop_timeout = checkpoint_timeout(backup_conn);
|
||||
stream_stop_timeout = stream_stop_timeout + stream_stop_timeout * 0.1;
|
||||
|
||||
join_path_components(dst_backup_path, database_path, PG_XLOG_DIR);
|
||||
if (IsDssMode()) {
|
||||
error_t rc;
|
||||
rc = snprintf_s(dst_backup_path, MAXPGPATH, MAXPGPATH - 1, "%s/%s%d", dssdata_path,
|
||||
PG_XLOG_DIR, instance_config.dss.instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
} else {
|
||||
join_path_components(dst_backup_path, database_path, PG_XLOG_DIR);
|
||||
}
|
||||
|
||||
fio_mkdir(dst_backup_path, DIR_PERMISSION, FIO_BACKUP_HOST);
|
||||
|
||||
stream_thread_arg.basedir = dst_backup_path;
|
||||
@ -390,16 +398,13 @@ static void get_prev_backup_info(parray **backup_list, pgBackup **prev_back, par
|
||||
*prev_back = prev_backup;
|
||||
}
|
||||
|
||||
static void calc_pgdata_bytes()
|
||||
static void calc_data_bytes()
|
||||
{
|
||||
int i;
|
||||
char pretty_bytes[20];
|
||||
char pretty_dssdata_bytes[20];
|
||||
char pretty_pgdata_bytes[20];
|
||||
|
||||
if (parray_num(backup_files_list) < 100)
|
||||
elog(ERROR, "PGDATA is almost empty. Either it was concurrently deleted or "
|
||||
"gs_probackup do not possess sufficient permissions to list PGDATA content");
|
||||
|
||||
/* Calculate pgdata_bytes */
|
||||
/* Calculate pgdata_bytes and dssdata_bytes */
|
||||
for (i = 0; i < (int)parray_num(backup_files_list); i++)
|
||||
{
|
||||
pgFile *file = (pgFile *) parray_get(backup_files_list, i);
|
||||
@ -407,17 +412,25 @@ static void calc_pgdata_bytes()
|
||||
if (file->external_dir_num != 0)
|
||||
continue;
|
||||
|
||||
if (S_ISDIR(file->mode))
|
||||
{
|
||||
current.pgdata_bytes += 4096;
|
||||
continue;
|
||||
if (S_ISDIR(file->mode)) {
|
||||
if (is_dss_type(file->type))
|
||||
current.dssdata_bytes += 4096;
|
||||
else
|
||||
current.pgdata_bytes += 4096;
|
||||
} else {
|
||||
if (is_dss_type(file->type))
|
||||
current.dssdata_bytes += file->size;
|
||||
else
|
||||
current.pgdata_bytes += file->size;
|
||||
}
|
||||
|
||||
current.pgdata_bytes += file->size;
|
||||
}
|
||||
|
||||
pretty_size(current.pgdata_bytes, pretty_bytes, lengthof(pretty_bytes));
|
||||
elog(INFO, "PGDATA size: %s", pretty_bytes);
|
||||
pretty_size(current.pgdata_bytes, pretty_pgdata_bytes, lengthof(pretty_pgdata_bytes));
|
||||
elog(INFO, "PGDATA size: %s", pretty_pgdata_bytes);
|
||||
if (IsDssMode()) {
|
||||
pretty_size(current.dssdata_bytes, pretty_dssdata_bytes, lengthof(pretty_dssdata_bytes));
|
||||
elog(INFO, "DSSDATA size: %s", pretty_dssdata_bytes);
|
||||
}
|
||||
}
|
||||
|
||||
static void add_xlog_files_into_backup_list(const char *database_path, const char *dssdata_path,
|
||||
@ -432,28 +445,11 @@ static void add_xlog_files_into_backup_list(const char *database_path, const cha
|
||||
/* Scan backup PG_XLOG_DIR */
|
||||
xlog_files_list = parray_new();
|
||||
|
||||
/* link dssdata's pg_xlog to database's pg_xlog */
|
||||
if (enable_dss) {
|
||||
char database_xlog[MAXPGPATH];
|
||||
char dssdata_xlog[MAXPGPATH];
|
||||
if (IsDssMode()) {
|
||||
errno_t rc;
|
||||
|
||||
rc = snprintf_s(dssdata_xlog, MAXPGPATH, MAXPGPATH - 1, "%s/%s%d", dssdata_path, PG_XLOG_DIR, instance_id);
|
||||
rc = snprintf_s(pg_xlog_path, MAXPGPATH, MAXPGPATH - 1, "%s/%s%d", dssdata_path, PG_XLOG_DIR, instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
join_path_components(database_xlog, database_path, PG_XLOG_DIR);
|
||||
|
||||
/* dssdata_xlog is already exist, destory it and recreate */
|
||||
if (rmdir(dssdata_xlog) != 0) {
|
||||
elog(ERROR, "can not remove xlog dir \"%s\" : %s", dssdata_xlog, strerror(errno));
|
||||
}
|
||||
|
||||
if (symlink(database_xlog, dssdata_xlog) < 0) {
|
||||
elog(ERROR, "can not link dss xlog dir \"%s\" to database xlog dir \"%s\": %s", dssdata_xlog, database_xlog,
|
||||
strerror(errno));
|
||||
}
|
||||
|
||||
rc = strcpy_s(pg_xlog_path, MAXPGPATH, dssdata_xlog);
|
||||
securec_check_c(rc, "\0", "\0");
|
||||
parent_path = dssdata_path;
|
||||
} else {
|
||||
join_path_components(pg_xlog_path, database_path, PG_XLOG_DIR);
|
||||
@ -683,7 +679,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
||||
/* start stream replication */
|
||||
if (stream_wal)
|
||||
{
|
||||
start_stream_wal(database_path, backup_conn);
|
||||
start_stream_wal(database_path, dssdata_path, backup_conn);
|
||||
}
|
||||
|
||||
/* initialize backup list */
|
||||
@ -736,11 +732,17 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
|
||||
*/
|
||||
|
||||
if (parray_num(backup_files_list) < 100)
|
||||
elog(ERROR, "PGDATA is almost empty. Either it was concurrently deleted or "
|
||||
"gs_probackup do not possess sufficient permissions to list PGDATA content");
|
||||
{
|
||||
if (IsDssMode())
|
||||
elog(ERROR, "VGNAME is almost empty. Either it was concurrently deleted or "
|
||||
"gs_probackup do not possess sufficient permissions to list VGNAME content");
|
||||
else
|
||||
elog(ERROR, "PGDATA is almost empty. Either it was concurrently deleted or "
|
||||
"gs_probackup do not possess sufficient permissions to list PGDATA content");
|
||||
}
|
||||
|
||||
/* Calculate pgdata_bytes */
|
||||
calc_pgdata_bytes();
|
||||
/* Calculate pgdata_bytes and dssdata_bytes */
|
||||
calc_data_bytes();
|
||||
/*
|
||||
* Sort pathname ascending. It is necessary to create intermediate
|
||||
* directories sequentially.
|
||||
@ -943,9 +945,6 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
|
||||
elog(ERROR, "required parameter not specified: PGDATA "
|
||||
"(-D, --pgdata)");
|
||||
|
||||
if (IsDssMode() && current.backup_mode != BACKUP_MODE_FULL)
|
||||
elog(ERROR, "only support full backup when enable dss.");
|
||||
|
||||
/* Update backup status and other metainfo. */
|
||||
current.status = BACKUP_STATUS_RUNNING;
|
||||
current.start_time = start_time;
|
||||
@ -1434,8 +1433,22 @@ wait_wal_lsn(XLogRecPtr target_lsn, bool is_start_lsn, TimeLineID tli,
|
||||
*/
|
||||
if (in_stream_dir)
|
||||
{
|
||||
pgBackupGetPath2(¤t, pg_wal_dir, lengthof(pg_wal_dir),
|
||||
DATABASE_DIR, PG_XLOG_DIR);
|
||||
if (IsDssMode())
|
||||
{
|
||||
errno_t rc;
|
||||
char dss_xlog[MAXPGPATH];
|
||||
|
||||
rc = snprintf_s(dss_xlog, MAXPGPATH, MAXPGPATH - 1, "%s%d",
|
||||
PG_XLOG_DIR, instance_config.dss.instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
pgBackupGetPath2(¤t, pg_wal_dir, lengthof(pg_wal_dir),
|
||||
DSSDATA_DIR, dss_xlog);
|
||||
}
|
||||
else
|
||||
{
|
||||
pgBackupGetPath2(¤t, pg_wal_dir, lengthof(pg_wal_dir),
|
||||
DATABASE_DIR, PG_XLOG_DIR);
|
||||
}
|
||||
join_path_components(wal_segment_path, pg_wal_dir, wal_segment);
|
||||
wal_segment_dir = pg_wal_dir;
|
||||
}
|
||||
@ -1558,9 +1571,21 @@ static void get_valid_stop_lsn(pgBackup *backup, bool *stop_lsn_exists, XLogRecP
|
||||
|
||||
if (stream_wal)
|
||||
{
|
||||
pgBackupGetPath2(backup, stream_xlog_path,
|
||||
lengthof(stream_xlog_path),
|
||||
if (IsDssMode())
|
||||
{
|
||||
errno_t rc;
|
||||
char dss_xlog[MAXPGPATH];
|
||||
rc = snprintf_s(dss_xlog, MAXPGPATH, MAXPGPATH - 1, "%s%d", PG_XLOG_DIR,
|
||||
instance_config.dss.instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
pgBackupGetPath2(backup, stream_xlog_path, lengthof(stream_xlog_path),
|
||||
DSSDATA_DIR, dss_xlog);
|
||||
}
|
||||
else
|
||||
{
|
||||
pgBackupGetPath2(backup, stream_xlog_path, lengthof(stream_xlog_path),
|
||||
DATABASE_DIR, PG_XLOG_DIR);
|
||||
}
|
||||
xlog_path = stream_xlog_path;
|
||||
}
|
||||
else
|
||||
@ -1961,7 +1986,7 @@ pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn,
|
||||
if (backup != NULL)
|
||||
{
|
||||
char *xlog_path,
|
||||
stream_xlog_path[MAXPGPATH];
|
||||
stream_xlog_path[MAXPGPATH];
|
||||
|
||||
/*
|
||||
* Wait for stop_lsn to be archived or streamed.
|
||||
@ -1983,9 +2008,22 @@ pg_stop_backup(pgBackup *backup, PGconn *pg_startbackup_conn,
|
||||
if (stream_thread_arg.ret == 1)
|
||||
elog(ERROR, "WAL streaming failed");
|
||||
|
||||
pgBackupGetPath2(backup, stream_xlog_path,
|
||||
lengthof(stream_xlog_path),
|
||||
DATABASE_DIR, PG_XLOG_DIR);
|
||||
if (IsDssMode())
|
||||
{
|
||||
errno_t rc;
|
||||
char dss_xlog[MAXPGPATH];
|
||||
|
||||
rc = snprintf_s(dss_xlog, MAXPGPATH, MAXPGPATH - 1, "%s%d",
|
||||
PG_XLOG_DIR, instance_config.dss.instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
pgBackupGetPath2(backup, stream_xlog_path, lengthof(stream_xlog_path),
|
||||
DSSDATA_DIR, dss_xlog);
|
||||
}
|
||||
else
|
||||
{
|
||||
pgBackupGetPath2(backup, stream_xlog_path, lengthof(stream_xlog_path),
|
||||
DATABASE_DIR, PG_XLOG_DIR);
|
||||
}
|
||||
xlog_path = stream_xlog_path;
|
||||
}
|
||||
else
|
||||
|
||||
@ -498,7 +498,7 @@ prepare_page(ConnectionArgs *conn_arg,
|
||||
/* read the block */
|
||||
int offset = blknum * BLCKSZ;
|
||||
int fileStartOff = offset - (offset % DSS_BLCKSZ);
|
||||
if (IsDssMode() && file->size - fileStartOff >= DSS_BLCKSZ)
|
||||
if (current.backup_mode == BACKUP_MODE_FULL && IsDssMode() && file->size - fileStartOff >= DSS_BLCKSZ)
|
||||
{
|
||||
int preReadOff = offset % DSS_BLCKSZ;
|
||||
if (offset / DSS_BLCKSZ == preReadBuf->num)
|
||||
@ -570,7 +570,7 @@ prepare_page(ConnectionArgs *conn_arg,
|
||||
blknum, from_fullpath, read_len, BLCKSZ);
|
||||
}
|
||||
else
|
||||
{
|
||||
{
|
||||
/* We have BLCKSZ of raw data, validate it */
|
||||
rc = validate_one_page(page, absolute_blknum,
|
||||
InvalidXLogRecPtr, page_st,
|
||||
@ -739,7 +739,7 @@ backup_data_file(ConnectionArgs* conn_arg, pgFile *file,
|
||||
* NOTE This is a normal situation, if the file size has changed
|
||||
* since the moment we computed it.
|
||||
*/
|
||||
file->n_blocks = file->size/BLCKSZ;
|
||||
file->n_blocks = file->size / BLCKSZ;
|
||||
|
||||
/*
|
||||
* Skip unchanged file only if it exists in previous backup.
|
||||
@ -1305,7 +1305,7 @@ restore_data_file_internal(FILE *in, FILE *out, pgFile *file, uint32 backup_vers
|
||||
/* If page is compressed and restore is in remote mode, send compressed
|
||||
* page to the remote side.
|
||||
*/
|
||||
if (IsDssMode() && targetSize >= DSS_BLCKSZ)
|
||||
if (!map && IsDssMode() && targetSize >= DSS_BLCKSZ)
|
||||
{
|
||||
if (is_compressed)
|
||||
{
|
||||
@ -1601,11 +1601,31 @@ backup_non_data_file_internal(const char *from_fullpath, fio_location from_locat
|
||||
/* open backup file for write */
|
||||
out = fopen(to_fullpath, PG_BINARY_W);
|
||||
if (out == NULL)
|
||||
elog(ERROR, "Cannot open destination file \"%s\": %s",
|
||||
to_fullpath, strerror(errno));
|
||||
{
|
||||
if (file->external_dir_num)
|
||||
{
|
||||
char parent[MAXPGPATH];
|
||||
errno_t rc = 0;
|
||||
|
||||
rc = strncpy_s(parent, MAXPGPATH, to_fullpath, MAXPGPATH - 1);
|
||||
securec_check_c(rc, "", "");
|
||||
get_parent_directory(parent);
|
||||
|
||||
dir_create_dir(parent, DIR_PERMISSION);
|
||||
out = fopen(to_fullpath, PG_BINARY_W);
|
||||
if (out == NULL)
|
||||
elog(ERROR, "Cannot open destination file \"%s\": %s",
|
||||
to_fullpath, strerror(errno));
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Cannot open destination file \"%s\": %s",
|
||||
to_fullpath, strerror(errno));
|
||||
}
|
||||
}
|
||||
|
||||
/* update file permission */
|
||||
if (!is_dss_file(from_fullpath))
|
||||
if (!is_dss_type(file->type))
|
||||
{
|
||||
if (chmod(to_fullpath, file->mode) == -1)
|
||||
elog(ERROR, "Cannot change mode of \"%s\": %s", to_fullpath,
|
||||
|
||||
@ -450,9 +450,9 @@ pgFileCompareRelPathWithExternal(const void *f1, const void *f2)
|
||||
res = strcmp(f1p->rel_path, f2p->rel_path);
|
||||
if (res == 0)
|
||||
{
|
||||
if (f1p->external_dir_num > f2p->external_dir_num)
|
||||
if (f1p->external_dir_num > f2p->external_dir_num || f1p->type > f2p->type)
|
||||
return 1;
|
||||
else if (f1p->external_dir_num < f2p->external_dir_num)
|
||||
else if (f1p->external_dir_num < f2p->external_dir_num || f1p->type < f2p->type)
|
||||
return -1;
|
||||
else
|
||||
return 0;
|
||||
@ -691,16 +691,21 @@ dir_check_file(pgFile *file, bool backup_logs, bool backup_replslots)
|
||||
Oid tblspcOid;
|
||||
char tmp_rel_path[MAXPGPATH];
|
||||
|
||||
if (in_tablespace && IsDssMode())
|
||||
return CHECK_FALSE;
|
||||
/*
|
||||
* Valid path for the tablespace is
|
||||
* pg_tblspc/tblsOid/TABLESPACE_VERSION_DIRECTORY
|
||||
*/
|
||||
if (!path_is_prefix_of_path(PG_TBLSPC_DIR, file->rel_path))
|
||||
return CHECK_FALSE;
|
||||
sscanf_res = sscanf_s(file->rel_path, PG_TBLSPC_DIR "/%u/%s",
|
||||
if (!IsDssMode())
|
||||
{
|
||||
if (!in_tablespace)
|
||||
return CHECK_FALSE;
|
||||
sscanf_res = sscanf_s(file->rel_path, PG_TBLSPC_DIR "/%u/%s",
|
||||
&tblspcOid, tmp_rel_path, MAXPGPATH);
|
||||
if (sscanf_res == 0)
|
||||
return CHECK_FALSE;
|
||||
if (sscanf_res == 0)
|
||||
return CHECK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/* skip other instance files in dss mode */
|
||||
@ -760,7 +765,7 @@ static char check_in_dss(pgFile *file, int include_id)
|
||||
|
||||
static char check_in_tablespace(pgFile *file, bool in_tablespace)
|
||||
{
|
||||
if (in_tablespace)
|
||||
if (in_tablespace)
|
||||
{
|
||||
int sscanf_res;
|
||||
char tmp_rel_path[MAXPGPATH];
|
||||
@ -1235,7 +1240,7 @@ opt_externaldir_map(ConfigOption *opt, const char *arg)
|
||||
*/
|
||||
void
|
||||
create_data_directories(parray *dest_files, const char *data_dir, const char *backup_dir,
|
||||
bool extract_tablespaces, bool incremental, fio_location location)
|
||||
bool extract_tablespaces, bool incremental, fio_location location, bool is_restore)
|
||||
{
|
||||
size_t i = 0;
|
||||
parray *links = NULL;
|
||||
@ -1312,7 +1317,7 @@ create_data_directories(parray *dest_files, const char *data_dir, const char *ba
|
||||
if (dir->external_dir_num != 0)
|
||||
continue;
|
||||
|
||||
if (is_dss_type(dir->type)) {
|
||||
if (is_dss_type(dir->type) && is_restore) {
|
||||
if (is_ss_xlog(dir->rel_path)) {
|
||||
ss_createdir(dir->rel_path, instance_config.dss.vgdata, instance_config.dss.vglog);
|
||||
continue;
|
||||
@ -1348,7 +1353,7 @@ create_data_directories(parray *dest_files, const char *data_dir, const char *ba
|
||||
{
|
||||
const char *linked_path = get_tablespace_mapping((*link)->linked);
|
||||
|
||||
if (!is_absolute_path(linked_path))
|
||||
if (!is_absolute_path(linked_path) && !ss_is_absolute_path(linked_path))
|
||||
elog(ERROR, "Tablespace directory is not an absolute path: %s\n",
|
||||
linked_path);
|
||||
|
||||
@ -1499,7 +1504,7 @@ check_tablespace_mapping(pgBackup *backup, bool incremental, bool *tblspaces_are
|
||||
break;
|
||||
}
|
||||
|
||||
if (!is_absolute_path(linked_path))
|
||||
if (!is_absolute_path(linked_path) && !ss_is_absolute_path(linked_path))
|
||||
elog(ERROR, "tablespace directory is not an absolute path: %s\n",
|
||||
linked_path);
|
||||
|
||||
@ -1551,6 +1556,9 @@ check_external_dir_mapping(pgBackup *backup, bool incremental)
|
||||
|
||||
if (strcmp(cell->old_dir, external_dir) == 0)
|
||||
{
|
||||
if (is_dss_file(cell->new_dir))
|
||||
elog(ERROR, "New external directory path \"%s\" "
|
||||
"contains dss path, which is not allow.", cell->new_dir);
|
||||
/* Swap new dir name with old one, it is used by 2-nd step */
|
||||
parray_set(external_dirs_to_restore, i,
|
||||
pgut_strdup(cell->new_dir));
|
||||
@ -1966,7 +1974,7 @@ make_external_directory_list(const char *colon_separated_dirs, bool remap)
|
||||
char *external_path = pg_strdup(p);
|
||||
|
||||
canonicalize_path(external_path);
|
||||
if (is_absolute_path(external_path))
|
||||
if (is_absolute_path(external_path) || ss_is_absolute_path(external_path))
|
||||
{
|
||||
if (remap)
|
||||
{
|
||||
|
||||
@ -27,6 +27,7 @@ typedef struct
|
||||
|
||||
const char *full_database_dir;
|
||||
const char *full_external_prefix;
|
||||
const char *full_dss_dir;
|
||||
|
||||
// size_t in_place_merge_bytes;
|
||||
bool compression_match;
|
||||
@ -55,15 +56,15 @@ get_external_index(const char *key, const parray *list);
|
||||
|
||||
static void
|
||||
merge_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
pgBackup *dest_backup, pgFile *dest_file,
|
||||
pgFile *tmp_file, const char *to_root, bool use_bitmap,
|
||||
bool is_retry);
|
||||
pgBackup *dest_backup, pgFile *dest_file,
|
||||
pgFile *tmp_file, const char *full_database_dir, const char *full_dss_dir,
|
||||
bool use_bitmap, bool is_retry);
|
||||
|
||||
static void
|
||||
merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
pgBackup *dest_backup, pgFile *dest_file,
|
||||
pgFile *tmp_file, const char *full_database_dir,
|
||||
const char *full_external_prefix);
|
||||
const char *full_dss_dir, const char *full_external_prefix);
|
||||
static pgBackup* find_dest_backup(parray *backups, time_t backup_id);
|
||||
static pgBackup *check_dest_backup(parray *backups,
|
||||
pgBackup *full_backup);
|
||||
@ -74,6 +75,7 @@ static void get_backup_files(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
char *full_external_prefix,
|
||||
char *full_database_dir,
|
||||
char *full_dss_dir,
|
||||
parray *dest_externals,
|
||||
parray *full_externals,
|
||||
parray *parent_chain);
|
||||
@ -81,6 +83,7 @@ static void threads_handle(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
char *full_external_prefix,
|
||||
char *full_database_dir,
|
||||
char *full_dss_dir,
|
||||
pthread_t *threads,
|
||||
merge_files_arg *threads_args,
|
||||
parray *parent_chain,
|
||||
@ -91,6 +94,7 @@ static void threads_handle(pgBackup *dest_backup,
|
||||
static void del_full_backup_files(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
const char *full_database_dir,
|
||||
const char *full_dss_dir,
|
||||
parray *full_externals);
|
||||
static void merge_rename(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
@ -106,7 +110,7 @@ static void forward_compatibility_check(parray *parent_chain);
|
||||
* Implementation of MERGE command.
|
||||
*
|
||||
* - Find target and its parent full backup
|
||||
* - Merge data files of target, parent and and intermediate backups
|
||||
* - Merge data files of target, parent and intermediate backups
|
||||
* - Remove unnecessary files, which doesn't exist in the target backup anymore
|
||||
*/
|
||||
void
|
||||
@ -513,6 +517,7 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
|
||||
int i;
|
||||
char full_external_prefix[MAXPGPATH];
|
||||
char full_database_dir[MAXPGPATH];
|
||||
char full_dss_dir[MAXPGPATH];
|
||||
parray *full_externals = NULL,
|
||||
*dest_externals = NULL;
|
||||
|
||||
@ -616,13 +621,13 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
|
||||
validate_parent_chain(parent_chain, dest_backup);
|
||||
|
||||
get_backup_files(dest_backup, full_backup, full_external_prefix, full_database_dir,
|
||||
dest_externals, full_externals, parent_chain);
|
||||
full_dss_dir, dest_externals, full_externals, parent_chain);
|
||||
|
||||
threads_handle(dest_backup, full_backup, full_external_prefix, full_database_dir,
|
||||
threads, threads_args, parent_chain, compression_match,
|
||||
full_dss_dir, threads, threads_args, parent_chain, compression_match,
|
||||
program_version_match, is_retry, result_filelist);
|
||||
|
||||
del_full_backup_files(dest_backup, full_backup, full_database_dir, full_externals);
|
||||
del_full_backup_files(dest_backup, full_backup, full_database_dir, full_dss_dir, full_externals);
|
||||
|
||||
merge_delete:
|
||||
for (i = parray_num(parent_chain) - 2; i >= 0; i--)
|
||||
@ -697,6 +702,7 @@ static void get_backup_files(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
char *full_external_prefix,
|
||||
char *full_database_dir,
|
||||
char *full_dss_dir,
|
||||
parray *dest_externals,
|
||||
parray *full_externals,
|
||||
parray *parent_chain)
|
||||
@ -728,12 +734,17 @@ static void get_backup_files(pgBackup *dest_backup,
|
||||
|
||||
/* Construct path to database dir: /backup_dir/instance_name/FULL/database */
|
||||
join_path_components(full_database_dir, full_backup->root_dir, DATABASE_DIR);
|
||||
/* Construct path to vgname dir: /backup_dir/instance_name/FULL/dssdata */
|
||||
join_path_components(full_dss_dir, full_backup->root_dir, DSSDATA_DIR);
|
||||
/* Construct path to external dir: /backup_dir/instance_name/FULL/external */
|
||||
join_path_components(full_external_prefix, full_backup->root_dir, EXTERNAL_DIR);
|
||||
|
||||
/* Create directories */
|
||||
/* Create directories in database_dir*/
|
||||
create_data_directories(dest_backup->files, full_database_dir,
|
||||
dest_backup->root_dir, false, false, FIO_BACKUP_HOST);
|
||||
dest_backup->root_dir, false, false, FIO_BACKUP_HOST, false);
|
||||
/* Create directories in dssdata_dir */
|
||||
create_data_directories(dest_backup->files, full_dss_dir,
|
||||
dest_backup->root_dir, false, false, FIO_BACKUP_HOST, false);
|
||||
|
||||
/* External directories stuff */
|
||||
if (dest_backup->external_dir_str)
|
||||
@ -752,6 +763,7 @@ static void threads_handle(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
char *full_external_prefix,
|
||||
char *full_database_dir,
|
||||
char *full_dss_dir,
|
||||
pthread_t *threads,
|
||||
merge_files_arg *threads_args,
|
||||
parray *parent_chain,
|
||||
@ -806,6 +818,7 @@ static void threads_handle(pgBackup *dest_backup,
|
||||
arg->dest_backup = dest_backup;
|
||||
arg->full_backup = full_backup;
|
||||
arg->full_database_dir = full_database_dir;
|
||||
arg->full_dss_dir = full_dss_dir;
|
||||
arg->full_external_prefix = full_external_prefix;
|
||||
|
||||
arg->compression_match = compression_match;
|
||||
@ -926,6 +939,7 @@ static void threads_handle(pgBackup *dest_backup,
|
||||
static void del_full_backup_files(pgBackup *dest_backup,
|
||||
pgBackup *full_backup,
|
||||
const char *full_database_dir,
|
||||
const char *full_dss_dir,
|
||||
parray *full_externals)
|
||||
{
|
||||
/* Delete FULL backup files, that do not exists in destination backup
|
||||
@ -950,7 +964,10 @@ static void del_full_backup_files(pgBackup *dest_backup,
|
||||
char full_file_path[MAXPGPATH];
|
||||
|
||||
/* We need full path, file object has relative path */
|
||||
join_path_components(full_file_path, full_database_dir, full_file->rel_path);
|
||||
if (is_dss_type(full_file->type))
|
||||
join_path_components(full_file_path, full_dss_dir, full_file->rel_path);
|
||||
else
|
||||
join_path_components(full_file_path, full_database_dir, full_file->rel_path);
|
||||
|
||||
pgFileDelete(full_file->mode, full_file_path);
|
||||
elog(VERBOSE, "Deleted \"%s\"", full_file_path);
|
||||
@ -1094,6 +1111,7 @@ merge_files(void *arg)
|
||||
tmp_file->is_cfs = dest_file->is_cfs;
|
||||
tmp_file->external_dir_num = dest_file->external_dir_num;
|
||||
tmp_file->dbOid = dest_file->dbOid;
|
||||
tmp_file->type = dest_file->type;
|
||||
|
||||
/* Directories were created before */
|
||||
if (S_ISDIR(dest_file->mode))
|
||||
@ -1127,6 +1145,7 @@ merge_files(void *arg)
|
||||
arguments->dest_backup,
|
||||
dest_file, tmp_file,
|
||||
arguments->full_database_dir,
|
||||
arguments->full_dss_dir,
|
||||
arguments->use_bitmap,
|
||||
arguments->is_retry);
|
||||
else
|
||||
@ -1135,6 +1154,7 @@ merge_files(void *arg)
|
||||
arguments->dest_backup,
|
||||
dest_file, tmp_file,
|
||||
arguments->full_database_dir,
|
||||
arguments->full_dss_dir,
|
||||
arguments->full_external_prefix);
|
||||
|
||||
done:
|
||||
@ -1281,6 +1301,7 @@ static void do_in_place_merge(merge_files_arg *arguments,
|
||||
//TODO: report in_place merge bytes.
|
||||
parray_append(arguments->merge_filelist, tmp_file);
|
||||
*iscontinue = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1368,7 +1389,8 @@ reorder_external_dirs(pgBackup *to_backup, parray *to_external,
|
||||
void
|
||||
merge_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
pgBackup *dest_backup, pgFile *dest_file, pgFile *tmp_file,
|
||||
const char *full_database_dir, bool use_bitmap, bool is_retry)
|
||||
const char *full_database_dir, const char *full_dss_dir,
|
||||
bool use_bitmap, bool is_retry)
|
||||
{
|
||||
FILE *out = NULL;
|
||||
char *buffer = (char *)pgut_malloc(STDIO_BUFSIZE);
|
||||
@ -1383,7 +1405,10 @@ merge_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
*/
|
||||
|
||||
/* set fullpath of destination file and temp files */
|
||||
join_path_components(to_fullpath, full_database_dir, tmp_file->rel_path);
|
||||
if (is_dss_type(tmp_file->type))
|
||||
join_path_components(to_fullpath, full_dss_dir, tmp_file->rel_path);
|
||||
else
|
||||
join_path_components(to_fullpath, full_database_dir, tmp_file->rel_path);
|
||||
nRet = snprintf_s(to_fullpath_tmp1, MAXPGPATH, MAXPGPATH - 1, "%s_tmp1", to_fullpath);
|
||||
securec_check_ss_c(nRet, "\0", "\0");
|
||||
nRet = snprintf_s(to_fullpath_tmp2, MAXPGPATH, MAXPGPATH - 1, "%s_tmp2", to_fullpath);
|
||||
@ -1463,7 +1488,8 @@ merge_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
void
|
||||
merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
pgBackup *dest_backup, pgFile *dest_file, pgFile *tmp_file,
|
||||
const char *full_database_dir, const char *to_external_prefix)
|
||||
const char *full_database_dir, const char *full_dss_dir,
|
||||
const char *to_external_prefix)
|
||||
{
|
||||
size_t i = 0;
|
||||
char to_fullpath[MAXPGPATH];
|
||||
@ -1481,8 +1507,14 @@ merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
dest_file->external_dir_num);
|
||||
join_path_components(to_fullpath, temp, dest_file->rel_path);
|
||||
}
|
||||
else if (is_dss_type(dest_file->type))
|
||||
{
|
||||
join_path_components(to_fullpath, full_dss_dir, dest_file->rel_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
join_path_components(to_fullpath, full_database_dir, dest_file->rel_path);
|
||||
}
|
||||
|
||||
nRet = snprintf_s(to_fullpath_tmp, MAXPGPATH, MAXPGPATH - 1, "%s_tmp", to_fullpath);
|
||||
securec_check_ss_c(nRet, "\0", "\0");
|
||||
@ -1537,6 +1569,12 @@ merge_non_data_file(parray *parent_chain, pgBackup *full_backup,
|
||||
|
||||
join_path_components(from_fullpath, temp, from_file->rel_path);
|
||||
}
|
||||
else if (is_dss_type(from_file->type))
|
||||
{
|
||||
char backup_dss_dir[MAXPGPATH];
|
||||
join_path_components(backup_dss_dir, from_backup->root_dir, DSSDATA_DIR);
|
||||
join_path_components(from_fullpath, backup_dss_dir, from_file->rel_path);
|
||||
}
|
||||
else
|
||||
{
|
||||
char backup_database_dir[MAXPGPATH];
|
||||
|
||||
@ -439,9 +439,19 @@ validate_wal(pgBackup *backup, const char *archivedir,
|
||||
char backup_database_dir[MAXPGPATH];
|
||||
char backup_xlog_path[MAXPGPATH];
|
||||
|
||||
join_path_components(backup_database_dir, backup->root_dir, DATABASE_DIR);
|
||||
join_path_components(backup_xlog_path, backup_database_dir, PG_XLOG_DIR);
|
||||
|
||||
if (IsDssMode())
|
||||
{
|
||||
errno_t rc;
|
||||
join_path_components(backup_database_dir, backup->root_dir, DSSDATA_DIR);
|
||||
rc = snprintf_s(backup_xlog_path, MAXPGPATH, MAXPGPATH - 1, "%s/%s%d",
|
||||
backup_database_dir, PG_XLOG_DIR, instance_config.dss.instance_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
}
|
||||
else
|
||||
{
|
||||
join_path_components(backup_database_dir, backup->root_dir, DATABASE_DIR);
|
||||
join_path_components(backup_xlog_path, backup_database_dir, PG_XLOG_DIR);
|
||||
}
|
||||
validate_backup_wal_from_start_to_stop(backup, backup_xlog_path, tli,
|
||||
wal_seg_size);
|
||||
}
|
||||
|
||||
@ -57,7 +57,7 @@ typedef struct pgFile_t
|
||||
int n_headers; /* number of blocks in the data file in backup */
|
||||
pg_crc32 hdr_crc; /* CRC value of header file: name_hdr */
|
||||
off_t hdr_off; /* offset in header map */
|
||||
int hdr_size; /* offset in header map */
|
||||
int hdr_size; /* the size of cpmpressed header */
|
||||
device_type_t type; /* file device type */
|
||||
} pgFile;
|
||||
|
||||
@ -250,6 +250,8 @@ struct pgBackup
|
||||
|
||||
/* Size of data files in PGDATA at the moment of backup. */
|
||||
int64 pgdata_bytes;
|
||||
/* Size of data files in vgdata(DSS) at the moment of backup. */
|
||||
int64 dssdata_bytes;
|
||||
|
||||
CompressAlg compress_alg;
|
||||
int compress_level;
|
||||
|
||||
@ -255,7 +255,8 @@ extern void create_data_directories(parray *dest_files,
|
||||
const char *backup_dir,
|
||||
bool extract_tablespaces,
|
||||
bool incremental,
|
||||
fio_location location);
|
||||
fio_location location,
|
||||
bool is_restore);
|
||||
|
||||
extern void read_tablespace_map(parray *files, const char *backup_dir);
|
||||
extern void opt_tablespace_map(ConfigOption *opt, const char *arg);
|
||||
@ -390,6 +391,7 @@ extern void get_redo(const char *pgdata_path, RedoParams *redo);
|
||||
extern void parse_vgname_args(const char* args);
|
||||
extern bool is_ss_xlog(const char *ss_dir);
|
||||
extern void ss_createdir(const char *ss_dir, const char *vgdata, const char *vglog);
|
||||
extern bool ss_create_if_pg_replication(pgFile *dir, const char *vgdata, const char *vglog);
|
||||
extern bool ss_create_if_doublewrite(pgFile* dir, const char* vgdata, int instance_id);
|
||||
extern bool ss_create_if_pg_replication(pgFile* dir, const char* vgdata, const char* vglog);
|
||||
extern char* xstrdup(const char* s);
|
||||
|
||||
@ -15,6 +15,7 @@
|
||||
#endif
|
||||
#include "catalog/pg_tablespace.h"
|
||||
#include "common/fe_memutils.h"
|
||||
#include "storage/file/fio_device.h"
|
||||
/*
|
||||
* Macro needed to parse ptrack.
|
||||
* NOTE Keep those values synchronized with definitions in ptrack.h
|
||||
@ -234,6 +235,7 @@ make_pagemap_from_ptrack(parray *files,
|
||||
pgFile *file = (pgFile *) parray_get(files, file_i);
|
||||
page_map_entry **res_map = NULL;
|
||||
page_map_entry *map = NULL;
|
||||
uint64 offset = 0;
|
||||
|
||||
/*
|
||||
* For now nondata files are not entitled to have pagemap
|
||||
@ -248,16 +250,28 @@ make_pagemap_from_ptrack(parray *files,
|
||||
continue;
|
||||
|
||||
if (filemaps) {
|
||||
dummy_map->path = file->rel_path;
|
||||
int rc = 0;
|
||||
char tmp_path[MAXPGPATH] = {0};
|
||||
// dummy_map->path = file->rel_path;
|
||||
if (file->compressed_file) {
|
||||
/* rel_path in filemaps is just oid without suffix of '_compress' */
|
||||
uint64 offset = strlen(file->rel_path) - strlen("_compress");
|
||||
offset = strlen(file->rel_path) - strlen("_compress");
|
||||
file->rel_path[offset] = '\0';
|
||||
res_map = (page_map_entry **)parray_bsearch(filemaps, dummy_map, pgFileMapComparePath);
|
||||
file->rel_path[offset] = '_';
|
||||
} else {
|
||||
res_map = (page_map_entry **)parray_bsearch(filemaps, dummy_map, pgFileMapComparePath);
|
||||
}
|
||||
|
||||
/* When enable dss, if the file is in VGNAME, the path needs to be an absolute path */
|
||||
if (is_dss_type(file->type)) {
|
||||
rc = sprintf_s(tmp_path, sizeof(tmp_path), "%s/%s",
|
||||
instance_config.dss.vgdata, file->rel_path);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
dummy_map->path = pgut_strdup(tmp_path);
|
||||
} else {
|
||||
dummy_map->path = file->rel_path;
|
||||
}
|
||||
res_map = (page_map_entry **)parray_bsearch(filemaps, dummy_map, pgFileMapComparePath);
|
||||
|
||||
if (file->compressed_file)
|
||||
file->rel_path[offset] = '_';
|
||||
map = (res_map) ? *res_map : NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -25,7 +25,7 @@
|
||||
|
||||
typedef struct
|
||||
{
|
||||
parray *pgdata_files;
|
||||
parray *pgdata_and_dssdata_files;
|
||||
parray *dest_files;
|
||||
pgBackup *dest_backup;
|
||||
parray *dest_external_dirs;
|
||||
@ -60,7 +60,7 @@ static void restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
pgRestoreParams *params, const char *pgdata_path,
|
||||
const char *dssdata_path, bool no_sync);
|
||||
static void check_incremental_compatibility(const char *pgdata, uint64 system_identifier,
|
||||
IncrRestoreMode incremental_mode);
|
||||
IncrRestoreMode incremental_mode);
|
||||
static pgBackup *find_backup_range(parray *backups,
|
||||
time_t target_backup_id,
|
||||
pgRecoveryTarget *rt,
|
||||
@ -70,11 +70,15 @@ static pgBackup * find_full_backup(parray *backups,
|
||||
pgBackup *dest_backup,
|
||||
const char *action);
|
||||
static XLogRecPtr determine_shift_lsn(pgBackup *dest_backup);
|
||||
static void get_pgdata_files(const char *pgdata_path,
|
||||
parray *pgdata_files,
|
||||
static void get_pgdata_and_dssdata_files(const char *pgdata_path,
|
||||
const char *dssdata_path,
|
||||
parray *pgdata_and_dssdata_files,
|
||||
parray *external_dirs);
|
||||
static bool skip_some_tblspc_files(pgFile *file);
|
||||
static char check_in_dss_instance(pgFile *file, int include_id);
|
||||
static void remove_redundant_files(const char *pgdata_path,
|
||||
parray *pgdata_files,
|
||||
const char *dssdata_path,
|
||||
parray *pgdata_and_dssdata_files,
|
||||
pgBackup *dest_backup,
|
||||
parray *external_dirs);
|
||||
static void threads_handle(pthread_t *threads,
|
||||
@ -172,29 +176,40 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
|
||||
elog(ERROR,
|
||||
"required parameter not specified: PGDATA (-D, --pgdata)");
|
||||
|
||||
/* Check if restore destination empty : vgdata and vglog */
|
||||
if (IsDssMode())
|
||||
{
|
||||
/* do not support increment restore in dss mode */
|
||||
if (params->incremental_mode != INCR_NONE)
|
||||
{
|
||||
elog(ERROR, "Incremental restore is not support when enable dss");
|
||||
}
|
||||
|
||||
if (!dir_is_empty(instance_config.dss.vgdata, FIO_DSS_HOST))
|
||||
{
|
||||
if (params->incremental_mode != INCR_NONE)
|
||||
{
|
||||
elog(INFO, "Running incremental restore into nonempty directory: \"%s\"",
|
||||
instance_config.dss.vgdata);
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Restore destination is not empty: \"%s\"",
|
||||
instance_config.dss.vgdata);
|
||||
}
|
||||
dssdata_is_empty = false;
|
||||
elog(ERROR, "Restore destination is not empty: \"%s\"",
|
||||
instance_config.dss.vgdata);
|
||||
}
|
||||
if (!dir_is_empty(instance_config.dss.vglog, FIO_DSS_HOST))
|
||||
{
|
||||
if (params->incremental_mode != INCR_NONE)
|
||||
{
|
||||
elog(INFO, "Running incremental restore into nonempty directory: \"%s\"",
|
||||
instance_config.dss.vglog);
|
||||
}
|
||||
else
|
||||
{
|
||||
elog(ERROR, "Restore destination is not empty: \"%s\"",
|
||||
instance_config.dss.vglog);
|
||||
}
|
||||
dssdata_is_empty = false;
|
||||
elog(ERROR, "Restore destination is not empty: \"%s\"",
|
||||
instance_config.dss.vglog);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if restore destination empty */
|
||||
/* Check if restore destination empty : PGDATA */
|
||||
if (!dir_is_empty(instance_config.pgdata, FIO_DB_HOST))
|
||||
{
|
||||
/* Check that remote system is NOT running and systemd id is the same as ours */
|
||||
@ -717,7 +732,7 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
{
|
||||
int i;
|
||||
char timestamp[100];
|
||||
parray *pgdata_files = NULL;
|
||||
parray *pgdata_and_dssdata_files = NULL;
|
||||
parray *dest_files = NULL;
|
||||
parray *external_dirs = NULL;
|
||||
/* arrays with meta info for multi threaded backup */
|
||||
@ -803,17 +818,18 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
/*
|
||||
* Restore dest_backup internal directories.
|
||||
*/
|
||||
|
||||
create_data_directories(dest_files, instance_config.pgdata,
|
||||
dest_backup->root_dir, true,
|
||||
params->incremental_mode != INCR_NONE,
|
||||
FIO_DB_HOST);
|
||||
FIO_DB_HOST, true);
|
||||
|
||||
/* some file is in dssserver */
|
||||
if (IsDssMode())
|
||||
create_data_directories(dest_files, instance_config.dss.vgdata,
|
||||
dest_backup->root_dir, true,
|
||||
params->incremental_mode != INCR_NONE,
|
||||
FIO_DSS_HOST);
|
||||
FIO_DSS_HOST, true);
|
||||
|
||||
/*
|
||||
* Restore dest_backup external directories.
|
||||
@ -836,9 +852,10 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
/* Get list of files in destination directory and remove redundant files */
|
||||
if (params->incremental_mode != INCR_NONE)
|
||||
{
|
||||
pgdata_files = parray_new();
|
||||
get_pgdata_files(pgdata_path, pgdata_files, external_dirs);
|
||||
remove_redundant_files(pgdata_path, pgdata_files, dest_backup, external_dirs);
|
||||
pgdata_and_dssdata_files = parray_new();
|
||||
get_pgdata_and_dssdata_files(pgdata_path, dssdata_path, pgdata_and_dssdata_files, external_dirs);
|
||||
remove_redundant_files(pgdata_path, dssdata_path, pgdata_and_dssdata_files,
|
||||
dest_backup, external_dirs);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -883,7 +900,7 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
num_threads);
|
||||
|
||||
threads_handle(threads, threads_args, dest_backup, dest_files,
|
||||
pgdata_files, external_dirs, parent_chain, params,
|
||||
pgdata_and_dssdata_files, external_dirs, parent_chain, params,
|
||||
pgdata_path, dssdata_path, use_bitmap, total_bytes);
|
||||
|
||||
/* Close page header maps */
|
||||
@ -907,10 +924,10 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
if (external_dirs != NULL)
|
||||
free_dir_list(external_dirs);
|
||||
|
||||
if (pgdata_files)
|
||||
if (pgdata_and_dssdata_files)
|
||||
{
|
||||
parray_walk(pgdata_files, pgFileFree);
|
||||
parray_free(pgdata_files);
|
||||
parray_walk(pgdata_and_dssdata_files, pgFileFree);
|
||||
parray_free(pgdata_and_dssdata_files);
|
||||
}
|
||||
|
||||
for (i = parray_num(parent_chain) - 1; i >= 0; i--)
|
||||
@ -922,8 +939,9 @@ restore_chain(pgBackup *dest_backup, parray *parent_chain,
|
||||
}
|
||||
}
|
||||
|
||||
static void get_pgdata_files(const char *pgdata_path,
|
||||
parray *pgdata_files,
|
||||
static void get_pgdata_and_dssdata_files(const char *pgdata_path,
|
||||
const char *dssdata_path,
|
||||
parray *pgdata_and_dssdata_files,
|
||||
parray *external_dirs)
|
||||
{
|
||||
char pretty_time[20];
|
||||
@ -933,11 +951,15 @@ static void get_pgdata_files(const char *pgdata_path,
|
||||
|
||||
time(&start_time);
|
||||
if (fio_is_remote(FIO_DB_HOST))
|
||||
fio_list_dir(pgdata_files, pgdata_path, false, true, false, false, true, 0);
|
||||
fio_list_dir(pgdata_and_dssdata_files, pgdata_path, false, true, false, false, true, 0);
|
||||
else
|
||||
dir_list_file(pgdata_files, pgdata_path,
|
||||
dir_list_file(pgdata_and_dssdata_files, pgdata_path,
|
||||
false, true, false, false, true, 0, FIO_LOCAL_HOST);
|
||||
|
||||
if (IsDssMode())
|
||||
dir_list_file(pgdata_and_dssdata_files, dssdata_path,
|
||||
false, true, false, false, true, 0, FIO_DSS_HOST);
|
||||
|
||||
/* get external dirs content */
|
||||
if (external_dirs)
|
||||
{
|
||||
@ -954,12 +976,12 @@ static void get_pgdata_files(const char *pgdata_path,
|
||||
false, true, false, false, true, i+1,
|
||||
FIO_LOCAL_HOST);
|
||||
|
||||
parray_concat(pgdata_files, external_files);
|
||||
parray_concat(pgdata_and_dssdata_files, external_files);
|
||||
parray_free(external_files);
|
||||
}
|
||||
}
|
||||
|
||||
parray_qsort(pgdata_files, pgFileCompareRelPathWithExternalDesc);
|
||||
parray_qsort(pgdata_and_dssdata_files, pgFileCompareRelPathWithExternalDesc);
|
||||
|
||||
time(&end_time);
|
||||
pretty_time_interval(difftime(end_time, start_time),
|
||||
@ -983,13 +1005,52 @@ static bool skip_some_tblspc_files(pgFile *file)
|
||||
prefix_equ_tbs_version_dir = (strncmp(tmp_rel_path, TABLESPACE_VERSION_DIRECTORY,
|
||||
strlen(TABLESPACE_VERSION_DIRECTORY)) == 0);
|
||||
|
||||
/* In DSS mode, we should skip PG_9.2_201611171 */
|
||||
if (sscanf_res == 2 && IsDssMode() && prefix_equ_tbs_version_dir)
|
||||
return true;
|
||||
/* If the dss is not enabled, we should skip PG_9.2_201611171_node1 */
|
||||
if (sscanf_res == 2 && !equ_tbs_version_dir && prefix_equ_tbs_version_dir)
|
||||
return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
#define CHECK_FALSE 0
|
||||
#define CHECK_TRUE 1
|
||||
#define CHECK_EXCLUDE_FALSE 2
|
||||
|
||||
static char check_in_dss_instance(pgFile *file, int include_id)
|
||||
{
|
||||
if (!is_dss_type(file->type)) {
|
||||
return CHECK_TRUE;
|
||||
}
|
||||
|
||||
char instance_id[MAX_INSTANCEID_LEN];
|
||||
char top_path[MAXPGPATH];
|
||||
errno_t rc = EOK;
|
||||
int move = 0;
|
||||
|
||||
/* step1 : skip other instance owner file or dir */
|
||||
strlcpy(top_path, file->rel_path, sizeof(top_path));
|
||||
get_top_path(top_path);
|
||||
|
||||
rc = snprintf_s(instance_id, sizeof(instance_id), sizeof(instance_id) - 1, "%d", include_id);
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
|
||||
move = (int)strlen(top_path) - (int)strlen(instance_id);
|
||||
if (move > 0 && move < MAXPGPATH && strcmp(top_path + move, instance_id) != 0) {
|
||||
char tail = top_path[strlen(top_path) - 1];
|
||||
/* Is this file or dir belongs to other instance? */
|
||||
if (tail >= '0' && tail <= '9') {
|
||||
return CHECK_FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
return CHECK_TRUE;
|
||||
}
|
||||
|
||||
static void remove_redundant_files(const char *pgdata_path,
|
||||
parray *pgdata_files,
|
||||
const char *dssdata_path,
|
||||
parray *pgdata_and_dssdata_files,
|
||||
pgBackup *dest_backup,
|
||||
parray *external_dirs)
|
||||
{
|
||||
@ -998,8 +1059,8 @@ static void remove_redundant_files(const char *pgdata_path,
|
||||
|
||||
elog(INFO, "Removing redundant files in destination directory");
|
||||
time(&start_time);
|
||||
for (int i = 0; (size_t)i < parray_num(pgdata_files); i++) {
|
||||
pgFile *file = (pgFile *)parray_get(pgdata_files, i);
|
||||
for (int i = 0; (size_t)i < parray_num(pgdata_and_dssdata_files); i++) {
|
||||
pgFile *file = (pgFile *)parray_get(pgdata_and_dssdata_files, i);
|
||||
bool in_tablespace = false;
|
||||
|
||||
/* For incremental backups, we need to skip some files */
|
||||
@ -1011,20 +1072,30 @@ static void remove_redundant_files(const char *pgdata_path,
|
||||
if (parray_bsearch(dest_backup->files, file,
|
||||
pgFileCompareRelPathWithExternal) == NULL) {
|
||||
char fullpath[MAXPGPATH];
|
||||
fio_location path_location;
|
||||
|
||||
if (file->external_dir_num) {
|
||||
char *external_path = (char *)parray_get(external_dirs,
|
||||
file->external_dir_num - 1);
|
||||
join_path_components(fullpath, external_path, file->rel_path);
|
||||
} else if (is_dss_type(file->type)) {
|
||||
/* skip other instance files in dss mode */
|
||||
char check_res = check_in_dss_instance(file, instance_config.dss.instance_id);
|
||||
if (check_res != CHECK_TRUE) {
|
||||
continue;
|
||||
} else {
|
||||
join_path_components(fullpath, dssdata_path, file->rel_path);
|
||||
}
|
||||
} else {
|
||||
join_path_components(fullpath, pgdata_path, file->rel_path);
|
||||
}
|
||||
|
||||
fio_delete(file->mode, fullpath, FIO_DB_HOST);
|
||||
path_location = is_dss_type(file->type) ? FIO_DSS_HOST : FIO_DB_HOST;
|
||||
fio_delete(file->mode, fullpath, path_location);
|
||||
elog(VERBOSE, "Deleted file \"%s\"", fullpath);
|
||||
|
||||
/* shrink pgdata list */
|
||||
parray_remove(pgdata_files, i);
|
||||
parray_remove(pgdata_and_dssdata_files, i);
|
||||
i--;
|
||||
}
|
||||
}
|
||||
@ -1033,7 +1104,7 @@ static void remove_redundant_files(const char *pgdata_path,
|
||||
pretty_time_interval(difftime(end_time, start_time),
|
||||
pretty_time, lengthof(pretty_time));
|
||||
|
||||
/* At this point PDATA do not contain files, that do not exists in dest backup file list */
|
||||
/* At this point PDATA and DSSDATA do not contain files, that do not exists in dest backup file list */
|
||||
elog(INFO, "Redundant files are removed, time elapsed: %s", pretty_time);
|
||||
}
|
||||
|
||||
@ -1041,7 +1112,7 @@ static void threads_handle(pthread_t *threads,
|
||||
restore_files_arg *threads_args,
|
||||
pgBackup *dest_backup,
|
||||
parray *dest_files,
|
||||
parray *pgdata_files,
|
||||
parray *pgdata_and_dssdata_files,
|
||||
parray *external_dirs,
|
||||
parray *parent_chain,
|
||||
pgRestoreParams *params,
|
||||
@ -1059,12 +1130,12 @@ static void threads_handle(pthread_t *threads,
|
||||
bool restore_isok = true;
|
||||
|
||||
if (dest_backup->stream)
|
||||
dest_bytes = dest_backup->pgdata_bytes + dest_backup->wal_bytes;
|
||||
dest_bytes = dest_backup->pgdata_bytes + dest_backup->dssdata_bytes + dest_backup->wal_bytes;
|
||||
else
|
||||
dest_bytes = dest_backup->pgdata_bytes;
|
||||
dest_bytes = dest_backup->pgdata_bytes + dest_backup->dssdata_bytes;
|
||||
|
||||
pretty_size(dest_bytes, pretty_dest_bytes, lengthof(pretty_dest_bytes));
|
||||
elog(INFO, "Start restoring backup files. PGDATA size: %s", pretty_dest_bytes);
|
||||
elog(INFO, "Start restoring backup files. DATA size: %s", pretty_dest_bytes);
|
||||
time(&start_time);
|
||||
thread_interrupted = false;
|
||||
|
||||
@ -1074,7 +1145,7 @@ static void threads_handle(pthread_t *threads,
|
||||
restore_files_arg *arg = &(threads_args[i]);
|
||||
|
||||
arg->dest_files = dest_files;
|
||||
arg->pgdata_files = pgdata_files;
|
||||
arg->pgdata_and_dssdata_files = pgdata_and_dssdata_files;
|
||||
arg->dest_backup = dest_backup;
|
||||
arg->dest_external_dirs = external_dirs;
|
||||
arg->parent_chain = parent_chain;
|
||||
@ -1199,7 +1270,7 @@ inline void RestoreCompressFile(FILE *out, char *to_fullpath, pgFile *dest_file)
|
||||
}
|
||||
|
||||
/*
|
||||
* Restore files into $PGDATA.
|
||||
* Restore files into $PGDATA and $VGNAME.
|
||||
*/
|
||||
static void *
|
||||
restore_files(void *arg)
|
||||
@ -1272,7 +1343,7 @@ restore_files(void *arg)
|
||||
join_path_components(to_fullpath, arguments->to_root, dest_file->rel_path);
|
||||
|
||||
if (arguments->incremental_mode != INCR_NONE &&
|
||||
parray_bsearch(arguments->pgdata_files, dest_file, pgFileCompareRelPathWithExternalDesc))
|
||||
parray_bsearch(arguments->pgdata_and_dssdata_files, dest_file, pgFileCompareRelPathWithExternalDesc))
|
||||
{
|
||||
already_exists = true;
|
||||
}
|
||||
|
||||
@ -471,6 +471,12 @@ print_backup_json_object(PQExpBuffer buf, pgBackup *backup)
|
||||
appendPQExpBuffer(buf, INT64_FORMAT, backup->pgdata_bytes);
|
||||
}
|
||||
|
||||
if (backup->uncompressed_bytes >= 0)
|
||||
{
|
||||
json_add_key(buf, "dssdata-bytes", json_level);
|
||||
appendPQExpBuffer(buf, INT64_FORMAT, backup->dssdata_bytes);
|
||||
}
|
||||
|
||||
if (backup->external_dir_str)
|
||||
json_add_value(buf, "external-dirs", backup->external_dir_str,
|
||||
json_level, true);
|
||||
|
||||
@ -551,7 +551,6 @@ bool
|
||||
is_ss_xlog(const char *ss_dir)
|
||||
{
|
||||
char ss_xlog[MAXPGPATH] = {0};
|
||||
char ss_doublewrite[MAXPGPATH] = {0};
|
||||
char ss_notify[MAXPGPATH] = {0};
|
||||
char ss_snapshots[MAXPGPATH] = {0};
|
||||
int rc = EOK;
|
||||
@ -588,6 +587,12 @@ ss_createdir(const char *ss_dir, const char *vgdata, const char *vglog)
|
||||
securec_check_ss_c(rc, "\0", "\0");
|
||||
|
||||
dir_create_dir(path, DIR_PERMISSION);
|
||||
|
||||
/* if xlog link is already exist, destroy it and recreate */
|
||||
if (unlink(link_path) != 0) {
|
||||
elog(ERROR, "can not remove xlog dir \"%s\" : %s", link_path, strerror(errno));
|
||||
}
|
||||
|
||||
if (symlink(path, link_path) < 0) {
|
||||
elog(ERROR, "can not link dss xlog dir \"%s\" to dss xlog dir \"%s\": %s", link_path, path,
|
||||
strerror(errno));
|
||||
|
||||
@ -50,6 +50,7 @@
|
||||
#include "storage/proc.h"
|
||||
#include "utils/memutils.h"
|
||||
#include "utils/relmapper.h"
|
||||
#include "storage/file/fio_device.h"
|
||||
|
||||
/* we can put the following globals into XlogCbmSys */
|
||||
static XLogRecPtr tmpTargetLSN = InvalidXLogRecPtr;
|
||||
@ -929,9 +930,13 @@ static int CBMXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr
|
||||
XLogPageReadPrivateCBM *readprivate = (XLogPageReadPrivateCBM *)xlogreader->private_data;
|
||||
uint32 targetPageOff;
|
||||
int rc = 0;
|
||||
char *dssdir = NULL;
|
||||
|
||||
targetPageOff = targetPagePtr % XLogSegSize;
|
||||
|
||||
if (ENABLE_DSS)
|
||||
dssdir = g_instance.attr.attr_storage.dss_attr.ss_dss_vg_name;
|
||||
|
||||
/*
|
||||
* See if we need to switch to a new segment because the requested record
|
||||
* is not in the currently open one.
|
||||
@ -955,8 +960,17 @@ static int CBMXLogPageRead(XLogReaderState *xlogreader, XLogRecPtr targetPagePtr
|
||||
(uint32)((t_thrd.cbm_cxt.XlogCbmSys->xlogRead.logSegNo) % XLogSegmentsPerXLogId));
|
||||
securec_check_ss(rc, "", "");
|
||||
|
||||
rc = snprintf_s(t_thrd.cbm_cxt.XlogCbmSys->xlogRead.filePath, MAXPGPATH, MAXPGPATH - 1, "%s/" XLOGDIR "/%s",
|
||||
readprivate->datadir, xlogfname);
|
||||
if (ENABLE_DSS) {
|
||||
char dss_xlog[MAXPGPATH];
|
||||
rc = snprintf_s(dss_xlog, MAXPGPATH, MAXPGPATH - 1, XLOGDIR "%d",
|
||||
g_instance.attr.attr_storage.dms_attr.instance_id);
|
||||
securec_check_ss(rc, "\0", "\0");
|
||||
rc = snprintf_s(t_thrd.cbm_cxt.XlogCbmSys->xlogRead.filePath, MAXPGPATH, MAXPGPATH - 1,
|
||||
"%s/%s/%s", dssdir, dss_xlog, xlogfname);
|
||||
} else {
|
||||
rc = snprintf_s(t_thrd.cbm_cxt.XlogCbmSys->xlogRead.filePath, MAXPGPATH, MAXPGPATH - 1,
|
||||
"%s/" XLOGDIR "/%s", readprivate->datadir, xlogfname);
|
||||
}
|
||||
securec_check_ss(rc, "\0", "\0");
|
||||
|
||||
t_thrd.cbm_cxt.XlogCbmSys->xlogRead.fd = BasicOpenFile(t_thrd.cbm_cxt.XlogCbmSys->xlogRead.filePath,
|
||||
|
||||
@ -89,6 +89,8 @@ extern void pgfnames_cleanup(char** filenames);
|
||||
(isalpha((unsigned char)((filename)[0])) && (filename)[1] == ':' && IS_DIR_SEP((filename)[2])))
|
||||
#endif
|
||||
|
||||
#define ss_is_absolute_path(filename) (((filename)[0] == '+') ? true : false)
|
||||
|
||||
/* Portable locale initialization (in exec.c) */
|
||||
extern void set_pglocale_pgservice(const char* argv0, const char* app);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user