Class: S3snapshot::BackupManager

Inherits:
SyncOp
  • Object
show all
Defined in:
lib/s3snapshot/backup_manager.rb

Overview

Handles retrieving all current backups and performing operations on them. This object is stateful, once snapshots are loaded it is cached. Create a new instance or call clear_snapshots to force a reload from aws

Constant Summary collapse

SECONDS_DAY =

Number of seconds in a day

60*60*24
SECONDS_WEEK =
SECONDS_DAY * 7

Constants inherited from SyncOp

SyncOp::COMPLETE_EXTENSION, SyncOp::COMPLETE_FILE, SyncOp::COMPLETE_MARKER

Instance Method Summary collapse

Methods inherited from SyncOp

#aws, #bucket, #complete_path, #complete_prefix, #timepath

Constructor Details

#initialize(aws_id, aws_key, bucket_name) ⇒ BackupManager

Returns a new instance of BackupManager.



19
20
21
# File 'lib/s3snapshot/backup_manager.rb', line 19

def initialize(aws_id, aws_key, bucket_name)
  super(aws_id, aws_key, bucket_name)
end

Instance Method Details

#clean(prefix) ⇒ Object

Removes all incomplete backups. Use wisely, will blitz a backup in progress



99
100
101
102
103
104
105
# File 'lib/s3snapshot/backup_manager.rb', line 99

def clean(prefix)
  snapshots(prefix).each do |time, complete|
    unless complete
      remove(prefix, time)
    end
  end
end

#clear_snapshots(prefix) ⇒ Object

clear the local cached copy of the snapshot



73
74
75
# File 'lib/s3snapshot/backup_manager.rb', line 73

def clear_snapshots(prefix)
  @snapshots[prefix] = nil
end

#complete?(prefix, time) ⇒ Boolean

Returns true if the backup is complete, false otherwise

Returns:

  • (Boolean)


80
81
82
83
# File 'lib/s3snapshot/backup_manager.rb', line 80

def complete?(prefix, time)
  value = snapshots(prefix)[time]
  value.nil? ? false : value
end

#exists?(prefix, time) ⇒ Boolean

Returns true if the backup exists

Returns:

  • (Boolean)


88
89
90
91
92
93
# File 'lib/s3snapshot/backup_manager.rb', line 88

def exists?(prefix, time)
  !snapshots(prefix)[time].nil?
  #      backups = bucket.files.all(:prefix => timepath(prefix, time))
  #      
  #      !backups.nil? && backups.length > 0
end

#latest(prefix) ⇒ Object

Get the latest completed backup for the given prefix. Will return nil if one isn’t available



60
61
62
63
64
65
66
67
68
# File 'lib/s3snapshot/backup_manager.rb', line 60

def latest(prefix)
  snapshots(prefix).reverse.each do  |time, complete|
    if complete
      return time
    end
  end
  
  nil
end

#list_files(prefix, time) ⇒ Object

Return all files that exist in this backup bucket with the given time



132
133
134
# File 'lib/s3snapshot/backup_manager.rb', line 132

def list_files(prefix, time)
  bucket.files.all(:prefix => timepath(prefix, time) )
end

#prefixesObject

Get all prefixes in the bucket



26
27
28
# File 'lib/s3snapshot/backup_manager.rb', line 26

def prefixes
  bucket.files.all(:delimiter => "/").common_prefixes
end

#remove(prefix, timestamp) ⇒ Object

Delete all files from a snapshot. Will remove the complete file first to avoid other clients using the backup



110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
# File 'lib/s3snapshot/backup_manager.rb', line 110

def remove(prefix, timestamp)
  complete_marker =  bucket.files.get(complete_path(prefix, timestamp))
  
  #Destroy the complete marker.  This prevents other clients from thinking this backup is complete when the s3 bucket is read
  unless complete_marker.nil?
    complete_marker.destroy
  end
  
  files = list_files(prefix, timestamp)
  
  files.each do |file|
    file.destroy
  end
  
  get_snapshot(prefix).delete(timestamp)
  
end

#roll(prefix, num_days, num_weeks, day_of_week) ⇒ Object

Perform a rolling delete for the given prefix. Keeps the “newest” daily backup for the given day, and keeps a backup for the day of the week specified by day of week. day_of_week follows cron style syntax, 0 = sunday and 6 = saturday



141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
# File 'lib/s3snapshot/backup_manager.rb', line 141

def roll(prefix, num_days, num_weeks, day_of_week)
  
  start =  TimeFactory.utc_time
  
  start = Time.utc(start.year, start.month, start.day)
  
  clean(prefix)
  
  merge_days(prefix, start)
  
  
  snaps = snapshots(prefix)
  
  #Nothing to do
  if snaps.nil? ||snaps.empty?
    return
  end
  
  newest_time =snaps.keys.last
  
  #Truncate the oldest daily to 00 hours minutes and seconds based on the "newest" completed backup after the merge
  oldest_daily = newest_time - SECONDS_DAY*num_days
  
  oldest_daily = Time.utc(oldest_daily.year, oldest_daily.month, oldest_daily.day)
  
  #Truncate the oldest weekly to 00 hours minutes and seconds
  oldest_weekly = newest_time - SECONDS_WEEK*num_weeks
  
  oldest_weekly = Time.utc(oldest_weekly.year, oldest_weekly.month, oldest_weekly.day)
  
  
  #Now iterate over every day and keep the number of days.  After that only keep the value that's on the number of weeks
  snaps.each do |time, complete|
    
    #We're done, we've fallen into the day range
    if time >= oldest_daily
      break
    end
    
    #Is older than the oldest daily,or not the right day of the week so should be deleted
    if time < oldest_weekly || !same_day(time, day_of_week)
      remove(prefix, time)
    end
    
  end
end

#snapshots(prefix) ⇒ Object

returns a map of snapshots. The key is the time, the value is a boolean signaling if it’s complete



33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
# File 'lib/s3snapshot/backup_manager.rb', line 33

def snapshots(prefix)
  
  prefix_snap = get_snapshot(prefix)
  
  unless prefix_snap.nil?
    return prefix_snap
  end
  
  prefix_snap = Dictionary.new
  
  timestamps(prefix).each do |timestamp|
    
    time = Time.parse(timestamp)
    
    prefix_snap[time]  = read_complete?(prefix, time)
    
  end
  
  set_snapshot(prefix, prefix_snap)
  
  prefix_snap
  
end