pub struct SnapshotManager { /* private fields */ }Expand description
Central allocator and liveness tracker.
Uses an atomic counter for xid allocation and a parking_lot-guarded HashSet for in-progress/aborted bookkeeping. The sets stay small — only unfinished transactions plus a finite rollback history — so a plain HashSet outperforms more complex data structures here.
§Autocommit xid pool
Single-row autocommit writes (MutationEngine::append_one) need an
xid that’s “born committed” — they call begin() then commit()
back-to-back before the row is even durable. The pre-commit pool
(autocommit_pool_*) batches the reservation: one
next_xid.fetch_add(BATCH) reserves a contiguous range of xids,
each handed out via a single atomic without touching the
RwLock<ManagerState>. Pool xids are never inserted into active
or aborted so they look like already-committed transactions to
every snapshot — identical visibility semantics to the legacy
begin()/commit() pair (which also leaves the xid in neither set).
Implementations§
Source§impl SnapshotManager
impl SnapshotManager
pub fn new() -> SnapshotManager
Sourcepub fn begin(&self) -> u64
pub fn begin(&self) -> u64
Allocate a new xid and mark it active. Returns the xid for
stamping onto UnifiedEntity::xmin/xmax.
Sourcepub fn snapshot(&self, xid: u64) -> Snapshot
pub fn snapshot(&self, xid: u64) -> Snapshot
Capture a point-in-time snapshot. Must be called after begin()
when using SnapshotIsolation/Serializable. ReadCommitted refreshes
this per statement via the same call.
Sourcepub fn commit(&self, xid: u64)
pub fn commit(&self, xid: u64)
Mark a transaction as committed. Its writes become visible to future snapshots; earlier snapshots keep their own view.
Sourcepub fn allocate_committed_xid(&self) -> u64
pub fn allocate_committed_xid(&self) -> u64
Allocate an xid that is born committed — for autocommit
callers (MutationEngine::append_one) that previously paid two
state.write() lock acquisitions per row to insert-then-remove
from the active set.
The returned xid is never inserted into active and never into
aborted, which matches the steady state of the legacy
begin()/commit() pair when called back-to-back: the xid leaves
the manager’s tracking sets unobservably. Concurrent readers
therefore see it as an already-committed transaction once
xmin <= snapshot.xid, which is exactly the semantics the
autocommit path needs.
Implementation: a small reservation pool (AUTOCOMMIT_POOL_BATCH
xids) is reserved with one fetch_add. Each caller hands itself
the next xid via a single atomic. When the pool drains, the
next caller serialises briefly through autocommit_pool_refill
to bump the window, then falls back into the lock-free hot path.
Durability note: this method does NOT make the row durable —
it only allocates the identifier. The caller must complete the
usual WAL-append + fsync cycle before acknowledging the write.
Pre-allocating the xid is safe because the xid carries no
promise that any row exists; it’s just a number for xmin.
Sourcepub fn rollback(&self, xid: u64)
pub fn rollback(&self, xid: u64)
Mark a transaction as rolled back. Its writes MUST stay hidden
from every future read — is_visible consults the aborted set
before honouring a row’s xmin.
Sourcepub fn is_aborted(&self, xid: u64) -> bool
pub fn is_aborted(&self, xid: u64) -> bool
Is this xid known to have rolled back? Called by the read path to skip tuples whose creator never committed.
Sourcepub fn oldest_active_xid(&self) -> Option<u64>
pub fn oldest_active_xid(&self) -> Option<u64>
Snapshot of every still-active xid (for VACUUM oldest-active-xid
calculation — any row with xmax < min(active) is reclaimable).
Sourcepub fn oldest_pinned_xid(&self) -> Option<u64>
pub fn oldest_pinned_xid(&self) -> Option<u64>
Oldest externally pinned xid. Pinned snapshots behave like active snapshots for VACUUM: any tuple visible to that xid must survive even when no SQL transaction is currently active.
Sourcepub fn peek_next_xid(&self) -> u64
pub fn peek_next_xid(&self) -> u64
Return the next xid that would be allocated. Useful for diagnostics and for VACUUM to know the upper bound of aborted-xid retention.
Sourcepub fn observe_committed_xid(&self, xid: u64)
pub fn observe_committed_xid(&self, xid: u64)
Advance the allocator so future snapshots consider an xid recovered from storage/WAL to be in the committed past.
Sourcepub fn prune_aborted(&self, below: u64)
pub fn prune_aborted(&self, below: u64)
Prune the aborted-xid set. Safe to call once every aborted xid is
below oldest_active, which guarantees no live snapshot depends
on the distinction between “aborted” and “never existed”. Pinned
xids are always retained so higher-level references (VCS commits,
replica snapshots) stay readable.
Sourcepub fn pin(&self, xid: u64)
pub fn pin(&self, xid: u64)
Pin an xid so its row versions stay reclaim-safe across VACUUM.
Reference-counted — call unpin once per pin to release.
Trait Implementations§
Source§impl Default for SnapshotManager
impl Default for SnapshotManager
Source§fn default() -> SnapshotManager
fn default() -> SnapshotManager
Auto Trait Implementations§
impl !Freeze for SnapshotManager
impl !RefUnwindSafe for SnapshotManager
impl Send for SnapshotManager
impl Sync for SnapshotManager
impl Unpin for SnapshotManager
impl UnsafeUnpin for SnapshotManager
impl UnwindSafe for SnapshotManager
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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 moreSource§impl<T> IntoRequest<T> for T
impl<T> IntoRequest<T> for T
Source§fn into_request(self) -> Request<T>
fn into_request(self) -> Request<T>
T in a tonic::Request