Skip to main content

MvStore

Struct MvStore 

Source
pub struct MvStore<Clock: LogicalClock, A: ConcurrentAllocator = TursoAllocator> {
    pub rows: SkipMap<RowID, RowVersions<A>, BasicComparator, A>,
    pub table_id_to_rootpage: SkipMap<MVTableId, RootEntry, BasicComparator, A>,
    pub index_rows: SkipMap<MVTableId, IndexRowsMap<A>, BasicComparator, A>,
    /* private fields */
}
Expand description

A multi-version concurrency control database.

Fields§

§rows: SkipMap<RowID, RowVersions<A>, BasicComparator, A>§table_id_to_rootpage: SkipMap<MVTableId, RootEntry, BasicComparator, A>

Table ID is an opaque identifier that is only meaningful to the MV store. Each checkpointed MVCC table corresponds to a single B-tree on the pager, which naturally has a root page. We cannot use root page as the MVCC table ID directly because:

  • We assign table IDs during MVCC commit, but
  • we commit pages to the pager only during checkpoint

which means the root page is not easily knowable ahead of time. Hence, we store the mapping here. The value is Option because tables created in an MVCC commit that have not been checkpointed yet have no real root page assigned yet.

Versioned root bindings; passive checkpoints update these at publish, not during collection.

§index_rows: SkipMap<MVTableId, IndexRowsMap<A>, BasicComparator, A>

Unlike table rows which are stored in a single map, we have a separate map for every index because operations like last() on an index are much easier when we don’t have to take the table identifier into account.

Implementations§

Source§

impl<Clock: LogicalClock> MvStore<Clock>

Source

pub fn new( clock: Clock, storage: Arc<dyn DurableStorage>, experimental_mvcc_passive_checkpoint: bool, ) -> Result<Self>

Creates a new database backed by the default TursoAllocator.

Source§

impl<Clock: LogicalClock, A: ConcurrentAllocator> MvStore<Clock, A>

Source

pub const DEFAULT_GC_VERSION_THRESHOLD: i64

Default mvcc_gc_threshold: run an incremental GC pass roughly every this many newly inserted versions. Small enough that steady-state memory stays bounded under heavy short-txn concurrency, large enough that small workloads (and most unit tests) never trigger a pass.

Source

pub const MAX_CHAINS_PER_GC: usize = 4096

Upper bound on table-row chains scanned by one inline gc_incremental pass on the commit path. Keeps a pass cheap (sub-millisecond) so it doesn’t noticeably slow the committing connection; steady state relies on frequent passes resuming via gc_table_cursor.

Source

pub fn new_in( clock: Clock, storage: Arc<dyn DurableStorage>, alloc: A, experimental_mvcc_passive_checkpoint: bool, ) -> Result<Self>

Creates a new database whose skiplists allocate through alloc.

Source

pub fn get_table_id_from_root_page(&self, root_page: i64) -> MVTableId

Get the table ID from the root page, resolving against the current (live) mapping. Equivalent to get_table_id_from_root_page_at(root_page, u64::MAX).

Source

pub fn get_table_id_from_root_page_at( &self, root_page: i64, snapshot_ts: u64, ) -> MVTableId

Get the table ID for root_page as seen by a transaction at snapshot_ts.

Negative root pages are non-checkpointed objects whose table ID equals the root page; they are never reused or versioned, so the snapshot is irrelevant.

For a positive (checkpointed) root page, a PASSIVE checkpoint may have dropped the object — and possibly reused the page for a new btree — while this transaction still references it at an older snapshot. Successive owners of a page hold disjoint, back-to-back lifetimes; we return the owner whose binding has not yet ended at the snapshot (smallest end > ts, live counting as +inf). We deliberately do NOT gate on begin here: a transaction’s physical schema (root pages) can run ahead of its data snapshot, because a checkpoint allocating a root page is not a logical schema change. Whether the btree should actually be read at the snapshot is decided separately by [Self::is_btree_allocated_at] / [Self::resolve_root_page_at], which do gate on begin. u64::MAX resolves the current live owner.

Source

pub fn try_get_table_id_from_root_page_at( &self, root_page: i64, snapshot_ts: u64, ) -> Option<MVTableId>

Fallible variant of Self::get_table_id_from_root_page_at: returns None when a positive root page has no binding that covers snapshot_ts. Under a PASSIVE checkpoint this is not an invariant violation but a stale-schema read: the transaction captured an older schema_cookie (the commit that dropped this object published its cookie after the transaction read the header, even though the drop’s commit ts precedes the transaction’s begin ts) and compiled a cursor against a table its own snapshot already sees dropped. The caller turns this into LimboError::SchemaUpdated so the statement reprepares against the current schema. See the begin/commit schema-coherence note in the passive checkpoint design.

Source

pub fn read_snapshot_ts(&self, tx_id: TxID) -> u64

Snapshot timestamp (begin_ts) of the given transaction, or u64::MAX if it is not tracked (resolving the live root-page binding). Used to make a transaction’s root-page lookups snapshot-consistent.

Source

pub fn read_tx_mark(&self, tx_id: TxID) -> WalPos

This transaction’s frozen WAL read mark, or WalPos::STAGED (sees everything published) if untracked. The physical-reachability coordinate of the btree-read gate. See Self::is_btree_readable_at.

Source

pub fn insert_table_id_to_rootpage( &self, table_id: MVTableId, root_page: Option<u64>, )

Insert a live table_id -> root_page binding (bootstrap/recovery, or an uncheckpointed-create with None). Visible to every snapshot. Checkpoint-time allocation of a real root page goes through Self::record_rootpage_alloc instead.

Source

pub fn remove_table_id_to_rootpage(&self, table_id: &MVTableId)

Source

pub fn current_root_page(&self, table_id: &MVTableId) -> Option<u64>

The current physical root page of table_id, if it is checkpointed and live.

Source

pub fn record_rootpage_alloc( &self, table_id: MVTableId, root_page: u64, begin_ts: u64, materialized_at: WalPos, )

Record that a PASSIVE checkpoint allocated root_page for table_id. begin_ts is the checkpoint’s snapshot ts (base-validity lower bound); materialized_at is the WAL position the pages reach durability at — WalPos::STAGED at btree_create (pages not committed yet), lowered to the real position by Self::publish_rootpage_visible in the post-CommitPagerTxn publish window.

Source

pub fn publish_rootpage_visible( &self, table_id: MVTableId, materialized_at: WalPos, )

Publish a staged root-page binding: set its materialized_at from WalPos::STAGED to the WAL position the pages were committed at, making the btree physically readable by any transaction whose read mark reaches that position. Called in the checkpoint’s post-commit publish window. No-op if the entry is gone (e.g. dropped same checkpoint).

Source

pub fn retire_rootpage(&self, table_id: MVTableId, end_ts: u64)

Close table_id’s binding at end_ts (the drop tombstone commit ts) but keep it, so a transaction whose snapshot predates the drop can still resolve the (read-mark-protected) root page. Reclaimed by Self::gc_rootpage_entries once end_ts <= lwm.

Source

pub fn gc_rootpage_entries(&self, lwm: u64) -> usize

Drop closed (retired) bindings no transaction can still see (dropped, with end <= lwm). Live bindings have end == u64::MAX and are never reclaimed — important because compute_lwm() is u64::MAX when no transactions are active. Returns count.

Source

pub fn bootstrap(&self, bootstrap_conn: Arc<Connection>) -> Result<()>

Bootstrap the MV store from the SQLite schema table and logical log.

  1. Get all root pages from the already parsed schema object
  2. Assign table IDs to the root pages (table_id = -1 * root_page)
  3. Complete interrupted WAL/log checkpoint reconciliation, if needed
  4. Promote the bootstrap connection to a regular connection so that it reads from the MV store again
  5. Recover the logical log
  6. Make sure schema changes reflected from deserialized logical log are captured in the schema

Blocking shim retained for synchronous callers. The open, attach, and journal-mode state machines drive MvStore::bootstrap_nonblock directly.

Source

pub fn get_next_table_id(&self) -> i64

MVCC does not use the pager/btree cursors to create pages until checkpoint. This method is used to assign root page numbers when Insn::CreateBtree is used. MVCC table ids are always negative. Their corresponding rootpage entry in sqlite_schema is the same negative value if the table has not been checkpointed yet. Otherwise, the root page will be positive and corresponds to the actual physical page.

Source

pub fn get_next_rowid(&self) -> i64

Source

pub fn insert(&self, tx_id: TxID, row: Row) -> Result<()>

Inserts a new row into a table in the database.

This function inserts a new row into the database within the context of the transaction tx_id.

§Arguments
  • tx_id - the ID of the transaction in which to insert the new row.
  • row - the row object containing the values to be inserted.
Source

pub fn insert_to_table_or_index( &self, tx_id: TxID, row: Row, maybe_index_id: Option<MVTableId>, ) -> Result<()>

Same as insert() but can insert to a table or an index, indicated by the maybe_index_id argument.

Source

pub fn insert_tombstone_to_table_or_index( &self, tx_id: TxID, id: RowID, row: Row, maybe_index_id: Option<MVTableId>, ) -> Result<()>

Inserts a deletion record for a row that does not currently have any versions in the MV store. This is used in cases where the BTree contains that record, but it is logically deleted.

Source

pub fn insert_btree_resident_to_table_or_index( &self, tx_id: TxID, row: Row, maybe_index_id: Option<MVTableId>, ) -> Result<()>

Inserts a row that was read from the B-tree (not in MvStore). This is used when updating a row that exists in B-tree but hasn’t been modified in MVCC yet. The btree_resident flag helps the checkpoint logic determine if subsequent deletes should be checkpointed to the B-tree file.

Source

pub fn update(&self, tx_id: TxID, row: Row) -> Result<bool>

Updates a row in a table in the database with new values.

This function updates an existing row in the database within the context of the transaction tx_id. The row argument identifies the row to be updated as id and contains the new values to be inserted.

If the row identified by the id does not exist, this function does nothing and returns false. Otherwise, the function updates the row with the new values and returns true.

§Arguments
  • tx_id - the ID of the transaction in which to update the new row.
  • row - the row object containing the values to be updated.
§Returns

Returns true if the row was successfully updated, and false otherwise.

Source

pub fn update_to_table_or_index( &self, tx_id: TxID, row: Row, maybe_index_id: Option<MVTableId>, ) -> Result<bool>

Same as update() but can update a table or an index, indicated by the maybe_index_id argument.

Source

pub fn upsert(&self, tx_id: TxID, row: Row) -> Result<()>

Inserts a row into a table in the database with new values, previously deleting any old data if it existed. Bails on a delete error, e.g. write-write conflict.

Source

pub fn upsert_to_table_or_index( &self, tx_id: TxID, row: Row, maybe_index_id: Option<MVTableId>, ) -> Result<()>

Same as upsert() but can upsert to a table or an index, indicated by the maybe_index_id argument.

Source

pub fn delete(&self, tx_id: TxID, id: RowID) -> Result<bool>

Deletes a row from the table with the given id.

This function deletes an existing row id in the database within the context of the transaction tx_id.

§Arguments
  • tx_id - the ID of the transaction in which to delete the new row.
  • id - the ID of the row to delete.
§Returns

Returns true if the row was successfully deleted, and false otherwise.

Source

pub fn delete_from_table_or_index( &self, tx_id: TxID, id: RowID, maybe_index_id: Option<MVTableId>, ) -> Result<bool>

Same as delete() but can delete from a table or an index, indicated by the maybe_index_id argument.

Source

pub fn read(&self, tx_id: TxID, id: &RowID) -> Result<Option<Row>>

Retrieves a row from the table with the given id.

This operation is performed within the scope of the transaction identified by tx_id.

§Arguments
  • tx_id - The ID of the transaction to perform the read operation in.
  • id - The ID of the row to retrieve.
§Returns

Returns Some(row) with the row data if the row with the given id exists, and None otherwise.

Source

pub fn read_from_table_or_index( &self, tx_id: TxID, id: &RowID, maybe_index_id: Option<MVTableId>, ) -> Result<Option<Row>>

Same as read() but can read from a table or an index, indicated by the maybe_index_id argument.

Source

pub fn scan_row_ids(&self) -> Result<Vec<RowID>>

Gets all row ids in the database.

Source

pub fn get_row_id_range( &self, table_id: MVTableId, start: i64, bucket: &mut Vec<RowID>, max_items: u64, ) -> Result<()>

Source

pub fn query_btree_version_is_valid( &self, table_id: MVTableId, row_id: &RowKey, tx_id: TxID, ) -> bool

Check if the B-tree version of a row should be shown to the given transaction.

Returns true if the B-tree version is valid (should be shown). Returns false if the B-tree version is shadowed or deleted by MVCC.

Source

pub fn seek_rowid( &self, start: RowID, inclusive: bool, eq_only: bool, direction: IterationDirection, tx_id: TxID, table_iterator: &mut Option<Box<dyn Iterator<Item = Entry<'static, RowID, RowVersions<A>, BasicComparator, A>> + Send + Sync>>, ) -> Option<RowID>

Source

pub fn seek_index( &self, index_id: MVTableId, start: SortableIndexKey, inclusive: bool, eq_only: bool, direction: IterationDirection, tx_id: TxID, index_iterator: &mut Option<Box<dyn Iterator<Item = Entry<'static, Arc<SortableIndexKey>, RowVersions<A>, BasicComparator, A>> + Send + Sync>>, ) -> Result<Option<RowID>>

Source

pub fn begin_exclusive_tx( &self, pager: Arc<Pager>, maybe_existing_tx_id: Option<TxID>, connection: &Connection, expected_schema_generation: Option<u64>, ) -> Result<TxID>

Begins an exclusive write transaction that prevents concurrent writes.

This is used for IMMEDIATE and EXCLUSIVE transaction types where we need to ensure exclusive write access as per SQLite semantics.

Source

pub fn begin_tx(&self, pager: Arc<Pager>) -> Result<TxID>

Begins a new transaction in the database.

This function starts a new transaction in the database and returns a TxID value that you can use to perform operations within the transaction. All changes made within the transaction are isolated from other transactions until you commit the transaction.

Source

pub fn begin_tx_with_schema_generation( &self, pager: Arc<Pager>, expected_schema_generation: Option<u64>, ) -> Result<TxID>

begin_tx with the connection’s validated schema_generation gate (see Connection::mvcc_begin_schema_generation). Used by the statement begin path so a passive checkpoint that republishes physical roots into the begin window forces a reprepare instead of a transaction beginning against stale roots.

Source

pub fn remove_tx(&self, tx_id: TxID) -> Result<(), TryReserveError>

Source

pub fn register_sequence_allocation( &self, tx_id: TxID, sequence_name: &str, sequence_value: i64, ) -> Result<()>

Source

pub fn set_sequence_watermark(&self, sequence_name: &str, watermark: i64)

Source

pub fn sequence_watermark(&self, sequence_name: &str) -> Option<i64>

Returns the first sequence value that is not safe for cursor scans to pass.

Readers can safely consume rows with sequence values less than this watermark. The value is the minimum of the current sequence boundary and any lower value already allocated by an active transaction.

Source

pub fn finish_committed_tx( &self, tx_id: TxID, conn: &Connection, db_id: usize, ) -> Result<(), TryReserveError>

Atomically retire a committed tx: clear the connection’s mv_tx_id cache for db_id, then remove the tx from txs. Pairs the two mutations so no concurrent observer (or in-flight statement) can see the divergent (cache=Some, txs=None) state — the production-panic shape from release_named_savepoint and NoSuchTransactionID read-path errors.

Order matches rollback_tx (cache cleared before remove_tx) so the commit and rollback paths are symmetric.

Use this anywhere the commit state machine would otherwise call remove_tx directly. Other call sites that don’t have a connection context (e.g. tests poking internal state) keep using remove_tx.

Source

pub fn get_transaction_database_header(&self, tx_id: &TxID) -> DatabaseHeader

Source

pub fn set_global_page_size(&self, size: PageSize)

Update the cached global header’s page size to match a fresh PRAGMA page_size.

global_header is captured from the pager during MVCC bootstrap, before any PRAGMA can run, so it always starts at the default 4 KiB. Subsequent transactions copy from it, which means a PRAGMA page_size = N issued on the connection would otherwise be invisible to MVCC header lookups even though the pager itself honors N for on-disk page allocation. Only valid before any data has been written; matches the same precondition Connection::reset_page_size enforces via db.initialized().

Source

pub fn with_header<T, F>(&self, f: F, tx_id: Option<&TxID>) -> Result<T>
where F: Fn(&DatabaseHeader) -> T,

Source

pub fn with_header_mut<T, F>(&self, f: F, tx_id: Option<&TxID>) -> Result<T>
where F: Fn(&mut DatabaseHeader) -> T,

Source

pub fn commit_tx( self: &Arc<Self>, tx_id: TxID, connection: &Arc<Connection>, db_id: usize, ) -> Result<StateMachine<Box<CommitStateMachine<Clock, A>>>>

Commits a transaction with the specified transaction ID.

This function commits the changes made within the specified transaction and finalizes the transaction. Once a transaction has been committed, all changes made within the transaction are visible to other transactions that access the same data.

§Arguments
  • tx_id - The ID of the transaction to commit.
Source

pub fn is_tx_rollbackable(&self, tx_id: TxID) -> bool

Returns true if the transaction can be rolled back (Active or Preparing).

Source

pub fn rollback_tx( &self, tx_id: TxID, _pager: Arc<Pager>, connection: &Connection, db: usize, )

Rolls back a transaction with the specified ID.

This function rolls back a transaction with the specified tx_id by discarding any changes made by the transaction.

§Arguments
  • tx_id - The ID of the transaction to abort.
  • db - The database index this transaction belongs to.
Source

pub fn begin_savepoint(&self, tx_id: TxID)

Begin a savepoint for the transaction. This should be called at the start of a statement in an interactive transaction.

Source

pub fn begin_named_savepoint( &self, tx_id: TxID, name: String, starts_transaction: bool, deferred_fk_violations: isize, )

Begin a user-visible named savepoint inside an existing transaction.

starts_transaction is true when the savepoint was opened in autocommit mode and therefore releasing the root savepoint should commit the transaction.

Source

pub fn release_savepoint(&self, tx_id: TxID)

Release the newest savepoint for the transaction. This should be called when a statement completes successfully. Silently returns if the transaction doesn’t exist (e.g., already committed).

Source

pub fn release_named_savepoint( &self, tx_id: TxID, name: &str, ) -> Result<SavepointResult>

Releases a named savepoint and nested savepoints above it.

Returns [SavepointResult::Commit] when releasing the root savepoint should commit the transaction.

Source

pub fn rollback_first_savepoint(&self, tx_id: u64) -> Result<bool>

Rolls back a savepoint within a transaction. Returns true if a savepoint was rolled back, false if no savepoint was active.

Source

pub fn rollback_to_named_savepoint( &self, tx_id: TxID, name: &str, ) -> Result<Option<isize>>

Rolls back to the newest matching named savepoint while keeping that savepoint active.

Returns the deferred FK snapshot stored on the named savepoint, or None if no matching savepoint exists.

Source

pub fn is_exclusive_tx(&self, tx_id: &TxID) -> bool

Returns true if the given transaction is the exclusive transaction.

Source

pub fn get_tx_id(&self) -> u64

Generates next unique transaction id

Source

pub fn get_version_id(&self) -> u64

Generates next unique version ID for RowVersion tracking.

Source

pub fn get_begin_timestamp(&self) -> u64

Generate a begin timestamp. No side-effect needed alongside generation.

Source

pub fn get_commit_timestamp<F: FnOnce(u64)>(&self, f: F) -> u64

Generate a commit timestamp and call f with it while the clock lock is held, atomically publishing the timestamp before release. See [MvccClock] for the full explanation.

Source

pub fn checkpoint_snapshot_ts(&self) -> u64

Snapshot timestamp for a checkpoint, clamped below any in-flight (Preparing) commit. The published durable boundary (durable_txid_max_new) derives from this. last_committed_tx_ts is a fetch_max high-water mark, so a transaction that already assigned a lower end_ts and is still Preparing can sit below it; the checkpoint would skip that transaction (not yet Committed) yet publish a boundary above its end_ts, and a crash after it finalizes would discard its log frame (commit_ts <= boundary) even though it was never written to the B-tree — silent data loss. Clamping below the lowest Preparing end_ts prevents the straddle.

Computed while holding the clock lock (via get_timestamp) so a transaction mid-(end_ts assignment + Preparing publish, which happen together under that lock) cannot be missed by the scan. Active transactions need no clamp: their future end_ts is drawn from the monotonic clock and is therefore > snapshot_ts.

Source

pub fn schema_still_valid_for_tx(&self, tx_id: TxID) -> Result<()>

Passive checkpoint published new physical roots after this transaction began.

Source

pub fn compute_lwm(&self) -> u64

Compute the low-water mark: the minimum begin_ts of all active or preparing transactions. Returns u64::MAX if no transactions are active. Used by GC to determine which row versions are safe to reclaim.

Source

pub fn live_version_count_approx(&self) -> usize

Current approximate live row-version count. Heuristic only (see the live_version_count_approx field) — never use for correctness decisions.

Source

pub fn set_gc_threshold(&self, threshold: i64)

Set the inline-GC trigger threshold (growth in live versions since the last GC pass). Negative disables inline GC. Mirrors set_checkpoint_threshold; wired to the mvcc_gc_threshold PRAGMA.

Source

pub fn gc_threshold(&self) -> i64

Source

pub fn should_gc(&self) -> bool

Whether an incremental GC pass should run now: inline GC is enabled (threshold >= 0) and live_version_count_approx has grown past the threshold since the last pass. Heuristic — drift only changes GC frequency.

Source

pub fn drop_unused_row_versions(&self) -> usize

Garbage-collects row versions that are invisible to all active transactions. Uses the low-water mark (LWM) to determine reclaimability in O(1) per version. Covers both table rows (self.rows) and index rows (self.index_rows). Returns the number of removed versions.

Source

pub fn drop_unused_row_versions_and_slots(&self) -> usize

Like Self::drop_unused_row_versions, but additionally removes chain slots that end up empty from the skip maps, bounding their entry counts.

The caller must hold the blocking checkpoint lock (or otherwise guarantee no concurrent writers): slot removal happens after the chain write lock is dropped, so without that guarantee it races a concurrent get_or_insert_with on the same key — see the TOCTOU note in gc_table_row_versions.

Source

pub fn gc_incremental(&self, max_chains: usize) -> usize

Incremental, non-blocking GC pass — the inline counterpart to Self::drop_unused_row_versions, driven from the commit path.

Reclaims invisible versions (same rules as gc_version_chain) from up to max_chains table-row chains, resuming from where the previous pass stopped (gc_table_cursor) so repeated calls eventually cover the whole rows map without scanning it all at once.

Safety / design notes:

  • Lazy mode only. Empty SkipMap slots are left in place (no entry.remove()), so the pass needs no blocking checkpoint lock — it races no concurrent get_or_insert_with (see the TOCTOU note in gc_table_row_versions). Physical slot removal stays exclusive to the checkpoint’s _and_slots sweep.
  • finalized_tx_states pruning is intentionally skipped here: it needs the complete referenced-txid set across all chains, which a partial sweep cannot produce. The checkpoint path still prunes it.
Source

pub fn insert_index_version( &self, index_id: MVTableId, key: Arc<SortableIndexKey>, row_version: RowVersion, ) -> Result<(Arc<SortableIndexKey>, RowVersions<A>)>

Inserts (or appends to) the version chain for an index entry and returns the id and versions of the modified row.

Source

pub fn insert_version_raw( &self, versions: &mut RowVersionChain<A>, row_version: RowVersion, ) -> Result<(), TryReserveError>

Inserts a new row version into the internal data structure for versions, while making sure that the row version is inserted in the correct order.

Source

pub fn write_row_to_pager( &self, row: &Row, cursor: Arc<RwLock<BTreeCursor>>, requires_seek: bool, ) -> Result<StateMachine<WriteRowStateMachine>>

Source

pub fn delete_row_from_pager( &self, rowid: RowID, cursor: Arc<RwLock<BTreeCursor>>, ) -> Result<StateMachine<DeleteRowStateMachine>>

Source

pub fn purge_row_versions_during_checkpoint(&self, rowid: RowID)

Clear every version-chain entry for rowid. Used by checkpoint-time compaction that deletes the corresponding B-tree row outside the normal MVCC delete path (e.g. SeqCompactDriver for sequence backing tables) so the two layers stay in sync — without this the version chain would keep RowVersion { begin: Timestamp(T), end: None, btree_resident: true } entries pointing at B-tree rows that no longer exist, until drop_unused_row_versions Rule 3 caught up.

Caller contract — the caller must hold a guarantee that no concurrent reader can observe mid-purge state. Today the only caller is SeqCompactDriver, which runs inside the checkpoint while the pager_commit_lock is held; nextval allocators serialize through that same lock, so they cannot see the chain in a partially purged state. Callers without that guarantee must add proper tombstones via the normal write path instead.

Empty chain slots are left in the SkipMap (lazy removal). The same TOCTOU rationale as gc_table_row_versions applies: removing the slot would race a concurrent get_or_insert_with from a future write to the same key.

Source

pub fn seqcompact_commit_delete( &self, rowid: RowID, num_cols: usize, end_ts: u64, )

Passive sequence compaction: record end-stamped deletes instead of inline B-tree purge.

Source

pub fn get_last_table_rowid( &self, table_id: MVTableId, table_iterator: &mut Option<Box<dyn Iterator<Item = Entry<'static, RowID, RowVersions<A>, BasicComparator, A>> + Send + Sync>>, tx_id: TxID, ) -> Option<RowKey>

Source

pub fn get_last_table_rowid_without_visibility_check( &self, table_id: MVTableId, ) -> Option<RowKey>

Source

pub fn get_last_index_rowid( &self, index_id: MVTableId, tx_id: TxID, index_iterator: &mut Option<Box<dyn Iterator<Item = Entry<'static, Arc<SortableIndexKey>, RowVersions<A>, BasicComparator, A>> + Send + Sync>>, ) -> Result<Option<RowKey>>

Source

pub fn get_logical_log_file(&self) -> Arc<dyn File>

Source

pub fn logical_log_offset(&self) -> u64

Source

pub fn reset_logical_log_after_external_restore(&self) -> Result<Completion>

Replace the logical log with a fresh valid header after the database file was restored outside MVCC.

The returned completion must finish before reopening/recovering MVCC state. Otherwise recovery could replay stale local logical-log frames on top of the restored database image.

Source

pub fn sync_logical_log_after_external_restore( &self, connection: &Arc<Connection>, ) -> Result<Option<Completion>>

Return the durable sync completion for the freshly reset logical log.

This is separate from reset_logical_log_after_external_restore so callers can drive the reset completion cooperatively, then issue the ordered sync only after the header/truncate group has completed.

Source

pub fn maybe_recover_logical_log( &self, connection: &Arc<Connection>, st: &mut RecoverLogicalLogState, ) -> Result<IOResult<bool>>

Replays committed logical-log frames into the in-memory MVCC store. Only frames with commit_ts > persistent_tx_ts_max (the durable replay boundary from the metadata table) are applied; earlier frames were already checkpointed. On success, reseeds the MVCC clock and sets the log writer offset so torn-tail bytes are overwritten. Returns true if any frames were replayed.

Source

pub fn set_checkpoint_threshold(&self, threshold: i64)

Source

pub fn checkpoint_threshold(&self) -> i64

Source

pub fn get_real_table_id(&self, table_id: i64) -> i64

Source

pub fn get_rowid_allocator(&self, table_id: &MVTableId) -> Arc<RowidAllocator>

Source

pub fn is_btree_allocated(&self, table_id: &MVTableId) -> bool

Whether table_id has a currently live checkpointed B-tree. Snapshot-agnostic; for transaction reads use Self::is_btree_readable_at.

Source

pub fn is_btree_readable_at( &self, table_id: &MVTableId, begin_ts: u64, read_mark: WalPos, ) -> bool

Whether a transaction may read table_id’s B-tree, given its logical snapshot begin_ts and its frozen WAL read_mark. Requires BOTH:

  • logical (base validity): the binding covers(begin_ts)begin <= begin_ts < end; and
  • physical reachability: materialized_at <= read_mark — the btree’s pages are at-or-below this transaction’s read mark (same WAL epoch and frame ≤ mark, or an earlier backfilled epoch). Without this a transaction that opened before an checkpoint materialization would seek a page its read mark cannot reach (a torn/foreign/zeroed-page read).

When this is false the transaction stays version-store-only; the GC floor (Self::compute_min_reader_mark) guarantees the version-store copy is still present.

Source

pub fn compute_min_reader_mark(&self) -> WalPos

Lexicographic minimum WAL read mark over all active/preparing transactions (WalPos::STAGED if none). A freshly-materialized object’s version-store rows may be GC’d only once materialized_at <= this, i.e. every live reader can now physically reach it — otherwise a reader whose read mark predates the materialization would lose the rows.

Source

pub fn tx_should_abort(&self, tx_id: u64) -> bool

Trait Implementations§

Source§

impl<Clock: Debug + LogicalClock, A: Debug + ConcurrentAllocator> Debug for MvStore<Clock, A>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<Clock, A = TursoAllocator> !Freeze for MvStore<Clock, A>

§

impl<Clock, A = TursoAllocator> !RefUnwindSafe for MvStore<Clock, A>

§

impl<Clock, A = TursoAllocator> !UnwindSafe for MvStore<Clock, A>

§

impl<Clock, A> Send for MvStore<Clock, A>

§

impl<Clock, A> Sync for MvStore<Clock, A>

§

impl<Clock, A> Unpin for MvStore<Clock, A>

§

impl<Clock, A> UnsafeUnpin for MvStore<Clock, A>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> ErasedDestructor for T
where T: 'static,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more