@@ -21,23 +21,74 @@ static const char *backupModes[] = {"", "PAGE", "PTRACK", "DELTA", "FULL"};
2121static pgBackup * readBackupControlFile (const char * path );
2222
2323static bool exit_hook_registered = false;
24- static char lock_file [ MAXPGPATH ] ;
24+ static parray * lock_files = NULL ;
2525
2626static void
2727unlink_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 */
3871void
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 */
0 commit comments