tiny.sql.FileTransaction
Defined in tiny.sql.
API (10)
Actions
Public operations.
commit: Appends every staged page to the write-ahead log as one committed batch to make those pages part of the database, sorting the staged pages by page number before appending them.deinit: Ends the transaction without committing it, usually called through a defer so that an abandoned transaction gives the database's single write slot back and another transaction can open.editPage: Returns the image this transaction staged forpage_id, or null when it staged none.getPageputPage
Fields and members
Public fields and members.
Source
Source: lib/sql/src/file.zig:3602
zig
pub const Transaction = struct { database: *Database, start_position: pager.Pager.Position, start_generation: u64, staging: *TransactionStaging, closed: bool = false, /// Ends the transaction without committing it, usually called through a /// defer so that an abandoned transaction gives the database's single write /// slot back and another transaction can open. The call drops the staged /// pages, so nothing the transaction put reaches the log, and does nothing /// on a transaction that has already committed or ended. pub fn deinit(self: *Transaction) void { self.close(); } pub fn putPage(self: *Transaction, page_id: u32, image: *const [page.size]u8) Error!void { if (self.closed) return error.TransactionClosed; if (page_id == 0) return error.InvalidPageId; try self.ensureCurrent(); const phase = trace.scope("file.transaction.put_page"); defer phase.end(); switch (self.findSlot(page_id)) { .existing => |index| try self.database.pager.stageWalPage(self.start_position, index, page_id, image), .empty => |index| { const page_index = self.staging.nextPage() catch return self.capacityError(); try self.database.pager.stageWalPage(self.start_position, page_index, page_id, image); self.staging.occupy(index, page_index); }, .full => return self.capacityError(), } } pub fn getPage(self: *const Transaction, page_id: u32) Error!?[]const u8 { if (self.closed) return error.TransactionClosed; if (page_id == 0) return error.InvalidPageId; try self.ensureCurrent(); return switch (self.findSlot(page_id)) { .existing => |index| self.database.pager.stagedWalPage(self.start_position, index), .empty => null, .full => null, }; } /// Returns the image this transaction staged for `page_id`, or null when /// it staged none. Edits through the image are staged as they happen, /// so putting the same image again copies nothing. The image stays /// valid until the transaction commits or ends. pub fn editPage(self: *Transaction, page_id: u32) Error!?*[page.size]u8 { if (self.closed) return error.TransactionClosed; if (page_id == 0) return error.InvalidPageId; try self.ensureCurrent(); return switch (self.findSlot(page_id)) { .existing => |index| self.database.pager.stagedWalPageMut(self.start_position, index), .empty => null, .full => null, }; } /// Appends every staged page to the write-ahead log as one committed batch /// to make those pages part of the database, sorting the staged pages by /// page number before appending them. Callers choose whether to wait for /// the bytes to reach the disk through durability options: with `synced` /// durability the call syncs the log before returning and reports the /// commit as synced, and with `buffered` it returns as soon as the bytes /// are written and reports the commit as not yet synced. A transaction with /// nothing staged commits as a no-op, reporting zero frames and zero pages. /// The call reports `TransactionConflict` when the database moved /// underneath the transaction, and `TransactionClosed` when the transaction /// has already ended. The transaction ends whichever way the call goes, so /// the write slot is free even after a failure. pub fn commit(self: *Transaction, options: CommitOptions) Error!Commit { if (self.closed) return error.TransactionClosed; defer self.close(); const phase = trace.scope("file.transaction.commit"); defer phase.end(); try self.ensureCurrent(); if (self.staging.pages == 0) { return .{ .view = try self.database.pager.currentView(), .frames = 0, .pages = 0, .synced = false, }; } self.sortPages(); var page_count = self.database.pager.databasePageCount(); for (0..self.staging.pages) |index| page_count = @max(page_count, self.pageId(index)); try self.database.advanceWriteSerial(); try self.database.appendStagedTransactionWal(self.start_position, self.staging.pages, page_count); const view = try self.database.pager.currentView(); const frames = self.staging.pages; const synced = switch (options.durability) { .buffered => false, .synced => synced: { try self.database.syncWal(); break :synced true; }, }; trace.progress("file.transaction.commit.complete"); return .{ .view = view, .frames = frames, .pages = frames, .synced = synced, }; } fn close(self: *Transaction) void { if (self.closed) return; std.debug.assert(self.database.write_transaction_open); self.staging.end(); self.database.write_transaction_open = false; self.closed = true; } fn ensureCurrent(self: *const Transaction) Error!void { try self.database.ensureUsable(); if (!std.meta.eql(self.database.pager.position(), self.start_position) or self.database.pager.baseGeneration() != self.start_generation) { return error.TransactionConflict; } } fn findSlot(self: *const Transaction, page_id: u32) TransactionSlot { const slots = self.staging.capacity.index_slots; if (slots == 0) return .full; var index = std.hash.Wyhash.hash(0x7469_6e79_7371_6c31, std.mem.asBytes(&page_id)) % slots; for (0..slots) |_| { const page_index = self.staging.pageIndex(index) orelse return .{ .empty = index }; if (self.database.pager.stagedWalPageId(self.start_position, page_index) == page_id) return .{ .existing = page_index }; index = if (index + 1 == slots) 0 else index + 1; } return .full; } fn capacityError(self: *const Transaction) DatabaseFileError { return if (self.staging.limit_frames < self.staging.capacity.frames) error.WalLimitExceeded else error.TransactionTooLarge; } fn sortPages(self: *Transaction) void { if (self.staging.pages < 2) return; self.quickSortPages(0, self.staging.pages); } fn quickSortPages(self: *Transaction, start: usize, end: usize) void { if (end - start < 16) return self.insertionSortPages(start, end); const pivot = self.pageId(start + (end - start) / 2); var left = start; var right = end - 1; while (left <= right) { while (self.pageId(left) < pivot) left += 1; while (self.pageId(right) > pivot) { if (right == start) break; right -= 1; } if (left <= right) { self.database.pager.swapStagedWalFrames(self.start_position, left, right); left += 1; if (right == start) break; right -= 1; } } if (right > start) self.quickSortPages(start, right + 1); if (left < end) self.quickSortPages(left, end); } fn insertionSortPages(self: *Transaction, start: usize, end: usize) void { var index = start + 1; while (index < end) : (index += 1) { var scan = index; while (scan > start and self.pageId(scan) < self.pageId(scan - 1)) : (scan -= 1) { self.database.pager.swapStagedWalFrames(self.start_position, scan, scan - 1); } } } fn pageId(self: *const Transaction, index: usize) u32 { return self.database.pager.stagedWalPageId(self.start_position, index); }};Source: lib/sql/src/root.zig:205
zig
pub const FileTransaction = file.Transaction;Complete call list for FileTransaction.commit
9 direct calls.
lib.sql.src.file.Database.advanceWriteSerial[method] — private source atlib/sql/src/file.zig:2607in nearest public ownertiny.sql.indexlib.sql.src.file.Database.appendStagedTransactionWal[method] — private source atlib/sql/src/file.zig:2564in nearest public ownertiny.sql.indextiny.sql.FileDatabase.syncWal[method] atlib/sql/src/file.zig:2335lib.sql.src.file.Transaction.close[method] — private source atlib/sql/src/file.zig:3712in nearest public ownertiny.sql.indexlib.sql.src.file.Transaction.ensureCurrent[method] — private source atlib/sql/src/file.zig:3720in nearest public ownertiny.sql.indexlib.sql.src.file.Transaction.pageId[method] — private source atlib/sql/src/file.zig:3780in nearest public ownertiny.sql.indexlib.sql.src.file.Transaction.sortPages[method] — private source atlib/sql/src/file.zig:3743in nearest public ownertiny.sql.indextiny.sql.trace.progress[function] atlib/sql/src/trace.zig:7tiny.sql.trace.scope[function] atlib/sql/src/trace.zig:3
Audit
| Definitions | 6 |
|---|---|
| Public names | 6 |
| Members | 5 |
| Version | 26.7.0 |
| Revision | daab053ee433 |