Skip to main content

WalWriter

Struct WalWriter 

Source
pub struct WalWriter { /* private fields */ }
Expand description

Write-Ahead Log writer.

Appends records to WAL files, manages rotation, and enforces the configured fsync policy. Thread-safe: internal state is protected by a mutex.

§Group commit

When using FsyncPolicy::PerBatch, the append_durable method enables group commit: concurrent callers write their records under the write lock, then coordinate so that a single fsync covers all pending writes. The first waiter becomes the sync leader and performs the flush; subsequent waiters piggy-back on the leader’s sync.

Implementations§

Source§

impl WalWriter

Source

pub fn open( dir: impl Into<PathBuf>, config: WalConfig, ) -> Result<Self, WalError>

Open or create a WAL writer in the given directory.

If existing WAL files are present, the writer resumes from the last sequence number. Otherwise, a new WAL file is created starting at sequence 1.

§Errors

Returns WalError if the directory cannot be created or files cannot be opened.

Source

pub fn is_poisoned(&self) -> bool

Returns true if the WAL writer has been poisoned due to an unrecoverable I/O error.

Source

pub fn clear_poison(&self) -> Result<(), WalError>

Clear the poison flag after operator-verified recovery.

Re-opens the current WAL file for appending to ensure the underlying file descriptor is in a known-good state. Returns an error if the WAL file cannot be reopened.

§Safety (logical)

Call this only after verifying the WAL directory is intact (e.g. via WalReader replay). Clearing poison on a genuinely corrupt WAL risks silent data loss.

Source

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

Append a single payload to the WAL.

Returns the assigned sequence number.

§Errors

Returns WalError on I/O failure, if the WAL is full, or if the internal lock was poisoned.

Source

pub fn append_batch(&self, payloads: &[&[u8]]) -> Result<u64, WalError>

Append a batch of payloads as a single atomic WAL record, followed by a single fsync (when using PerBatch policy).

All payloads are serialized into a batch-framed compound record whose CRC covers the entire batch. On crash recovery, either all sub-payloads survive (CRC valid) or none (CRC mismatch / truncation), guaranteeing all-or-nothing batch atomicity.

Uses the same group-commit pattern as append_durable: the write lock is released before fsync, allowing concurrent writers to proceed while the sync leader fsyncs for all pending records.

Returns the sequence number of the batch record.

§Errors

Returns WalError on I/O failure or if the internal lock was poisoned.

Source

pub fn append_durable(&self, payload: &[u8]) -> Result<u64, WalError>

Append a single payload and ensure it is durably committed.

With FsyncPolicy::PerBatch this participates in group commit: the calling thread writes its record and then either becomes the sync leader (flushing and calling fsync for all pending records) or waits for an in-progress sync to complete. This amortises the cost of fsync across concurrent callers.

With FsyncPolicy::PerWrite this behaves identically to append.

With FsyncPolicy::Periodic the record is written and then unconditionally flushed + synced, because “durable” means the caller requires the data to be on stable storage before returning .

§Errors

Returns WalError on I/O failure, if the WAL is full, or if the internal lock was poisoned.

Source

pub fn sync(&self) -> Result<(), WalError>

Flush the WAL buffer and sync to disk.

§Errors

Returns WalError on I/O failure or if the internal lock was poisoned.

Source

pub fn fsync_count(&self) -> u64

Number of fsync calls issued against the WAL data file.

The observable form of the fsync policy: with FsyncPolicy::Periodic this grows with elapsed time, not with the number of appends.

Source

pub fn start_periodic_sync(self: &Arc<Self>)

Start the background periodic sync thread.

When the WAL is configured with FsyncPolicy::Periodic(interval), this spawns a dedicated thread that calls flush + fsync at the configured interval. The thread runs until shutdown_periodic_sync is called or the WalWriter is dropped.

No-op if the policy is not Periodic.

Source

pub fn shutdown_periodic_sync(&self)

Stop the periodic sync thread and wait for it to finish.

Source

pub fn rotate(&self) -> Result<(), WalError>

Force rotation to a new WAL file.

§Errors

Returns WalError on I/O failure or if the internal lock was poisoned.

Source

pub fn truncate_before(&self, sequence_no: u64) -> Result<usize, WalError>

Delete WAL files whose maximum sequence number is ≤ the threshold.

Never deletes the active WAL file. Idempotent.

§Errors

Returns WalError on I/O failure or if the internal lock was poisoned.

Source

pub fn memory_bytes(&self) -> usize

Approximate heap bytes held by the writer’s own buffers.

The BufWriter’s capacity, which is what stands between an append and an fsync. It is one of the three terms the memtable budget does not count, and unlike the other two it is fixed rather than a function of the workload — so it is worth having as a number precisely because it is easy to forget.

Source

pub fn current_sequence(&self) -> u64

Returns the current sequence number (the last assigned).

Source

pub fn dir(&self) -> &Path

Returns the path to the WAL directory.

Source

pub fn file_count(&self) -> Result<usize, WalError>

Returns the number of WAL files in the directory.

§Errors

Returns WalError if the directory cannot be read.

Source

pub fn total_bytes(&self) -> Result<u64, WalError>

Returns the total size in bytes of all WAL files on disk.

§Errors

Returns WalError if the directory cannot be read.

Source

pub fn emit_metrics(&self)

Emit WAL gauge metrics for monitoring lag and resource usage.

Emits chronix_wal_file_count, chronix_wal_total_bytes, and chronix_wal_sequence_number gauges.

Source

pub fn close(self) -> Result<(), WalError>

Explicitly close the WAL writer, flushing all data to stable storage.

Unlike the implicit Drop cleanup, this method returns I/O errors so close failures are not silently ignored.

The shutdown sequence is:

  1. Stop the periodic sync thread (if running).
  2. Flush all buffered data to the operating system.
  3. Issue sync_all to commit data and metadata to stable storage.
§Close-path efficiency

This method takes ownership of self (mut self), which guarantees exclusive access. The inner state is obtained via Mutex::get_mut (no-lock fast path), so flush and fsync execute outside any lock scope. This prevents mutex contention with concurrent readers or writers during shutdown.

§Errors

Returns WalError if the flush or fsync fails.

Trait Implementations§

Source§

impl Drop for WalWriter

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more
Source§

fn pin_drop(self: Pin<&mut Self>)

🔬This is a nightly-only experimental API. (pin_ergonomics)
Execute the destructor for this type, but different to Drop::drop, it requires self to be pinned. Read more

Auto Trait Implementations§

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> 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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. 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<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