Skip to content

Commit 286d30d

Browse files
committed
[Issue #231] make several attempts when creating backup directory, so two consecutive backups didn`t get the same backup ID
1 parent 8993131 commit 286d30d

File tree

9 files changed

+90
-50
lines changed

9 files changed

+90
-50
lines changed

src/backup.c

Lines changed: 15 additions & 19 deletions
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];
@@ -265,18 +264,15 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
265264
/* Update running backup meta with START LSN */
266265
write_backup(&current, true);
267266

268-
pgBackupGetPath(&current, database_path, lengthof(database_path),
269-
DATABASE_DIR);
270-
pgBackupGetPath(&current, external_prefix, lengthof(external_prefix),
271-
EXTERNAL_DIR);
267+
join_path_components(external_prefix, current.database_dir, EXTERNAL_DIR);
272268

273269
/* initialize backup's file list */
274270
backup_files_list = parray_new();
275271

276272
/* start stream replication */
277273
if (stream_wal)
278274
{
279-
join_path_components(dst_backup_path, database_path, PG_XLOG_DIR);
275+
join_path_components(dst_backup_path, current.database_dir, PG_XLOG_DIR);
280276
fio_mkdir(dst_backup_path, DIR_PERMISSION, FIO_BACKUP_HOST);
281277

282278
start_WAL_streaming(backup_conn, dst_backup_path, &instance_config.conn_opt,
@@ -441,7 +437,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
441437
join_path_components(dirpath, temp, file->rel_path);
442438
}
443439
else
444-
join_path_components(dirpath, database_path, file->rel_path);
440+
join_path_components(dirpath, current.database_dir, file->rel_path);
445441

446442
elog(VERBOSE, "Create directory '%s'", dirpath);
447443
fio_mkdir(dirpath, DIR_PERMISSION, FIO_BACKUP_HOST);
@@ -475,7 +471,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
475471

476472
arg->nodeInfo = nodeInfo;
477473
arg->from_root = instance_config.pgdata;
478-
arg->to_root = database_path;
474+
arg->to_root = current.database_dir;
479475
arg->external_prefix = external_prefix;
480476
arg->external_dirs = external_dirs;
481477
arg->files_list = backup_files_list;
@@ -552,7 +548,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
552548
elog(ERROR, "Failed to find file \"%s\" in backup filelist.",
553549
XLOG_CONTROL_FILE);
554550

555-
set_min_recovery_point(pg_control, database_path, current.stop_lsn);
551+
set_min_recovery_point(pg_control, current.database_dir, current.stop_lsn);
556552
}
557553

558554
/* close and sync page header map */
@@ -609,7 +605,7 @@ do_backup_instance(PGconn *backup_conn, PGNodeInfo *nodeInfo, bool no_sync, bool
609605

610606
/* construct fullpath */
611607
if (file->external_dir_num == 0)
612-
join_path_components(to_fullpath, database_path, file->rel_path);
608+
join_path_components(to_fullpath, current.database_dir, file->rel_path);
613609
else
614610
{
615611
char external_dst[MAXPGPATH];
@@ -726,8 +722,8 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
726722
* Entry point of pg_probackup BACKUP subcommand.
727723
*/
728724
int
729-
do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
730-
bool no_validate, bool no_sync, bool backup_logs)
725+
do_backup(pgSetBackupParams *set_backup_params,
726+
bool no_validate, bool no_sync, bool backup_logs)
731727
{
732728
PGconn *backup_conn = NULL;
733729
PGNodeInfo nodeInfo;
@@ -736,13 +732,16 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
736732
/* Initialize PGInfonode */
737733
pgNodeInit(&nodeInfo);
738734

735+
/* Create backup directory and BACKUP_CONTROL_FILE */
736+
pgBackupCreateDir(&current, backup_instance_path);
737+
739738
if (!instance_config.pgdata)
740739
elog(ERROR, "required parameter not specified: PGDATA "
741740
"(-D, --pgdata)");
742741

743742
/* Update backup status and other metainfo. */
744743
current.status = BACKUP_STATUS_RUNNING;
745-
current.start_time = start_time;
744+
current.start_time = current.backup_id;
746745

747746
StrNCpy(current.program_version, PROGRAM_VERSION,
748747
sizeof(current.program_version));
@@ -757,16 +756,13 @@ do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
757756

758757
elog(INFO, "Backup start, pg_probackup version: %s, instance: %s, backup ID: %s, backup mode: %s, "
759758
"wal mode: %s, remote: %s, compress-algorithm: %s, compress-level: %i",
760-
PROGRAM_VERSION, instance_name, base36enc(start_time), pgBackupGetBackupMode(&current),
759+
PROGRAM_VERSION, instance_name, base36enc(current.backup_id), pgBackupGetBackupMode(&current),
761760
current.stream ? "STREAM" : "ARCHIVE", IsSshProtocol() ? "true" : "false",
762761
deparse_compress_alg(current.compress_alg), current.compress_level);
763762

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

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

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

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

src/catalog.c

Lines changed: 50 additions & 10 deletions
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;
@@ -1136,12 +1137,18 @@ get_multi_timeline_parent(parray *backup_list, parray *tli_list,
11361137
return NULL;
11371138
}
11381139

1139-
/* create backup directory in $BACKUP_PATH */
1140-
int
1141-
pgBackupCreateDir(pgBackup *backup)
1140+
/* Create backup directory in $BACKUP_PATH
1141+
* Note, that backup_id attribute is updated,
1142+
* so it is possible to get diffrent values in
1143+
* pgBackup.start_time and pgBackup.backup_id.
1144+
* It may be ok or maybe not, so it's up to the caller
1145+
* to fix it or let it be.
1146+
*/
1147+
1148+
void
1149+
pgBackupCreateDir(pgBackup *backup, const char *backup_instance_path)
11421150
{
11431151
int i;
1144-
char path[MAXPGPATH];
11451152
parray *subdirs = parray_new();
11461153

11471154
parray_append(subdirs, pg_strdup(DATABASE_DIR));
@@ -1163,13 +1170,10 @@ pgBackupCreateDir(pgBackup *backup)
11631170
free_dir_list(external_list);
11641171
}
11651172

1166-
pgBackupGetPath(backup, path, lengthof(path), NULL);
1167-
1168-
if (!dir_is_empty(path, FIO_BACKUP_HOST))
1169-
elog(ERROR, "backup destination is not empty \"%s\"", path);
1173+
backup->backup_id = create_backup_dir(backup, backup_instance_path);
11701174

1171-
fio_mkdir(path, DIR_PERMISSION, FIO_BACKUP_HOST);
1172-
backup->root_dir = pgut_strdup(path);
1175+
if (backup->backup_id == 0)
1176+
elog(ERROR, "Cannot create backup directory: %s", strerror(errno));
11731177

11741178
backup->database_dir = pgut_malloc(MAXPGPATH);
11751179
join_path_components(backup->database_dir, backup->root_dir, DATABASE_DIR);
@@ -1180,11 +1184,47 @@ pgBackupCreateDir(pgBackup *backup)
11801184
/* create directories for actual backup files */
11811185
for (i = 0; i < parray_num(subdirs); i++)
11821186
{
1187+
char path[MAXPGPATH];
1188+
11831189
join_path_components(path, backup->root_dir, parray_get(subdirs, i));
11841190
fio_mkdir(path, DIR_PERMISSION, FIO_BACKUP_HOST);
11851191
}
11861192

11871193
free_dir_list(subdirs);
1194+
}
1195+
1196+
/*
1197+
* Create root directory for backup,
1198+
* update pgBackup.root_dir if directory creation was a success
1199+
*/
1200+
time_t
1201+
create_backup_dir(pgBackup *backup, const char *backup_instance_path)
1202+
{
1203+
int attempts = 10;
1204+
1205+
while (attempts--)
1206+
{
1207+
int rc;
1208+
char path[MAXPGPATH];
1209+
time_t backup_id = time(NULL);
1210+
1211+
join_path_components(path, backup_instance_path, base36enc(backup_id));
1212+
1213+
/* TODO: add wrapper for remote mode */
1214+
rc = dir_create_dir(path, DIR_PERMISSION, true);
1215+
1216+
if (rc == 0)
1217+
{
1218+
backup->root_dir = pgut_strdup(path);
1219+
return backup_id;
1220+
}
1221+
else
1222+
{
1223+
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1224+
sleep(1);
1225+
}
1226+
}
1227+
11881228
return 0;
11891229
}
11901230

src/dir.c

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -138,9 +138,13 @@ static TablespaceList external_remap_list = {NULL, NULL};
138138

139139
/*
140140
* Create directory, also create parent directories if necessary.
141+
* In strict mode treat already existing directory as error.
142+
* Return values:
143+
* 0 - ok
144+
* -1 - error (check errno)
141145
*/
142146
int
143-
dir_create_dir(const char *dir, mode_t mode)
147+
dir_create_dir(const char *dir, mode_t mode, bool strict)
144148
{
145149
char parent[MAXPGPATH];
146150

@@ -149,14 +153,14 @@ dir_create_dir(const char *dir, mode_t mode)
149153

150154
/* Create parent first */
151155
if (access(parent, F_OK) == -1)
152-
dir_create_dir(parent, mode);
156+
dir_create_dir(parent, mode, false);
153157

154158
/* Create directory */
155159
if (mkdir(dir, mode) == -1)
156160
{
157-
if (errno == EEXIST) /* already exist */
161+
if (errno == EEXIST && !strict) /* already exist */
158162
return 0;
159-
elog(ERROR, "cannot create directory \"%s\": %s", dir, strerror(errno));
163+
return -1;
160164
}
161165

162166
return 0;

src/init.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,15 @@ do_init(void)
3434
}
3535

3636
/* create backup catalog root directory */
37-
dir_create_dir(backup_path, DIR_PERMISSION);
37+
dir_create_dir(backup_path, DIR_PERMISSION, false);
3838

3939
/* create backup catalog data directory */
4040
join_path_components(path, backup_path, BACKUPS_DIR);
41-
dir_create_dir(path, DIR_PERMISSION);
41+
dir_create_dir(path, DIR_PERMISSION, false);
4242

4343
/* create backup catalog wal directory */
4444
join_path_components(arclog_path_dir, backup_path, "wal");
45-
dir_create_dir(arclog_path_dir, DIR_PERMISSION);
45+
dir_create_dir(arclog_path_dir, DIR_PERMISSION, false);
4646

4747
elog(INFO, "Backup catalog '%s' successfully inited", backup_path);
4848
return 0;
@@ -91,8 +91,8 @@ do_add_instance(InstanceConfig *instance)
9191
instance->name, instance->arclog_path);
9292

9393
/* Create directory for data files of this specific instance */
94-
dir_create_dir(instance->backup_instance_path, DIR_PERMISSION);
95-
dir_create_dir(instance->arclog_path, DIR_PERMISSION);
94+
dir_create_dir(instance->backup_instance_path, DIR_PERMISSION, false);
95+
dir_create_dir(instance->arclog_path, DIR_PERMISSION, false);
9696

9797
/*
9898
* Write initial configuration file.

src/merge.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,7 @@ merge_chain(parray *parent_chain, pgBackup *full_backup, pgBackup *dest_backup)
639639
makeExternalDirPathByNum(new_container, full_external_prefix,
640640
file->external_dir_num);
641641
join_path_components(dirpath, new_container, file->rel_path);
642-
dir_create_dir(dirpath, DIR_PERMISSION);
642+
dir_create_dir(dirpath, DIR_PERMISSION, false);
643643
}
644644

645645
pg_atomic_init_flag(&file->lock);

src/pg_probackup.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -799,16 +799,14 @@ main(int argc, char *argv[])
799799
return do_init();
800800
case BACKUP_CMD:
801801
{
802-
time_t start_time = time(NULL);
803-
804802
current.stream = stream_wal;
805803

806804
/* sanity */
807805
if (current.backup_mode == BACKUP_MODE_INVALID)
808806
elog(ERROR, "required parameter not specified: BACKUP_MODE "
809807
"(-b, --backup-mode)");
810808

811-
return do_backup(start_time, set_backup_params, no_validate, no_sync, backup_logs);
809+
return do_backup(set_backup_params, no_validate, no_sync, backup_logs);
812810
}
813811
case RESTORE_CMD:
814812
return do_restore_or_validate(current.backup_id,

src/pg_probackup.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -781,7 +781,7 @@ extern char** commands_args;
781781
extern const char *pgdata_exclude_dir[];
782782

783783
/* in backup.c */
784-
extern int do_backup(time_t start_time, pgSetBackupParams *set_backup_params,
784+
extern int do_backup(pgSetBackupParams *set_backup_params,
785785
bool no_validate, bool no_sync, bool backup_logs);
786786
extern void do_checkdb(bool need_amcheck, ConnectionOptions conn_opt,
787787
char *pgdata);
@@ -916,7 +916,7 @@ extern void pgBackupGetPath2(const pgBackup *backup, char *path, size_t len,
916916
extern void pgBackupGetPathInInstance(const char *instance_name,
917917
const pgBackup *backup, char *path, size_t len,
918918
const char *subdir1, const char *subdir2);
919-
extern int pgBackupCreateDir(pgBackup *backup);
919+
extern void pgBackupCreateDir(pgBackup *backup, const char *backup_instance_path);
920920
extern void pgNodeInit(PGNodeInfo *node);
921921
extern void pgBackupInit(pgBackup *backup);
922922
extern void pgBackupFree(void *backup);
@@ -980,7 +980,7 @@ extern void makeExternalDirPathByNum(char *ret_path, const char *pattern_path,
980980
const int dir_num);
981981
extern bool backup_contains_external(const char *dir, parray *dirs_list);
982982

983-
extern int dir_create_dir(const char *path, mode_t mode);
983+
extern int dir_create_dir(const char *path, mode_t mode, bool strict);
984984
extern bool dir_is_empty(const char *path, fio_location location);
985985

986986
extern bool fileExists(const char *path, fio_location location);

src/utils/file.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1048,7 +1048,7 @@ int fio_mkdir(char const* path, int mode, fio_location location)
10481048
}
10491049
else
10501050
{
1051-
return dir_create_dir(path, mode);
1051+
return dir_create_dir(path, mode, false);
10521052
}
10531053
}
10541054

@@ -2648,7 +2648,7 @@ void fio_communicate(int in, int out)
26482648
break;
26492649
case FIO_MKDIR: /* Create directory */
26502650
hdr.size = 0;
2651-
hdr.arg = dir_create_dir(buf, hdr.arg);
2651+
hdr.arg = dir_create_dir(buf, hdr.arg, false);
26522652
IO_CHECK(fio_write_all(out, &hdr, sizeof(hdr)), sizeof(hdr));
26532653
break;
26542654
case FIO_CHMOD: /* Change file mode */

tests/backup.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2921,12 +2921,14 @@ def test_issue_231(self):
29212921

29222922
try:
29232923
self.backup_node(
2924-
backup_dir, 'node', node,
2925-
data_dir='{0}'.format(datadir), return_id=False)
2924+
backup_dir, 'node', node, data_dir='{0}'.format(datadir))
29262925
except:
29272926
pass
29282927

2929-
self.backup_node(backup_dir, 'node', node, options=['--stream'])
2928+
out = self.backup_node(backup_dir, 'node', node, options=['--stream'], return_id=False)
2929+
2930+
# it is a bit racy
2931+
self.assertIn("WARNING: Cannot create directory", out)
29302932

29312933
# Clean after yourself
29322934
self.del_test_dir(module_name, fname)

0 commit comments

Comments
 (0)