tiny.machine.checkpoint.roots
Defined in checkpoint.
Holding one capture is easy, and holding fifty is the problem the calls here solve: the calls write captures into a store the caller supplies and read them back.
API (40)
Actions
Public operations.
Capacity.derive: Derives the exact object and byte counts from the limits.Storage.abort: Drops the open publication transaction with no staged object made visible.Storage.abortCollection: Aborts the collection and removes no storage.Storage.begin: Reserves the whole capacity first, then opens one publication transaction.Storage.beginCollection: Reserves the capacity, records the seeds of every class, and opens the collection.Storage.commit: Publishes the staged objects underrootin one atomic step.Storage.commitCollection: Removes the unmarked storage in one atomic step and returns the retention and removal counts.Storage.put: Copies one object into the open publication transaction.Storage.read: Copies one committed object into caller-owned output.Storage.readSeed: Returns one snapshotted manifest root by owner class and zero-based index.Storage.readStaged: Copies one staged object out into caller-owned output, so the caller can check it.Storage.retainBlock: Marks the data held under one block root, answering whether the mark is the first this collection set on that root.Storage.retainObject: Marks one stored object, answering whether the mark is the first this collection set on it.Storage.verifyBlock: Opens every byte the provider holds underblockagain and authenticates it.bind: Writes a verified durable checkpoint into the store as a full page tree under a manifest that has no parent.bindDelta: Stores a hot snapshot as a manifest whose parent isparent_root.materialize: Opens the chain again, fills an aligned destination the caller owns with the newest normalized memory, and checks that image against its memory digest.reopen: Opens a manifest chain again and authenticates it together with every page-tree object beneath it and every block closure it names.
Types and contracts
Public types and contracts.
Binding: The result of one root publication.Capacity: The exact publication requirement derived fromLimits.Capacity.DeriveErrorError: The failures of the provider joined with those of capacity, checkpoints, manifests, page trees, and delta chains.Limits: A ceiling on the pages, tree nodes, and manifests one publication writes.Manifest: The stored record links a checkpoint root, a page tree, the settled receipt's block root, and the restore material.ManifestRoot: The digest identity of one encoded checkpoint manifest.ObjectKind: The family of a stored object, used to select its exact byte length and digest check.PageRoot: The digest identity of a complete page tree.Storage: The borrowed transaction, read, block, and collection capabilities of one provider.Storage.VTable: The table of function pointers a provider supplies.StorageError: Names every failure a provider reports, covering capacity, transactions, collisions, reads, writes, and collection.
Namespaces
Public namespaces.
Values and defaults
Public values and defaults.
chain_limitmanifest_bytesnode_bytesnode_countpage_bytespage_countpublication_capacitypublication_limits
Source
Source: lib/machine/src/checkpoint/roots/types.zig:49
/// The result of one root publication. The `root` field authenticates the/// returned manifest.pub const Binding = struct { root: ManifestRoot, manifest: Manifest,};Source: lib/machine/src/checkpoint/roots/types.zig:242
/// The exact publication requirement derived from `Limits`. The `objects` field/// counts object slots and the `bytes` field counts their complete values.pub const Capacity = struct { limits: Limits, objects: u32, bytes: u64, pub const DeriveError: type = CapacityDeriveError; /// Derives the exact object and byte counts from the limits. More pages /// than 16,384 returns `PageCapacityExceeded`, more nodes than 32,767 /// returns `NodeCapacityExceeded`, and more than one manifest returns /// `ManifestCapacityExceeded`. Overflow in any product or sum returns /// `RootCapacityOverflow`. pub fn derive(limits: Limits) DeriveError!Capacity { if (limits.pages > page_count) return error.PageCapacityExceeded; if (limits.nodes > node_count) return error.NodeCapacityExceeded; if (limits.manifests > 1) return error.ManifestCapacityExceeded; const first = std.math.add( u32, limits.pages, limits.nodes, ) catch return error.RootCapacityOverflow; const objects = std.math.add( u32, first, limits.manifests, ) catch return error.RootCapacityOverflow; const page_storage = std.math.mul( u64, limits.pages, page_bytes, ) catch return error.RootCapacityOverflow; const node_storage = std.math.mul( u64, limits.nodes, node_bytes, ) catch return error.RootCapacityOverflow; const manifest_storage = std.math.mul( u64, limits.manifests, manifest_bytes, ) catch return error.RootCapacityOverflow; const partial = std.math.add( u64, page_storage, node_storage, ) catch return error.RootCapacityOverflow; return .{ .limits = limits, .objects = objects, .bytes = std.math.add( u64, partial, manifest_storage, ) catch return error.RootCapacityOverflow, }; }};Source: lib/machine/src/checkpoint/roots/types.zig:227
/// A ceiling on the pages, tree nodes, and manifests one publication writes.pub const Limits = struct { pages: u32, nodes: u32, manifests: u16,};Source: lib/machine/src/checkpoint/roots/types.zig:37
/// The stored record links a checkpoint root, a page tree, the settled/// receipt's block root, and the restore material. The `parent` field forms a/// delta chain. The `dirty_pages` field counts the changed pages, and it is/// every page for a parentless manifest.pub const Manifest = struct { machine: owner.Root, memory: owner.MemoryDigest, pages: PageRoot, block: os.abi.BlockRoot, material: owner.Material, parent: ?ManifestRoot, dirty_pages: u16,};Source: lib/machine/src/checkpoint/roots/types.zig:29
/// The digest identity of one encoded checkpoint manifest.pub const ManifestRoot = struct { digest: os.abi.Digest,};Source: lib/machine/src/checkpoint/roots/types.zig:17
/// The family of a stored object, used to select its exact byte length and/// digest check. A page is 4096 bytes, a tree node is 80 bytes, and a manifest/// is 4352 bytes.pub const ObjectKind = enum(u8) { page = 1, node = 2, manifest = 3,};Source: lib/machine/src/checkpoint/roots/types.zig:24
/// The digest identity of a complete page tree.pub const PageRoot = struct { digest: os.abi.Digest,};Source: lib/machine/src/checkpoint/roots/types.zig:397
/// The borrowed transaction, read, block, and collection capabilities of one/// provider. Every stored byte and all context belong to the provider. A/// committed binding from a digest to its bytes stays fixed. The caller keeps/// the provider and the table of function pointers alive while the capability/// is used.pub const Storage = struct { context: *anyopaque, vtable: *const VTable, /// The table of function pointers a provider supplies. A provider reserves /// capacity first, and a failed reservation opens no transaction. The `put` /// call copies its input and rejects unequal bytes for a key that already /// exists. Commit makes every staged object and the new root visible in one /// step. A collection begins by snapshotting every seed class before /// marking. A collection commit removes only unmarked storage. An abort, /// and a crash before commit, expose no changes. pub const VTable: type = StorageVTable; /// Reserves the whole capacity first, then opens one publication /// transaction. pub fn begin(self: Storage, capacity: Capacity) StorageError!void { const derived = Capacity.derive(capacity.limits) catch unreachable; std.debug.assert(std.meta.eql(derived, capacity)); return self.vtable.begin(self.context, capacity); } /// Copies one object into the open publication transaction. The byte count /// must equal the length its kind fixes, checked by an assertion. pub fn put( self: Storage, kind: ObjectKind, digest: os.abi.Digest, bytes: []const u8, ) StorageError!void { std.debug.assert(bytes.len == objectBytes(kind)); return self.vtable.put(self.context, kind, digest, bytes); } /// Copies one staged object out into caller-owned output, so the caller can /// check it. The output length must equal the length its kind fixes, /// checked by an assertion. pub fn readStaged( self: Storage, kind: ObjectKind, digest: os.abi.Digest, output: []u8, ) StorageError!void { std.debug.assert(output.len == objectBytes(kind)); return self.vtable.read_staged(self.context, kind, digest, output); } /// Publishes the staged objects under `root` in one atomic step. pub fn commit(self: Storage, root: ManifestRoot) StorageError!void { return self.vtable.commit(self.context, root); } /// Drops the open publication transaction with no staged object made /// visible. pub fn abort(self: Storage) void { self.vtable.abort(self.context); } /// Copies one committed object into caller-owned output. The output length /// must equal the length its kind fixes, checked by an assertion. pub fn read( self: Storage, kind: ObjectKind, digest: os.abi.Digest, output: []u8, ) StorageError!void { std.debug.assert(output.len == objectBytes(kind)); return self.vtable.read(self.context, kind, digest, output); } /// Opens every byte the provider holds under `block` again and /// authenticates it. pub fn verifyBlock( self: Storage, block: os.abi.BlockRoot, ) StorageError!void { return self.vtable.verify_block(self.context, block); } /// Reserves the capacity, records the seeds of every class, and opens the /// collection. pub fn beginCollection( self: Storage, capacity: CollectionCapacity, ) StorageError!CollectionSnapshot { const derived = CollectionCapacity.derive(capacity.limits) catch unreachable; std.debug.assert(std.meta.eql(derived, capacity)); return self.vtable.begin_collection(self.context, capacity); } /// Returns one snapshotted manifest root by owner class and zero-based /// index. pub fn readSeed( self: Storage, class: ReachabilityClass, index: u16, ) StorageError!ManifestRoot { return self.vtable.read_seed(self.context, class, index); } /// Marks one stored object, answering whether the mark is the first this /// collection set on it. pub fn retainObject( self: Storage, kind: ObjectKind, digest: os.abi.Digest, ) StorageError!Retention { return self.vtable.retain_object(self.context, kind, digest); } /// Marks the data held under one block root, answering whether the mark is /// the first this collection set on that root. pub fn retainBlock( self: Storage, block: os.abi.BlockRoot, ) StorageError!Retention { return self.vtable.retain_block(self.context, block); } /// Removes the unmarked storage in one atomic step and returns the /// retention and removal counts. pub fn commitCollection(self: Storage) StorageError!CollectionReport { return self.vtable.commit_collection(self.context); } /// Aborts the collection and removes no storage. pub fn abortCollection(self: Storage) void { self.vtable.abort_collection(self.context); }};Source: lib/machine/src/checkpoint/roots/types.zig:320
/// Names every failure a provider reports, covering capacity, transactions,/// collisions, reads, writes, and collection.pub const StorageError = error{ RootCapacityExceeded, RootCollision, RootCollectionCapacityExceeded, RootCollectionFailed, RootCollectionUnsupported, RootMissing, RootReadFailed, RootSeedMissing, RootTransactionInUse, RootWriteFailed,};Source: lib/machine/src/checkpoint/roots/owner.zig:16
/// Writes a verified durable checkpoint into the store as a full page tree/// under a manifest that has no parent. The provider reserves/// `publication_capacity`, takes a copy of each object, verifies the settled/// block closure, and commits in one step. A page root whose memory digest/// differs from the checkpoint's returns `PageRootMismatch`. Any failure aborts/// the publication transaction. The caller puts a complete capture into the/// store to get a name for it.pub fn bind( storage: types.Storage, checkpoint: *const owner.Checkpoint,) types.Error!types.Binding { try storage.begin(types.publication_capacity); var transaction_open = true; defer if (transaction_open) storage.abort(); const contents = try owner.inspect(checkpoint); const pages = try tree.stage(storage, checkpoint.ram); const memory: owner.MemoryDigest = .{ .digest = canon.memory(pages.digest) }; if (!std.meta.eql(memory, contents.memory)) { return error.PageRootMismatch; } const value: types.Manifest = .{ .machine = contents.root, .memory = memory, .pages = pages, .block = contents.material.receipt.block_root, .material = contents.material, .parent = null, .dirty_pages = @intCast(types.page_count), }; try storage.verifyBlock(value.block); const root = try manifest.stage(storage, value); try storage.commit(root); transaction_open = false; return .{ .root = root, .manifest = value };}Source: lib/machine/src/checkpoint/roots/owner.zig:53
/// Stores a hot snapshot as a manifest whose parent is `parent_root`. The call/// validates each material link along the parent manifest chain and verifies/// the parent checkpoint and the child identity. A chain already 64 entries/// deep returns `DeltaChainCapacityExceeded`. Each changed page becomes a new/// page object, and the tree path above it is staged with it. A block closure/// differing from the parent's is verified. Any failure after the transaction/// opens aborts it.pub fn bindDelta( storage: types.Storage, parent_root: types.ManifestRoot, snapshot: *const hot.Snapshot,) types.Error!types.Binding { const parent = try inspectParentChain(storage, parent_root); _ = try admitNextDepth(parent.depth); const parent_contents = try owner.inspect(snapshot.parent); try validateSnapshotParent(parent.manifest, parent_contents); const snapshot_identity = try snapshot.identity(); const capacity = try tree.deltaCapacity(snapshot.indices); try storage.begin(capacity); var transaction_open = true; defer if (transaction_open) storage.abort(); const pages = try tree.stageDelta( storage, parent.manifest.pages, snapshot.indices, snapshot.pages, ); const memory: owner.MemoryDigest = .{ .digest = canon.memory(pages.digest) }; if (!std.meta.eql(memory, snapshot.memory)) return error.PageRootMismatch; const identity = try owner.identify(snapshot.material, memory); if (!std.meta.eql(identity, snapshot_identity)) { return error.DeltaParentMismatch; } const block = snapshot.material.receipt.block_root; if (!std.meta.eql(block, parent.manifest.block)) { try storage.verifyBlock(block); } const value: types.Manifest = .{ .machine = identity.root, .memory = memory, .pages = pages, .block = block, .material = snapshot.material, .parent = parent_root, .dirty_pages = snapshot.dirtyPageCount(), }; const root = try manifest.stage(storage, value); try storage.commit(root); transaction_open = false; return .{ .root = root, .manifest = value };}Source: lib/machine/src/checkpoint/roots/owner.zig:115
/// Opens the chain again, fills an aligned destination the caller owns with the/// newest normalized memory, and checks that image against its memory digest. A/// destination whose memory digest differs from the manifest's returns/// `PageRootMismatch`.pub fn materialize( storage: types.Storage, expected: types.ManifestRoot, destination: []align(types.page_bytes) u8,) types.Error!types.Manifest { return open(storage, expected, destination);}Source: lib/machine/src/checkpoint/roots/owner.zig:104
/// Opens a manifest chain again and authenticates it together with every/// page-tree object beneath it and every block closure it names. The call walks/// the parentless tree in full, then authenticates the changed paths between/// each manifest and its child, which together covers every object the newest/// root reaches. The call then returns the newest manifest.pub fn reopen( storage: types.Storage, expected: types.ManifestRoot,) types.Error!types.Manifest { return open(storage, expected, null);}Source: lib/machine/src/checkpoint/roots/types.zig:345
/// The failures of the provider joined with those of capacity, checkpoints,/// manifests, page trees, and delta chains.pub const Error = StorageError || Capacity.DeriveError || owner.Error || IntegrityError;Source: lib/machine/src/checkpoint/roots/types.zig:12
pub const chain_limit: usize = 64;Source: lib/machine/src/checkpoint/roots/types.zig:11
pub const manifest_bytes: usize = 256 + stream.header_bytes;Source: lib/machine/src/checkpoint/roots/types.zig:9
pub const node_bytes: usize = 80;Source: lib/machine/src/checkpoint/roots/types.zig:10
pub const node_count: u32 = 2 * page_count - 1;Source: lib/machine/src/checkpoint/roots/types.zig:306
pub const publication_capacity = Capacity.derive(publication_limits) catch unreachable;Source: lib/machine/src/checkpoint/roots/types.zig:300
pub const publication_limits: Limits = .{ .pages = page_count, .nodes = node_count, .manifests = 1,};Source: lib/machine/src/checkpoint/canon/digest.zig:12
pub const page_bytes: usize = core.layout.page_bytes;Source: lib/machine/src/checkpoint/root.zig:91
pub const roots = @import("roots/root.zig");Source: lib/machine/src/checkpoint/roots/root.zig
//! Holding one capture is easy, and holding fifty is the problem the calls here//! solve: the calls write captures into a store the caller supplies and read//! them back.//!//! A caller keeping many captures pays a full memory image for each one unless//! the captures share the pages they hold in common. The machine's fixed//! 67,108,864 bytes, addressed from zero, holding 16,384 pages, are its//! *memory*. The 4096 contiguous bytes of a machine's memory, named by their//! zero-based index, are a *page*.//!//! A store outside the process can hand back the wrong bytes, so a reader has//! to check each object it receives. A publication interrupted part way would//! leave a root pointing at objects that were never written. Captures//! accumulate, so something has to remove the objects nobody reaches without//! removing the ones a reader still holds.//!//! A content-addressed object store keys each object by the digest of its bytes//! and shares the subtrees two versions have in common, as Git does for its//! trees. Mark and sweep reclaims storage by marking everything reachable from//! a set of roots and then removing the rest (McCarthy, 1960).//!//! The complete binary tree over the 16,384 page digests, 14 levels deep, where//! each node binds its level to its two ordered child digests, is a *page//! tree*. The digest identifying a complete page tree held as stored objects is//! the *page root*. Pages, tree nodes, and manifests are all written under//! their digests, and a capture against a parent restages only the changed//! pages and the tree paths above them. The caller-supplied content-addressed//! store that owns every stored byte and answers reads and writes by digest is//! the *provider*. One manifest root the provider reports as owned at the//! moment collection opens is a *seed*. Marking every object reachable from the//! provider's snapshotted seeds, then one atomic sweep that removes the//! unmarked, is a *collection*.//!//! One page, one page-tree node, or one manifest, each written under its digest//! at the exact byte length its kind fixes: 4096, 80, or 4352, is a *stored//! object*. Every stored object fixes its byte length, so a read knows its//! length before it asks.//!//! The digest binding one profile fingerprint to one state digest is the//! *checkpoint root*. The SHA-256 identity of a normalized memory image,//! binding the page tree's root to the fixed memory geometry, is the *memory//! digest*. A generation and digest naming the stored data an execution read is//! a *block root*. The fixed-size values needed to recompute an identity and//! rebuild execution: profile fingerprint, settled receipt, CPU restart frame,//! and immutable image descriptor, are the restore *material*. The stored//! record joining a checkpoint root, a memory digest, a page root, a block//! root, the restore material, an optional parent, and a changed-page count is//! a *manifest*, so one object carries everything a restore needs.//!//! A manifest and its parents, at most 64 entries long, form a *delta chain*.//! The delta chain bounds the work any reopen can do.//!//! An object copied into an open transaction, readable back for verification//! before commit, is a *staged object*. The window between reserving the exact//! capacity and the commit that exposes every staged object and the new root at//! once is a *publication transaction*, so an abort or a crash before the//! commit exposes nothing.//!//! Every object read back is hashed and compared against the digest it was//! asked for, so the store holds bytes without being trusted.//!//! The four kinds of collection seed the provider counts separately form each//! *owner class*. Collection snapshots every owner class before marking and//! derives a work bound from the snapshot, so a trace that reaches the bound is//! refused.//!//! The store itself is a caller-supplied capability of function pointers, so//! the bytes can live in a file tree, a database, or a test double. Reopening//! walks the delta chain, authenticates the page trees, and verifies each//! referenced block root, and it returns the newest manifest. A memory image//! whose page tables have been rewritten to their canonical form and whose boot//! frame, request ring, event ring, and kernel stack are zeroed is *normalized//! memory*. Materializing does the same and also writes the newest normalized//! memory into an aligned caller-owned destination. The digest of one encoded//! manifest is a *manifest root*. A mutable memory view over one manifest root,//! authenticating a shared page on first read and copying it into a private//! pool on first write, is a *branch*.const owner = @import("owner.zig");const types = @import("types.zig");pub const branch = @import("branch.zig");pub const maintenance = @import("maintenance.zig");pub const Binding = types.Binding;pub const Capacity = types.Capacity;pub const Error = types.Error;pub const Limits = types.Limits;pub const Manifest = types.Manifest;pub const ManifestRoot = types.ManifestRoot;pub const ObjectKind = types.ObjectKind;pub const PageRoot = types.PageRoot;pub const Storage = types.Storage;pub const StorageError = types.StorageError;pub const bind = owner.bind;pub const bindDelta = owner.bindDelta;pub const chain_limit = types.chain_limit;pub const manifest_bytes = types.manifest_bytes;pub const materialize = owner.materialize;pub const node_bytes = types.node_bytes;pub const node_count = types.node_count;pub const page_bytes = types.page_bytes;pub const page_count = types.page_count;pub const publication_capacity = types.publication_capacity;pub const publication_limits = types.publication_limits;pub const reopen = owner.reopen;Audit
| Definitions | 38 |
|---|---|
| Public names | 38 |
| Members | 32 |
| Version | 26.7.0 |
| Revision | daab053ee433 |