Skip to content

Commit d557b40

Browse files
committed
PGPRO-1918: Remove instance-level lock, introduce backup-level lock
1 parent 53cb7c1 commit d557b40

File tree

7 files changed

+107
-64
lines changed

7 files changed

+107
-64
lines changed

src/backup.c

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -943,9 +943,6 @@ do_backup(time_t start_time)
943943
instance_config.master_user);
944944
}
945945

946-
/* Get exclusive lock of backup catalog */
947-
catalog_lock();
948-
949946
/*
950947
* Ensure that backup directory was initialized for the same PostgreSQL
951948
* instance we opened connection to. And that target backup database PGDATA
@@ -955,7 +952,6 @@ do_backup(time_t start_time)
955952
if (!is_remote_backup)
956953
check_system_identifiers();
957954

958-
959955
/* Start backup. Update backup status. */
960956
current.status = BACKUP_STATUS_RUNNING;
961957
current.start_time = start_time;
@@ -965,6 +961,7 @@ do_backup(time_t start_time)
965961
/* Create backup directory and BACKUP_CONTROL_FILE */
966962
if (pgBackupCreateDir(&current))
967963
elog(ERROR, "cannot create backup directory");
964+
lock_backup(&current);
968965
write_backup(&current);
969966

970967
elog(LOG, "Backup destination is initialized");

src/catalog.c

Lines changed: 82 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,73 @@ static const char *backupModes[] = {"", "PAGE", "PTRACK", "DELTA", "FULL"};
2121
static pgBackup *readBackupControlFile(const char *path);
2222

2323
static bool exit_hook_registered = false;
24-
static char lock_file[MAXPGPATH];
24+
static parray *lock_files = NULL;
2525

2626
static void
2727
unlink_lock_atexit(void)
2828
{
29-
int res;
30-
res = unlink(lock_file);
31-
if (res != 0 && res != ENOENT)
32-
elog(WARNING, "%s: %s", lock_file, strerror(errno));
29+
int i;
30+
31+
if (lock_files == NULL)
32+
return;
33+
34+
for (i = 0; i < parray_num(lock_files); i++)
35+
{
36+
char *lock_file = (char *) parray_get(lock_files, i);
37+
int res;
38+
39+
res = unlink(lock_file);
40+
if (res != 0 && res != ENOENT)
41+
elog(WARNING, "%s: %s", lock_file, strerror(errno));
42+
}
43+
44+
parray_walk(lock_files, pfree);
45+
parray_free(lock_files);
46+
lock_files = NULL;
3347
}
3448

3549
/*
36-
* Create a lockfile.
50+
* Read backup meta information from BACKUP_CONTROL_FILE.
51+
* If no backup matches, return NULL.
52+
*/
53+
pgBackup *
54+
read_backup(time_t timestamp)
55+
{
56+
pgBackup tmp;
57+
char conf_path[MAXPGPATH];
58+
59+
tmp.start_time = timestamp;
60+
pgBackupGetPath(&tmp, conf_path, lengthof(conf_path), BACKUP_CONTROL_FILE);
61+
62+
return readBackupControlFile(conf_path);
63+
}
64+
65+
/*
66+
* Save the backup status into BACKUP_CONTROL_FILE.
67+
*
68+
* We need to reread the backup using its ID and save it changing only its
69+
* status.
3770
*/
3871
void
39-
catalog_lock(void)
72+
write_backup_status(pgBackup *backup)
4073
{
74+
pgBackup *tmp;
75+
76+
tmp = read_backup(backup->start_time);
77+
78+
tmp->status = backup->status;
79+
write_backup(tmp);
80+
81+
pgBackupFree(tmp);
82+
}
83+
84+
/*
85+
* Create exclusive lockfile in the backup's directory.
86+
*/
87+
void
88+
lock_backup(pgBackup *backup)
89+
{
90+
char lock_file[MAXPGPATH];
4191
int fd;
4292
char buffer[MAXPGPATH * 2 + 256];
4393
int ntries;
@@ -46,7 +96,7 @@ catalog_lock(void)
4696
pid_t my_pid,
4797
my_p_pid;
4898

49-
join_path_components(lock_file, backup_instance_path, BACKUP_CATALOG_PID);
99+
pgBackupGetPath(backup, lock_file, lengthof(lock_file), BACKUP_CATALOG_PID);
50100

51101
/*
52102
* If the PID in the lockfile is our own PID or our parent's or
@@ -200,41 +250,11 @@ catalog_lock(void)
200250
atexit(unlink_lock_atexit);
201251
exit_hook_registered = true;
202252
}
203-
}
204253

205-
/*
206-
* Read backup meta information from BACKUP_CONTROL_FILE.
207-
* If no backup matches, return NULL.
208-
*/
209-
pgBackup *
210-
read_backup(time_t timestamp)
211-
{
212-
pgBackup tmp;
213-
char conf_path[MAXPGPATH];
214-
215-
tmp.start_time = timestamp;
216-
pgBackupGetPath(&tmp, conf_path, lengthof(conf_path), BACKUP_CONTROL_FILE);
217-
218-
return readBackupControlFile(conf_path);
219-
}
220-
221-
/*
222-
* Save the backup status into BACKUP_CONTROL_FILE.
223-
*
224-
* We need to reread the backup using its ID and save it changing only its
225-
* status.
226-
*/
227-
void
228-
write_backup_status(pgBackup *backup)
229-
{
230-
pgBackup *tmp;
231-
232-
tmp = read_backup(backup->start_time);
233-
234-
tmp->status = backup->status;
235-
write_backup(tmp);
236-
237-
pgBackupFree(tmp);
254+
/* Use parray so that the lock files are unlinked in a loop */
255+
if (lock_files == NULL)
256+
lock_files = parray_new();
257+
parray_append(lock_files, pgut_strdup(lock_file));
238258
}
239259

240260
/*
@@ -381,6 +401,26 @@ catalog_get_backup_list(time_t requested_backup_id)
381401
return NULL;
382402
}
383403

404+
/*
405+
* Lock list of backups. Function goes in backward direction.
406+
*/
407+
void
408+
catalog_lock_backup_list(parray *backup_list, int from_idx, int to_idx)
409+
{
410+
int start_idx,
411+
end_idx;
412+
int i;
413+
414+
if (parray_num(backup_list) == 0)
415+
return;
416+
417+
start_idx = Max(from_idx, to_idx);
418+
end_idx = Min(from_idx, to_idx);
419+
420+
for (i = start_idx; i >= end_idx; i--)
421+
lock_backup((pgBackup *) parray_get(backup_list, i));
422+
}
423+
384424
/*
385425
* Find the last completed backup on given timeline
386426
*/

src/delete.c

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,6 @@ do_delete(time_t backup_id)
2828
XLogRecPtr oldest_lsn = InvalidXLogRecPtr;
2929
TimeLineID oldest_tli = 0;
3030

31-
/* Get exclusive lock of backup catalog */
32-
catalog_lock();
33-
3431
/* Get complete list of backups */
3532
backup_list = catalog_get_backup_list(INVALID_BACKUP_ID);
3633

@@ -76,6 +73,8 @@ do_delete(time_t backup_id)
7673
if (parray_num(delete_list) == 0)
7774
elog(ERROR, "no backup found, cannot delete");
7875

76+
catalog_lock_backup_list(delete_list, parray_num(delete_list) - 1, 0);
77+
7978
/* Delete backups from the end of list */
8079
for (i = (int) parray_num(delete_list) - 1; i >= 0; i--)
8180
{
@@ -146,9 +145,6 @@ do_retention_purge(void)
146145
}
147146
}
148147

149-
/* Get exclusive lock of backup catalog */
150-
catalog_lock();
151-
152148
/* Get a complete list of backups. */
153149
backup_list = catalog_get_backup_list(INVALID_BACKUP_ID);
154150
if (parray_num(backup_list) == 0)
@@ -206,6 +202,8 @@ do_retention_purge(void)
206202
continue;
207203
}
208204

205+
lock_backup(backup);
206+
209207
/* Delete backup and update status to DELETED */
210208
delete_backup_files(backup);
211209
backup_deleted = true;
@@ -438,6 +436,8 @@ do_delete_instance(void)
438436
/* Delete all backups. */
439437
backup_list = catalog_get_backup_list(INVALID_BACKUP_ID);
440438

439+
catalog_lock_backup_list(backup_list, 0, parray_num(backup_list) - 1);
440+
441441
for (i = 0; i < parray_num(backup_list); i++)
442442
{
443443
pgBackup *backup = (pgBackup *) parray_get(backup_list, i);

src/merge.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,6 @@ do_merge(time_t backup_id)
6161

6262
elog(INFO, "Merge started");
6363

64-
catalog_lock();
65-
6664
/* Get list of all backups sorted in order of descending start time */
6765
backups = catalog_get_backup_list(INVALID_BACKUP_ID);
6866

@@ -125,6 +123,8 @@ do_merge(time_t backup_id)
125123

126124
Assert(full_backup_idx != dest_backup_idx);
127125

126+
catalog_lock_backup_list(backups, full_backup_idx, dest_backup_idx);
127+
128128
/*
129129
* Found target and full backups, merge them and intermediate backups
130130
*/

src/pg_probackup.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
#define PG_GLOBAL_DIR "global"
4444
#define BACKUP_CONTROL_FILE "backup.control"
4545
#define BACKUP_CATALOG_CONF_FILE "pg_probackup.conf"
46-
#define BACKUP_CATALOG_PID "pg_probackup.pid"
46+
#define BACKUP_CATALOG_PID "backup.pid"
4747
#define DATABASE_FILE_LIST "backup_content.control"
4848
#define PG_BACKUP_LABEL_FILE "backup_label"
4949
#define PG_BLACK_LIST "black_list"
@@ -459,13 +459,15 @@ extern int do_validate_all(void);
459459
extern pgBackup *read_backup(time_t timestamp);
460460
extern void write_backup(pgBackup *backup);
461461
extern void write_backup_status(pgBackup *backup);
462+
extern void lock_backup(pgBackup *backup);
462463

463464
extern const char *pgBackupGetBackupMode(pgBackup *backup);
464465

465466
extern parray *catalog_get_backup_list(time_t requested_backup_id);
467+
extern void catalog_lock_backup_list(parray *backup_list, int from_idx,
468+
int to_idx);
466469
extern pgBackup *catalog_get_last_data_backup(parray *backup_list,
467470
TimeLineID tli);
468-
extern void catalog_lock(void);
469471
extern void pgBackupWriteControl(FILE *out, pgBackup *backup);
470472
extern void write_backup_filelist(pgBackup *backup, parray *files,
471473
const char *root);

src/restore.c

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -74,8 +74,6 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
7474

7575
elog(LOG, "%s begin.", action);
7676

77-
/* Get exclusive lock of backup catalog */
78-
catalog_lock();
7977
/* Get list of all backups sorted in order of descending start time */
8078
backups = catalog_get_backup_list(INVALID_BACKUP_ID);
8179

@@ -300,7 +298,7 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
300298

301299
if (is_parent(base_full_backup->start_time, tmp_backup, true))
302300
{
303-
301+
lock_backup(tmp_backup);
304302
pgBackupValidate(tmp_backup);
305303
/* Maybe we should be more paranoid and check for !BACKUP_STATUS_OK? */
306304
if (tmp_backup->status == BACKUP_STATUS_CORRUPT)
@@ -388,6 +386,13 @@ do_restore_or_validate(time_t target_backup_id, pgRecoveryTarget *rt,
388386
elog(ERROR, "Backup %s was created for version %s which doesn't support recovery_target_lsn",
389387
base36enc(dest_backup->start_time), dest_backup->server_version);
390388

389+
/*
390+
* Backup was locked during validation if no-validate wasn't
391+
* specified.
392+
*/
393+
if (rt->restore_no_validate)
394+
lock_backup(backup);
395+
391396
restore_backup(backup);
392397
}
393398

src/validate.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ pgBackupValidate(pgBackup *backup)
5353
int i;
5454

5555
/* Check backup version */
56-
if (backup->program_version &&
57-
parse_program_version(backup->program_version) > parse_program_version(PROGRAM_VERSION))
56+
if (parse_program_version(backup->program_version) >
57+
parse_program_version(PROGRAM_VERSION))
5858
elog(ERROR, "pg_probackup binary version is %s, but backup %s version is %s. "
5959
"pg_probackup do not guarantee to be forward compatible. "
6060
"Please upgrade pg_probackup binary.",
@@ -356,9 +356,6 @@ do_validate_instance(void)
356356

357357
elog(INFO, "Validate backups of the instance '%s'", instance_name);
358358

359-
/* Get exclusive lock of backup catalog */
360-
catalog_lock();
361-
362359
/* Get list of all backups sorted in order of descending start time */
363360
backups = catalog_get_backup_list(INVALID_BACKUP_ID);
364361

@@ -439,6 +436,7 @@ do_validate_instance(void)
439436
else
440437
base_full_backup = current_backup;
441438

439+
lock_backup(current_backup);
442440
/* Valiate backup files*/
443441
pgBackupValidate(current_backup);
444442

@@ -525,6 +523,7 @@ do_validate_instance(void)
525523

526524
if (backup->status == BACKUP_STATUS_ORPHAN)
527525
{
526+
lock_backup(backup);
528527
/* Revaliate backup files*/
529528
pgBackupValidate(backup);
530529

0 commit comments

Comments
 (0)