Skip to main content

Wal

Struct Wal 

Source
pub struct Wal<O: DurabilityObserver = NullObserver> { /* private fields */ }
Expand description

Single-writer, append-only write-ahead log handle.

Send but not Sync (§6.2): the write methods take &mut self, and the PhantomData<Cell<()>> marker makes sharing the handle across threads a compile error, so concurrent writers cannot exist. Generic over a DurabilityObserver; the default NullObserver compiles away.

Implementations§

Source§

impl Wal<NullObserver>

Source

pub fn open( dir: &Path, config: WalConfig, ) -> Result<(Wal<NullObserver>, RecoveryReport)>

Open or create a WAL in dir with the default no-op observer.

Source§

impl<O: DurabilityObserver> Wal<O>

Source

pub fn open_with( dir: &Path, config: WalConfig, observer: O, ) -> Result<(Wal<O>, RecoveryReport)>

Open or create a WAL in dir, running recovery, with an explicit observer (§6). Acquires an exclusive advisory lock on the directory; fails with Locked if already held.

Runs full recovery (§8): it cold-starts an empty directory (creating …0001.wal) or discovers every *.wal segment, sorts them by base_lsn, validates each header, discards an incomplete-header highest-base file left by a crash mid-create (§8.4), recovers each segment’s record run (§8.2 — torn-tail truncation + durable zeroing on the active segment, fatal mid-log corruption), and verifies cross-segment LSN continuity (§8.1).

Source

pub fn append(&mut self, payload: &[u8]) -> Result<Lsn>

Sequence + buffer a record (§7.1). Pure memory: no syscall, no allocation once the staging buffer is warm. The record is not durable until a later commit returns covering it.

Source

pub fn commit(&mut self) -> Result<Lsn>

Make all buffered records durable (§7.2), splitting across segments on whole-record boundaries when the batch does not fit the active segment (§7.3). Each segment touched gets its own write + fdatasync (F_FULLFSYNC on macOS) and advances durable_lsn to that segment’s last LSN; the observer fires after each advance (§15.3).

commit is not atomic (§4.1): on a multi-segment split a crash or an I/O failure between two segments’ syncs leaves the first segment durable and the rest lost — a valid dense suffix (D9), never an internal gap. On any write/fdatasync/roll failure the handle is poisoned (§12); durable_lsn keeps whatever earlier segments achieved (monotonic, never regresses).

Source

pub fn durable_lsn(&self) -> Lsn

Highest durable LSN (§6).

Source

pub fn last_lsn(&self) -> Lsn

Highest assigned LSN, durable or still buffered (§6).

Source

pub fn reader_from(&self, from: Lsn) -> Result<Reader<'_>>

A streaming replay Reader starting at from (§6).

from == Lsn(0) means “from the beginning”. A from below the oldest available LSN is a fatal gap (§15.4) — the needed records were checkpointed away; never a silent skip. (Dormant in M2, where oldest_lsn == 1.)

Source

pub fn checkpoint(&mut self, up_to: Lsn) -> Result<()>

Delete whole sealed segments fully superseded by up_to, reclaiming space (§9). A segment covering [b, b') (b' = the next segment’s base) is deletable iff b' − 1 ≤ up_to; the active segment is never deleted.

Deletion is oldest-first, then a single directory fsync makes the unlinks durable. Because only a prefix is ever removed, survivors remain a contiguous suffix at every crash point (D8/D9): a crash before the dir-fsync recovers via the §4 D2 “missing prefix accepted silently” path to the same suffix. Checkpoint only unlinks whole files — it never rewrites or compacts — and advances oldest_lsn (P).

Caller rule (§9): pass only up_to ≤ your latest durable *snapshot* LSN, never durable_lsn — recovery is “latest durable snapshot + replay of the log after it”, so deleting the log past your snapshot silently caps recovery. The WAL trusts the caller and cannot verify this (the inverse of D8). Any unlink/fsync failure poisons the handle (§12).

Auto Trait Implementations§

§

impl<O = NullObserver> !RefUnwindSafe for Wal<O>

§

impl<O = NullObserver> !Sync for Wal<O>

§

impl<O> Freeze for Wal<O>
where O: Freeze,

§

impl<O> Send for Wal<O>
where O: Send,

§

impl<O> Unpin for Wal<O>
where O: Unpin,

§

impl<O> UnsafeUnpin for Wal<O>
where O: UnsafeUnpin,

§

impl<O> UnwindSafe for Wal<O>
where O: UnwindSafe,

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<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

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

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

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.