Module: Igniter::Store::NativeFileBackendSnapshotSupport

Includes:
WireProtocol
Included in:
FileBackend
Defined in:
lib/igniter/store/file_backend.rb

Overview

Patch native FileBackend to add snapshot support. The native class exposes write_fact, replay (WAL-only), and close. We add: write_snapshot, snapshot_path, SNAPSHOT_SUFFIX, and a snapshot-aware replay that merges snapshot facts with the WAL delta.

Deduplication uses the original fact id embedded in the snapshot JSON (not the id on the reconstructed Fact object, which is regenerated by Fact.build in native mode).

Constant Summary collapse

SNAPSHOT_SUFFIX =
".snap"

Constants included from WireProtocol

WireProtocol::FRAME_CRC_SIZE, WireProtocol::FRAME_HEADER_SIZE

Instance Method Summary collapse

Methods included from WireProtocol

#encode_frame, #read_frame

Instance Method Details

#replace_with_snapshot!(facts) ⇒ Object

Pruning-safe barrier for native-backed stores. Writes the snapshot atomically, then truncates the WAL file so that dropped facts cannot be replayed on reopen. The native write handle is still open; after truncation, the next native write will restart from offset 0 (append mode semantics).



182
183
184
185
# File 'lib/igniter/store/file_backend.rb', line 182

def replace_with_snapshot!(facts)
  write_snapshot(facts)
  File.open(@_ruby_path, "wb") {}   # truncate WAL
end

#replayObject

Merges snapshot facts (if any) with WAL facts not already in the snapshot. Deduplication is by original id read directly from the JSON frame, because Fact.from_h in native mode regenerates ids via Fact.build.



204
205
206
207
208
209
# File 'lib/igniter/store/file_backend.rb', line 204

def replay
  snapshot_facts, seen_ids = load_native_snapshot
  wal_facts = _native_replay_wal
  delta = wal_facts.reject { |f| seen_ids.include?(f.id) }
  snapshot_facts + delta
end

#snapshot_pathObject



173
174
175
# File 'lib/igniter/store/file_backend.rb', line 173

def snapshot_path
  @_ruby_path + SNAPSHOT_SUFFIX
end

#write_snapshot(facts) ⇒ Object



187
188
189
190
191
192
193
194
195
196
197
198
199
# File 'lib/igniter/store/file_backend.rb', line 187

def write_snapshot(facts)
  tmp = "#{snapshot_path}.tmp"
  File.open(tmp, "wb") do |f|
    header = JSON.generate({
      type:       "snapshot_header",
      fact_count: facts.size,
      written_at: Process.clock_gettime(Process::CLOCK_REALTIME)
    })
    f.write(encode_frame(header))
    facts.each { |fact| f.write(encode_frame(JSON.generate(fact.to_h))) }
  end
  FileUtils.mv(tmp, snapshot_path)
end