tiny.sql.BranchPage
Defined in page.
API (17)
Actions
Public operations.
cellCountchildAtchildForchildIndexForcopyTofirstLowerfromValidated: Wraps a branch image thatloadvalidated, without walking its cells again.generationidinitloadlowerAtputremovereplacesplitPut
Fields and members
Public fields and members.
Source
Source: lib/sql/src/page.zig:414
zig
pub const Branch = struct { bytes: *[size]u8, pub fn init(bytes: *[size]u8, page_id: u64) Branch { var branch = Branch{ .bytes = bytes }; @memset(branch.bytes, 0); @memcpy(branch.bytes[magic_offset..][0..magic.len], magic[0..]); branch.bytes[version_offset] = format_version; branch.bytes[kind_offset] = branch_kind; branch.writeU16(flags_offset, 0); branch.writeU64(id_offset, page_id); branch.writeU64(generation_offset, 0); branch.writeU16(lower_offset, header_size); branch.writeU16(upper_offset, size); branch.writeU16(cells_offset, 0); branch.writeU16(reserved_offset, 0); return branch; } pub fn load(bytes: *[size]u8) Error!Branch { const branch = Branch{ .bytes = bytes }; try branch.validate(); return branch; } /// Wraps a branch image that `load` validated, without walking its cells /// again. The image must be unchanged since that `load`. pub fn fromValidated(bytes: *[size]u8) Branch { std.debug.assert(bytes[kind_offset] == branch_kind); return .{ .bytes = bytes }; } pub fn id(self: *const Branch) u64 { return self.readU64(id_offset); } pub fn generation(self: *const Branch) u64 { return self.readU64(generation_offset); } pub fn cellCount(self: *const Branch) usize { return self.readU16(cells_offset); } pub fn childAt(self: *const Branch, index: usize) u32 { return self.childPayloadAt(index); } pub fn lowerAt(self: *const Branch, index: usize) []const u8 { return self.keyAt(index); } pub fn firstLower(self: *const Branch) ?[]const u8 { if (self.cellCount() == 0) return null; return self.keyAt(0); } pub fn childIndexFor(self: *const Branch, key: []const u8) usize { const index = self.lowerBound(key); if (index < self.cellCount() and std.mem.eql(u8, self.keyAt(index), key)) return index; if (index == 0) return 0; return index - 1; } pub fn childFor(self: *const Branch, key: []const u8) u32 { return self.childAt(self.childIndexFor(key)); } pub fn put(self: *Branch, lower_key: []const u8, child: u32) Error!void { if (child == 0) return error.InvalidPage; const child_bytes = childBytes(child); try checkLengths(lower_key, child_bytes[0..]); const next_generation = try self.nextGeneration(); const index = self.lowerBound(lower_key); if (index < self.cellCount() and std.mem.eql(u8, self.keyAt(index), lower_key)) { const slot = self.slotAt(index); const child_offset: usize = slot.offset + slot.key_len; self.bytes[child_offset..][0..child_bytes.len].* = child_bytes; } else { try self.cells().insert(index, lower_key, child_bytes[0..]); } self.writeU64(generation_offset, next_generation); } pub fn splitPut(self: *const Branch, left: *Branch, right: *Branch, lower_key: []const u8, child: u32) Error![]const u8 { if (child == 0) return error.InvalidPage; const child_bytes = childBytes(child); try checkLengths(lower_key, child_bytes[0..]); const next_generation = try self.nextGeneration(); left.writeU64(generation_offset, next_generation); right.writeU64(generation_offset, next_generation); var replacement = false; var index: usize = 0; while (index < self.cellCount()) : (index += 1) { if (std.mem.eql(u8, self.keyAt(index), lower_key)) replacement = true; } const total = self.cellCount() + if (replacement) @as(usize, 0) else 1; const split_index = try splitIndexFor(self, lower_key, child_bytes.len, total); var ordinal: usize = 0; var inserted = false; index = 0; while (index < self.cellCount()) : (index += 1) { const entry = self.entryAt(index); switch (simd.order(Bytes, entry.lower, lower_key)) { .lt => try appendSplitBranchEntry(left, right, split_index, &ordinal, entry.lower, entry.child), .eq => { if (!inserted) { try appendSplitBranchEntry(left, right, split_index, &ordinal, lower_key, child); inserted = true; } }, .gt => { if (!inserted) { try appendSplitBranchEntry(left, right, split_index, &ordinal, lower_key, child); inserted = true; } try appendSplitBranchEntry(left, right, split_index, &ordinal, entry.lower, entry.child); }, } } if (!inserted) try appendSplitBranchEntry(left, right, split_index, &ordinal, lower_key, child); return right.firstLower() orelse error.InvalidPage; } pub fn replace(self: *Branch, index: usize, lower_key: []const u8, child: u32) Error!void { if (index >= self.cellCount()) return error.InvalidPage; if (child == 0) return error.InvalidPage; const child_bytes = childBytes(child); try checkLengths(lower_key, child_bytes[0..]); const next_generation = try self.nextGeneration(); var scratch: [size]u8 = undefined; var rebuilt = Branch.init(&scratch, self.id()); rebuilt.writeU64(generation_offset, next_generation); var cursor: usize = 0; while (cursor < self.cellCount()) : (cursor += 1) { if (cursor == index) { try rebuilt.appendEntry(lower_key, child); } else { const entry = self.entryAt(cursor); try rebuilt.appendEntry(entry.lower, entry.child); } } self.bytes.* = scratch; } pub fn remove(self: *Branch, index: usize) Error!void { if (index >= self.cellCount()) return error.InvalidPage; const next_generation = try self.nextGeneration(); self.cells().remove(index); self.writeU64(generation_offset, next_generation); } pub fn copyTo(self: *const Branch, target: *Branch) Error!void { target.writeU64(generation_offset, self.generation()); var index: usize = 0; while (index < self.cellCount()) : (index += 1) { const entry = self.entryAt(index); try target.appendEntry(entry.lower, entry.child); } } fn validate(self: *const Branch) Error!void { if (!std.mem.eql(u8, self.bytes[magic_offset..][0..magic.len], magic[0..])) return error.InvalidPage; if (self.bytes[version_offset] != format_version) return error.InvalidPage; if (self.bytes[kind_offset] != branch_kind) return error.InvalidPage; if (self.readU16(flags_offset) != 0) return error.InvalidPage; if (self.readU16(reserved_offset) != 0) return error.InvalidPage; const count = self.cellCount(); if (count > (size - header_size) / slot_size) return error.InvalidPage; const lower_bound = self.lower(); const upper_bound = self.upper(); if (lower_bound != header_size + count * slot_size) return error.InvalidPage; if (upper_bound < lower_bound or upper_bound > size) return error.InvalidPage; if (count == 0) return error.InvalidPage; var index: usize = 0; while (index < count) : (index += 1) { const slot = self.slotAt(index); const offset: usize = slot.offset; const payload_end = offset + @as(usize, slot.key_len) + @as(usize, slot.value_len); if (offset < upper_bound or payload_end > size) return error.InvalidPage; if (slot.flags != 0) return error.InvalidPage; if (slot.value_len != 4) return error.InvalidPage; if (self.childPayloadAt(index) == 0) return error.InvalidPage; if (index > 0 and simd.order(Bytes, self.keyAt(index - 1), self.keyAt(index)) != .lt) return error.InvalidPage; } } fn appendEntry(self: *Branch, lower_key: []const u8, child: u32) Error!void { const child_bytes = childBytes(child); try self.cells().insert(self.cellCount(), lower_key, child_bytes[0..]); } fn cells(self: *Branch) Cells { return .{ .bytes = self.bytes }; } fn entryAt(self: *const Branch, index: usize) BranchEntry { return .{ .lower = self.keyAt(index), .child = self.childPayloadAt(index) }; } fn lowerBound(self: *const Branch, key: []const u8) usize { var low: usize = 0; var high = self.cellCount(); while (low < high) { const mid = low + (high - low) / 2; switch (simd.order(Bytes, self.keyAt(mid), key)) { .lt => low = mid + 1, .eq, .gt => high = mid, } } return low; } fn nextGeneration(self: *const Branch) Error!u64 { const current = self.generation(); if (current == std.math.maxInt(u64)) return error.GenerationOverflow; return current + 1; } fn keyAt(self: *const Branch, index: usize) []const u8 { const slot = self.slotAt(index); const start: usize = slot.offset; return self.bytes[start..][0..slot.key_len]; } fn childPayloadAt(self: *const Branch, index: usize) u32 { const slot = self.slotAt(index); const start: usize = slot.offset + slot.key_len; return std.mem.readInt(u32, self.bytes[start..][0..4], .big); } fn slotAt(self: *const Branch, index: usize) Slot { const offset = header_size + index * slot_size; return .{ .offset = self.readU16(offset), .key_len = self.readU16(offset + 2), .value_len = self.readU16(offset + 4), .flags = self.readU16(offset + 6), }; } fn lower(self: *const Branch) usize { return self.readU16(lower_offset); } fn upper(self: *const Branch) usize { return self.readU16(upper_offset); } fn readU16(self: *const Branch, offset: usize) u16 { return std.mem.readInt(u16, self.bytes[offset..][0..2], .big); } fn readU64(self: *const Branch, offset: usize) u64 { return std.mem.readInt(u64, self.bytes[offset..][0..8], .big); } fn writeU16(self: *Branch, offset: usize, value: u16) void { std.mem.writeInt(u16, self.bytes[offset..][0..2], value, .big); } fn writeU64(self: *Branch, offset: usize, value: u64) void { std.mem.writeInt(u64, self.bytes[offset..][0..8], value, .big); }};Source: lib/sql/src/root.zig:57
zig
pub const BranchPage = page.Branch;Complete caller list for BranchPage.cellCount
11 direct callers.
lib.sql.src.page.Branch.appendEntry[method] — private source atlib/sql/src/page.zig:606in nearest public ownertiny.sql.pagetiny.sql.BranchPage.childIndexFor[method] atlib/sql/src/page.zig:471tiny.sql.BranchPage.copyTo[method] atlib/sql/src/page.zig:570tiny.sql.BranchPage.firstLower[method] atlib/sql/src/page.zig:466lib.sql.src.page.Branch.lowerBound[method] — private source atlib/sql/src/page.zig:619in nearest public ownertiny.sql.pagetiny.sql.BranchPage.put[method] atlib/sql/src/page.zig:482tiny.sql.BranchPage.remove[method] atlib/sql/src/page.zig:563tiny.sql.BranchPage.replace[method] atlib/sql/src/page.zig:540tiny.sql.BranchPage.splitPut[method] atlib/sql/src/page.zig:498lib.sql.src.page.Branch.validate[method] — private source atlib/sql/src/page.zig:579in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_inserts_replaces_children_and_removes_cells_in_place[function] — test source atlib/sql/src/page.zig:1581in nearest public ownertiny.sql.page
Complete caller list for BranchPage.init
14 direct callers.
tiny.sql.BranchPage.replace[method] atlib/sql/src/page.zig:540lib.sql.src.page.test_branch_page_inserts_replaces_children_and_removes_cells_in_place[function] — test source atlib/sql/src/page.zig:1581in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_rejects_zero_child_identifiers[function] — test source atlib/sql/src/page.zig:1493in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replacement_preserves_lower_bound_order[function] — test source atlib/sql/src/page.zig:1475in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replaces_and_removes_child_entries_by_index[function] — test source atlib/sql/src/page.zig:1560in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_balances_uneven_lower_bound_sizes[function] — test source atlib/sql/src/page.zig:1527in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_returns_the_first_lower_bound_of_the_right_page[function] — test source atlib/sql/src/page.zig:1501in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_stores_lower_bounds_and_routes_children[function] — test source atlib/sql/src/page.zig:1450in nearest public ownertiny.sql.pagelib.sql.src.page.test_pages_copy_entries_into_a_new_page_identity[function] — test source atlib/sql/src/page.zig:1622in nearest public ownertiny.sql.pagelib.sql.src.tree.Tree.putBranch[method] — private source atlib/sql/src/tree.zig:1327in nearest public ownertiny.sql.treelib.sql.src.tree.Tree.putRootBranch[method] — private source atlib/sql/src/tree.zig:1235in nearest public ownertiny.sql.treelib.sql.src.tree.Tree.putRootLeaf[method] — private source atlib/sql/src/tree.zig:1195in nearest public ownertiny.sql.treelib.sql.src.tree.copyRootPage[function] — private source atlib/sql/src/tree.zig:2202in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_delete_retains_a_safe_lower_bound_when_exact_replacement_does_not_fit[function] — test source atlib/sql/src/tree.zig:2861in nearest public ownertiny.sql.tree
Complete caller list for BranchPage.load
20 direct callers.
lib.sql.src.page.test_branch_page_inserts_replaces_children_and_removes_cells_in_place[function] — test source atlib/sql/src/page.zig:1581in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_rejects_zero_child_identifiers[function] — test source atlib/sql/src/page.zig:1493in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replacement_preserves_lower_bound_order[function] — test source atlib/sql/src/page.zig:1475in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replaces_and_removes_child_entries_by_index[function] — test source atlib/sql/src/page.zig:1560in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_balances_uneven_lower_bound_sizes[function] — test source atlib/sql/src/page.zig:1527in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_returns_the_first_lower_bound_of_the_right_page[function] — test source atlib/sql/src/page.zig:1501in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_stores_lower_bounds_and_routes_children[function] — test source atlib/sql/src/page.zig:1450in nearest public ownertiny.sql.pagelib.sql.src.page.test_pages_copy_entries_into_a_new_page_identity[function] — test source atlib/sql/src/page.zig:1622in nearest public ownertiny.sql.pagelib.sql.src.tree.RootBuild.finishBranch[method] — private source atlib/sql/src/tree.zig:1857in nearest public ownertiny.sql.treelib.sql.src.tree.Tree.collectReleasedPages[method] — private source atlib/sql/src/tree.zig:1495in nearest public ownertiny.sql.treelib.sql.src.tree.Tree.compactRoot[method] — private source atlib/sql/src/tree.zig:1436in nearest public ownertiny.sql.treelib.sql.src.tree.copyRootPage[function] — private source atlib/sql/src/tree.zig:2202in nearest public ownertiny.sql.treelib.sql.src.tree.corruptLastLeaf[function] — private source atlib/sql/src/tree.zig:4009in nearest public ownertiny.sql.treelib.sql.src.tree.loadTreePage[function] — private source atlib/sql/src/tree.zig:1998in nearest public ownertiny.sql.treelib.sql.src.tree.summarizePage[function] — private source atlib/sql/src/tree.zig:2043in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_reads_mark_the_pages_they_validate[function] — test source atlib/sql/src/tree.zig:3835in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_recursively_splits_branch_pages[function] — test source atlib/sql/src/tree.zig:2499in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_root_split_creates_a_branch_over_leaf_children[function] — test source atlib/sql/src/tree.zig:2288in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_splits_a_full_child_leaf_under_branch_root[function] — test source atlib/sql/src/tree.zig:2431in nearest public ownertiny.sql.treelib.sql.src.tree.validTreePage[function] — private source atlib/sql/src/tree.zig:2018in nearest public ownertiny.sql.tree
Complete caller list for BranchPage.put
11 direct callers.
lib.sql.src.page.test_branch_page_inserts_replaces_children_and_removes_cells_in_place[function] — test source atlib/sql/src/page.zig:1581in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_rejects_zero_child_identifiers[function] — test source atlib/sql/src/page.zig:1493in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replacement_preserves_lower_bound_order[function] — test source atlib/sql/src/page.zig:1475in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_replaces_and_removes_child_entries_by_index[function] — test source atlib/sql/src/page.zig:1560in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_balances_uneven_lower_bound_sizes[function] — test source atlib/sql/src/page.zig:1527in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_split_returns_the_first_lower_bound_of_the_right_page[function] — test source atlib/sql/src/page.zig:1501in nearest public ownertiny.sql.pagelib.sql.src.page.test_branch_page_stores_lower_bounds_and_routes_children[function] — test source atlib/sql/src/page.zig:1450in nearest public ownertiny.sql.pagelib.sql.src.page.test_pages_copy_entries_into_a_new_page_identity[function] — test source atlib/sql/src/page.zig:1622in nearest public ownertiny.sql.pagelib.sql.src.tree.Tree.putRootBranch[method] — private source atlib/sql/src/tree.zig:1235in nearest public ownertiny.sql.treelib.sql.src.tree.Tree.putRootLeaf[method] — private source atlib/sql/src/tree.zig:1195in nearest public ownertiny.sql.treelib.sql.src.tree.test_tree_delete_retains_a_safe_lower_bound_when_exact_replacement_does_not_fit[function] — test source atlib/sql/src/tree.zig:2861in nearest public ownertiny.sql.tree
Complete call list for BranchPage.put
9 direct calls.
tiny.sql.BranchPage.cellCount[method] atlib/sql/src/page.zig:454lib.sql.src.page.Branch.cells[method] — private source atlib/sql/src/page.zig:611in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.keyAt[method] — private source atlib/sql/src/page.zig:638in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.lowerBound[method] — private source atlib/sql/src/page.zig:619in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.nextGeneration[method] — private source atlib/sql/src/page.zig:632in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.slotAt[method] — private source atlib/sql/src/page.zig:650in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.writeU64[method] — private source atlib/sql/src/page.zig:680in nearest public ownertiny.sql.pagelib.sql.src.page.checkLengths[function] — private source atlib/sql/src/page.zig:1067in nearest public ownertiny.sql.pagelib.sql.src.page.childBytes[function] — private source atlib/sql/src/page.zig:1245in nearest public ownertiny.sql.page
Complete call list for BranchPage.replace
9 direct calls.
lib.sql.src.page.Branch.appendEntry[method] — private source atlib/sql/src/page.zig:606in nearest public ownertiny.sql.pagetiny.sql.BranchPage.cellCount[method] atlib/sql/src/page.zig:454lib.sql.src.page.Branch.entryAt[method] — private source atlib/sql/src/page.zig:615in nearest public ownertiny.sql.pagetiny.sql.BranchPage.id[method] atlib/sql/src/page.zig:446tiny.sql.BranchPage.init[function] atlib/sql/src/page.zig:417lib.sql.src.page.Branch.nextGeneration[method] — private source atlib/sql/src/page.zig:632in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.writeU64[method] — private source atlib/sql/src/page.zig:680in nearest public ownertiny.sql.pagelib.sql.src.page.checkLengths[function] — private source atlib/sql/src/page.zig:1067in nearest public ownertiny.sql.pagelib.sql.src.page.childBytes[function] — private source atlib/sql/src/page.zig:1245in nearest public ownertiny.sql.page
Complete call list for BranchPage.splitPut
8 direct calls.
tiny.sql.BranchPage.cellCount[method] atlib/sql/src/page.zig:454lib.sql.src.page.Branch.entryAt[method] — private source atlib/sql/src/page.zig:615in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.keyAt[method] — private source atlib/sql/src/page.zig:638in nearest public ownertiny.sql.pagelib.sql.src.page.Branch.nextGeneration[method] — private source atlib/sql/src/page.zig:632in nearest public ownertiny.sql.pagelib.sql.src.page.appendSplitBranchEntry[function] — private source atlib/sql/src/page.zig:1236in nearest public ownertiny.sql.pagelib.sql.src.page.checkLengths[function] — private source atlib/sql/src/page.zig:1067in nearest public ownertiny.sql.pagelib.sql.src.page.childBytes[function] — private source atlib/sql/src/page.zig:1245in nearest public ownertiny.sql.pagelib.sql.src.page.splitIndexFor[function] — private source atlib/sql/src/page.zig:1171in nearest public ownertiny.sql.page
Audit
| Definitions | 17 |
|---|---|
| Public names | 34 |
| Members | 1 |
| Version | 26.7.0 |
| Revision | daab053ee433 |