Skip to content

Commit 1bb0762

Browse files
kulaginmdlepikhova
andauthored
[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 95471ac commit 1bb0762

File tree

8 files changed

+217
-357
lines changed

8 files changed

+217
-357
lines changed

src/backup.c

+55-5
Original file line numberDiff line numberDiff line change
@@ -692,15 +692,22 @@ pgdata_basic_setup(ConnectionOptions conn_opt, PGNodeInfo *nodeInfo)
692692

693693
/*
694694
* Entry point of pg_probackup BACKUP subcommand.
695+
*
696+
* if start_time == INVALID_BACKUP_ID then we can generate backup_id
695697
*/
696698
int
697699
do_backup(InstanceState *instanceState, pgSetBackupParams *set_backup_params,
698700
bool no_validate, bool no_sync, bool backup_logs, time_t start_time)
699701
{
700702
PGconn *backup_conn = NULL;
701703
PGNodeInfo nodeInfo;
704+
time_t latest_backup_id = INVALID_BACKUP_ID;
702705
char pretty_bytes[20];
703706

707+
if (!instance_config.pgdata)
708+
elog(ERROR, "required parameter not specified: PGDATA "
709+
"(-D, --pgdata)");
710+
704711
/* Initialize PGInfonode */
705712
pgNodeInit(&nodeInfo);
706713

@@ -709,12 +716,55 @@ do_backup(InstanceState *instanceState, pgSetBackupParams *set_backup_params,
709716
(pg_strcasecmp(instance_config.external_dir_str, "none") != 0))
710717
current.external_dir_str = instance_config.external_dir_str;
711718

712-
/* Create backup directory and BACKUP_CONTROL_FILE */
713-
pgBackupCreateDir(&current, instanceState, start_time);
719+
/* Find latest backup_id */
720+
{
721+
parray *backup_list = catalog_get_backup_list(instanceState, INVALID_BACKUP_ID);
714722

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

719769
/* Update backup status and other metainfo. */
720770
current.status = BACKUP_STATUS_RUNNING;

src/catalog.c

+38-60
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;
@@ -969,6 +969,7 @@ catalog_get_backup_list(InstanceState *instanceState, time_t requested_backup_id
969969
}
970970
else if (strcmp(base36enc(backup->start_time), data_ent->d_name) != 0)
971971
{
972+
/* TODO there is no such guarantees */
972973
elog(WARNING, "backup ID in control file \"%s\" doesn't match name of the backup folder \"%s\"",
973974
base36enc(backup->start_time), backup_conf_path);
974975
}
@@ -1411,22 +1412,34 @@ get_multi_timeline_parent(parray *backup_list, parray *tli_list,
14111412
return NULL;
14121413
}
14131414

1414-
/* Create backup directory in $BACKUP_PATH
1415-
* Note, that backup_id attribute is updated,
1416-
* so it is possible to get diffrent values in
1415+
/*
1416+
* Create backup directory in $BACKUP_PATH
1417+
* (with proposed backup->backup_id)
1418+
* and initialize this directory.
1419+
* If creation of directory fails, then
1420+
* backup_id will be cleared (set to INVALID_BACKUP_ID).
1421+
* It is possible to get diffrent values in
14171422
* pgBackup.start_time and pgBackup.backup_id.
14181423
* It may be ok or maybe not, so it's up to the caller
14191424
* to fix it or let it be.
14201425
*/
14211426

14221427
void
1423-
pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_time)
1428+
pgBackupInitDir(pgBackup *backup, const char *backup_instance_path)
14241429
{
1425-
int i;
1426-
parray *subdirs = parray_new();
1427-
parray * backups;
1428-
pgBackup *target_backup;
1430+
int i;
1431+
char temp[MAXPGPATH];
1432+
parray *subdirs;
14291433

1434+
/* Try to create backup directory at first */
1435+
if (create_backup_dir(backup, backup_instance_path) != 0)
1436+
{
1437+
/* Clear backup_id as indication of error */
1438+
backup->backup_id = INVALID_BACKUP_ID;
1439+
return;
1440+
}
1441+
1442+
subdirs = parray_new();
14301443
parray_append(subdirs, pg_strdup(DATABASE_DIR));
14311444

14321445
/* Add external dirs containers */
@@ -1438,38 +1451,13 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
14381451
false);
14391452
for (i = 0; i < parray_num(external_list); i++)
14401453
{
1441-
char temp[MAXPGPATH];
14421454
/* Numeration of externaldirs starts with 1 */
14431455
makeExternalDirPathByNum(temp, EXTERNAL_DIR, i+1);
14441456
parray_append(subdirs, pg_strdup(temp));
14451457
}
14461458
free_dir_list(external_list);
14471459
}
14481460

1449-
/* Get list of all backups*/
1450-
backups = catalog_get_backup_list(instanceState, INVALID_BACKUP_ID);
1451-
if (parray_num(backups) > 0)
1452-
{
1453-
target_backup = (pgBackup *) parray_get(backups, 0);
1454-
if (start_time > target_backup->backup_id)
1455-
{
1456-
backup->backup_id = start_time;
1457-
create_backup_dir(backup, instanceState->instance_backup_subdir_path);
1458-
}
1459-
else
1460-
{
1461-
elog(ERROR, "Cannot create directory for older backup");
1462-
}
1463-
}
1464-
else
1465-
{
1466-
backup->backup_id = start_time;
1467-
create_backup_dir(backup, instanceState->instance_backup_subdir_path);
1468-
}
1469-
1470-
if (backup->backup_id == 0)
1471-
elog(ERROR, "Cannot create backup directory: %s", strerror(errno));
1472-
14731461
backup->database_dir = pgut_malloc(MAXPGPATH);
14741462
join_path_components(backup->database_dir, backup->root_dir, DATABASE_DIR);
14751463

@@ -1479,10 +1467,8 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
14791467
/* create directories for actual backup files */
14801468
for (i = 0; i < parray_num(subdirs); i++)
14811469
{
1482-
char path[MAXPGPATH];
1483-
1484-
join_path_components(path, backup->root_dir, parray_get(subdirs, i));
1485-
fio_mkdir(path, DIR_PERMISSION, FIO_BACKUP_HOST);
1470+
join_path_components(temp, backup->root_dir, parray_get(subdirs, i));
1471+
fio_mkdir(temp, DIR_PERMISSION, FIO_BACKUP_HOST);
14861472
}
14871473

14881474
free_dir_list(subdirs);
@@ -1491,34 +1477,26 @@ pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_t
14911477
/*
14921478
* Create root directory for backup,
14931479
* update pgBackup.root_dir if directory creation was a success
1480+
* Return values (same as dir_create_dir()):
1481+
* 0 - ok
1482+
* -1 - error (warning message already emitted)
14941483
*/
1495-
void
1484+
int
14961485
create_backup_dir(pgBackup *backup, const char *backup_instance_path)
14971486
{
1498-
int attempts = 10;
1487+
int rc;
1488+
char path[MAXPGPATH];
14991489

1500-
while (attempts--)
1501-
{
1502-
int rc;
1503-
char path[MAXPGPATH];
1504-
1505-
join_path_components(path, backup_instance_path, base36enc(backup->backup_id));
1490+
join_path_components(path, backup_instance_path, base36enc(backup->backup_id));
15061491

1507-
/* TODO: add wrapper for remote mode */
1508-
rc = dir_create_dir(path, DIR_PERMISSION, true);
1509-
1510-
if (rc == 0)
1511-
{
1512-
backup->root_dir = pgut_strdup(path);
1513-
return;
1514-
}
1515-
else
1516-
{
1517-
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1518-
sleep(1);
1519-
}
1520-
}
1492+
/* TODO: add wrapper for remote mode */
1493+
rc = dir_create_dir(path, DIR_PERMISSION, true);
15211494

1495+
if (rc == 0)
1496+
backup->root_dir = pgut_strdup(path);
1497+
else
1498+
elog(WARNING, "Cannot create directory \"%s\": %s", path, strerror(errno));
1499+
return rc;
15221500
}
15231501

15241502
/*

src/pg_probackup.c

+3-5
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
#if PG_VERSION_NUM >= 100000
8383
char *replication_slot = NULL;
8484
bool temp_slot = false;
@@ -202,7 +202,6 @@ static ConfigOption cmd_options[] =
202202
{ 's', 'i', "backup-id", &backup_id_string, SOURCE_CMD_STRICT },
203203
{ 'b', 133, "no-sync", &no_sync, SOURCE_CMD_STRICT },
204204
{ 'b', 134, "no-color", &no_color, SOURCE_CMD_STRICT },
205-
{ 'U', 241, "start-time", &start_time, SOURCE_CMD_STRICT },
206205
/* backup options */
207206
{ 'b', 180, "backup-pg-log", &backup_logs, SOURCE_CMD_STRICT },
208207
{ 'f', 'b', "backup-mode", opt_backup_mode, SOURCE_CMD_STRICT },
@@ -217,6 +216,7 @@ static ConfigOption cmd_options[] =
217216
{ 'b', 184, "merge-expired", &merge_expired, SOURCE_CMD_STRICT },
218217
{ 'b', 185, "dry-run", &dry_run, SOURCE_CMD_STRICT },
219218
{ 's', 238, "note", &backup_note, SOURCE_CMD_STRICT },
219+
{ 'U', 241, "start-time", &start_time, SOURCE_CMD_STRICT },
220220
/* catchup options */
221221
{ 's', 239, "source-pgdata", &catchup_source_pgdata, SOURCE_CMD_STRICT },
222222
{ '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

+5-2
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,10 @@ struct pgBackup
450450
{
451451
BackupMode backup_mode; /* Mode - one of BACKUP_MODE_xxx above*/
452452
time_t backup_id; /* Identifier of the backup.
453-
* Currently it's the same as start_time */
453+
* By default it's the same as start_time
454+
* but can be increased if same backup_id
455+
* already exists. It can be also set by
456+
* start_time parameter */
454457
BackupStatus status; /* Status - one of BACKUP_STATUS_xxx above*/
455458
TimeLineID tli; /* timeline of start and stop backup lsns */
456459
XLogRecPtr start_lsn; /* backup's starting transaction log location */
@@ -985,7 +988,7 @@ extern void write_backup_filelist(pgBackup *backup, parray *files,
985988
const char *root, parray *external_list, bool sync);
986989

987990

988-
extern void pgBackupCreateDir(pgBackup *backup, InstanceState *instanceState, time_t start_time);
991+
extern void pgBackupInitDir(pgBackup *backup, const char *backup_instance_path);
989992
extern void pgNodeInit(PGNodeInfo *node);
990993
extern void pgBackupInit(pgBackup *backup);
991994
extern void pgBackupFree(void *backup);

0 commit comments

Comments
 (0)