Skip to content

Commit d26a68f

Browse files
kulaginmdlepikhova
authored andcommitted
[PBCKP-259] fix for 'ERROR: Cannot create directory for older backup'… (#526)
* [PBCKP-259] fix for 'ERROR: Cannot create directory for older backup', rewrite --start_time implementation * rewritten 5f2283c * fixes for several tests * disabled tests.merge.MergeTest.test_merge_backup_from_future and tests.restore.RestoreTest.test_restore_backup_from_future as incorrect for now Co-authored-by: d.lepikhova <[email protected]>
1 parent d749372 commit d26a68f

File tree

8 files changed

+217
-356
lines changed

8 files changed

+217
-356
lines changed

src/backup.c

Lines changed: 55 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -685,15 +685,22 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
685685

686686
/*
687687
* Entry point of pg_probackup BACKUP subcommand.
688+
*
689+
* if start_time == INVALID_BACKUP_ID then we can generate backup_id
688690
*/
689691
int
690692
do_backup(InstanceState *instanceState, pgSetBackupParams *set_backup_params,
691693
bool no_validate, bool no_sync, bool backup_logs, time_t start_time)
692694
{
693695
PGconn *backup_conn = NULL;
694696
PGNodeInfo nodeInfo;
697+
time_t latest_backup_id = INVALID_BACKUP_ID;
695698
char pretty_bytes[20];
696699

700+
if (!instance_config.pgdata)
701+
elog(ERROR, "required parameter not specified: PGDATA "
702+
"(-D, --pgdata)");
703+
697704
/* Initialize PGInfonode */
698705
pgNodeInit(&nodeInfo);
699706

@@ -702,12 +709,55 @@ do_backup(InstanceState *instanceState, pgSetBackupParams *set_backup_params,
702709
(pg_strcasecmp(instance_config.external_dir_str, "none") != 0))
703710
current.external_dir_str = instance_config.external_dir_str;
704711

705-
/* Create backup directory and BACKUP_CONTROL_FILE */
706-
pgBackupCreateDir(&current, instanceState, start_time);
712+
/* Find latest backup_id */
713+
{
714+
parray *backup_list = catalog_get_backup_list(instanceState, INVALID_BACKUP_ID);
707715

708-
if (!instance_config.pgdata)
709-
elog(ERROR, "required parameter not specified: PGDATA "
710-
"(-D, --pgdata)");
716+
if (parray_num(backup_list) > 0)
717+
latest_backup_id = ((pgBackup *)parray_get(backup_list, 0))->backup_id;
718+
719+
parray_walk(backup_list, pgBackupFree);
720+
parray_free(backup_list);
721+
}
722+
723+
/* Try to pick backup_id and create backup directory with BACKUP_CONTROL_FILE */
724+
if (start_time != INVALID_BACKUP_ID)
725+
{
726+
/* If user already choosed backup_id for us, then try to use it. */
727+
if (start_time <= latest_backup_id)
728+
/* don't care about freeing base36enc_dup memory, we exit anyway */
729+
elog(ERROR, "Can't assign backup_id from requested start_time (%s), "
730+
"this time must be later that backup %s",
731+
base36enc_dup(start_time), base36enc_dup(latest_backup_id));
732+
733+
current.backup_id = start_time;
734+
pgBackupInitDir(&current, instanceState->instance_backup_subdir_path);
735+
}
736+
else
737+
{
738+
/* We can generate our own unique backup_id
739+
* Sometimes (when we try to backup twice in one second)
740+
* backup_id will be duplicated -> try more times.
741+
*/
742+
int attempts = 10;
743+
744+
if (time(NULL) < latest_backup_id)
745+
elog(ERROR, "Can't assign backup_id, there is already a backup in future (%s)",
746+
base36enc(latest_backup_id));
747+
748+
do
749+
{
750+
current.backup_id = time(NULL);
751+
pgBackupInitDir(&current, instanceState->instance_backup_subdir_path);
752+
if (current.backup_id == INVALID_BACKUP_ID)
753+
sleep(1);
754+
}
755+
while (current.backup_id == INVALID_BACKUP_ID && attempts-- > 0);
756+
}
757+
758+
/* If creation of backup dir was unsuccessful, there will be WARNINGS in logs already */
759+
if (current.backup_id == INVALID_BACKUP_ID)
760+
elog(ERROR, "Can't create backup directory");
711761

712762
/* Update backup status and other metainfo. */
713763
current.status = BACKUP_STATUS_RUNNING;

src/catalog.c

Lines changed: 38 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +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 void create_backup_dir(pgBackup *backup, const char *backup_instance_path);
26+
static int create_backup_dir(pgBackup *backup, const char *backup_instance_path);
2727

2828
static bool backup_lock_exit_hook_registered = false;
2929
static parray *locks = NULL;
@@ -976,6 +976,7 @@ catalog_get_backup_list(InstanceState *instanceState, time_t requested_backup_id
976976
}
977977
else if (strcmp(base36enc(backup->start_time), data_ent->d_name) != 0)
978978
{
979+
/* TODO there is no such guarantees */
979980
elog(WARNING, "backup ID in control file \"%s\" doesn't match name of the backup folder \"%s\"",
980981
base36enc(backup->start_time), backup_conf_path);
981982
}
@@ -1421,21 +1422,33 @@ get_multi_timeline_parent(parray *backup_list, parray *tli_list,
14211422
return NULL;
14221423
}
14231424

1424-
/* Create backup directory in $BACKUP_PATH
1425-
* Note, that backup_id attribute is updated,
1426-
* so it is possible to get diffrent values in
1425+
/*
1426+
* Create backup directory in $BACKUP_PATH
1427+
* (with proposed backup->backup_id)
1428+
* and initialize this directory.
1429+
* If creation of directory fails, then
1430+
* backup_id will be cleared (set to INVALID_BACKUP_ID).
1431+
* It is possible to get diffrent values in
14271432
* pgBackup.start_time and pgBackup.backup_id.
14281433
* It may be ok or maybe not, so it's up to the caller
14291434
* to fix it or let it be.
14301435
*/
14311436
void
1432-
pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_time)
1437+
pgBackupInitDir(pgBackup *backup, const char *backup_instance_path)
14331438
{
1434-
int i;
1435-
parray *subdirs = parray_new();
1436-
parray * backups;
1437-
pgBackup *target_backup;
1439+
int i;
1440+
char temp[MAXPGPATH];
1441+
parray *subdirs;
14381442

1443+
/* Try to create backup directory at first */
1444+
if (create_backup_dir(backup, backup_instance_path) != 0)
1445+
{
1446+
/* Clear backup_id as indication of error */
1447+
backup->backup_id = INVALID_BACKUP_ID;
1448+
return;
1449+
}
1450+
1451+
subdirs = parray_new();
14391452
parray_append(subdirs, pg_strdup(DATABASE_DIR));
14401453

14411454
/* Add external dirs containers */
@@ -1447,38 +1460,13 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
14471460
false);
14481461
for (i = 0; i < parray_num(external_list); i++)
14491462
{
1450-
char temp[MAXPGPATH];
14511463
/* Numeration of externaldirs starts with 1 */
14521464
makeExternalDirPathByNum(temp, EXTERNAL_DIR, i+1);
14531465
parray_append(subdirs, pg_strdup(temp));
14541466
}
14551467
free_dir_list(external_list);
14561468
}
14571469

1458-
/* Get list of all backups*/
1459-
backups = catalog_get_backup_list(instanceState, INVALID_BACKUP_ID);
1460-
if (parray_num(backups) > 0)
1461-
{
1462-
target_backup = (pgBackup *) parray_get(backups, 0);
1463-
if (start_time > target_backup->backup_id)
1464-
{
1465-
backup->backup_id = start_time;
1466-
create_backup_dir(backup, instanceState->instance_backup_subdir_path);
1467-
}
1468-
else
1469-
{
1470-
elog(ERROR, "Cannot create directory for older backup");
1471-
}
1472-
}
1473-
else
1474-
{
1475-
backup->backup_id = start_time;
1476-
create_backup_dir(backup, instanceState->instance_backup_subdir_path);
1477-
}
1478-
1479-
if (backup->backup_id == 0)
1480-
elog(ERROR, "Cannot create backup directory: %s", strerror(errno));
1481-
14821470
backup->database_dir = pgut_malloc(MAXPGPATH);
14831471
join_path_components(backup->database_dir, backup->root_dir, DATABASE_DIR);
14841472

@@ -1488,10 +1476,8 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
14881476
/* create directories for actual backup files */
14891477
for (i = 0; i < parray_num(subdirs); i++)
14901478
{
1491-
char path[MAXPGPATH];
1492-
1493-
join_path_components(path, backup->root_dir, parray_get(subdirs, i));
1494-
fio_mkdir(FIO_BACKUP_HOST, path, DIR_PERMISSION, false);
1479+
join_path_components(temp, backup->root_dir, parray_get(subdirs, i));
1480+
fio_mkdir(FIO_BACKUP_HOST, temp, DIR_PERMISSION, false);
14951481
}
14961482

14971483
free_dir_list(subdirs);
@@ -1500,33 +1486,26 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
15001486
/*
15011487
* Create root directory for backup,
15021488
* update pgBackup.root_dir if directory creation was a success
1489+
* Return values (same as dir_create_dir()):
1490+
* 0 - ok
1491+
* -1 - error (warning message already emitted)
15031492
*/
1504-
void
1493+
int
15051494
create_backup_dir(pgBackup *backup, const char *backup_instance_path)
15061495
{
1507-
int attempts = 10;
1496+
int rc;
1497+
char path[MAXPGPATH];
15081498

1509-
while (attempts--)
1510-
{
1511-
int rc;
1512-
char path[MAXPGPATH];
1513-
1514-
join_path_components(path, backup_instance_path, base36enc(backup->backup_id));
1499+
join_path_components(path, backup_instance_path, base36enc(backup->backup_id));
15151500

1516-
rc = fio_mkdir(FIO_BACKUP_HOST, path, DIR_PERMISSION, true);
1517-
1518-
if (rc == 0)
1519-
{
1520-
backup->root_dir = pgut_strdup(path);
1521-
return;
1522-
}
1523-
else
1524-
{
1525-
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1526-
sleep(1);
1527-
}
1528-
}
1501+
/* TODO: add wrapper for remote mode */
1502+
rc = fio_mkdir(FIO_BACKUP_HOST, path, DIR_PERMISSION, true);
15291503

1504+
if (rc == 0)
1505+
backup->root_dir = pgut_strdup(path);
1506+
else
1507+
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1508+
return rc;
15301509
}
15311510

15321511
/*

src/pg_probackup.c

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ pid_t my_pid = 0;
7878
__thread int my_thread_num = 1;
7979
bool progress = false;
8080
bool no_sync = false;
81-
time_t start_time = 0;
81+
time_t start_time = INVALID_BACKUP_ID;
8282
char *replication_slot = NULL;
8383
bool temp_slot = false;
8484
bool perm_slot = false;
@@ -200,7 +200,6 @@ static ConfigOption cmd_options[] =
200200
{ 's', 'i', "backup-id", &backup_id_string, SOURCE_CMD_STRICT },
201201
{ 'b', 133, "no-sync", &no_sync, SOURCE_CMD_STRICT },
202202
{ 'b', 134, "no-color", &no_color, SOURCE_CMD_STRICT },
203-
{ 'U', 241, "start-time", &start_time, SOURCE_CMD_STRICT },
204203
/* backup options */
205204
{ 'b', 180, "backup-pg-log", &backup_logs, SOURCE_CMD_STRICT },
206205
{ 'f', 'b', "backup-mode", opt_backup_mode, SOURCE_CMD_STRICT },
@@ -213,6 +212,7 @@ static ConfigOption cmd_options[] =
213212
{ 'b', 184, "merge-expired", &merge_expired, SOURCE_CMD_STRICT },
214213
{ 'b', 185, "dry-run", &dry_run, SOURCE_CMD_STRICT },
215214
{ 's', 238, "note", &backup_note, SOURCE_CMD_STRICT },
215+
{ 'U', 241, "start-time", &start_time, SOURCE_CMD_STRICT },
216216
/* catchup options */
217217
{ 's', 239, "source-pgdata", &catchup_source_pgdata, SOURCE_CMD_STRICT },
218218
{ 's', 240, "destination-pgdata", &catchup_destination_pgdata, SOURCE_CMD_STRICT },
@@ -975,9 +975,7 @@ main(int argc, char *argv[])
975975
case BACKUP_CMD:
976976
{
977977
current.stream = stream_wal;
978-
if (start_time == 0)
979-
start_time = current_time;
980-
else
978+
if (start_time != INVALID_BACKUP_ID)
981979
elog(WARNING, "Please do not use the --start-time option to start backup. "
982980
"This is a service option required to work with other extensions. "
983981
"We do not guarantee future support for this flag.");

src/pg_probackup.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -439,7 +439,10 @@ struct pgBackup
439439
{
440440
BackupMode backup_mode; /* Mode - one of BACKUP_MODE_xxx above*/
441441
time_t backup_id; /* Identifier of the backup.
442-
* Currently it's the same as start_time */
442+
* By default it's the same as start_time
443+
* but can be increased if same backup_id
444+
* already exists. It can be also set by
445+
* start_time parameter */
443446
BackupStatus status; /* Status - one of BACKUP_STATUS_xxx above*/
444447
TimeLineID tli; /* timeline of start and stop backup lsns */
445448
XLogRecPtr start_lsn; /* backup's starting transaction log location */
@@ -969,7 +972,7 @@ extern void write_backup_filelist(pgBackup *backup, parray *files,
969972
const char *root, parray *external_list, bool sync);
970973

971974

972-
extern void pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_time);
975+
extern void pgBackupInitDir(pgBackup *backup, const char *backup_instance_path);
973976
extern void pgNodeInit(PGNodeInfo *node);
974977
extern void pgBackupInit(pgBackup *backup);
975978
extern void pgBackupFree(void *backup);

0 commit comments

Comments
 (0)