tiny.reducer.Storage
Defined in bytes.storage.
Workspace, allocated up front and double-buffered, that carries reduction in steady state.
API (17)
Actions
Public operations.
acquire: Takes exclusive use of the workspace for a run overinput_bytesbytes.activate: Moves the workspace from.initializationto.steady.deinit: Frees the backing allocation and moves the workspace to.teardown.init: Allocates a reduction workspace and divides it into the two lanes, sized for inputs up tolimits.max_input_bytes.release: Gives up this run's lease, returning the workspace to steady and idle so it can serve another run.status: Returns a snapshot of this workspace, taken by value at the moment of the call.
Types and contracts
Public types and contracts.
Capacity: Re-export of the derived capacity type.Exhaustion: Re-export of the exhaustion error set.InitError: ErrorsStorage.init()may return.Limits: Re-export of the capacity limits type.claim: Stardust capacity declaration that phase-directed allocation verification reads.
Fields and members
Public fields and members.
Source
Source: lib/reducer/src/bytes/storage.zig:95
zig
/// Workspace, allocated up front and double-buffered, that carries reduction in/// steady state. It holds the backing allocation and tracks the phase it is in/// and whether a lease is out.pub const Storage = struct { /// Lifecycle phase that `alloc_phase` enforces. phase: alloc_phase.capacity.Phase, /// Layout derived while initializing. capacity: capacity_mod.Capacity, /// Entire contiguous backing byte allocation. bytes: []u8, /// Fixed sub-slice reserved for the witness lane, spanning $0 \dots N$. current: []u8, /// Fixed sub-slice reserved for the scratch lane, spanning /// $N \dots N + \max(N - 1, 0)$. candidate: []u8, /// Flag recording that a lease is out, turning away a reentrant acquisition /// and one made while an earlier result is still live. in_use: bool = false, /// Re-export of the capacity limits type. pub const Limits: type = capacity_mod.Limits; /// Re-export of the derived capacity type. pub const Capacity: type = capacity_mod.Capacity; /// Re-export of the exhaustion error set. pub const Exhaustion: type = model.Exhaustion; /// Errors `Storage.init()` may return. pub const InitError = std.mem.Allocator.Error || capacity_mod.DeriveError; /// Stardust capacity declaration that phase-directed allocation /// verification reads. It records that the workspace owner makes no further /// backing allocation once sealed into steady state. It bounds the storage /// by $2 \times \text{max\_input\_bytes}$. It leaves out the memory and the /// effects the caller's predicate owns. pub const claim: alloc_phase.capacity.Declaration = .{ .source = .{ .id = "reducer.byte_storage", .kind = .phase_static, .limit_source = .caller, .storage = .{ .covered = &.{ .{ .id = "accepted_input_and_borrowed_result_bytes", .lifetime = .steady, .detail = "accepted input and borrowed result bytes", }, .{ .id = "deletion_candidate_scratch_bytes", .lifetime = .steady, .detail = "deletion candidate scratch bytes", }, }, .excluded = &.{ "caller-owned initial input bytes", "caller-owned predicate context, allocation, and effects", }, }, .capacity = .{ .inputs = &.{ alloc_phase.capacity.bindInput(Limits, "max_input_bytes", "max_input_bytes"), }, .type_selectors = &.{}, .nodes = &.{ .{ .input = 0 }, .{ .scale = .{ .node = 0, .coefficient = .{ .literal = 2 } } }, }, .assertions = &.{.{ .scope = .closure_total, .measure = .retained, .relation = .upper_bound, .expression = 1, }}, }, .overload = .{ .kind = .reject_before_mutation, .detail = "oversize and concurrent requests fail before workspace bytes change", }, .risks = .{ .transitive = .{ .status = .witnessed, .detail = "reduction uses byte lanes; predicate effects remain caller-owned", }, .foreign = .{ .status = .excluded, .detail = "predicate and operating-system effects are caller-owned", }, }, .obligations = &.{ .{ .key = "reducer_byte_capacity", .role = .capacity_model }, .{ .key = "reducer_byte_acquisition", .role = .custom }, .{ .key = "reducer_byte_oom", .role = .custom }, .{ .key = "reducer_byte_boundaries", .role = .overload }, .{ .key = "reducer_byte_reuse", .role = .overload }, .{ .key = "reducer_byte_sealed", .role = .transitive_risk }, .{ .key = "reducer_byte_callback", .role = .foreign_risk }, .{ .key = "reducer_byte_root", .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, }, }, }, }; /// Allocates a reduction workspace and divides it into the two lanes, sized /// for inputs up to `limits.max_input_bytes`. The new workspace is in /// `.initialization`, and the caller calls `storage.activate()` on it /// before passing it to `reduce()`. A workspace that is never activated can /// be freed directly by `storage.deinit()`. /// /// ## Errors /// - `error.CapacityOverflow` when $N + \max(N - 1, 0)$ overflows `usize`. /// - `error.OutOfMemory` when the allocator declines the request. pub fn init(allocator: std.mem.Allocator, limits: Limits) InitError!Storage { const capacity = try Capacity.derive(limits); const bytes = try allocator.alloc(u8, capacity.storage_bytes); const owner = Storage{ .phase = .initialization, .capacity = capacity, .bytes = bytes, .current = bytes[0..limits.max_input_bytes], .candidate = bytes[capacity.candidate_offset..][0..capacity.candidate_bytes], }; std.debug.assert(owner.current.len == limits.max_input_bytes); std.debug.assert(owner.candidate.len == capacity.candidate_bytes); std.debug.assert(owner.current.len + owner.candidate.len == owner.bytes.len); return owner; } /// Moves the workspace from `.initialization` to `.steady`. Once it /// returns, the workspace owner makes no further heap allocation. /// /// ## Preconditions /// - `self.phase` is `.initialization`. /// - The backing allocation's length equals `self.capacity.storage_bytes`. pub fn activate(self: *Storage) void { std.debug.assert(self.phase == .initialization); std.debug.assert(self.bytes.len == self.capacity.storage_bytes); self.phase = .steady; } /// Takes exclusive use of the workspace for a run over `input_bytes` bytes. /// It returns `Regions` holding sub-slices of the backing buffer. It copies /// nothing into `Regions.current`. /// /// ## Preconditions /// - `self.phase` is `.steady`. /// /// ## Errors /// - `error.ReductionStorageInUse` when `self.in_use` is already true. A /// reentrant call, and a call made while an earlier result is still live, /// are both turned away without disturbing the hold that is already out. /// - `error.InputCapacityExceeded` when `input_bytes` exceeds /// `max_input_bytes`. pub fn acquire(self: *Storage, input_bytes: usize) Exhaustion!Regions { std.debug.assert(self.phase == .steady); if (self.in_use) return error.ReductionStorageInUse; if (input_bytes > self.capacity.limits.max_input_bytes) { return error.InputCapacityExceeded; } std.debug.assert(self.current.len == self.capacity.limits.max_input_bytes); std.debug.assert(self.candidate.len == self.capacity.candidate_bytes); self.in_use = true; return .{ .current = self.current[0..input_bytes], .candidate = self.candidate, }; } /// Gives up this run's lease, returning the workspace to steady and idle so /// it can serve another run. `Result.deinit()` calls it, and it moves the /// workspace no closer to teardown. /// /// ## Preconditions /// - `self.phase` is `.steady`. /// - `self.in_use` is true. pub fn release(self: *Storage) void { std.debug.assert(self.phase == .steady); std.debug.assert(self.in_use); self.in_use = false; std.debug.assert(!self.in_use); } /// Returns a snapshot of this workspace, taken by value at the moment of /// the call. pub fn status(self: *const Storage) Status { return .{ .phase = self.phase, .in_use = self.in_use, .storage_bytes = self.capacity.storage_bytes, .max_input_bytes = self.capacity.limits.max_input_bytes, }; } /// Frees the backing allocation and moves the workspace to `.teardown`. It /// works on an idle steady workspace and on one still in `.initialization` /// that was never activated. It needs the same allocator `Storage.init()` /// received. /// /// ## Preconditions /// - `self.phase` is anything other than `.teardown`. /// - `self.in_use` is false, so every result has had its `deinit()` called. pub fn deinit(self: *Storage, allocator: std.mem.Allocator) void { std.debug.assert(self.phase != .teardown); std.debug.assert(!self.in_use); std.debug.assert(self.bytes.len == self.capacity.storage_bytes); self.phase = .teardown; allocator.free(self.bytes); self.bytes = &.{}; self.current = &.{}; self.candidate = &.{}; }};Source: lib/reducer/src/root.zig:351
zig
/// Workspace, allocated up front and double-buffered, that carries reduction in/// steady state.pub const Storage = bytes.Storage;Also reachable as
Audit
| Definitions | 12 |
|---|---|
| Public names | 36 |
| Members | 6 |
| Version | 26.7.0 |
| Revision | daab053ee433 |