Skip to content

Commit 9243a8a

Browse files
committed
Merge branch 'pgpro-1918'
2 parents 49705d7 + ff4d470 commit 9243a8a

File tree

11 files changed

+830
-123
lines changed

11 files changed

+830
-123
lines changed

src/backup.c

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -959,9 +959,6 @@ do_backup(time_t start_time)
959959
instance_config.master_user);
960960
}
961961

962-
/* Get exclusive lock of backup catalog */
963-
catalog_lock();
964-
965962
/*
966963
* Ensure that backup directory was initialized for the same PostgreSQL
967964
* instance we opened connection to. And that target backup database PGDATA
@@ -971,7 +968,6 @@ do_backup(time_t start_time)
971968
if (!is_remote_backup)
972969
check_system_identifiers();
973970

974-
975971
/* Start backup. Update backup status. */
976972
current.status = BACKUP_STATUS_RUNNING;
977973
current.start_time = start_time;
@@ -980,7 +976,10 @@ do_backup(time_t start_time)
980976

981977
/* Create backup directory and BACKUP_CONTROL_FILE */
982978
if (pgBackupCreateDir(&current))
983-
elog(ERROR, "cannot create backup directory");
979+
elog(ERROR, "Cannot create backup directory");
980+
if (!lock_backup(&current))
981+
elog(ERROR, "Cannot lock backup %s directory",
982+
base36enc(current.start_time));
984983
write_backup(&current);
985984

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

src/catalog.c

Lines changed: 113 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -21,23 +21,74 @@ 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, BackupStatus status)
73+
{
74+
pgBackup *tmp;
75+
76+
tmp = read_backup(backup->start_time);
77+
78+
backup->status = status;
79+
tmp->status = backup->status;
80+
write_backup(tmp);
81+
82+
pgBackupFree(tmp);
83+
}
84+
85+
/*
86+
* Create exclusive lockfile in the backup's directory.
87+
*/
88+
bool
89+
lock_backup(pgBackup *backup)
4090
{
91+
char lock_file[MAXPGPATH];
4192
int fd;
4293
char buffer[MAXPGPATH * 2 + 256];
4394
int ntries;
@@ -46,7 +97,7 @@ catalog_lock(void)
4697
pid_t my_pid,
4798
my_p_pid;
4899

49-
join_path_components(lock_file, backup_instance_path, BACKUP_CATALOG_PID);
100+
pgBackupGetPath(backup, lock_file, lengthof(lock_file), BACKUP_CATALOG_PID);
50101

51102
/*
52103
* If the PID in the lockfile is our own PID or our parent's or
@@ -99,7 +150,7 @@ catalog_lock(void)
99150
* Couldn't create the pid file. Probably it already exists.
100151
*/
101152
if ((errno != EEXIST && errno != EACCES) || ntries > 100)
102-
elog(ERROR, "could not create lock file \"%s\": %s",
153+
elog(ERROR, "Could not create lock file \"%s\": %s",
103154
lock_file, strerror(errno));
104155

105156
/*
@@ -111,22 +162,22 @@ catalog_lock(void)
111162
{
112163
if (errno == ENOENT)
113164
continue; /* race condition; try again */
114-
elog(ERROR, "could not open lock file \"%s\": %s",
165+
elog(ERROR, "Could not open lock file \"%s\": %s",
115166
lock_file, strerror(errno));
116167
}
117168
if ((len = read(fd, buffer, sizeof(buffer) - 1)) < 0)
118-
elog(ERROR, "could not read lock file \"%s\": %s",
169+
elog(ERROR, "Could not read lock file \"%s\": %s",
119170
lock_file, strerror(errno));
120171
close(fd);
121172

122173
if (len == 0)
123-
elog(ERROR, "lock file \"%s\" is empty", lock_file);
174+
elog(ERROR, "Lock file \"%s\" is empty", lock_file);
124175

125176
buffer[len] = '\0';
126177
encoded_pid = atoi(buffer);
127178

128179
if (encoded_pid <= 0)
129-
elog(ERROR, "bogus data in lock file \"%s\": \"%s\"",
180+
elog(ERROR, "Bogus data in lock file \"%s\": \"%s\"",
130181
lock_file, buffer);
131182

132183
/*
@@ -140,9 +191,21 @@ catalog_lock(void)
140191
*/
141192
if (encoded_pid != my_pid && encoded_pid != my_p_pid)
142193
{
143-
if (kill(encoded_pid, 0) == 0 ||
144-
(errno != ESRCH && errno != EPERM))
145-
elog(ERROR, "lock file \"%s\" already exists", lock_file);
194+
if (kill(encoded_pid, 0) == 0)
195+
{
196+
elog(WARNING, "Process %d is using backup %s and still is running",
197+
encoded_pid, base36enc(backup->start_time));
198+
return false;
199+
}
200+
else
201+
{
202+
if (errno == ESRCH)
203+
elog(WARNING, "Process %d which used backup %s no longer exists",
204+
encoded_pid, base36enc(backup->start_time));
205+
else
206+
elog(ERROR, "Failed to send signal 0 to a process %d: %s",
207+
encoded_pid, strerror(errno));
208+
}
146209
}
147210

148211
/*
@@ -151,7 +214,7 @@ catalog_lock(void)
151214
* would-be creators.
152215
*/
153216
if (unlink(lock_file) < 0)
154-
elog(ERROR, "could not remove old lock file \"%s\": %s",
217+
elog(ERROR, "Could not remove old lock file \"%s\": %s",
155218
lock_file, strerror(errno));
156219
}
157220

@@ -169,7 +232,7 @@ catalog_lock(void)
169232
unlink(lock_file);
170233
/* if write didn't set errno, assume problem is no disk space */
171234
errno = save_errno ? save_errno : ENOSPC;
172-
elog(ERROR, "could not write lock file \"%s\": %s",
235+
elog(ERROR, "Could not write lock file \"%s\": %s",
173236
lock_file, strerror(errno));
174237
}
175238
if (fsync(fd) != 0)
@@ -179,7 +242,7 @@ catalog_lock(void)
179242
close(fd);
180243
unlink(lock_file);
181244
errno = save_errno;
182-
elog(ERROR, "could not write lock file \"%s\": %s",
245+
elog(ERROR, "Could not write lock file \"%s\": %s",
183246
lock_file, strerror(errno));
184247
}
185248
if (close(fd) != 0)
@@ -188,7 +251,7 @@ catalog_lock(void)
188251

189252
unlink(lock_file);
190253
errno = save_errno;
191-
elog(ERROR, "could not write lock file \"%s\": %s",
254+
elog(ERROR, "Culd not write lock file \"%s\": %s",
192255
lock_file, strerror(errno));
193256
}
194257

@@ -200,41 +263,13 @@ catalog_lock(void)
200263
atexit(unlink_lock_atexit);
201264
exit_hook_registered = true;
202265
}
203-
}
204266

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];
267+
/* Use parray so that the lock files are unlinked in a loop */
268+
if (lock_files == NULL)
269+
lock_files = parray_new();
270+
parray_append(lock_files, pgut_strdup(lock_file));
214271

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);
272+
return true;
238273
}
239274

240275
/*
@@ -381,6 +416,31 @@ catalog_get_backup_list(time_t requested_backup_id)
381416
return NULL;
382417
}
383418

419+
/*
420+
* Lock list of backups. Function goes in backward direction.
421+
*/
422+
void
423+
catalog_lock_backup_list(parray *backup_list, int from_idx, int to_idx)
424+
{
425+
int start_idx,
426+
end_idx;
427+
int i;
428+
429+
if (parray_num(backup_list) == 0)
430+
return;
431+
432+
start_idx = Max(from_idx, to_idx);
433+
end_idx = Min(from_idx, to_idx);
434+
435+
for (i = start_idx; i >= end_idx; i--)
436+
{
437+
pgBackup *backup = (pgBackup *) parray_get(backup_list, i);
438+
if (!lock_backup(backup))
439+
elog(ERROR, "Cannot lock backup %s directory",
440+
base36enc(backup->start_time));
441+
}
442+
}
443+
384444
/*
385445
* Find the last completed backup on given timeline
386446
*/

src/delete.c

Lines changed: 17 additions & 9 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,17 @@ do_retention_purge(void)
206202
continue;
207203
}
208204

205+
/*
206+
* If the backup still is used do not interrupt go to the next
207+
* backup.
208+
*/
209+
if (!lock_backup(backup))
210+
{
211+
elog(WARNING, "Cannot lock backup %s directory, skip purging",
212+
base36enc(backup->start_time));
213+
continue;
214+
}
215+
209216
/* Delete backup and update status to DELETED */
210217
delete_backup_files(backup);
211218
backup_deleted = true;
@@ -240,7 +247,7 @@ do_retention_purge(void)
240247
if (backup_deleted)
241248
elog(INFO, "Purging finished");
242249
else
243-
elog(INFO, "Nothing to delete by retention policy");
250+
elog(INFO, "There are no backups to delete by retention policy");
244251

245252
return 0;
246253
}
@@ -277,8 +284,7 @@ delete_backup_files(pgBackup *backup)
277284
* Update STATUS to BACKUP_STATUS_DELETING in preparation for the case which
278285
* the error occurs before deleting all backup files.
279286
*/
280-
backup->status = BACKUP_STATUS_DELETING;
281-
write_backup_status(backup);
287+
write_backup_status(backup, BACKUP_STATUS_DELETING);
282288

283289
/* list files to be deleted */
284290
files = parray_new();
@@ -430,6 +436,8 @@ do_delete_instance(void)
430436
/* Delete all backups. */
431437
backup_list = catalog_get_backup_list(INVALID_BACKUP_ID);
432438

439+
catalog_lock_backup_list(backup_list, 0, parray_num(backup_list) - 1);
440+
433441
for (i = 0; i < parray_num(backup_list); i++)
434442
{
435443
pgBackup *backup = (pgBackup *) parray_get(backup_list, i);

0 commit comments

Comments
 (0)