Skip to documentation
SLOP

tiny.sql.FileDatabaseWorkspace

Reference tiny.sql FileDatabaseWorkspace

Defined in tiny.sql.

The reusable storage an open database runs on, built once by a caller so that the pager, the caches, and the paths for every database opened through it come from storage laid out in advance.

API (36)

Actions

Public operations.

Types and contracts

Public types and contracts.

Fields and members

Public fields and members.

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

Source

Source: lib/sql/src/file.zig:816

zig
/// The reusable storage an open database runs on, built once by a caller so/// that the pager, the caches, and the paths for every database opened through/// it come from storage laid out in advance. The workspace covers the pager,/// path storage, read cache, digest memo, and transaction staging area. One set/// of limits sizes all of them, naming the write-ahead log header, the log byte/// ceiling, the path limits, read cache pages, and digest memo entries. The/// workspace takes storage from the caller with `init` or from an allocator/// with `allocate`, gives it back with the matching `deinit` or `deallocate`,/// and lends each region to one holder at a time. A second request receives/// `WorkspaceBusy`./// Because the path storage inside records the workspace's address, callers/// keep the workspace at one address across every database opened from it, and/// teardown refuses by assertion until every region has been returned.pub const DatabaseWorkspace = struct {    pub const Limits = struct {        header: wal.Header,        max_wal_bytes: usize,        path_storage: PathStorage.Limits,        read_cache_pages: usize = default_read_cache_capacity,        /// Direct-mapped slots, keyed by identity page, each holding one        /// stored tree digest. Zero disables reuse.        digest_memo_entries: usize = default_digest_memo_entries,    };    pub const Storage = struct {        pager: pager.Pager.Workspace,        paths: PathStorage.Storage,        read_cache: ReadCache.Storage,        digest_memo: DigestMemo.Storage,        transaction_staging: TransactionStaging.Storage,    };    pub const Capacity = struct {        wal_frames: usize,        pager: pager.Pager.Workspace.Capacity,        paths: PathStorage.Capacity,        read_cache: ReadCache.Capacity,        digest_memo: DigestMemo.Capacity,        transaction_staging: TransactionStaging.Capacity,        requested_bytes: usize,        pub const DeriveError = pager.Pager.Workspace.Capacity.DeriveError ||            error{ InvalidWalLimit, CapacityOverflow };        pub fn derive(limits: Limits) DeriveError!Capacity {            const wal_frames = try walFrameCapacity(limits.max_wal_bytes);            const pager_capacity = try pager.Pager.Workspace.Capacity.derive(.{                .header = limits.header,                .wal_frames = wal_frames,            });            const transaction_staging = try TransactionStaging.Capacity.derive(.{                .frames = wal_frames,            });            const paths = try PathStorage.Capacity.derive(limits.path_storage);            const read_cache = try ReadCache.Capacity.derive(.{                .pages = limits.read_cache_pages,            });            const digest_memo = try DigestMemo.Capacity.derive(limits.digest_memo_entries);            var requested_bytes = pager_capacity.journal.storage_bytes;            requested_bytes = std.math.add(                usize,                requested_bytes,                pager_capacity.checkpoint.storage_bytes,            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                pager_capacity.checkpoint_once.storage_bytes,            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                pager_capacity.wal_index.storage_bytes,            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                paths.storageBytes(),            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                read_cache.storage_bytes,            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                digest_memo.storage_bytes,            ) catch return error.CapacityOverflow;            requested_bytes = std.math.add(                usize,                requested_bytes,                transaction_staging.storage_bytes,            ) catch return error.CapacityOverflow;            return .{                .wal_frames = wal_frames,                .pager = pager_capacity,                .paths = paths,                .read_cache = read_cache,                .digest_memo = digest_memo,                .transaction_staging = transaction_staging,                .requested_bytes = requested_bytes,            };        }    };    pub const InitError = Capacity.DeriveError || PathStorage.IdentityError ||        error{StorageTooShort};    pub const AllocateError = Allocator.Error || Capacity.DeriveError ||        PathStorage.IdentityError;    pub const AcquireError = Error || error{ WorkspaceBusy, WorkspaceCapacityExceeded };    const State = enum {        free,        busy,    };    phase: alloc_phase.capacity.Phase,    limits: Limits,    capacity: Capacity,    storage: Storage,    path_storage: PathStorage,    state: State = .free,    loan: pager.Pager.Workspace.Capacity = undefined,    read_cache_live: bool = false,    read_cache_loan: ReadCache.Capacity = undefined,    digest_memo_live: bool = false,    transaction_staging_live: bool = false,    transaction_staging_loan: TransactionStaging.Capacity = undefined,    pub fn init(storage: Storage, limits: Limits) InitError!DatabaseWorkspace {        const capacity = try Capacity.derive(limits);        if (!fits(storage, capacity)) return error.StorageTooShort;        const path_storage = try PathStorage.init(            storage.paths[0..capacity.paths.storageBytes()],            limits.path_storage,        );        return .{            .phase = .initialization,            .limits = limits,            .capacity = capacity,            .storage = storage,            .path_storage = path_storage,        };    }    pub fn allocate(allocator: Allocator, limits: Limits) AllocateError!DatabaseWorkspace {        const capacity = try Capacity.derive(limits);        var pager_storage = try pager.Pager.Workspace.allocate(allocator, .{            .header = limits.header,            .wal_frames = capacity.wal_frames,        });        errdefer pager_storage.deallocate(allocator);        const paths = if (capacity.paths.storageBytes() == 0)            @as(PathStorage.Storage, &.{})        else            try allocator.alloc(u8, capacity.paths.storageBytes());        errdefer if (paths.len != 0) allocator.free(paths);        const read_cache = if (capacity.read_cache.storage_bytes == 0)            @as(ReadCache.Storage, &.{})        else            try allocator.alignedAlloc(                u8,                .fromByteUnits(ReadCache.storage_alignment),                capacity.read_cache.storage_bytes,            );        errdefer if (read_cache.len != 0) allocator.free(read_cache);        const digest_memo = if (capacity.digest_memo.entries == 0)            @as(DigestMemo.Storage, &.{})        else            try allocator.alloc(DigestMemo.Entry, capacity.digest_memo.entries);        errdefer if (digest_memo.len != 0) allocator.free(digest_memo);        const transaction_staging = if (capacity.transaction_staging.storage_bytes == 0)            @as(TransactionStaging.Storage, &.{})        else            try allocator.alignedAlloc(                u8,                .fromByteUnits(TransactionStaging.storage_alignment),                capacity.transaction_staging.storage_bytes,            );        errdefer if (transaction_staging.len != 0) allocator.free(transaction_staging);        var workspace = init(.{            .pager = pager_storage,            .paths = paths,            .read_cache = read_cache,            .digest_memo = digest_memo,            .transaction_staging = transaction_staging,        }, limits) catch |err| switch (err) {            error.StorageTooShort => unreachable,            else => |other| return other,        };        workspace.activate();        return workspace;    }    pub fn activate(self: *DatabaseWorkspace) void {        std.debug.assert(self.phase == .initialization);        self.assertValid();        self.phase = .steady;    }    pub fn acquire(        self: *DatabaseWorkspace,        allocator: Allocator,        options: pager.InitOptions,    ) AcquireError!pager.Pager {        self.assertSteady();        if (self.state == .busy) return error.WorkspaceBusy;        const loan = try pager.Pager.Workspace.Capacity.derive(options);        if (options.wal_frames > self.capacity.wal_frames or            !fitsPager(self.storage.pager, loan))        {            return error.WorkspaceCapacityExceeded;        }        var storage = pager.Pager.Workspace.init(            self.storage.pager.journal[0..loan.journal.storage_bytes],            self.storage.pager.checkpoint[0..loan.checkpoint.storage_bytes],            self.storage.pager.checkpoint_once[0..loan.checkpoint_once.storage_bytes],            self.storage.pager.wal_index[0..loan.wal_index.storage_bytes],        );        const owned = pager.Pager.init(allocator, &storage, options) catch |err| switch (err) {            error.StorageTooShort => unreachable,            else => return err,        };        self.state = .busy;        self.loan = loan;        return owned;    }    pub fn release(self: *DatabaseWorkspace, owned: *pager.Pager) void {        self.assertSteady();        std.debug.assert(self.state == .busy);        const returned = owned.deinit();        assertReturned(self.storage.pager.journal, returned.journal, self.loan.journal.storage_bytes);        assertReturned(self.storage.pager.checkpoint, returned.checkpoint, self.loan.checkpoint.storage_bytes);        assertReturned(            self.storage.pager.checkpoint_once,            returned.checkpoint_once,            self.loan.checkpoint_once.storage_bytes,        );        assertReturned(self.storage.pager.wal_index, returned.wal_index, self.loan.wal_index.storage_bytes);        self.state = .free;        self.loan = undefined;    }    pub fn acquirePathStorage(        self: *DatabaseWorkspace,        limits: PathStorage.Limits,    ) AcquireError!PathStorage.Loan {        self.assertSteady();        return self.path_storage.acquire(limits) catch |err| switch (err) {            error.PathStorageBusy => error.WorkspaceBusy,            error.PathCapacityExceeded => error.WorkspaceCapacityExceeded,            else => |other| other,        };    }    pub fn releasePathStorage(        self: *DatabaseWorkspace,        owned: *PathStorage.Loan,    ) PathStorage.Loan.LoanError!void {        self.assertSteady();        try self.path_storage.release(owned);    }    pub fn acquireReadCache(        self: *DatabaseWorkspace,        limits: ReadCache.Limits,    ) AcquireError!ReadCache {        self.assertSteady();        if (self.read_cache_live) return error.WorkspaceBusy;        const loan = try ReadCache.Capacity.derive(limits);        if (loan.storage_bytes > self.storage.read_cache.len) {            return error.WorkspaceCapacityExceeded;        }        const owned = ReadCache.init(            self.storage.read_cache[0..loan.storage_bytes],            limits,        ) catch |err| switch (err) {            error.StorageTooShort => unreachable,            else => return err,        };        self.read_cache_live = true;        self.read_cache_loan = loan;        return owned;    }    pub fn releaseReadCache(        self: *DatabaseWorkspace,        owned: *ReadCache,    ) void {        self.assertSteady();        std.debug.assert(self.read_cache_live);        const returned = owned.deinit();        assertReturned(            self.storage.read_cache,            returned,            self.read_cache_loan.storage_bytes,        );        self.read_cache_live = false;        self.read_cache_loan = undefined;    }    pub fn acquireDigestMemo(self: *DatabaseWorkspace) AcquireError!DigestMemo {        self.assertSteady();        if (self.digest_memo_live) return error.WorkspaceBusy;        self.digest_memo_live = true;        return DigestMemo.init(self.storage.digest_memo, self.capacity.digest_memo.entries);    }    pub fn releaseDigestMemo(self: *DatabaseWorkspace, owned: *DigestMemo) void {        self.assertSteady();        std.debug.assert(self.digest_memo_live);        std.debug.assert(owned.slots.ptr == self.storage.digest_memo.ptr);        std.debug.assert(owned.slots.len == self.capacity.digest_memo.entries);        owned.* = undefined;        self.digest_memo_live = false;    }    pub fn acquireTransactionStaging(        self: *DatabaseWorkspace,        limits: TransactionStaging.Limits,    ) AcquireError!TransactionStaging {        self.assertSteady();        if (self.transaction_staging_live) return error.WorkspaceBusy;        const loan = try TransactionStaging.Capacity.derive(limits);        if (loan.storage_bytes > self.storage.transaction_staging.len) {            return error.WorkspaceCapacityExceeded;        }        const owned = TransactionStaging.init(            self.storage.transaction_staging[0..loan.storage_bytes],            limits,        ) catch |err| switch (err) {            error.StorageTooShort => unreachable,            else => return err,        };        self.transaction_staging_live = true;        self.transaction_staging_loan = loan;        return owned;    }    pub fn releaseTransactionStaging(        self: *DatabaseWorkspace,        owned: *TransactionStaging,    ) void {        self.assertSteady();        std.debug.assert(self.transaction_staging_live);        const returned = owned.deinit();        assertReturned(            self.storage.transaction_staging,            returned,            self.transaction_staging_loan.storage_bytes,        );        self.transaction_staging_live = false;        self.transaction_staging_loan = undefined;    }    pub fn deinit(self: *DatabaseWorkspace) Storage {        std.debug.assert(self.phase != .teardown);        self.assertValid();        std.debug.assert(self.state == .free);        std.debug.assert(!self.path_storage.loan_live);        std.debug.assert(!self.read_cache_live);        std.debug.assert(!self.digest_memo_live);        std.debug.assert(!self.transaction_staging_live);        const returned_paths = self.path_storage.deinit();        assertReturned(            self.storage.paths,            returned_paths,            self.capacity.paths.storageBytes(),        );        self.phase = .teardown;        const storage = self.storage;        self.* = undefined;        return storage;    }    pub fn deallocate(self: *DatabaseWorkspace, allocator: Allocator) void {        var storage = self.deinit();        if (storage.transaction_staging.len != 0) {            allocator.free(storage.transaction_staging);        }        if (storage.read_cache.len != 0) allocator.free(storage.read_cache);        if (storage.digest_memo.len != 0) allocator.free(storage.digest_memo);        if (storage.paths.len != 0) allocator.free(storage.paths);        storage.pager.deallocate(allocator);    }    pub fn retainedBytes(self: *const DatabaseWorkspace) usize {        self.assertValid();        return self.capacity.requested_bytes;    }    fn assertSteady(self: *const DatabaseWorkspace) void {        std.debug.assert(self.phase == .steady);        self.assertValid();    }    fn assertValid(self: *const DatabaseWorkspace) void {        std.debug.assert(fits(self.storage, self.capacity));    }    fn fits(        storage: Storage,        capacity: Capacity,    ) bool {        return fitsPager(storage.pager, capacity.pager) and            storage.paths.len >= capacity.paths.storageBytes() and            storage.read_cache.len >= capacity.read_cache.storage_bytes and            storage.digest_memo.len >= capacity.digest_memo.entries and            storage.transaction_staging.len >= capacity.transaction_staging.storage_bytes;    }    fn fitsPager(        storage: pager.Pager.Workspace,        capacity: pager.Pager.Workspace.Capacity,    ) bool {        return storage.journal.len >= capacity.journal.storage_bytes and            storage.checkpoint.len >= capacity.checkpoint.storage_bytes and            storage.checkpoint_once.len >= capacity.checkpoint_once.storage_bytes and            storage.wal_index.len >= capacity.wal_index.storage_bytes;    }    fn assertReturned(full: []u8, returned: []u8, loan_bytes: usize) void {        std.debug.assert(returned.ptr == full.ptr);        std.debug.assert(returned.len == loan_bytes);        std.debug.assert(returned.len <= full.len);    }};

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

zig
pub const FileDatabaseWorkspace = file.DatabaseWorkspace;
Called byCallstest sourcelib.sql.src.filetest: file database workspace rejects...private sourcelib.sql.src.file.DigestMemo.Capacityderiveprivate sourcelib.sql.src.file.PathStorage.CapacityderiveFileReadCache.CapacityderiveFileTransactionStaging.Capacityderiveprivate sourcelib.sql.src.filewalFrameCapacityFileDatabaseWorkspace.Capacityderive
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyprivate sourcelib.sql.src.file.DatabaseWorkspacefitsPagerPagerinitFileDatabaseWorkspaceacquire
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyprivate sourcelib.sql.src.file.DigestMemoinitFileDatabaseWorkspaceacquireDigestMemo
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyprivate sourcelib.sql.src.file.PathStorageacquireFileDatabaseWorkspaceacquirePathStorage
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileReadCache.CapacityderiveFileReadCacheinitFileDatabaseWorkspaceacquireReadCache
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileTransactionStaging.CapacityderiveFileTransactionStaginginitFileDatabaseWorkspaceacquireTransactionStaging
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallstest sourcelib.sql.src.filetest: file database workspace rejects...private sourcelib.sql.src.file.DatabaseWorkspaceassertValidFileDatabaseWorkspaceactivate
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callstest sourcelib.sql.src.filetest: file database rejects path over...test sourcelib.sql.src.filetest: file database rejects read cach...test sourcelib.sql.src.filetest: file database workspace reuses ...test sourcelib.sql.src.filetest: file recover materializes clean...test sourcelib.sql.src.filetest: file recovery ignores uncommitt...+5 moreFileDatabaseWorkspaceallocate
Static calls · unresolved targets: 2 · external targets: 7.
Called byCallsNo direct callersFileDatabaseWorkspacedeinitFileDatabaseWorkspacedeallocate
Static calls · unresolved targets: 0 · external targets: 2.
Called byCallsFileDatabaseWorkspacedeallocatetest sourcelib.sql.src.filetest: file database workspace rejects...private sourcelib.sql.src.file.DatabaseWorkspaceassertReturnedprivate sourcelib.sql.src.file.DatabaseWorkspaceassertValidprivate sourcelib.sql.src.file.PathStoragedeinitFileDatabaseWorkspacedeinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallstest sourcelib.sql.src.filetest: file database workspace rejects...private sourcelib.sql.src.file.DatabaseWorkspacefitsprivate sourcelib.sql.src.file.PathStorageinitFileDatabaseWorkspaceinit
Static calls · unresolved targets: 1 · external targets: 0.
Called byCallsprivate sourcelib.sql.src.file.RecoveryStatedeinitprivate sourcelib.sql.src.file.DatabaseWorkspaceassertReturnedprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileDatabaseWorkspacerelease
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileDatabaseWorkspacereleaseDigestMemo
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyprivate sourcelib.sql.src.file.PathStoragereleaseFileDatabaseWorkspacereleasePathStorage
Static calls · unresolved targets: 0 · external targets: 0.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertReturnedprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileDatabaseWorkspacereleaseReadCache
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertReturnedprivate sourcelib.sql.src.file.DatabaseWorkspaceassertSteadyFileDatabaseWorkspacereleaseTransactionStaging
Static calls · unresolved targets: 0 · external targets: 1.
Called byCallsNo direct callersprivate sourcelib.sql.src.file.DatabaseWorkspaceassertValidFileDatabaseWorkspaceretainedBytes
Static calls · unresolved targets: 0 · external targets: 0.

Complete caller list for FileDatabaseWorkspace.allocate

10 direct callers.

Audit

Definitions25
Public names25
Members29
Version26.7.0
Revisiondaab053ee433