Skip to content

Commit 0fdcc73

Browse files
committed
Merge branch 'master' into release_2_5
2 parents 6e20f55 + 4e44502 commit 0fdcc73

17 files changed

+1174
-196
lines changed

doc/pgprobackup.xml

+4
Original file line numberDiff line numberDiff line change
@@ -3978,6 +3978,10 @@ pg_probackup restore -B <replaceable>backup_dir</replaceable> --instance <replac
39783978
this flag if you need to restore the
39793979
<productname>PostgreSQL</productname> cluster from a corrupt or an invalid backup.
39803980
Use with caution.
3981+
When used with <link linkend="pbk-incremental-restore">incremental restore</link> this flag
3982+
allows to replace already existing PGDATA with different system ID. In case of tablespaces,
3983+
remapped via <literal>--tablespace-mapping</literal> option into not empty directories,
3984+
the old content of such directories will be deleted.
39813985
</para>
39823986
</listitem>
39833987
</varlistentry>

src/backup.c

+39-41
Original file line numberDiff line numberDiff line change
@@ -95,7 +95,6 @@ static void
9595
do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool backup_logs)
9696
{
9797
int i;
98-
char database_path[MAXPGPATH];
9998
char external_prefix[MAXPGPATH]; /* Temp value. Used as template */
10099
char dst_backup_path[MAXPGPATH];
101100
char label[1024];
@@ -147,15 +146,6 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
147146
current.tli = get_current_timeline_from_control(false);
148147
#endif
149148

150-
/* In PAGE mode or in ARCHIVE wal-mode wait for current segment */
151-
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE ||!stream_wal)
152-
/*
153-
* Do not wait start_lsn for stream backup.
154-
* Because WAL streaming will start after pg_start_backup() in stream
155-
* mode.
156-
*/
157-
wait_wal_lsn(current.start_lsn, true, current.tli, false, true, ERROR, false);
158-
159149
/*
160150
* In incremental backup mode ensure that already-validated
161151
* backup on current timeline exists and get its filelist.
@@ -265,31 +255,39 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
265255
/* Update running backup meta with START LSN */
266256
write_backup(&current, true);
267257

268-
pgBackupGetPath(&current, database_path, lengthof(database_path),
269-
DATABASE_DIR);
270-
pgBackupGetPath(&current, external_prefix, lengthof(external_prefix),
271-
EXTERNAL_DIR);
258+
/* In PAGE mode or in ARCHIVE wal-mode wait for current segment */
259+
if (current.backup_mode == BACKUP_MODE_DIFF_PAGE || !stream_wal)
260+
{
261+
/* Check that archive_dir can be reached */
262+
if (fio_access(arclog_path, F_OK, FIO_BACKUP_HOST) != 0)
263+
elog(ERROR, "WAL archive directory is not accessible \"%s\": %s",
264+
arclog_path, strerror(errno));
272265

273-
/* initialize backup's file list */
274-
backup_files_list = parray_new();
266+
/*
267+
* Do not wait start_lsn for stream backup.
268+
* Because WAL streaming will start after pg_start_backup() in stream
269+
* mode.
270+
*/
271+
wait_wal_lsn(current.start_lsn, true, current.tli, false, true, ERROR, false);
272+
}
275273

276274
/* start stream replication */
277275
if (stream_wal)
278276
{
279-
join_path_components(dst_backup_path, database_path, PG_XLOG_DIR);
277+
join_path_components(dst_backup_path, current.database_dir, PG_XLOG_DIR);
280278
fio_mkdir(dst_backup_path, DIR_PERMISSION, FIO_BACKUP_HOST);
281279

282280
start_WAL_streaming(backup_conn, dst_backup_path, &instance_config.conn_opt,
283281
current.start_lsn, current.tli);
284282
}
285283

284+
/* initialize backup's file list */
285+
backup_files_list = parray_new();
286+
join_path_components(external_prefix, current.root_dir, EXTERNAL_DIR);
287+
286288
/* list files with the logical path. omit $PGDATA */
287-
if (fio_is_remote(FIO_DB_HOST))
288-
fio_list_dir(backup_files_list, instance_config.pgdata,
289-
true, true, false, backup_logs, true, 0);
290-
else
291-
dir_list_file(backup_files_list, instance_config.pgdata,
292-
true, true, false, backup_logs, true, 0, FIO_LOCAL_HOST);
289+
fio_list_dir(backup_files_list, instance_config.pgdata,
290+
true, true, false, backup_logs, true, 0);
293291

294292
/*
295293
* Get database_map (name to oid) for use in partial restore feature.
@@ -441,7 +439,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
441439
join_path_components(dirpath, temp, file->rel_path);
442440
}
443441
else
444-
join_path_components(dirpath, database_path, file->rel_path);
442+
join_path_components(dirpath, current.database_dir, file->rel_path);
445443

446444
elog(VERBOSE, "Create directory '%s'", dirpath);
447445
fio_mkdir(dirpath, DIR_PERMISSION, FIO_BACKUP_HOST);
@@ -475,7 +473,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
475473

476474
arg->nodeInfo = nodeInfo;
477475
arg->from_root = instance_config.pgdata;
478-
arg->to_root = database_path;
476+
arg->to_root = current.database_dir;
479477
arg->external_prefix = external_prefix;
480478
arg->external_dirs = external_dirs;
481479
arg->files_list = backup_files_list;
@@ -552,7 +550,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
552550
elog(ERROR, "Failed to find file \"%s\" in backup filelist.",
553551
XLOG_CONTROL_FILE);
554552

555-
set_min_recovery_point(pg_control, database_path, current.stop_lsn);
553+
set_min_recovery_point(pg_control, current.database_dir, current.stop_lsn);
556554
}
557555

558556
/* close and sync page header map */
@@ -609,7 +607,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
609607

610608
/* construct fullpath */
611609
if (file->external_dir_num == 0)
612-
join_path_components(to_fullpath, database_path, file->rel_path);
610+
join_path_components(to_fullpath, current.database_dir, file->rel_path);
613611
else
614612
{
615613
char external_dst[MAXPGPATH];
@@ -726,8 +724,8 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
726724
* Entry point of pg_probackup BACKUP subcommand.
727725
*/
728726
int
729-
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
730-
bool no_validate, bool no_sync, bool backup_logs)
727+
do_backup(pgSetBackupParams *set_backup_params,
728+
bool no_validate, bool no_sync, bool backup_logs)
731729
{
732730
PGconn *backup_conn = NULL;
733731
PGNodeInfo nodeInfo;
@@ -736,37 +734,37 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
736734
/* Initialize PGInfonode */
737735
pgNodeInit(&nodeInfo);
738736

737+
/* Save list of external directories */
738+
if (instance_config.external_dir_str &&
739+
(pg_strcasecmp(instance_config.external_dir_str, "none") != 0))
740+
current.external_dir_str = instance_config.external_dir_str;
741+
742+
/* Create backup directory and BACKUP_CONTROL_FILE */
743+
pgBackupCreateDir(&current, backup_instance_path);
744+
739745
if (!instance_config.pgdata)
740746
elog(ERROR, "required parameter not specified: PGDATA "
741747
"(-D, --pgdata)");
742748

743749
/* Update backup status and other metainfo. */
744750
current.status = BACKUP_STATUS_RUNNING;
745-
current.start_time = start_time;
751+
current.start_time = current.backup_id;
746752

747753
StrNCpy(current.program_version, PROGRAM_VERSION,
748754
sizeof(current.program_version));
749755

750756
current.compress_alg = instance_config.compress_alg;
751757
current.compress_level = instance_config.compress_level;
752758

753-
/* Save list of external directories */
754-
if (instance_config.external_dir_str &&
755-
(pg_strcasecmp(instance_config.external_dir_str, "none") != 0))
756-
current.external_dir_str = instance_config.external_dir_str;
757-
758759
elog(INFO, "Backup start, pg_probackup version: %s, instance: %s, backup ID: %s, backup mode: %s, "
759760
"wal mode: %s, remote: %s, compress-algorithm: %s, compress-level: %i",
760-
PROGRAM_VERSION, instance_name, base36enc(start_time), pgBackupGetBackupMode(&current, false),
761+
PROGRAM_VERSION, instance_name, base36enc(current.backup_id), pgBackupGetBackupMode(&current, false),
761762
current.stream ? "STREAM" : "ARCHIVE", IsSshProtocol() ? "true" : "false",
762763
deparse_compress_alg(current.compress_alg), current.compress_level);
763764

764-
/* Create backup directory and BACKUP_CONTROL_FILE */
765-
if (pgBackupCreateDir(&current))
766-
elog(ERROR, "Cannot create backup directory");
767765
if (!lock_backup(&current, true, true))
768766
elog(ERROR, "Cannot lock backup %s directory",
769-
base36enc(current.start_time));
767+
base36enc(current.backup_id));
770768
write_backup(&current, true);
771769

772770
/* set the error processing function for the backup process */
@@ -781,7 +779,7 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
781779
backup_conn = pgdata_basic_setup(instance_config.conn_opt, &nodeInfo);
782780

783781
if (current.from_replica)
784-
elog(INFO, "Backup %s is going to be taken from standby", base36enc(start_time));
782+
elog(INFO, "Backup %s is going to be taken from standby", base36enc(current.backup_id));
785783

786784
/* TODO, print PostgreSQL full version */
787785
//elog(INFO, "PostgreSQL version: %s", nodeInfo.server_version_str);

src/catalog.c

+50-10
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ static pgBackup* get_closest_backup(timelineInfo *tlinfo);
2323
static pgBackup* get_oldest_backup(timelineInfo *tlinfo);
2424
static const char *backupModes[] = {"", "PAGE", "PTRACK", "DELTA", "FULL"};
2525
static pgBackup *readBackupControlFile(const char *path);
26+
static time_t create_backup_dir(pgBackup *backup, const char *backup_instance_path);
2627

2728
static bool backup_lock_exit_hook_registered = false;
2829
static parray *lock_files = NULL;
@@ -1149,12 +1150,18 @@ get_multi_timeline_parent(parray *backup_list, parray *tli_list,
11491150
return NULL;
11501151
}
11511152

1152-
/* create backup directory in $BACKUP_PATH */
1153-
int
1154-
pgBackupCreateDir(pgBackup *backup)
1153+
/* Create backup directory in $BACKUP_PATH
1154+
* Note, that backup_id attribute is updated,
1155+
* so it is possible to get diffrent values in
1156+
* pgBackup.start_time and pgBackup.backup_id.
1157+
* It may be ok or maybe not, so it's up to the caller
1158+
* to fix it or let it be.
1159+
*/
1160+
1161+
void
1162+
pgBackupCreateDir(pgBackup *backup, const char *backup_instance_path)
11551163
{
11561164
int i;
1157-
char path[MAXPGPATH];
11581165
parray *subdirs = parray_new();
11591166

11601167
parray_append(subdirs, pg_strdup(DATABASE_DIR));
@@ -1176,13 +1183,10 @@ pgBackupCreateDir(pgBackup *backup)
11761183
free_dir_list(external_list);
11771184
}
11781185

1179-
pgBackupGetPath(backup, path, lengthof(path), NULL);
1180-
1181-
if (!dir_is_empty(path, FIO_BACKUP_HOST))
1182-
elog(ERROR, "backup destination is not empty \"%s\"", path);
1186+
backup->backup_id = create_backup_dir(backup, backup_instance_path);
11831187

1184-
fio_mkdir(path, DIR_PERMISSION, FIO_BACKUP_HOST);
1185-
backup->root_dir = pgut_strdup(path);
1188+
if (backup->backup_id == 0)
1189+
elog(ERROR, "Cannot create backup directory: %s", strerror(errno));
11861190

11871191
backup->database_dir = pgut_malloc(MAXPGPATH);
11881192
join_path_components(backup->database_dir, backup->root_dir, DATABASE_DIR);
@@ -1193,11 +1197,47 @@ pgBackupCreateDir(pgBackup *backup)
11931197
/* create directories for actual backup files */
11941198
for (i = 0; i < parray_num(subdirs); i++)
11951199
{
1200+
char path[MAXPGPATH];
1201+
11961202
join_path_components(path, backup->root_dir, parray_get(subdirs, i));
11971203
fio_mkdir(path, DIR_PERMISSION, FIO_BACKUP_HOST);
11981204
}
11991205

12001206
free_dir_list(subdirs);
1207+
}
1208+
1209+
/*
1210+
* Create root directory for backup,
1211+
* update pgBackup.root_dir if directory creation was a success
1212+
*/
1213+
time_t
1214+
create_backup_dir(pgBackup *backup, const char *backup_instance_path)
1215+
{
1216+
int attempts = 10;
1217+
1218+
while (attempts--)
1219+
{
1220+
int rc;
1221+
char path[MAXPGPATH];
1222+
time_t backup_id = time(NULL);
1223+
1224+
join_path_components(path, backup_instance_path, base36enc(backup_id));
1225+
1226+
/* TODO: add wrapper for remote mode */
1227+
rc = dir_create_dir(path, DIR_PERMISSION, true);
1228+
1229+
if (rc == 0)
1230+
{
1231+
backup->root_dir = pgut_strdup(path);
1232+
return backup_id;
1233+
}
1234+
else
1235+
{
1236+
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1237+
sleep(1);
1238+
}
1239+
}
1240+
12011241
return 0;
12021242
}
12031243

src/delete.c

+1
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,7 @@ do_retention_wal(bool dry_run)
720720
/*
721721
* Delete backup files of the backup and update the status of the backup to
722722
* BACKUP_STATUS_DELETED.
723+
* TODO: delete files on multiple threads
723724
*/
724725
void
725726
delete_backup_files(pgBackup *backup)

0 commit comments

Comments
 (0)