tiny.trace.Session
Defined in session.
API (26)
Actions
Public operations.
allocationboundaryBytesAlloccheckpointCapturecheckpointRestoredeinitfreefunctionEnterfunctionExitinitOffinitRecordinitReplayreplayProgresssafepointsessionEndsessionStartuserEventverifyReplayComplete
Fields and members
Public fields and members.
Source
Source: lib/trace/src/session.zig:17
zig
pub const Session = struct { allocator: Allocator, mode: event.Mode, sink: ?event.Sink = null, source: ?event.Source = null, epoch: u64 = 0, next_seq: u64 = 1, sequence_exhausted: bool = false, replay_cursor: u64 = 0, last_checkpoint: ?event.Event = null, pub fn initOff(allocator: Allocator) Session { return .{ .allocator = allocator, .mode = .off }; } pub fn initRecord(allocator: Allocator, sink: event.Sink) Session { return .{ .allocator = allocator, .mode = .record, .sink = sink }; } pub fn initReplay(allocator: Allocator, source: event.Source) Session { return .{ .allocator = allocator, .mode = .replay, .source = source }; } pub fn deinit(self: *Session) void { if (self.last_checkpoint) |*item| item.deinit(self.allocator); self.* = undefined; } pub fn replayProgress(self: *const Session) ReplayProgress { const event_count = if (self.source) |source| source.count() else 0; std.debug.assert(self.replay_cursor <= event_count); return .{ .cursor = self.replay_cursor, .event_count = event_count, .remaining_count = event_count - self.replay_cursor, }; } pub fn sessionStart( self: *Session, thread_id: event.ThreadId, label: []const u8, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.sessionStart(timepoint, label)); } pub fn sessionEnd( self: *Session, thread_id: event.ThreadId, status: i64, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.sessionEnd(timepoint, status)); } pub fn functionEnter( self: *Session, thread_id: event.ThreadId, site: event.Safepoint, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.functionEnter(timepoint, site)); } pub fn functionExit( self: *Session, thread_id: event.ThreadId, site: event.Safepoint, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.functionExit(timepoint, site)); } pub fn safepoint( self: *Session, thread_id: event.ThreadId, site: event.Safepoint, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.safepointReached(timepoint, site)); } pub fn allocation( self: *Session, thread_id: event.ThreadId, object_id: u64, size: u64, alignment: u32, label: ?[]const u8, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.allocation( timepoint, object_id, size, alignment, label, )); } pub fn free( self: *Session, thread_id: event.ThreadId, object_id: u64, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.free(timepoint, object_id)); } pub fn boundaryBytesAlloc( self: *Session, thread_id: event.ThreadId, operation: []const u8, recorded_value: ?[]const u8, ) ![]u8 { const timepoint = try self.prepareTimepoint(thread_id); switch (self.mode) { .off => { const source_value = recorded_value orelse return error.MissingBoundaryValue; const value = try self.allocator.dupe(u8, source_value); self.commitTimepoint(timepoint); return value; }, .record => { const value = recorded_value orelse return error.MissingBoundaryValue; const owned = try self.allocator.dupe(u8, value); errdefer self.allocator.free(owned); try self.sink.?.append(event.Event.boundaryBytes(timepoint, operation, value)); self.commitTimepoint(timepoint); return owned; }, .replay => { const source = self.source.?; const actual = (try source.peek()) orelse return error.MissingReplayEvent; const recorded = actual.data orelse return error.ReplayEventMismatch; const expected = event.Event.boundaryBytes(timepoint, operation, recorded); if (!expected.eqlForReplay(actual.*)) return error.ReplayEventMismatch; const next_replay_cursor = try self.prepareReplayCursor(); const value = try self.allocator.dupe(u8, recorded); source.advance(); self.replay_cursor = next_replay_cursor; self.commitTimepoint(timepoint); return value; }, } } pub fn checkpointCapture( self: *Session, thread_id: event.ThreadId, label: []const u8, provider: checkpoint.Provider, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); const bytes = try provider.captureAlloc(self.allocator); defer self.allocator.free(bytes); return try self.handleEvent(event.Event.checkpoint(timepoint, label, bytes)); } pub fn checkpointRestore( self: *Session, thread_id: event.ThreadId, label: []const u8, provider: checkpoint.Provider, ) !event.Timepoint { const checkpoint_event = self.last_checkpoint orelse return error.MissingCheckpoint; const checkpoint_bytes = checkpoint_event.data orelse return error.MissingCheckpoint; const timepoint = try self.prepareTimepoint(thread_id); const expected = event.Event.checkpointRestore(timepoint, label); const prepared_replay = if (self.mode == .replay) try self.prepareReplay(expected) else null; const replay_timepoint = if (prepared_replay) |prepared| prepared.actual.timepoint else timepoint; provider.prepareRestoreBytes(checkpoint_bytes) catch |err| { provider.cancelRestore(); return err; }; errdefer provider.cancelRestore(); if (self.mode == .record) try self.sink.?.append(expected); provider.commitRestore(); if (prepared_replay) |prepared| self.commitReplay(prepared); self.commitTimepoint(timepoint); return replay_timepoint; } pub fn userEvent( self: *Session, thread_id: event.ThreadId, label: []const u8, bytes: []const u8, ) !event.Timepoint { const timepoint = try self.prepareTimepoint(thread_id); return try self.handleEvent(event.Event.user(timepoint, label, bytes)); } pub fn verifyReplayComplete(self: *Session) !void { if (self.mode != .replay) return; const source = self.source.?; if (self.replay_cursor != source.count()) return error.ReplayNotComplete; if (try source.peek() != null) return error.ReplayNotComplete; } fn prepareTimepoint(self: *const Session, thread_id: event.ThreadId) !event.Timepoint { if (self.sequence_exhausted) return error.SequenceExhausted; return event.Timepoint{ .epoch = self.epoch, .thread_id = thread_id, .seq = self.next_seq, }; } fn commitTimepoint(self: *Session, timepoint: event.Timepoint) void { std.debug.assert(!self.sequence_exhausted); std.debug.assert(timepoint.epoch == self.epoch); std.debug.assert(timepoint.seq == self.next_seq); if (self.next_seq == std.math.maxInt(u64)) { self.sequence_exhausted = true; } else { self.next_seq += 1; } } fn handleEvent(self: *Session, expected: event.Event) !event.Timepoint { var owned_checkpoint: ?event.Event = null; errdefer if (owned_checkpoint) |*owned| owned.deinit(self.allocator); var replay_timepoint: ?event.Timepoint = null; switch (self.mode) { .off => { if (expected.kind == .checkpoint) { owned_checkpoint = try expected.cloneAlloc(self.allocator); } }, .record => { if (expected.kind == .checkpoint) { owned_checkpoint = try expected.cloneAlloc(self.allocator); } try self.sink.?.append(expected); }, .replay => { const prepared = try self.prepareReplay(expected); replay_timepoint = prepared.actual.timepoint; if (prepared.actual.kind == .checkpoint) { owned_checkpoint = try prepared.actual.cloneAlloc(self.allocator); } self.commitReplay(prepared); }, } self.commitTimepoint(expected.timepoint); if (owned_checkpoint) |owned| { self.replaceCheckpoint(owned); owned_checkpoint = null; } return replay_timepoint orelse expected.timepoint; } const PreparedReplay = struct { source: event.Source, actual: *const event.Event, next_cursor: u64, }; fn prepareReplay(self: *Session, expected: event.Event) !PreparedReplay { const source = self.source.?; const actual = (try source.peek()) orelse return error.MissingReplayEvent; if (!expected.eqlForReplay(actual.*)) return error.ReplayEventMismatch; return .{ .source = source, .actual = actual, .next_cursor = try self.prepareReplayCursor(), }; } fn prepareReplayCursor(self: *const Session) !u64 { return std.math.add(u64, self.replay_cursor, 1) catch return error.ReplayCursorExhausted; } fn commitReplay(self: *Session, prepared: PreparedReplay) void { prepared.source.advance(); self.replay_cursor = prepared.next_cursor; } fn replaceCheckpoint(self: *Session, owned: event.Event) void { if (self.last_checkpoint) |*previous| previous.deinit(self.allocator); self.last_checkpoint = owned; }};Source: lib/trace/src/root.zig:52
zig
pub const Session = session.Session;Complete caller list for Session.initReplay
10 direct callers.
lib.trace.src.properties.session.ReplayFailureAtomicityProperty.property[function] — private source atlib/trace/src/properties/session.zig:230in nearest public ownerlib.trace.src.properties.sessionlib.trace.src.session.test_boundary_replay_copies_borrowed_bytes_before_advancing[function] — test source atlib/trace/src/session.zig:650in nearest public ownertiny.trace.sessionlib.trace.src.session.test_replay_mismatch_leaves_the_session_retryable[function] — test source atlib/trace/src/session.zig:632in nearest public ownertiny.trace.sessionlib.trace.src.session.test_replay_validates_a_borrowed_stream_and_exposes_numeric_progress[function] — test source atlib/trace/src/session.zig:525in nearest public ownertiny.trace.sessionlib.trace.src.session.test_session_failure_atomicity_preserves_a_checkpoint_when_replacement_allocation_fails[function] — test source atlib/trace/src/session.zig:705in nearest public ownertiny.trace.sessionlib.trace.src.session.test_session_failure_atomicity_rejects_noncanonical_boundary_fields[function] — test source atlib/trace/src/session.zig:594in nearest public ownertiny.trace.sessionlib.trace.src.session.test_session_failure_atomicity_retries_a_failed_source_peek[function] — test source atlib/trace/src/session.zig:505in nearest public ownertiny.trace.sessionlib.trace.src.session.test_session_failure_atomicity_retries_boundary_replay_after_allocation_failure[function] — test source atlib/trace/src/session.zig:568in nearest public ownertiny.trace.sessionlib.trace.src.session.test_session_failure_atomicity_validates_restore_before_staging_provider_state[function] — test source atlib/trace/src/session.zig:663in nearest public ownertiny.trace.sessionlib.trace.src.test.test_record_and_replay_sessions_stream_through_root-composed_storage[function] — test source atlib/trace/src/test.zig:22in nearest public ownerlib.trace.src.test
Audit
| Definitions | 18 |
|---|---|
| Public names | 36 |
| Members | 9 |
| Version | 26.7.0 |
| Revision | daab053ee433 |