Class: SnapshotSet

Inherits:
Object
  • Object
show all
Defined in:
lib/snapshot_set.rb

Overview

A set of snapshots. This class has methods that allow to determine which snapshots must be deleted in order to clean up space.

Defined Under Namespace

Classes: Snapshot

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(snapshot_names) ⇒ SnapshotSet

Initialize this class with an unordered set of snapshot names. Names that are of the form ‘YYYYMMDDHHMM*’ or ‘YYYYMMDD*’ will be treated as timestamps to which time based rules apply.



47
48
49
50
51
# File 'lib/snapshot_set.rb', line 47

def initialize(snapshot_names)
  @snapshots = snapshot_names.
    map { |name| Snapshot.new(name) }.
    sort_by { |snapshot| snapshot.time }
end

Instance Attribute Details

#snapshotsObject (readonly)

Returns the value of attribute snapshots.



12
13
14
# File 'lib/snapshot_set.rb', line 12

def snapshots
  @snapshots
end

Instance Method Details

#gpc(keep_specification, now = Time.now) ⇒ Object

Computes snapshots to keep according to grandparent-parent-child algorithm. If called with

set.gpc(1.day: 3, 1.week: 3)

it will return a snapshot set that contains (ideally) 6 snapshots, 3 in the current week starting one day ago, spaced out by one day. The other three will be on week boundaries starting one week ago and going back 3 weeks.

The algorithm will also return all the snapshots that are less than one day ago.



78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/snapshot_set.rb', line 78

def gpc(keep_specification, now=Time.now)
  keep_snapshot_names = Set.new

  # No snapshots, nothing to keep
  if snapshots.empty?
    return self.class.new([])
  end

  # Filter snapshots that we need to keep according to keep_specification
  keep_specification.each do |interval, keep_number|
    next if keep_number <= 0
    
    # We would like to sample the existing snapshots at regular offsets
    # (n * interval). 
    sampling_points = Array(1..keep_number).map { |offset| now - (offset*interval) }
    
    # For all sampling points, we'll compute the best snapshot to keep. 
    winners = sampling_points.map { |sp| 
      snapshots.map { |sh| [(sh.time-sp).abs, sh] }.    # <score, snapshot>
        sort_by { |score, sh| score }.                  # sort by score
        first.                                          # best match
        last                                            # snapshot
    }
    
    keep_snapshot_names += winners.map(&:name)
  end
  
  # Add snapshots that are within [now, smallest_interval]
  smallest_interval = keep_specification.map { |i,c| i }.min
  keep_snapshot_names += snapshots.
    select { |snapshot| snapshot.time > now-smallest_interval }.
    map(&:name)
  
  self.class.new(keep_snapshot_names.to_a)
end

#sizeObject

Returns the size of this set.



55
56
57
# File 'lib/snapshot_set.rb', line 55

def size
  snapshots.size
end

#to_aObject

Returns the set as an array of snapshot names.



61
62
63
# File 'lib/snapshot_set.rb', line 61

def to_a
  snapshots.map(&:name)
end