Class: MongoOplogBackup::Rotate

Inherits:
Object
  • Object
show all
Includes:
Lockable
Defined in:
lib/mongo_oplog_backup/rotate.rb

Constant Summary collapse

DAY =
86400
RECOVERY_POINT_OBJECTIVE =

Longest month + 1

32 * DAY
KEEP_MINIMUM_SETS =

Current & Previous

2
BACKUP_DIR_NAME_FORMAT =
/\Abackup-\d+:\d+\z/

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from Lockable

included, #lock

Constructor Details

#initialize(config) ⇒ Rotate

Returns a new instance of Rotate.



13
14
15
16
17
18
19
20
21
22
# File 'lib/mongo_oplog_backup/rotate.rb', line 13

def initialize(config)
  @config = config
  @dry_run = !!@config.options[:dryRun]
  @backup_list = find_backup_directories
  if @config.options[:keepDays].nil?
    @recovery_point_objective = RECOVERY_POINT_OBJECTIVE
  else
    @recovery_point_objective = @config.options[:keepDays] * DAY
  end
end

Instance Attribute Details

#backup_listObject (readonly)

Returns the value of attribute backup_list.



6
7
8
# File 'lib/mongo_oplog_backup/rotate.rb', line 6

def backup_list
  @backup_list
end

#configObject (readonly)

Returns the value of attribute config.



6
7
8
# File 'lib/mongo_oplog_backup/rotate.rb', line 6

def config
  @config
end

Instance Method Details

#current_backup_nameObject



24
25
26
27
28
29
30
31
32
# File 'lib/mongo_oplog_backup/rotate.rb', line 24

def current_backup_name
  if @current_backup_name.nil?
    state_file = config.global_state_file
    state = JSON.parse(File.read(state_file)) rescue nil
    state ||= {}
    @current_backup_name = state['backup']
  end
  @current_backup_name
end

#filter_for_deletion(source_list) ⇒ Array<Pathname]

Returns Array<Pathname].

Parameters:

  • source_list (Array<Pathname>)

    List of Pathnames for the full backup sets in the backup directory.

Returns:

  • (Array<Pathname])

    Array<Pathname]



67
68
69
70
71
72
73
# File 'lib/mongo_oplog_backup/rotate.rb', line 67

def filter_for_deletion(source_list)
  source_list = source_list.sort.reverse.drop(KEEP_MINIMUM_SETS) # Keep a minimum number of full backups
  # The most recent dir might not be the active one (eg. if the mongodump fails). Ensure that it is excluded.
  source_list = source_list.reject { |path| path.basename.to_s == current_backup_name }

  source_list.select {|path| age_of_backup_in_seconds(path.basename) > @recovery_point_objective }
end

#find_backup_directoriesArray<Pathname>

Lists subdirectories in the backup location that match the backup set naming format and appear to have completed successfully.

Returns:

  • (Array<Pathname>)

    backup directories.



58
59
60
61
62
63
# File 'lib/mongo_oplog_backup/rotate.rb', line 58

def find_backup_directories
  dirs = Pathname.new(@config.backup_dir).children.select(&:directory?)
  dirs = dirs.select { |dir| dir.basename.to_s =~ BACKUP_DIR_NAME_FORMAT }
  dirs = dirs.select { |dir| File.exist?(File.join(dir, 'state.json')) }
  dirs.sort
end

#performObject



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

def perform
  lock(config.global_lock_file) do
    MongoOplogBackup.log.info "Rotating out old backups."

    if @backup_list.count >= 0 && @backup_list.count <= KEEP_MINIMUM_SETS
      MongoOplogBackup.log.info "Too few backup sets to automatically rotate."
    elsif @backup_list.count > KEEP_MINIMUM_SETS
      filter_for_deletion(@backup_list).each do |path|
        MongoOplogBackup.log.info "#{@dry_run ? '[DRYRUN] Would delete' : 'Deleting'} #{path}."
        begin
          FileUtils.remove_entry_secure(path) unless @dry_run
        rescue StandardError => e
          MongoOplogBackup.log.error "Delete failed: #{e.message}"
        end
      end
    end

    MongoOplogBackup.log.info "Rotating out old backups completed."
  end
end