Skip to documentation
SLOP

tiny.sql.LeafPage

Reference tiny.sql LeafPage

Defined in page.

API (17)

Actions

Public operations.

Fields and members

Public fields and members.

No direct callersNo direct callspageLeaf
Static calls · unresolved targets: unknown · external targets: unknown.

Source

Source: lib/sql/src/page.zig:102

zig
pub const Leaf = struct {    bytes: *[size]u8,    pub fn init(bytes: *[size]u8, page_id: u64) Leaf {        var leaf = Leaf{ .bytes = bytes };        @memset(leaf.bytes, 0);        @memcpy(leaf.bytes[magic_offset..][0..magic.len], magic[0..]);        leaf.bytes[version_offset] = format_version;        leaf.bytes[kind_offset] = leaf_kind;        leaf.writeU16(flags_offset, 0);        leaf.writeU64(id_offset, page_id);        leaf.writeU64(generation_offset, 0);        leaf.writeU16(lower_offset, header_size);        leaf.writeU16(upper_offset, size);        leaf.writeU16(cells_offset, 0);        leaf.writeU16(reserved_offset, 0);        return leaf;    }    pub fn load(bytes: *[size]u8) Error!Leaf {        const leaf = Leaf{ .bytes = bytes };        try leaf.validate();        return leaf;    }    /// Wraps a leaf image that `load` validated, without walking its cells    /// again. The image must be unchanged since that `load`. A reader that    /// returns to one leaf once per cell validates it once through `load` and    /// resumes through this.    pub fn fromValidated(bytes: *[size]u8) Leaf {        std.debug.assert(bytes[kind_offset] == leaf_kind);        return .{ .bytes = bytes };    }    pub fn id(self: *const Leaf) u64 {        return self.readU64(id_offset);    }    pub fn generation(self: *const Leaf) u64 {        return self.readU64(generation_offset);    }    pub fn cellCount(self: *const Leaf) usize {        return self.readU16(cells_offset);    }    pub fn firstKey(self: *const Leaf) ?[]const u8 {        if (self.cellCount() == 0) return null;        return self.keyAt(0);    }    pub fn freeBytes(self: *const Leaf) usize {        const lower_bound = self.lower();        const upper_bound = self.upper();        if (upper_bound < lower_bound) return 0;        return upper_bound - lower_bound;    }    pub fn usedBytes(self: *const Leaf) usize {        return size - self.freeBytes();    }    pub fn get(self: *const Leaf, key: []const u8) ?[]const u8 {        const phase = trace.scope("page.leaf.get");        defer phase.end();        const index = self.lowerBound(key);        if (index < self.cellCount() and std.mem.eql(u8, self.keyAt(index), key)) return self.valueAt(index);        return null;    }    pub fn put(self: *Leaf, key: []const u8, value: []const u8) Error!void {        const phase = trace.scope("page.leaf.put");        defer phase.end();        try checkLengths(key, value);        const next_generation = try self.nextGeneration();        const existing_index = self.lowerBound(key);        if (existing_index == self.cellCount() or            !std.mem.eql(u8, self.keyAt(existing_index), key))        {            try self.cells().insert(existing_index, key, value);            self.writeU64(generation_offset, next_generation);            trace.progress("page.leaf.put.insert.complete");            return;        }        const slot = self.slotAt(existing_index);        if (value.len == slot.value_len) {            const value_offset: usize = slot.offset + slot.key_len;            @memcpy(self.bytes[value_offset..][0..value.len], value);            self.writeU64(generation_offset, next_generation);            trace.progress("page.leaf.put.inplace.complete");            return;        }        var scratch: [size]u8 = undefined;        var rebuilt = Leaf.init(&scratch, self.id());        rebuilt.writeU64(generation_offset, next_generation);        var inserted = false;        var index: usize = 0;        while (index < self.cellCount()) : (index += 1) {            const entry = self.entryAt(index);            switch (simd.order(Bytes, entry.key, key)) {                .lt => try rebuilt.appendEntry(entry.key, entry.value),                .eq => {                    if (!inserted) {                        try rebuilt.appendEntry(key, value);                        inserted = true;                    }                },                .gt => {                    if (!inserted) {                        try rebuilt.appendEntry(key, value);                        inserted = true;                    }                    try rebuilt.appendEntry(entry.key, entry.value);                },            }        }        if (!inserted) try rebuilt.appendEntry(key, value);        self.bytes.* = scratch;        trace.progress("page.leaf.put.complete");    }    pub fn delete(self: *Leaf, key: []const u8) Error!void {        const phase = trace.scope("page.leaf.delete");        defer phase.end();        const next_generation = try self.nextGeneration();        const index = self.lowerBound(key);        if (index == self.cellCount() or !std.mem.eql(u8, self.keyAt(index), key)) {            return error.KeyNotFound;        }        self.cells().remove(index);        self.writeU64(generation_offset, next_generation);        trace.progress("page.leaf.delete.complete");    }    pub fn range(self: *const Leaf, start: ?[]const u8, end: ?[]const u8) Error!Range {        if (start) |lower_key| {            if (end) |upper_key| {                if (simd.order(Bytes, lower_key, upper_key) == .gt) return error.InvalidRange;            }        }        return .{            .leaf = self,            .end = end,            .index = if (start) |key| self.lowerBound(key) else 0,        };    }    pub fn splitPut(self: *const Leaf, left: *Leaf, right: *Leaf, key: []const u8, value: []const u8) Error![]const u8 {        const phase = trace.scope("page.leaf.split_put");        defer phase.end();        try checkLengths(key, value);        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), key)) replacement = true;        }        const total = self.cellCount() + if (replacement) @as(usize, 0) else 1;        const split_index = try splitIndexFor(self, key, value.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.key, key)) {                .lt => {                    try appendSplitEntry(left, right, split_index, &ordinal, entry.key, entry.value);                },                .eq => {                    if (!inserted) {                        try appendSplitEntry(left, right, split_index, &ordinal, key, value);                        inserted = true;                    }                },                .gt => {                    if (!inserted) {                        try appendSplitEntry(left, right, split_index, &ordinal, key, value);                        inserted = true;                    }                    try appendSplitEntry(left, right, split_index, &ordinal, entry.key, entry.value);                },            }        }        if (!inserted) try appendSplitEntry(left, right, split_index, &ordinal, key, value);        return right.firstKey() orelse error.InvalidPage;    }    pub fn copyTo(self: *const Leaf, target: *Leaf) 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.key, entry.value);        }    }    fn validate(self: *const Leaf) 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] != leaf_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;        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 (index > 0 and simd.order(Bytes, self.keyAt(index - 1), self.keyAt(index)) != .lt) return error.InvalidPage;        }    }    fn appendEntry(self: *Leaf, key: []const u8, value: []const u8) Error!void {        try self.cells().insert(self.cellCount(), key, value);    }    fn cells(self: *Leaf) Cells {        return .{ .bytes = self.bytes };    }    fn lowerBound(self: *const Leaf, 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 Leaf) Error!u64 {        const current = self.generation();        if (current == std.math.maxInt(u64)) return error.GenerationOverflow;        return current + 1;    }    pub fn lastKey(self: *const Leaf) ?[]const u8 {        const count = self.cellCount();        if (count == 0) return null;        return self.keyAt(count - 1);    }    fn entryAt(self: *const Leaf, index: usize) Entry {        return .{ .key = self.keyAt(index), .value = self.valueAt(index) };    }    fn keyAt(self: *const Leaf, index: usize) []const u8 {        const slot = self.slotAt(index);        const start: usize = slot.offset;        return self.bytes[start..][0..slot.key_len];    }    fn valueAt(self: *const Leaf, index: usize) []const u8 {        const slot = self.slotAt(index);        const start: usize = slot.offset + slot.key_len;        return self.bytes[start..][0..slot.value_len];    }    fn slotAt(self: *const Leaf, 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 Leaf) usize {        return self.readU16(lower_offset);    }    fn upper(self: *const Leaf) usize {        return self.readU16(upper_offset);    }    fn readU16(self: *const Leaf, offset: usize) u16 {        return std.mem.readInt(u16, self.bytes[offset..][0..2], .big);    }    fn readU64(self: *const Leaf, offset: usize) u64 {        return std.mem.readInt(u64, self.bytes[offset..][0..8], .big);    }    fn writeU16(self: *Leaf, offset: usize, value: u16) void {        std.mem.writeInt(u16, self.bytes[offset..][0..2], value, .big);    }    fn writeU64(self: *Leaf, offset: usize, value: u64) void {        std.mem.writeInt(u64, self.bytes[offset..][0..8], value, .big);    }};

Source: lib/sql/src/root.zig:56

zig
pub const LeafPage = page.Leaf;
Called byCallsprivate sourcelib.sql.src.page.LeafappendEntryLeafPagecopyToLeafPagedeleteLeafPagefirstKeyLeafPageget+11 moreprivate sourcelib.sql.src.page.LeafreadU16LeafPagecellCount
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sql.src.pagetest: pages copy entries into a new p...LeafPagecellCountprivate sourcelib.sql.src.page.LeafentryAtLeafPagegenerationLeafPagecopyTo
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallstest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page replacement and delet...private sourcelib.sql.src.properties.page.LeafPropertypropertyLeafPagecellCountprivate sourcelib.sql.src.page.Leafcellsprivate sourcelib.sql.src.page.LeafkeyAtprivate sourcelib.sql.src.page.LeaflowerBoundprivate sourcelib.sql.src.page.LeafnextGeneration+2 moreLeafPagedelete
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallstest sourcelib.sql.src.pagetest: leaf page split balances uneven...LeafPagecellCountprivate sourcelib.sql.src.page.LeafkeyAtLeafPagefirstKey
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsLeafPageusedBytestest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page initializes a stable ...test sourcelib.sql.src.pagetest: leaf page replacement and delet...private sourcelib.sql.src.properties.pageexpectLeafprivate sourcelib.sql.src.page.Leaflowerprivate sourcelib.sql.src.page.LeafupperLeafPagefreeBytes
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsprivate sourcelib.sql.src.tree.Scaninitprivate sourcelib.sql.src.tree.ScannextEntryprivate sourcelib.sql.src.treetrustedTreePageLeafPagefromValidated
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsLeafPagecopyToprivate sourcelib.sql.src.page.LeafnextGenerationtest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page initializes a stable ...test sourcelib.sql.src.pagetest: leaf page inserts between cells...+2 moreprivate sourcelib.sql.src.page.LeafreadU64LeafPagegeneration
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page failed writes leave e...test sourcelib.sql.src.pagetest: leaf page inserts between cells...test sourcelib.sql.src.pagetest: leaf page replacement and delet...test sourcelib.sql.src.pagetest: leaf page same size replacement...+2 moreLeafPagecellCountprivate sourcelib.sql.src.page.LeafkeyAtprivate sourcelib.sql.src.page.LeaflowerBoundprivate sourcelib.sql.src.page.LeafvalueAtLeafPageget
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsLeafPageputtest sourcelib.sql.src.pagetest: leaf page initializes a stable ...private sourcelib.sql.src.page.LeafreadU64LeafPageid
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callsLeafPageputtest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page failed writes leave e...test sourcelib.sql.src.pagetest: leaf page initializes a stable ...test sourcelib.sql.src.pagetest: leaf page insert into a full pa...+21 moreLeafPageinit
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersLeafPagecellCountprivate sourcelib.sql.src.page.LeafkeyAtLeafPagelastKey
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page initializes a stable ...test sourcelib.sql.src.pagetest: leaf page inserts between cells...test sourcelib.sql.src.pagetest: leaf page same size replacement...test sourcelib.sql.src.pagetest: leaf page split balances uneven...+12 moreLeafPageload
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.sql.src.pagetest: leaf page deletion closes the g...test sourcelib.sql.src.pagetest: leaf page failed writes leave e...test sourcelib.sql.src.pagetest: leaf page insert into a full pa...test sourcelib.sql.src.pagetest: leaf page inserts between cells...test sourcelib.sql.src.pagetest: leaf page range scans honor hal...+10 moreprivate sourcelib.sql.src.page.LeafappendEntryLeafPagecellCountprivate sourcelib.sql.src.page.Leafcellsprivate sourcelib.sql.src.page.LeafentryAtLeafPageid+8 moreLeafPageput
Static calls · unresolved targets: 0 · external targets: 3.
Called byCallstest sourcelib.sql.src.pagetest: leaf page range scans honor hal...private sourcelib.sql.src.page.LeaflowerBoundLeafPagerange
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallstest sourcelib.sql.src.pagetest: leaf page split balances uneven...LeafPagecellCountprivate sourcelib.sql.src.page.LeafentryAtprivate sourcelib.sql.src.page.LeafkeyAtprivate sourcelib.sql.src.page.LeafnextGenerationprivate sourcelib.sql.src.pageappendSplitEntry+2 moreLeafPagesplitPut
Static calls · unresolved targets: 0 · external targets: 6.
Called byCallstest sourcelib.sql.src.pagetest: leaf page replacement and delet...test sourcelib.sql.src.pagetest: leaf page same size replacement...LeafPagefreeBytesLeafPageusedBytes
Static calls · unresolved targets: 0 · external targets: 0.

Complete caller list for LeafPage.cellCount

16 direct callers.

Complete call list for LeafPage.delete

7 direct calls.

Complete caller list for LeafPage.generation

7 direct callers.

Complete caller list for LeafPage.get

7 direct callers.

Complete caller list for LeafPage.init

26 direct callers.

Complete caller list for LeafPage.load

17 direct callers.

Complete caller list for LeafPage.put

15 direct callers.

Complete call list for LeafPage.put

13 direct calls.

Complete call list for LeafPage.splitPut

7 direct calls.

Audit

Definitions17
Public names34
Members1
Version26.7.0
Revisiondaab053ee433