16
16
17
17
static void delete_walfiles (XLogRecPtr oldest_lsn ,TimeLineID oldest_tli ,
18
18
uint32 xlog_seg_size );
19
- static void do_retention_internal (void );
19
+ static void do_retention_internal (parray * backup_list ,parray * to_keep_list ,
20
+ parray * to_purge_list );
21
+ static void do_retention_merge (parray * backup_list ,parray * to_keep_list ,
22
+ parray * to_purge_list );
23
+ static void do_retention_purge (parray * to_keep_list ,parray * to_purge_list );
20
24
static void do_retention_wal (void );
21
25
22
26
static bool backup_deleted = false;/* At least one backup was deleted */
@@ -108,8 +112,15 @@ do_delete(time_t backup_id)
108
112
109
113
int do_retention (void )
110
114
{
115
+ parray * backup_list = NULL ;
116
+ parray * to_keep_list = parray_new ();
117
+ parray * to_purge_list = parray_new ();
118
+
111
119
bool retention_is_set = false;/* At least one retention policy is set */
112
120
121
+ /* Get a complete list of backups. */
122
+ backup_list = catalog_get_backup_list (INVALID_BACKUP_ID );
123
+
113
124
if (delete_expired || merge_expired )
114
125
{
115
126
if (instance_config .retention_redundancy > 0 )
@@ -131,9 +142,17 @@ int do_retention(void)
131
142
retention_is_set = true;
132
143
}
133
144
134
- if (retention_is_set && ((delete_expired || merge_expired )|| dry_run ))
135
- do_retention_internal ();
145
+ /* show fancy message */
146
+ if (retention_is_set )
147
+ do_retention_internal (backup_list ,to_keep_list ,to_purge_list );
148
+
149
+ if (merge_expired && !dry_run )
150
+ do_retention_merge (backup_list ,to_keep_list ,to_purge_list );
151
+
152
+ if (delete_expired && !dry_run )
153
+ do_retention_purge (to_keep_list ,to_purge_list );
136
154
155
+ /* TODO: some sort of dry run for delete_wal */
137
156
if (delete_wal && !dry_run )
138
157
do_retention_wal ();
139
158
@@ -145,6 +164,12 @@ int do_retention(void)
145
164
else
146
165
elog (INFO ,"There are no backups to delete by retention policy" );
147
166
167
+ /* Cleanup */
168
+ parray_walk (backup_list ,pgBackupFree );
169
+ parray_free (backup_list );
170
+ parray_free (to_keep_list );
171
+ parray_free (to_purge_list );
172
+
148
173
return 0 ;
149
174
150
175
}
@@ -160,13 +185,9 @@ int do_retention(void)
160
185
* but if invalid backup is not guarded by retention - it is removed
161
186
*/
162
187
static void
163
- do_retention_internal (void )
188
+ do_retention_internal (parray * backup_list , parray * to_keep_list , parray * to_purge_list )
164
189
{
165
- parray * backup_list = NULL ;
166
- parray * to_purge_list = parray_new ();
167
- parray * to_keep_list = parray_new ();
168
190
int i ;
169
- int j ;
170
191
time_t current_time ;
171
192
bool backup_list_is_empty = false;
172
193
@@ -178,8 +199,7 @@ do_retention_internal(void)
178
199
/* For fancy reporting */
179
200
float actual_window = 0 ;
180
201
181
- /* Get a complete list of backups. */
182
- backup_list = catalog_get_backup_list (INVALID_BACKUP_ID );
202
+ /* sanity */
183
203
if (parray_num (backup_list )== 0 )
184
204
backup_list_is_empty = true;
185
205
@@ -257,36 +277,66 @@ do_retention_internal(void)
257
277
parray_append (to_purge_list ,backup );
258
278
continue ;
259
279
}
280
+ }
281
+
282
+ /* sort keep_list and purge list */
283
+ parray_qsort (to_keep_list ,pgBackupCompareIdDesc );
284
+ parray_qsort (to_purge_list ,pgBackupCompareIdDesc );
285
+
286
+ /* FULL
287
+ * PAGE
288
+ * PAGE <- Only such backups must go into keep list
289
+ ---------retention window ----
290
+ * PAGE
291
+ * FULL
292
+ * PAGE
293
+ * FULL
294
+ */
295
+
296
+ for (i = 0 ;i < parray_num (backup_list );i ++ )
297
+ {
298
+
299
+ pgBackup * backup = (pgBackup * )parray_get (backup_list ,i );
260
300
261
301
/* Do not keep invalid backups by retention */
262
302
if (backup -> status != BACKUP_STATUS_OK &&
263
303
backup -> status != BACKUP_STATUS_DONE )
264
304
continue ;
265
305
266
- elog (VERBOSE ,"Mark backup %s for retention." ,base36enc (backup -> start_time ));
267
- parray_append (to_keep_list ,backup );
306
+ if (backup -> backup_mode == BACKUP_MODE_FULL )
307
+ continue ;
308
+
309
+ /* orphan backup cannot be in keep list */
310
+ if (!backup -> parent_backup_link )
311
+ continue ;
312
+
313
+ if (parray_bsearch (to_purge_list ,backup ,pgBackupCompareIdDesc ))
314
+ continue ;
315
+
316
+ /* if parent in purge_list, add backup to keep list */
317
+ if (parray_bsearch (to_purge_list ,
318
+ backup -> parent_backup_link ,
319
+ pgBackupCompareIdDesc ))
320
+ {
321
+ /* make keep list a bit sparse */
322
+ parray_append (to_keep_list ,backup );
323
+ continue ;
324
+ }
268
325
}
269
326
270
327
/* Message about retention state of backups
271
328
* TODO: Float is ugly, rewrite somehow.
272
329
*/
273
330
274
- /* sort keep_list and purge list */
275
- parray_qsort (to_keep_list ,pgBackupCompareIdDesc );
276
- parray_qsort (to_purge_list ,pgBackupCompareIdDesc );
277
-
278
331
cur_full_backup_num = 1 ;
279
332
for (i = 0 ;i < parray_num (backup_list );i ++ )
280
333
{
281
- char * action = "Ignore " ;
334
+ char * action = "Keep " ;
282
335
283
336
pgBackup * backup = (pgBackup * )parray_get (backup_list ,i );
284
337
285
- if (parray_bsearch (to_keep_list ,backup ,pgBackupCompareIdDesc ))
286
- action = "Keep" ;
287
-
288
338
if (parray_bsearch (to_purge_list ,backup ,pgBackupCompareIdDesc ))
289
- action = "Keep " ;
339
+ action = "Purge " ;
290
340
291
341
if (backup -> recovery_time == 0 )
292
342
actual_window = 0 ;
@@ -305,33 +355,21 @@ do_retention_internal(void)
305
355
if (backup -> backup_mode == BACKUP_MODE_FULL )
306
356
cur_full_backup_num ++ ;
307
357
}
358
+ }
308
359
309
- if (dry_run )
310
- gotofinish ;
311
-
312
- /* Extreme example of keep_list
313
- *
314
- *FULLc <- keep
315
- *PAGEb2 <- keep
316
- *PAGEb1 <- keep
317
- *PAGEa2 <- keep
318
- *PAGEa1 <- keep
319
- *FULLb <- in purge_list
320
- *FULLa <- in purge_list
321
- */
322
-
323
- /* Go to purge */
324
- if (delete_expired && !merge_expired )
325
- gotopurge ;
360
+ static void
361
+ do_retention_merge (parray * backup_list ,parray * to_keep_list ,parray * to_purge_list )
362
+ {
363
+ int i ;
364
+ int j ;
326
365
327
366
/* IMPORTANT: we can merge to only those FULL backup, that is NOT
328
367
* guarded by retention and final targets of such merges must be
329
368
* incremental backup that is guarded by retention !!!
330
369
*
331
- *
332
370
* PAGE4 E
333
371
* PAGE3 D
334
- * --------retention window ---
372
+ --------retention window ---
335
373
* PAGE2 C
336
374
* PAGE1 B
337
375
* FULL A
@@ -352,32 +390,9 @@ do_retention_internal(void)
352
390
353
391
/* keep list may shrink during merge */
354
392
if (!keep_backup )
355
- break ;
356
-
357
- elog (INFO ,"Consider backup %s for merge" ,base36enc (keep_backup -> start_time ));
358
-
359
- /* In keep list we are looking for incremental backups */
360
- if (keep_backup -> backup_mode == BACKUP_MODE_FULL )
361
- continue ;
362
-
363
- /* Retain orphan backups in keep_list */
364
- if (!keep_backup -> parent_backup_link )
365
393
continue ;
366
394
367
- /* If parent of current backup is also in keep list, go to the next */
368
- if (parray_bsearch (to_keep_list ,
369
- keep_backup -> parent_backup_link ,
370
- pgBackupCompareIdDesc ))
371
- {
372
- /* make keep list a bit sparse */
373
- elog (LOG ,"Sparsing keep list, remove %s" ,base36enc (keep_backup -> start_time ));
374
- parray_remove (to_keep_list ,i );
375
- i -- ;
376
- continue ;
377
- }
378
-
379
- elog (INFO ,"Lookup parents for backup %s" ,
380
- base36enc (keep_backup -> start_time ));
395
+ elog (INFO ,"Consider backup %s for merge" ,base36enc (keep_backup -> start_time ));
381
396
382
397
/* Got valid incremental backup, find its FULL ancestor */
383
398
full_backup = find_parent_full_backup (keep_backup );
@@ -473,9 +488,7 @@ do_retention_internal(void)
473
488
474
489
/* Try to remove merged incremental backup from both keep and purge lists */
475
490
parray_rm (to_purge_list ,from_backup ,pgBackupCompareId );
476
-
477
- if (parray_rm (to_keep_list ,from_backup ,pgBackupCompareId )&& (i >=0 ))
478
- i -- ;
491
+ parray_set (to_keep_list ,i ,NULL );
479
492
}
480
493
481
494
/* Cleanup */
@@ -484,11 +497,13 @@ do_retention_internal(void)
484
497
485
498
elog (INFO ,"Retention merging finished" );
486
499
487
- if (!delete_expired )
488
- gotofinish ;
500
+ }
489
501
490
- /* Do purging here */
491
- purge :
502
+ static void
503
+ do_retention_purge (parray * to_keep_list ,parray * to_purge_list )
504
+ {
505
+ int i ;
506
+ int j ;
492
507
493
508
/* Remove backups by retention policy. Retention policy is configured by
494
509
* retention_redundancy and retention_window
@@ -517,6 +532,10 @@ do_retention_internal(void)
517
532
518
533
pgBackup * keep_backup = (pgBackup * )parray_get (to_keep_list ,i );
519
534
535
+ /* item could have been nullified in merge */
536
+ if (!keep_backup )
537
+ continue ;
538
+
520
539
/* Full backup cannot be a descendant */
521
540
if (keep_backup -> backup_mode == BACKUP_MODE_FULL )
522
541
continue ;
@@ -557,14 +576,6 @@ do_retention_internal(void)
557
576
backup_deleted = true;
558
577
559
578
}
560
-
561
- finish :
562
- /* Cleanup */
563
- parray_walk (backup_list ,pgBackupFree );
564
- parray_free (backup_list );
565
- parray_free (to_keep_list );
566
- parray_free (to_purge_list );
567
-
568
579
}
569
580
570
581
/* Purge WAL */