Class: Foundries::Snapshot::Store

Inherits:
Object
  • Object
show all
Defined in:
lib/foundries/snapshot/store.rb

Instance Method Summary collapse

Constructor Details

#initialize(preset_name, adapter: Snapshot.adapter, storage_path: Snapshot.storage_path, source_paths: Snapshot.source_paths) ⇒ Store

Returns a new instance of Store.



8
9
10
11
12
13
14
15
16
17
18
# File 'lib/foundries/snapshot/store.rb', line 8

def initialize(preset_name, adapter: Snapshot.adapter,
  storage_path: Snapshot.storage_path,
  source_paths: Snapshot.source_paths)
  @preset_name = preset_name.to_s
  @adapter = adapter
  @storage_path = storage_path
  @fingerprint = Fingerprint.new(
    adapter.instance_variable_get(:@connection),
    source_paths: source_paths
  )
end

Instance Method Details

#cached?Boolean

Returns:

  • (Boolean)


20
21
22
23
24
# File 'lib/foundries/snapshot/store.rb', line 20

def cached?
  cache_dir.exist? &&
    cache_dir.join(".fingerprint").exist? &&
    cache_dir.join(".fingerprint").read.strip == @fingerprint.current
end

#captureObject



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
# File 'lib/foundries/snapshot/store.rb', line 46

def capture
  spoiled = spoiled_tables
  unless spoiled.empty?
    warn "[Foundries] Not caching preset :#{@preset_name} — it wrote to " \
      "#{spoiled.join(", ")}, which already held rows when it ran. " \
      "Only tables the preset fills from empty can be snapshotted, so " \
      "caching this would restore an incomplete tree."
    return
  end

  tables = @capturable_tables || @adapter.table_names

  tmp_dir = Pathname.new("#{cache_dir}.#{$$}.tmp")
  tmp_dir.mkpath

  tables.each do |table|
    tmp_dir.join("#{table}.dat").open("w") do |f|
      @adapter.capture(table, f)
    end
  end

  tmp_dir.join(".fingerprint").write(@fingerprint.current)

  # Atomic swap
  FileUtils.rm_rf(cache_dir) if cache_dir.exist?
  FileUtils.mv(tmp_dir, cache_dir)
end

#record_empty_tablesObject

Record which tables are empty before the preset block runs. Only these tables will be captured after the block completes.

The already-populated tables are counted too, so #capture can tell whether the preset wrote into one of them. A preset that only updates existing rows leaves the count unchanged and slips past this check; presets insert, so the count is a good enough signal.



33
34
35
36
37
38
39
40
41
42
43
44
# File 'lib/foundries/snapshot/store.rb', line 33

def record_empty_tables
  @capturable_tables = []
  @preexisting_counts = {}

  @adapter.table_names.each do |table|
    if @adapter.empty?(table)
      @capturable_tables << table
    else
      @preexisting_counts[table] = @adapter.count(table)
    end
  end
end

#restoreObject



74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/foundries/snapshot/store.rb', line 74

def restore
  @adapter.disable_referential_integrity do
    cache_dir.glob("*.dat").each do |file|
      next unless file.size > 0

      table = file.basename(".dat").to_s
      file.open("r") do |f|
        @adapter.restore(table, f)
      end
      @adapter.reset_sequence(table)
    end
  end
end