tiny.sql.WalWriter
Defined in wal.
API (39)
Actions
Public operations.
Capacity.deriveactivateappendbyteCapacitybytescommitStagedFramedeinitframeCapacityframeCountinitloadloadControlledpositionremainingFramesrestorerewriteTailstagePagestagedPagestagedPageIdstagedPageMut: Returns a staged image for editing in place.swapStagedFrames
Types and contracts
Public types and contracts.
CapacityCapacity.DeriveErrorControlledLoadErrorExhaustionInitErrorLimitsLoadErrorPositionStorageclaimstorage_alignmentwork_limits
Fields and members
Public fields and members.
Source
Source: lib/sql/src/wal.zig:637
zig
pub const Writer = struct { pub const storage_alignment: usize = @alignOf(u8); pub const Storage = []align(storage_alignment) u8; pub const Limits = struct { header: Header, frames: usize, }; pub const Capacity = struct { frames: usize, storage_bytes: usize, pub const DeriveError = error{CapacityOverflow}; pub fn derive(limits: Limits) DeriveError!Capacity { const frame_bytes = std.math.mul(usize, limits.frames, frame_size) catch { return error.CapacityOverflow; }; const storage_bytes = std.math.add(usize, header_size, frame_bytes) catch { return error.CapacityOverflow; }; return .{ .frames = limits.frames, .storage_bytes = storage_bytes }; } }; pub const Exhaustion = error{WalFull}; pub const InitError = Capacity.DeriveError || error{StorageTooShort}; pub const LoadError = ReadError || Exhaustion; pub const ControlledLoadError = LoadError || error{Interrupted}; pub const work_limits: alloc_phase.capacity.WorkLimits = .{ .transition_steps_max = 1, .cleanup_steps_per_call_max = 0, .cleanup_calls_at_capacity_max = 0, }; pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "sql.wal_writer", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{ .{ .id = "exact_header_and_committed_frame_byte_region", .lifetime = .steady, .detail = "mutable borrow of the caller-provisioned exact header and frame byte region", }, .{ .id = "invisible_staged_frame_tail_transferred_into_the_co_0ed8d0c7aca0", .lifetime = .transferred, .detail = "invisible staged frame tail transferred into the committed prefix", }, }, .excluded = &.{ "caller-owned storage outside the exact borrowed prefix", "caller-owned page images and recovery source bytes", "pager frame indexes, page indexes, checkpoint plans, files, and I/O runtime state", "trace instrumentation and allocator implementation state", }, }, .capacity = .{ .inputs = &.{ alloc_phase.capacity.bindInput(Limits, "frames", "frames"), }, .type_selectors = &.{ alloc_phase.capacity.bindType([frame_size]u8, "walframebytes"), alloc_phase.capacity.bindType([header_size]u8, "walheaderbytes"), }, .nodes = &.{ .{ .input = 0 }, .{ .scale = .{ .node = 0, .coefficient = .{ .size_of_concrete_type = 0 } } }, .{ .constant = 1 }, .{ .scale = .{ .node = 2, .coefficient = .{ .size_of_concrete_type = 1 } } }, .{ .add = .{ .left = 1, .right = 3 } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .exact, .expression = 4, }}, }, .overload = .{ .kind = .reject_before_mutation, .detail = "append staging and recovery load return WalFull before bytes length salt or checksum mutate", }, .risks = .{ .transitive = .{ .status = .open, .detail = "pager indexes and trace instrumentation are outside the writer-owned byte region", }, .foreign = .{ .status = .open, .detail = "file reads and writes that consume WAL bytes are owned by the file database", }, }, .work = .{ .equation = "transition_steps <= transition_steps_max" }, .obligations = &.{ .{ .key = "sql_wal_capacity", .role = .capacity_model }, .{ .key = "sql_wal_storage_rejection", .role = .initialization_failure }, .{ .key = "sql_wal_sealed", .role = .overload }, .{ .key = "sql_wal_work_bound", .role = .work_bound }, .{ .key = "sql_wal_semantics", .role = .custom }, .{ .key = "sql_wal_staged_transfer", .role = .custom }, .{ .key = "sql_wal_corruption", .role = .custom }, }, }, .bindings = .{ .owner = @This(), .seal = .{ .family = alloc_phase.capacity.selector(@This().activate), .premise = .{ .class = .checked_semantic_fact, .authority = .checker, }, }, .teardown = .{ .family = alloc_phase.capacity.selector(@This().deinit), .premise = .{ .class = .checked_semantic_fact, .authority = .checker, }, }, }, }; phase: alloc_phase.capacity.Phase, capacity: Capacity, storage: Storage, len: usize, salt: Salt, checksum: Checksum, pub const Position = struct { len: usize, checksum_first: u32, checksum_second: u32, }; pub fn init(storage: Storage, limits: Limits) InitError!Writer { const capacity = try Capacity.derive(limits); if (storage.len < capacity.storage_bytes) return error.StorageTooShort; const borrowed = storage[0..capacity.storage_bytes]; const checksum = encodeHeader(borrowed[0..header_size], limits.header); return .{ .phase = .initialization, .capacity = capacity, .storage = borrowed, .len = header_size, .salt = limits.header.salt, .checksum = checksum, }; } pub fn activate(self: *Writer) void { std.debug.assert(self.phase == .initialization); std.debug.assert(self.storage.len == self.capacity.storage_bytes); std.debug.assert(self.len == header_size); self.phase = .steady; } pub fn deinit(self: *Writer) Storage { std.debug.assert(self.phase != .teardown); std.debug.assert(self.storage.len == self.capacity.storage_bytes); self.phase = .teardown; const storage = self.storage; self.* = undefined; return storage; } pub fn bytes(self: *const Writer) []const u8 { std.debug.assert(self.phase == .steady); std.debug.assert(self.len <= self.storage.len); return self.storage[0..self.len]; } pub fn frameCount(self: *const Writer) usize { std.debug.assert(self.phase == .steady); return (self.len - header_size) / frame_size; } pub fn frameCapacity(self: *const Writer) usize { std.debug.assert(self.phase == .steady); return self.capacity.frames; } pub fn byteCapacity(self: *const Writer) usize { std.debug.assert(self.phase == .steady); return self.capacity.storage_bytes; } pub fn remainingFrames(self: *const Writer) usize { std.debug.assert(self.phase == .steady); return self.capacity.frames - self.frameCount(); } pub fn position(self: *const Writer) Position { std.debug.assert(self.phase == .steady); return .{ .len = self.len, .checksum_first = self.checksum.first, .checksum_second = self.checksum.second, }; } pub fn restore(self: *Writer, position_value: Position) void { std.debug.assert(self.phase == .steady); std.debug.assert(position_value.len >= header_size); std.debug.assert((position_value.len - header_size) % frame_size == 0); std.debug.assert(position_value.len <= self.len); self.len = position_value.len; self.checksum = .{ .first = position_value.checksum_first, .second = position_value.checksum_second, }; } pub fn load(self: *Writer, source: []const u8, committed_len: usize) LoadError!void { return self.loadControlled(source, committed_len, .{}) catch |err| switch (err) { error.Interrupted => unreachable, else => return @errorCast(err), }; } pub fn loadControlled( self: *Writer, source: []const u8, committed_len: usize, control: Control, ) ControlledLoadError!void { std.debug.assert(self.phase == .steady); if (committed_len > source.len) return error.InvalidWal; if (committed_len > self.capacity.storage_bytes) return error.WalFull; var reader = try Reader.initControlled(source[0..committed_len], control); const frames_max = (committed_len - header_size) / frame_size; var frame_index: usize = 0; while (frame_index < frames_max) : (frame_index += 1) { if (try reader.nextControlled(control) == null) break; } if (reader.offset != committed_len) return error.InvalidWal; var copied: usize = 0; var chunks: usize = 0; const chunks_max = std.math.divCeil( usize, committed_len, controlled_copy_chunk_bytes, ) catch unreachable; while (copied < committed_len) : (chunks += 1) { std.debug.assert(chunks < chunks_max); try control.check(); const end = copied + @min( controlled_copy_chunk_bytes, committed_len - copied, ); std.mem.copyForwards(u8, self.storage[copied..end], source[copied..end]); copied = end; } try control.check(); self.len = committed_len; self.salt = reader.salt; self.checksum = reader.checksum; } pub fn append(self: *Writer, page_id: u32, db_page_count: u32, image: *const [page.size]u8) Exhaustion!void { const phase = trace.scope("wal.append"); defer phase.end(); std.debug.assert(self.phase == .steady); if (self.remainingFrames() == 0) return error.WalFull; var frame_header = @as([frame_header_size]u8, @splat(0)); writeU32(frame_header[0..4], page_id); writeU32(frame_header[4..8], db_page_count); writeU32(frame_header[8..12], self.salt.first); writeU32(frame_header[12..16], self.salt.second); var checksum = self.checksum; checksum.update(frame_header[0..8]); checksum.update(image[0..]); writeU32(frame_header[16..20], checksum.first); writeU32(frame_header[20..24], checksum.second); @memcpy(self.storage[self.len..][0..frame_header_size], frame_header[0..]); @memcpy(self.storage[self.len + frame_header_size ..][0..page.size], image[0..]); self.len += frame_size; self.checksum = checksum; trace.progress("wal.append.complete"); } pub fn stagePage(self: *Writer, position_value: Position, index: usize, page_id: u32, image: *const [page.size]u8) Exhaustion!void { std.debug.assert(self.phase == .steady); std.debug.assert(position_value.len == self.len); const offset = try self.stagedFrameOffset(position_value, index); writeU32(self.storage[offset..][0..4], page_id); const staged = self.storage[offset + frame_header_size ..][0..page.size]; if (staged != image) @memcpy(staged, image); } pub fn stagedPage(self: *const Writer, position_value: Position, index: usize) []const u8 { std.debug.assert(self.phase == .steady); std.debug.assert(position_value.len == self.len); const offset = self.stagedFrameOffset(position_value, index) catch unreachable; return self.storage[offset + frame_header_size ..][0..page.size]; } /// Returns a staged image for editing in place. Staging the returned /// image again copies nothing, and the checksum covers the edits /// when the frame commits. pub fn stagedPageMut(self: *Writer, position_value: Position, index: usize) *[page.size]u8 { std.debug.assert(self.phase == .steady); std.debug.assert(position_value.len == self.len); const offset = self.stagedFrameOffset(position_value, index) catch unreachable; return self.storage[offset + frame_header_size ..][0..page.size]; } pub fn stagedPageId(self: *const Writer, position_value: Position, index: usize) u32 { std.debug.assert(self.phase == .steady); const offset = self.stagedFrameOffset(position_value, index) catch unreachable; return readU32(self.storage[offset..][0..4]); } pub fn swapStagedFrames(self: *Writer, position_value: Position, left_index: usize, right_index: usize) void { std.debug.assert(self.phase == .steady); std.debug.assert(position_value.len == self.len); if (left_index == right_index) return; const left_offset = self.stagedFrameOffset(position_value, left_index) catch unreachable; const right_offset = self.stagedFrameOffset(position_value, right_index) catch unreachable; const left: *[frame_size]u8 = self.storage[left_offset..][0..frame_size]; const right: *[frame_size]u8 = self.storage[right_offset..][0..frame_size]; const temporary = left.*; left.* = right.*; right.* = temporary; } pub fn commitStagedFrame(self: *Writer, position_value: Position, index: usize, db_page_count: u32) void { std.debug.assert(self.phase == .steady); const offset = self.stagedFrameOffset(position_value, index) catch unreachable; std.debug.assert(self.len == offset); const frame_header = self.storage[offset..][0..frame_header_size]; const image = self.storage[offset + frame_header_size ..][0..page.size]; std.debug.assert(readU32(frame_header[0..4]) != 0); writeU32(frame_header[4..8], db_page_count); writeU32(frame_header[8..12], self.salt.first); writeU32(frame_header[12..16], self.salt.second); var checksum = self.checksum; checksum.update(frame_header[0..8]); checksum.update(image); writeU32(frame_header[16..20], checksum.first); writeU32(frame_header[20..24], checksum.second); self.len += frame_size; self.checksum = checksum; } pub fn rewriteTail(self: *Writer, checkpoint_mark: usize, header: Header) void { std.debug.assert(self.phase == .steady); std.debug.assert(checkpoint_mark <= self.frameCount()); const source = self.bytes(); var reader = Reader.init(source) catch @panic("invalid wal writer storage"); self.writeHeader(header); while (reader.next() catch @panic("invalid wal writer storage")) |frame| { if (frame.index <= checkpoint_mark) continue; const image = frame.image[0..page.size].*; self.append(frame.page_id, frame.db_page_count, &image) catch unreachable; } if (reader.offset != source.len) @panic("invalid wal writer storage"); } fn writeHeader(self: *Writer, header: Header) void { const checksum = encodeHeader(self.storage[0..header_size], header); self.len = header_size; self.salt = header.salt; self.checksum = checksum; } fn stagedFrameOffset(self: *const Writer, position_value: Position, index: usize) Exhaustion!usize { std.debug.assert(position_value.len >= header_size); std.debug.assert((position_value.len - header_size) % frame_size == 0); const staged_bytes = std.math.mul(usize, index, frame_size) catch return error.WalFull; const offset = std.math.add(usize, position_value.len, staged_bytes) catch return error.WalFull; if (offset > self.storage.len or frame_size > self.storage.len - offset) return error.WalFull; return offset; }};Source: lib/sql/src/root.zig:303
zig
pub const WalWriter = wal.Writer;Audit
| Definitions | 34 |
|---|---|
| Public names | 68 |
| Members | 15 |
| Version | 26.7.0 |
| Revision | daab053ee433 |