Skip to documentation
SLOP

tiny.sql.TreeWrite

Reference tiny.sql TreeWrite

Defined in tree.

API (20)

Actions

Public operations.

Fields and members

Public fields and members.

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

Source

Source: lib/sql/src/tree.zig:397

zig
pub const Write = struct {    database: *file.Database,    meta_page: u32,    reserved_page_max: u32,    transaction: file.Transaction,    read: file.ReadLease,    snapshot: file.Snapshot,    allocation: Allocation,    identities: std.AutoHashMapUnmanaged(u32, IdentityScratch),    batch_roots: [max_write_batches]u32 = undefined,    batch_root_count: usize = 0,    /// Snapshot pages this write validated, by page id modulo the    /// capacity. The snapshot cannot change during the write, so a page    /// validated once stays valid, and a collision costs one more    /// validation.    validated_pages: [validated_page_capacity]u32 = @splat(0),    pub fn begin(database: *file.Database, options: WriteOptions) Error!Write {        if (options.meta_page == 0) return error.InvalidPageId;        const reserved_page_max = @max(options.reserved_page_max, options.meta_page);        var transaction = try database.beginWrite();        errdefer transaction.deinit();        var read = try database.beginRead();        errdefer read.deinit();        const snapshot = read.snapshot();        return .{            .database = database,            .meta_page = options.meta_page,            .reserved_page_max = reserved_page_max,            .transaction = transaction,            .read = read,            .snapshot = snapshot,            .allocation = try Allocation.init(database, snapshot, options.meta_page, reserved_page_max),            .identities = .empty,        };    }    pub fn beginTree(tree: *const Tree) Error!Write {        return try Write.begin(tree.database, .{            .meta_page = tree.meta_page,            .reserved_page_max = tree.reserved_page_max,        });    }    pub fn deinit(self: *Write) void {        self.identities.deinit(self.database.allocator);        self.transaction.deinit();        self.read.deinit();        self.* = undefined;    }    fn identityScratch(self: *Write, tree: *const Tree) Error!?*IdentityScratch {        if (tree.identity_page == 0) return null;        const slot = try self.identities.getOrPut(self.database.allocator, tree.root_page);        if (!slot.found_existing) {            slot.value_ptr.* = .{                .identity_page = tree.identity_page,                .entries = 0,                .key_bytes = 0,                .value_bytes = 0,                .state = lattice.State.empty,            };            var image: [page.size]u8 = undefined;            if (try self.readPage(tree.identity_page, &image)) {                if (!zeroPage(&image)) {                    const loaded = try page.Identity.load(&image);                    slot.value_ptr.entries = loaded.entries();                    slot.value_ptr.key_bytes = loaded.keyBytes();                    slot.value_ptr.value_bytes = loaded.valueBytes();                    slot.value_ptr.state = loaded.state();                }            }        }        return slot.value_ptr;    }    pub fn put(self: *Write, tree: *Tree, key: []const u8, value: []const u8) Error!void {        try self.ensureTree(tree);        try tree.putInWrite(self, key, value);    }    pub fn delete(self: *Write, tree: *Tree, key: []const u8) Error!void {        try self.ensureTree(tree);        try tree.deleteInWrite(self, key);    }    pub fn clear(self: *Write, tree: *Tree) Error!void {        try self.ensureTree(tree);        try tree.clearInWrite(self);    }    pub fn claimBatch(self: *Write, root_page: u32) Error!void {        if (root_page == 0) return error.InvalidPageId;        for (self.batch_roots[0..self.batch_root_count]) |claimed| {            if (claimed == root_page) return error.WriteBatchRepeated;        }        if (self.batch_root_count == self.batch_roots.len) {            return error.WriteBatchLimitExceeded;        }        self.batch_roots[self.batch_root_count] = root_page;        self.batch_root_count += 1;    }    pub fn allocateRoot(self: *Write) Error!u32 {        const phase = trace.scope("tree.write.allocate_root");        defer phase.end();        const root_page = try self.allocatePage();        var image: [page.size]u8 = @splat(0);        try self.putPage(root_page, &image);        self.reserved_page_max = @max(self.reserved_page_max, root_page);        return root_page;    }    fn allocatePage(self: *Write) Error!u32 {        var meta = try page.Meta.load(&self.allocation.image);        if (meta.isChained() and meta.freeCount() == 0) return try self.refillFreeList(&meta);        const page_id = try meta.allocate();        self.allocation.dirty = true;        return page_id;    }    fn releasePage(self: *Write, root_page: u32, page_id: u32) Error!void {        if (page_id == self.meta_page or page_id == root_page) return error.InvalidPageId;        var meta = try page.Meta.load(&self.allocation.image);        meta.release(page_id) catch |err| switch (err) {            error.FreeListFull => {                try self.spillFreeList(&meta);                try meta.release(page_id);            },            else => return err,        };        self.allocation.dirty = true;    }    fn spillFreeList(self: *Write, meta: *page.Meta) Error!void {        const chain_page = try meta.allocate();        var entries: [page.meta_chain_page_entries + 1]u32 = undefined;        const count = try meta.spillEntries(&entries);        var fragment: [page.meta_chain_page_entries * free_entry_size]u8 = undefined;        for (entries[0..count], 0..) |entry, index| {            std.mem.writeInt(u32, fragment[index * free_entry_size ..][0..free_entry_size], entry, .big);        }        var image: [page.size]u8 = undefined;        _ = try page.Overflow.init(&image, chain_page, meta.chainHead(), fragment[0 .. count * free_entry_size]);        try self.transaction.putPage(chain_page, &image);        try meta.adoptChain(chain_page);        self.allocation.dirty = true;    }    fn refillFreeList(self: *Write, meta: *page.Meta) Error!u32 {        const head = meta.chainHead();        var image: [page.size]u8 = undefined;        try self.readExistingPage(head, &image);        const overflow = try page.Overflow.load(&image);        const content = overflow.content();        if (content.len % free_entry_size != 0) return error.InvalidPage;        const count = content.len / free_entry_size;        var entries: [page.meta_chain_page_entries]u32 = undefined;        if (count > entries.len) return error.InvalidPage;        for (entries[0..count], 0..) |*entry, index| {            entry.* = std.mem.readInt(u32, content[index * free_entry_size ..][0..free_entry_size], .big);        }        try meta.refillFromChain(overflow.next(), entries[0..count]);        self.allocation.dirty = true;        return head;    }    pub fn commit(self: *Write, options: file.CommitOptions) Error!file.Commit {        var identities = self.identities.valueIterator();        while (identities.next()) |scratch| {            if (!scratch.dirty) continue;            var image: [page.size]u8 = undefined;            var identity = page.Identity.init(&image, scratch.identity_page);            identity.setEntries(scratch.entries);            identity.setKeyBytes(scratch.key_bytes);            identity.setValueBytes(scratch.value_bytes);            identity.setState(&scratch.state);            try self.transaction.putPage(scratch.identity_page, &image);        }        try self.allocation.write(self.meta_page, &self.transaction);        return try self.transaction.commit(options);    }    fn ensureTree(self: *const Write, tree: *const Tree) Error!void {        if (self.database != tree.database) return error.TreeSpaceMismatch;        if (self.meta_page != tree.meta_page) return error.TreeSpaceMismatch;        if (self.reserved_page_max < tree.reserved_page_max) return error.TreeSpaceMismatch;    }    fn readRoot(self: *const Write, tree: *const Tree, image: *[page.size]u8) Error!void {        if (try self.readPage(tree.root_page, image)) {            if (!zeroPage(image)) return;        }        _ = page.Leaf.init(image, tree.root_page);    }    fn readExistingPage(self: *const Write, page_id: u32, image: *[page.size]u8) Error!void {        if (try self.readPage(page_id, image)) return;        return error.InvalidPage;    }    fn readPage(self: *const Write, page_id: u32, image: *[page.size]u8) Error!bool {        if (try self.transaction.getPage(page_id)) |bytes| {            image.* = bytes[0..page.size].*;            return true;        }        return try self.snapshot.copyPage(page_id, image);    }    /// Reads a page for editing. A page this write staged comes back as    /// its staged image, and a snapshot page as a copy in `scratch`.    fn readPageSource(self: *Write, page_id: u32, scratch: *[page.size]u8) Error!?SourcedPage {        if (try self.transaction.editPage(page_id)) |staged| {            return .{ .bytes = staged, .source = .transaction };        }        if (try self.snapshot.copyPage(page_id, scratch)) {            return .{ .bytes = scratch, .source = .snapshot };        }        return null;    }    /// Reads the root of `tree` as a leaf or branch. A reserved root that    /// was never written reads as an empty leaf in `scratch`.    fn readRootPage(self: *Write, tree: *const Tree, scratch: *[page.size]u8) Error!TreePage {        const sourced = (try self.readPageSource(tree.root_page, scratch)) orelse            return .{ .leaf = page.Leaf.init(scratch, tree.root_page) };        if (zeroPage(sourced.bytes)) return .{ .leaf = page.Leaf.init(scratch, tree.root_page) };        return try self.treePage(tree.root_page, sourced);    }    /// Reads a leaf or branch named by a branch this write read.    fn readTreePage(self: *Write, page_id: u32, scratch: *[page.size]u8) Error!TreePage {        const sourced = (try self.readPageSource(page_id, scratch)) orelse            return error.InvalidPage;        return try self.treePage(page_id, sourced);    }    /// Wraps a leaf or branch image, validating its cells unless this write    /// wrote the page or already validated it in the snapshot. Safety    /// builds assert that a page skipped that way still validates.    fn treePage(self: *Write, page_id: u32, sourced: SourcedPage) Error!TreePage {        std.debug.assert(page_id != 0);        const slot = &self.validated_pages[page_id % validated_page_capacity];        if (sourced.source == .transaction or slot.* == page_id) {            if (std.debug.runtime_safety) std.debug.assert(validTreePage(sourced.bytes));            return try trustedTreePage(sourced.bytes);        }        const loaded = try loadTreePage(sourced.bytes);        slot.* = page_id;        return loaded;    }    fn copyPage(self: *const Write, page_id: u32, image: *[page.size]u8) Error!bool {        return try self.readPage(page_id, image);    }    fn putPage(self: *Write, page_id: u32, image: *const [page.size]u8) Error!void {        try self.transaction.putPage(page_id, image);    }};

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

zig
pub const TreeWrite = tree.Write;
Called byCallsNo direct callersprivate sourcelib.sql.src.tree.WriteallocatePageprivate sourcelib.sql.src.tree.WriteputPageTreeWriteallocateRoot
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsTreeWritebeginTreetest sourcelib.sql.src.treetest: tree write trusts a snapshot pa...private sourcelib.sql.src.tree.AllocationinitTreeWritebegin
Static calls · unresolved targets: 0 · external targets: 5.
Called byCallsIndexdeleteIndexputIndexputPayloadRowIdTabledeleteRowIdTableput+10 moreTreeWritebeginTreeWritebeginTree
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.tree.WriteensureTreeTreeWriteclear
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallscatalog.MaterializationcommitFileTransactioncommitFileTransactionputPagepage.Identityinitpage.IdentitysetEntriespage.IdentitysetKeyBytes+3 moreTreeWritecommit
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallscatalog.MaterializationdeinitFileReadLeasedeinitFileTransactiondeinitTreeWritedeinit
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.tree.WriteensureTreeTreeWritedelete
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.tree.WriteensureTreeTreeWriteput
Static calls · unresolved targets: 0 · external targets: 1.

Complete caller list for TreeWrite.beginTree

15 direct callers.

Complete call list for TreeWrite.commit

8 direct calls.

Audit

Definitions10
Public names20
Members11
Version26.7.0
Revisiondaab053ee433