Module: Vivarium::RawStore
- Defined in:
- lib/vivarium/raw_store.rb
Overview
Reads and writes the vivarium-raw file format: a single JSON metadata line followed by fixed-size (EVENT_STRUCT_SIZE) event_t records. The record layout mirrors the C struct event_t so it round-trips losslessly.
Defined Under Namespace
Classes: FormatError
Constant Summary collapse
- FORMAT =
"vivarium-raw"- VERSION =
1- PACK_FMT =
struct event_t (296B)
"Q<L<L<a16a256Q<"
Class Method Summary collapse
-
.dump(io, events:, meta:) ⇒ Object
io: a binary-writable IO.
-
.load(io) ⇒ Object
Returns { meta: Hash(symbol keys), events: [RawEvent, …] }.
- .pack_record(ev) ⇒ Object
- .unpack_record(bytes) ⇒ Object
Class Method Details
.dump(io, events:, meta:) ⇒ Object
io: a binary-writable IO. meta: session metadata Hash.
46 47 48 49 50 51 52 53 54 55 |
# File 'lib/vivarium/raw_store.rb', line 46 def self.dump(io, events:, meta:) header = .merge( format: FORMAT, version: VERSION, event_struct_size: EVENT_STRUCT_SIZE, event_count: events.size ) io.binmode io.write(JSON.generate(header)) io.write("\n") events.each { |ev| io.write(pack_record(ev)) } end |
.load(io) ⇒ Object
Returns { meta: Hash(symbol keys), events: [RawEvent, …] }.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 |
# File 'lib/vivarium/raw_store.rb', line 58 def self.load(io) io.binmode line = io.gets raise FormatError, "empty file" if line.nil? begin = JSON.parse(line, symbolize_names: true) rescue JSON::ParserError => e raise FormatError, "header is not valid JSON: #{e.}" end raise FormatError, "missing JSON object header" unless .is_a?(Hash) unless [:format] == FORMAT raise FormatError, "format=#{[:format].inspect} (expected #{FORMAT.inspect})" end events = [] while (rec = io.read(EVENT_STRUCT_SIZE)) break if rec.bytesize < EVENT_STRUCT_SIZE events << unpack_record(rec) end { meta: , events: events } end |
.pack_record(ev) ⇒ Object
22 23 24 25 26 27 28 29 |
# File 'lib/vivarium/raw_store.rb', line 22 def self.pack_record(ev) [ ev.ktime_ns, ev.pid, ev.tid, ev.event_name.to_s.b.ljust(EVENT_NAME_SIZE, "\x00")[0, EVENT_NAME_SIZE], ev.payload.to_s.b.ljust(EVENT_PAYLOAD_SIZE, "\x00")[0, EVENT_PAYLOAD_SIZE], ev.dropped_since_last ].pack(PACK_FMT) end |
.unpack_record(bytes) ⇒ Object
31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/vivarium/raw_store.rb', line 31 def self.unpack_record(bytes) bytes = bytes.to_s.b bytes = bytes.ljust(EVENT_STRUCT_SIZE, "\x00") if bytes.bytesize < EVENT_STRUCT_SIZE RawEvent.new( ktime_ns: bytes[EVENT_TS_OFFSET, EVENT_TS_SIZE].unpack1("Q<"), pid: bytes[EVENT_PID_OFFSET, 4].unpack1("L<"), tid: bytes[EVENT_TID_OFFSET, 4].unpack1("L<"), event_name: Vivarium.c_string(bytes[EVENT_NAME_OFFSET, EVENT_NAME_SIZE]), payload: bytes[EVENT_PAYLOAD_OFFSET, EVENT_PAYLOAD_SIZE].to_s.b, dropped_since_last: bytes[EVENT_DROPPED_OFFSET, 8].unpack1("Q<") ) end |