Skip to documentation
SLOP

tiny.sql.space

Reference tiny.sql space

Defined in tiny.sql.

API (11)

Actions

Public operations.

Types and contracts

Public types and contracts.

Values and defaults

Public values and defaults.

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

Source

Called byCallsNo direct callersspace.ReadertreeOptionsspace.Readerindex
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.space.Layoutinitspace.Readeropen
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersspace.ReadertreeOptionstable.Readeropenspace.ReaderrowidTable
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersspace.ReadertreeOptionsspace.Readertree
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsspace.Readerindexspace.ReaderrowidTablespace.Readertreeprivate sourcelib.sql.src.spaceoptionsForRootspace.ReadertreeOptions
Static calls · unresolved targets: 0 · external targets: 0.

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

zig
pub const space = @import("space.zig");

Source: lib/sql/src/space.zig

zig
const std = @import("std");const file = @import("file.zig");const index_mod = @import("index.zig");const page = @import("page.zig");const row = @import("row.zig");const table = @import("table.zig");const tree_mod = @import("tree.zig");const wal = @import("wal.zig");const SpaceError = error{    TooManyRoots,};pub const Error = table.Error || index_mod.Error || tree_mod.Error || page.Error || SpaceError;pub const max_roots: usize = 32;pub const RootSpec = struct {    root_page: u32,    identity_page: u32 = 0,};pub const Options = struct {    meta_page: u32 = 1,    roots: []const RootSpec = &.{.{ .root_page = 2 }},    reserved_page_max: u32 = 0,};const Layout = struct {    meta_page: u32,    roots: [max_roots]RootSpec,    root_count: usize,    reserved_page_max: u32,    fn init(options: Options) Error!Layout {        if (options.meta_page == 0) return error.InvalidPageId;        if (options.roots.len == 0) return error.InvalidPageId;        if (options.roots.len > max_roots) return error.TooManyRoots;        var layout = Layout{            .meta_page = options.meta_page,            .roots = undefined,            .root_count = options.roots.len,            .reserved_page_max = @max(options.meta_page, options.reserved_page_max),        };        for (options.roots, 0..) |spec, offset| {            try layout.addRoot(spec, offset);        }        return layout;    }    fn addRoot(self: *Layout, spec: RootSpec, offset: usize) Error!void {        if (spec.root_page == 0 or spec.root_page == self.meta_page) {            return error.InvalidPageId;        }        if (spec.identity_page != 0) {            if (spec.identity_page == self.meta_page) return error.InvalidPageId;            if (spec.identity_page == spec.root_page) return error.InvalidPageId;        }        for (self.roots[0..offset]) |previous| {            if (previous.root_page == spec.root_page) return error.InvalidPageId;            if (spec.identity_page != 0 and previous.identity_page == spec.identity_page) {                return error.InvalidPageId;            }            if (previous.root_page == spec.identity_page) return error.InvalidPageId;            if (previous.identity_page == spec.root_page) return error.InvalidPageId;        }        self.roots[offset] = spec;        self.reserved_page_max = @max(            self.reserved_page_max,            @max(spec.root_page, spec.identity_page),        );    }};fn optionsForRoot(    meta_page: u32,    roots: []const RootSpec,    reserved_page_max: u32,    root_page: u32,) Error!tree_mod.Options {    for (roots) |spec| {        if (spec.root_page == root_page) return .{            .meta_page = meta_page,            .root_page = spec.root_page,            .identity_page = spec.identity_page,            .reserved_page_max = reserved_page_max,        };    }    return error.InvalidPageId;}pub const Reader = struct {    snapshot: file.Snapshot,    meta_page: u32,    roots: [max_roots]RootSpec,    root_count: usize,    reserved_page_max: u32,    pub fn open(snapshot: file.Snapshot, options: Options) Error!Reader {        const layout = try Layout.init(options);        return .{            .snapshot = snapshot,            .meta_page = layout.meta_page,            .roots = layout.roots,            .root_count = layout.root_count,            .reserved_page_max = layout.reserved_page_max,        };    }    pub fn treeOptions(self: *const Reader, root_page: u32) Error!tree_mod.Options {        return try optionsForRoot(            self.meta_page,            self.roots[0..self.root_count],            self.reserved_page_max,            root_page,        );    }    pub fn tree(self: *const Reader, root_page: u32) Error!tree_mod.Reader {        return try tree_mod.Reader.open(self.snapshot, try self.treeOptions(root_page));    }    pub fn rowidTable(self: *const Reader, root_page: u32) Error!table.Reader {        return try table.Reader.open(self.snapshot, .{ .tree = try self.treeOptions(root_page) });    }    pub fn index(        self: *const Reader,        root_page: u32,        columns: []const row.Column,    ) Error!index_mod.Reader {        return try index_mod.Reader.open(self.snapshot, .{            .tree = try self.treeOptions(root_page),            .columns = columns,        });    }};pub const Space = struct {    database: *file.Database,    meta_page: u32,    roots: [max_roots]RootSpec,    root_count: usize,    reserved_page_max: u32,    pub fn open(database: *file.Database, options: Options) Error!Space {        const layout = try Layout.init(options);        return .{            .database = database,            .meta_page = layout.meta_page,            .roots = layout.roots,            .root_count = layout.root_count,            .reserved_page_max = layout.reserved_page_max,        };    }    pub fn reader(self: *const Space, snapshot: file.Snapshot) Error!Reader {        return .{            .snapshot = snapshot,            .meta_page = self.meta_page,            .roots = self.roots,            .root_count = self.root_count,            .reserved_page_max = self.reserved_page_max,        };    }    pub fn treeOptions(self: *const Space, root_page: u32) Error!tree_mod.Options {        return try optionsForRoot(            self.meta_page,            self.roots[0..self.root_count],            self.reserved_page_max,            root_page,        );    }    pub fn tree(self: *const Space, root_page: u32) Error!tree_mod.Tree {        return try tree_mod.Tree.open(self.database, try self.treeOptions(root_page));    }    pub fn rowidTable(self: *const Space, root_page: u32) Error!table.Table {        return try table.Table.open(self.database, .{ .tree = try self.treeOptions(root_page) });    }    pub fn index(self: *const Space, root_page: u32, columns: []const row.Column) Error!index_mod.Index {        return try index_mod.Index.open(self.database, .{            .tree = try self.treeOptions(root_page),            .columns = columns,        });    }    pub fn beginWrite(self: *const Space) Error!tree_mod.Write {        return try tree_mod.Write.begin(self.database, .{            .meta_page = self.meta_page,            .reserved_page_max = self.reserved_page_max,        });    }};test "space rejects invalid roots" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    var database = try file.Database.openForTesting(std.testing.allocator, tmp.dir, .{        .paths = .{ .database = "space.db", .wal = "space.wal" },        .header = testingHeader(),    });    defer database.deinit();    try std.testing.expectError(error.InvalidPageId, Space.open(&database, .{ .roots = &.{} }));    try std.testing.expectError(error.InvalidPageId, Space.open(&database, .{ .meta_page = 1, .roots = &.{ .{ .root_page = 2 }, .{ .root_page = 2 } } }));    const space = try Space.open(&database, .{ .meta_page = 1, .roots = &.{ .{ .root_page = 2 }, .{ .root_page = 3 } } });    try std.testing.expectError(error.InvalidPageId, space.treeOptions(4));}test "space keeps table growth away from reserved index root" {    var tmp = std.testing.tmpDir(.{});    defer tmp.cleanup();    {        var database = try file.Database.openForTesting(std.testing.allocator, tmp.dir, .{            .paths = .{ .database = "space.db", .wal = "space.wal" },            .header = testingHeader(),        });        defer database.deinit();        try database.reserve(.{ .wal_frames = 480 });        const space = try Space.open(&database, .{ .meta_page = 1, .roots = &.{ .{ .root_page = 2 }, .{ .root_page = 3 } } });        var rows = try space.rowidTable(2);        var rowid: i64 = 0;        while (rowid < 180) : (rowid += 1) {            _ = try rows.put(rowid, &.{ .{ .integer = rowid }, .{ .text = "payload" } }, .{ .durability = .buffered });        }        {            var read = try database.beginRead();            defer read.deinit();            var index_root_image: [page.size]u8 = undefined;            try std.testing.expect(!(try read.snapshot().copyPage(                3,                &index_root_image,            )));        }        var secondary = try space.index(3, &.{});        rowid = 0;        while (rowid < 180) : (rowid += 1) {            _ = try secondary.put(rowid, &.{.{ .integer = @mod(rowid, 9) }}, .{ .durability = .buffered });        }        try database.syncWal();    }    var reopened = try file.Database.openForTesting(std.testing.allocator, tmp.dir, .{        .paths = .{ .database = "space.db", .wal = "space.wal" },        .header = recoveredHeader(),    });    defer reopened.deinit();    const space = try Space.open(&reopened, .{ .meta_page = 1, .roots = &.{ .{ .root_page = 2 }, .{ .root_page = 3 } } });    var rows = try space.rowidTable(2);    var secondary = try space.index(3, &.{});    var lookup: index_mod.Scan = undefined;    try secondary.lookup(&lookup, std.testing.allocator, &.{.{ .integer = 4 }});    defer lookup.deinit();    var seen: usize = 0;    while (try lookup.next()) |entry| {        const bytes = (try rows.get(std.testing.allocator, entry.rowid)).?;        defer std.testing.allocator.free(bytes);        const view = try row.View.init(bytes);        try std.testing.expectEqual(entry.rowid, (try view.column(0)).integer);        try std.testing.expectEqual(@as(i64, 4), @mod(entry.rowid, 9));        seen += 1;    }    try std.testing.expect(seen > 0);}fn testingHeader() wal.Header {    return .{        .sequence = 901,        .salt = .{ .first = 0x9191_7272, .second = 0x6363_5454 },    };}fn recoveredHeader() wal.Header {    return .{        .sequence = 902,        .salt = .{ .first = 0xaaaa_8888, .second = 0x9999_bbbb },    };}

Audit

Definitions9
Public names9
Members5
Version26.7.0
Revisiondaab053ee433