Skip to main content

Wal

Struct Wal 

Source
pub struct Wal<F: FileBackend = FileHandle> { /* private fields */ }
Expand description

The write-ahead log.

Owns the on-disk WAL file, the current generation salt, and the LSN counter. The pager talks to a Wal via Wal::begin_txn, staging per-page writes in a WalTxn and then calling WalTxn::commit to make them durable.

Generic over F: FileBackend (Rule 9: static dispatch on the hot path). Production code uses Wal<FileHandle>; the fault-injection harness substitutes Wal<FaultyFileHandle> to drive recovery against torn writes, dropped fsyncs, and bit flips.

Phase 4 (issue #9): when the parent pager opens an encryption-capable file with the right key, the WAL also encrypts each frame body with XChaCha20-Poly1305. The frame layout gains a 40-byte suffix (nonce || tag), the on-disk per-frame stride becomes 4200 bytes, and the frame’s existing CRC32C is computed over (header_sans_crc + PLAINTEXT body) — the CRC catches in-memory bit-flips on the post-decryption representation rather than running on attacker-controlled ciphertext.

Implementations§

Source§

impl Wal<FileHandle>

Source

pub fn create_fresh(path: &Path, config: WalConfig) -> Result<Self>

Create or truncate the WAL sidecar at path to a fresh, empty WAL backed by a FileHandle. Convenience for production callers; see Wal::create_fresh_with when the caller already holds a backend instance (e.g. a fault-injection harness).

§Errors

Returns Error::Io on syscall failure.

Source

pub fn open_for_recovery( path: &Path, expected_salt: u32, size_limit: u64, ) -> Result<Recovered>

Walk the on-disk WAL at path and produce a Recovered snapshot, opening the WAL with a production FileHandle.

See Wal::open_for_recovery_with for the documented algorithm; see Wal::create_fresh for the file-handle rationale.

§Errors

See Wal::open_for_recovery_with.

Source§

impl<F: FileBackend> Wal<F>

Source

pub fn create_fresh_with( file: F, path: PathBuf, config: WalConfig, ) -> Result<Self>

Create or truncate the WAL sidecar at path to a fresh, empty WAL on top of an already-opened backend file. Any existing content is overwritten with a new WAL header carrying a freshly-sampled generation salt.

§Errors

Returns Error::Io on syscall failure.

Source

pub fn from_recovered_meta( file: F, path: PathBuf, salt: u32, next_lsn: Lsn, end_offset: u64, committed_frames: u64, config: WalConfig, ) -> Self

Adopt an already-walked WAL handle. Used by Pager::open after Wal::open_for_recovery has returned a Recovered. salt, next_lsn, committed_frames, and end_offset are taken from recovered; the caller separately merges recovered.view into the pager’s in-memory state.

Source

pub fn open_for_recovery_with( file: &F, expected_salt: u32, size_limit: u64, ) -> Result<Recovered>

Walk an already-open WAL file and produce a Recovered snapshot.

Algorithm (matches docs/format.md § Recovery semantics):

  1. If path does not exist, or is shorter than a WAL header, return an empty Recovered carrying expected_salt.
  2. Read the WAL header. If magic / format-major / page-size disagree with the build, fail with Error::InvalidFormat.
  3. If the header’s salt does not equal expected_salt, the WAL is from a previous generation; return an empty Recovered.
  4. Pass 1: scan every aligned frame in the WAL and record the byte offset of the last frame whose salt matches and whose CRC validates AND whose commit-marker bit is set. Frames whose CRC fails (or whose salt does not match) in pass 1 are silently skipped — they might be torn-tail noise that precedes a later valid commit marker.
  5. Pass 2: walk frames from offset WAL_HEADER_SIZE up to (but not past) the last-commit-end offset from pass 1. Any frame in this range whose salt matches MUST have a valid CRC; otherwise return Error::WalCorruption — the bad frame sits between two intact commit markers and recovery cannot determine if data was lost.
  6. Salt-mismatched frames inside pass 2’s range are skipped (they are stale-generation noise, not corruption). Frames past the last commit marker are torn tail and are silently discarded.
§Errors
  • Error::Io on syscall failure.
  • Error::InvalidFormat when the WAL header is malformed in a way that indicates a config mismatch rather than torn tail.
  • Error::WalCorruption when a CRC-invalid frame sits before the last committed frame in the current generation.
  • Error::InvalidArgument if size_limit would be exceeded during the walk (a runaway WAL caps recovery).
Source

pub fn open_for_recovery_with_key( file: &F, expected_salt: u32, size_limit: u64, key: Option<[u8; 32]>, ) -> Result<Recovered>

Phase 4 (issue #9): same as Self::open_for_recovery_with but takes an optional per-file page-encryption key. On encrypted WALs each frame body is decrypted with the supplied key BEFORE the frame’s CRC32C is validated; the recovery walker therefore needs the key at construction. The pager calls this entry point.

§Errors

As Self::open_for_recovery_with, plus Error::EncryptionKeyInvalid when a salt-matching frame in the WAL fails Poly1305 verification — the smoking-gun wrong-key signal.

Source

pub fn path(&self) -> &Path

Path the WAL was opened at. Used by the pager to remove the sidecar on clean shutdown.

Source

pub fn salt(&self) -> u32

Current WAL generation salt.

Source

pub fn next_lsn(&self) -> Lsn

LSN the next appended frame will carry.

Source

pub fn committed_frames(&self) -> u64

Frames currently on disk (committed; torn-tail not counted).

Source

pub fn checkpoint_threshold(&self) -> u64

Configured auto-checkpoint threshold.

Source

pub fn begin_txn(&mut self) -> WalTxn<'_, F>

Begin a new transaction. The returned WalTxn holds a mutable borrow of the WAL; only one transaction can be open at a time.

Source

pub fn reset_after_checkpoint(&mut self) -> Result<()>

Reset the WAL after a successful checkpoint: rotate the salt, write the new header, fsync, and truncate to header-only.

§Errors

Returns Error::Io on syscall failure.

Trait Implementations§

Source§

impl<F: Debug + FileBackend> Debug for Wal<F>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

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

§

impl<F> RefUnwindSafe for Wal<F>
where F: RefUnwindSafe,

§

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

§

impl<F> Sync for Wal<F>
where F: Sync,

§

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

§

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

§

impl<F> UnwindSafe for Wal<F>
where F: 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.
Source§

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

Source§

fn vzip(self) -> V