@@ -175,6 +175,8 @@ int do_retention(void)
175175if (delete_wal && !dry_run )
176176do_retention_wal ();
177177
178+ /* TODO: consider dry-run flag */
179+
178180if (!backup_merged )
179181elog (INFO ,"There are no backups to merge by retention policy" );
180182
@@ -203,6 +205,8 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
203205int i ;
204206time_t current_time ;
205207
208+ parray * redundancy_full_backup_list = NULL ;
209+
206210/* For retention calculation */
207211uint32 n_full_backups = 0 ;
208212int cur_full_backup_num = 0 ;
@@ -228,8 +232,19 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
228232backup -> status == BACKUP_STATUS_DONE ))
229233{
230234n_full_backups ++ ;
235+
236+ if (n_full_backups <=instance_config .retention_redundancy )
237+ {
238+ if (!redundancy_full_backup_list )
239+ redundancy_full_backup_list = parray_new ();
240+
241+ parray_append (redundancy_full_backup_list ,backup );
242+ }
231243}
232244}
245+ /* Sort list of full backups to keep */
246+ if (redundancy_full_backup_list )
247+ parray_qsort (redundancy_full_backup_list ,pgBackupCompareIdDesc );
233248}
234249
235250if (instance_config .retention_window > 0 )
@@ -242,8 +257,20 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
242257for (i = (int )parray_num (backup_list )- 1 ;i >=0 ;i -- )
243258{
244259
260+ bool redundancy_keep = false;
245261pgBackup * backup = (pgBackup * )parray_get (backup_list , (size_t )i );
246262
263+ /* check if backups FULL parent is in redundancy list */
264+ if (redundancy_full_backup_list )
265+ {
266+ pgBackup * full_backup = find_parent_full_backup (backup );
267+
268+ if (full_backup && parray_bsearch (redundancy_full_backup_list ,
269+ full_backup ,
270+ pgBackupCompareIdDesc ))
271+ redundancy_keep = true;
272+ }
273+
247274/* Remember the serial number of latest valid FULL backup */
248275if (backup -> backup_mode == BACKUP_MODE_FULL &&
249276(backup -> status == BACKUP_STATUS_OK ||
@@ -256,7 +283,8 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
256283 * TODO: consider that ERROR backup most likely to have recovery_time == 0
257284 */
258285if ((days_threshold == 0 || (days_threshold > backup -> recovery_time ))&&
259- (instance_config .retention_redundancy <= (n_full_backups - cur_full_backup_num )))
286+ //(instance_config.retention_redundancy <= (n_full_backups - cur_full_backup_num)))
287+ (instance_config .retention_redundancy == 0 || !redundancy_keep ))
260288{
261289/* This backup is not guarded by retention
262290 *
@@ -344,6 +372,7 @@ do_retention_internal(parray *backup_list, parray *to_keep_list, parray *to_purg
344372else
345373actual_window = (current_time - backup -> recovery_time )/(60 * 60 * 24 );
346374
375+ /* TODO: add ancestor(chain full backup) ID */
347376elog (INFO ,"Backup %s, mode: %s, status: %s. Redundancy: %i/%i, Time Window: %ud/%ud. %s" ,
348377base36enc (backup -> start_time ),
349378pgBackupGetBackupMode (backup ),