Class: MongoOplogBackup::Restore

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

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Restore

Returns a new instance of Restore.



17
18
19
# File 'lib/mongo_oplog_backup/restore.rb', line 17

def initialize(config)
  @config = config
end

Instance Attribute Details

#configObject (readonly)

Returns the value of attribute config.



7
8
9
# File 'lib/mongo_oplog_backup/restore.rb', line 7

def config
  @config
end

Instance Method Details

#backup_folderObject



9
10
11
# File 'lib/mongo_oplog_backup/restore.rb', line 9

def backup_folder
  File.join(config.backup_dir)
end

#oplog_restore_folderObject



13
14
15
# File 'lib/mongo_oplog_backup/restore.rb', line 13

def oplog_restore_folder
  File.join(backup_folder, 'tmp-restore')
end

#perform(mode, options = {}) ⇒ Object



96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/mongo_oplog_backup/restore.rb', line 96

def perform(mode, options={})
  if options[:oplogLimit]
    raise ArgumentError, "oplogLimit is not a timestamp: eg. <seconds>[:ordinal]" unless options[:oplogLimit] =~ /\A\d+(?::\d+)?\z/
  end

  if mode == :oplog
    restore_oplogs(backup_folder, options)
  elsif mode == :full
    restore_dump(backup_folder, options)
    restore_oplogs(backup_folder, options)
  end
end

#restore_dump(dir, options = {}) ⇒ Object



81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/mongo_oplog_backup/restore.rb', line 81

def restore_dump(dir, options={})
  restore_args = ['--stopOnError']
  restore_args << '--noIndexRestore' if !!config.options[:noIndexRestore]
  restore_args << '--gzip' if config.use_compression?
  restore_args << File.join(dir, 'dump')

  MongoOplogBackup.log.debug "Starting full restore..."
  status = config.mongorestore(restore_args).status
  if status != 0
    MongoOplogBackup.log.error("Mongorestore failed.")
    raise 'Full restore failed.'
  end
  MongoOplogBackup.log.debug "Full restore complete."
end

#restore_oplogs(dir, options = {}) ⇒ Object

Given a directory of oplog dumps generated by the backup feature, iteratively mongorestore them. Mongorestore <3.4 expects a file named oplog.bson the directory specified Mongorestore 3.4 adds support for –oplogFile parameter, which simplifies things.



25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/mongo_oplog_backup/restore.rb', line 25

def restore_oplogs(dir, options={})
  default_restore_args = ['--stopOnError', '--oplogReplay']
  default_restore_args << '--noIndexRestore' if !!config.options[:noIndexRestore]
  if options[:oplogLimit]
    default_restore_args += ['--oplogLimit', options[:oplogLimit]]
    oplog_limit = BSON::Timestamp.from_string(options[:oplogLimit])
  end

  oplog_start_at = BSON::Timestamp.from_string(config.options[:oplogStartAt]) if config.options[:oplogStartAt]

  source_files = Oplog.find_oplogs(dir)

  validate_continuity!(source_files)

  MongoOplogBackup.log.debug "Starting oplog restore..."
  source_files.each do |filename|
    # TODO: mongorestore 3.4 supports --oplogFile

    unless oplog_start_at.nil?
      timestamps = Oplog.timestamps_from_filename(filename)
      if timestamps[:last] <= oplog_start_at
        MongoOplogBackup.log.debug "Skipping batch: #{filename}. Last op in batch (ts: #{timestamps[:last]}) is before oplogStartAt: #{oplog_start_at}"
        next
      end
    end
    unless oplog_limit.nil?
      timestamps = Oplog.timestamps_from_filename(filename)
      if timestamps[:first] > oplog_limit
        MongoOplogBackup.log.debug "Skipping batch: #{filename}. First op in batch (ts: #{timestamps[:first]}) is after oplogLimit: #{oplog_limit}"
        next
      end
    end

    temp_file_path = create_temp_oplog_dir(dir, filename)
    oplog_dir_path = File.dirname(temp_file_path)

    restore_args = default_restore_args.dup
    restore_args << '--gzip' if Oplog.gzip_fingerprint(filename)
    restore_args << oplog_dir_path
    status = config.mongorestore(restore_args).status
    if status != 0
      MongoOplogBackup.log.error("Mongorestore failed during oplog restore. Aborting. Exit code: #{status}")
      raise 'Oplog restore failed.'
    end

    begin
      File.unlink(temp_file_path)
      Dir.rmdir(oplog_dir_path)
    rescue SystemCallError => e
      MongoOplogBackup.log.error("Clean-up error for '#{temp_file_path}. #{e.message}")
      raise
    end
  end
  MongoOplogBackup.log.debug "Oplog restore complete."
end