1
|
1 |
|
import logging |
|
|
|
|
2
|
|
|
|
3
|
1 |
|
log = logging.getLogger(__name__) |
4
|
|
|
|
5
|
|
|
|
6
|
1 |
|
class CompactTask(object): |
7
|
1 |
|
@classmethod |
8
|
|
|
def run(cls, period, key, revisions, policy): |
9
|
|
|
log.info('Compacting %s: %r - len(revisions): %r, policy: %r', period, key, len(revisions), policy) |
10
|
|
|
|
11
|
|
|
# Retrieve options |
12
|
|
|
p_maximum = policy.get('maximum') |
13
|
|
|
|
14
|
|
|
if p_maximum is None: |
15
|
|
|
raise ValueError('Policy "%s" is missing the "maximum" attribute' % period) |
16
|
|
|
|
17
|
|
|
# Sort revisions by timestamp |
18
|
|
|
revisions = sorted(revisions, key=lambda b: b.timestamp) |
19
|
|
|
|
20
|
|
|
# Build list of revisions, sorted by time to closest revision |
21
|
|
|
close_revisions = cls.close_revisions(revisions) |
22
|
|
|
|
23
|
|
|
# Remove closest revisions (by timestamp) until maximum count is reached |
24
|
|
|
for x in xrange(len(revisions) - p_maximum): |
|
|
|
|
25
|
|
|
distance, _, revision = close_revisions[x] |
|
|
|
|
26
|
|
|
|
27
|
|
|
# Delete revision (metadata + contents) |
28
|
|
|
revision.delete() |
29
|
|
|
|
30
|
1 |
|
@staticmethod |
31
|
|
|
def close_revisions(revisions): |
32
|
|
|
close_revisions = [] |
33
|
|
|
|
34
|
|
|
# Calculate seconds between revisions |
35
|
|
|
for x in xrange(len(revisions)): |
|
|
|
|
36
|
|
|
if x + 1 >= len(revisions): |
37
|
|
|
continue |
38
|
|
|
|
39
|
|
|
left = revisions[x] |
40
|
|
|
right = revisions[x + 1] |
41
|
|
|
|
42
|
|
|
# Calculate time between `left` and `right` |
43
|
|
|
span = right.timestamp - left.timestamp |
44
|
|
|
|
45
|
|
|
# Append item to list |
46
|
|
|
close_revisions.append((span.total_seconds(), left, right)) |
47
|
|
|
|
48
|
|
|
# Sort by closest revisions first |
49
|
|
|
return sorted(close_revisions, key=lambda item: item[0]) |
50
|
|
|
|
Cyclic imports may cause partly loaded modules to be returned. This might lead to unexpected runtime behavior which is hard to debug.