Skip to content

Commit ae3dbea

Browse files
committed
Rewrite retention algorithm to iterate forward
This helps identify the pattern for the oldest backups and then blend cleanly into the increased retention on the newer backups.
1 parent 9d8a276 commit ae3dbea

File tree

2 files changed

+13
-15
lines changed

2 files changed

+13
-15
lines changed

lib/Date/RetentionPolicy.pm

Lines changed: 10 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -180,34 +180,32 @@ sub _mark_for_retention {
180180
my ($self, $reference_date, $rule, $list, $trace)= @_;
181181
my ($interval, $duration, $reach_factor)= @{$rule}{'interval','duration','reach_factor'};
182182
$reach_factor= $self->reach_factor unless defined $reach_factor;
183-
my $next_date= $reference_date->clone;
183+
my $next_date= $reference_date->clone->subtract(%$duration)->add(%$interval);
184184
my $epoch= $next_date->epoch;
185-
my $search_idx= $#$list; # high value, iterates downward
186-
my $final_epoch= $next_date->clone->subtract(%$duration)->epoch;
187-
my $next_epoch= $next_date->subtract(%$interval)->epoch;
188-
my $radius= ($epoch - $next_epoch) * $reach_factor;
185+
my $search_idx= 0;
186+
my $next_epoch= $next_date->add(%$interval)->epoch;
187+
my $radius= -($epoch - $next_epoch) * $reach_factor;
189188
my $drift= 0; # only used for auto_sync
190189
my $rule_key;
191190

192-
# Iterating backward accross date intervals and also input points, which is awkward.
193191
# The epoch variables track the current date interval, and the _idx
194192
# variables track our position in the list.
195-
while ($epoch > $final_epoch && $search_idx >= 0) {
193+
while ($epoch-abs($drift) <= $reference_date->epoch && $search_idx < @$list) {
196194
my $best;
197-
for (my $i= $search_idx; $i >= 0 and $list->[$i][0] > $epoch+$drift-$radius; --$i) {
198-
if ($list->[$i][0] <= $epoch+$drift+$radius
195+
for (my $i= $search_idx; $i < @$list and $list->[$i][0] < $epoch+$drift+$radius; ++$i) {
196+
if ($list->[$i][0] >= $epoch+$drift-$radius
199197
and (!defined $best or abs($list->[$i][0] - ($epoch+$drift)) < abs($list->[$best][0] - ($epoch+$drift)))
200198
) {
201199
$best= $i;
202200
}
203201
# update the start_idx for next interval iteration
204-
$search_idx= $i-1 if $list->[$i][0] > $next_epoch+$drift+$radius;
202+
$search_idx= $i+1 if $list->[$i][0] < $next_epoch-$radius*2;
205203
}
206204
if (defined $best) {
207205
$list->[$best][2]= 1; # mark as a keeper
208206
# If option enabled, drift toward the time we found, so that gap between next
209207
# is closer to $interval
210-
$drift += ($list->[$best][0] - ($epoch+$drift))/2
208+
$drift= $list->[$best][0] - $epoch
211209
if $self->auto_sync;
212210
}
213211
if ($trace) {
@@ -221,7 +219,7 @@ sub _mark_for_retention {
221219
push @{$trace->{$rule_key}{interval}}, { epoch => $epoch, best => $best, drift => $drift };
222220
}
223221
$epoch= $next_epoch;
224-
$next_epoch= $next_date->subtract(%$interval)->epoch;
222+
$next_epoch= $next_date->add(%$interval)->epoch;
225223

226224
# if auto_sync enabled, cause drift to decay back toward 0
227225
$drift= int($drift * 7/8)

t/11-multi-prune.t

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ my @tests= (
2020
keep => [
2121
date_series('2018-01-01 00:00', '2017-12-18 00:01', hours => 6),
2222
date_series('2017-12-18 00:00', '2017-11-01 00:01', days => 1),
23-
date_series('2017-10-30 00:00', '2017-01-01 00:01', days => 7),
23+
date_series('2017-10-29 00:00', '2017-01-01 00:01', days => 7),
2424
],
2525
reach => .5,
2626
},
@@ -33,9 +33,9 @@ for my $t (@tests) {
3333
reach_factor => $t->{reach}
3434
] );
3535
my @list= @{ $t->{dates} };
36-
$rp->prune(\@list);
36+
my $pruned= $rp->prune(\@list);
3737
is_deeply( \@list, $t->{keep}, 'kept' )
38-
or diag explain $t->{keep};
38+
or diag $rp->visualize($t->{dates});
3939
};
4040
}
4141

0 commit comments

Comments
 (0)