Skip to main content

WalManager

Struct WalManager 

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

Write-Ahead Log manager

Implementations§

Source§

impl WalManager

Source

pub async fn new( path: PathBuf, config: WalConfig, ) -> Result<WalManager, WalError>

Create a new WAL manager instance.

This constructor initializes a WAL manager with the specified file path and configuration. It creates the necessary directory structure and opens the WAL file for append operations. The file is created if it doesn’t exist, and opened in append mode for existing files.

§Arguments
  • path - The file system path where the WAL file should be stored
  • config - Configuration options including format, size limits, and compression settings
§Returns

Returns a Result containing the initialized WalManager, or a WalError if initialization fails.

§Errors
  • WalError::Io - If directory creation or file operations fail
§Examples
use std::path::PathBuf;

use sentinel_wal::{WalConfig, WalFormat, WalManager};

let config = WalConfig {
    format: WalFormat::Binary, // or WalFormat::JsonLines
    max_file_size: Some(10 * 1024 * 1024), // 10MB
    ..Default::default()
};

let wal = WalManager::new(PathBuf::from("data/myapp.wal"), config).await?;

// WAL is now ready for writing entries
Source

pub async fn write_entry(&self, entry: LogEntry) -> Result<(), WalError>

Write a log entry to the WAL.

This method appends a log entry to the WAL file using the configured format (binary or JSON Lines). The entry is serialized and written atomically to ensure data integrity. For JSON Lines format, each entry is written as a separate line.

§Arguments
  • entry - The log entry to write to the WAL
§Returns

Returns Ok(()) on successful write, or a WalError if the operation fails.

§Errors
  • WalError::Serialization - If entry serialization fails
  • WalError::Io - If file write operations fail
§Examples
use sentinel_wal::{WalManager, WalConfig, LogEntry, EntryType};
use std::path::PathBuf;
use serde_json::json;

let config = WalConfig::default();
let mut wal = WalManager::new(PathBuf::from("data/app.wal"), config).await?;

// Write an insert operation
let entry = LogEntry::new(
    EntryType::Insert,
    "users".to_string(),
    "user-123".to_string(),
    Some(json!({"name": "Alice", "email": "alice@example.com"}))
);

wal.write_entry(entry).await?;

// Write a delete operation
let delete_entry = LogEntry::new(
    EntryType::Delete,
    "users".to_string(),
    "user-123".to_string(),
    None
);

wal.write_entry(delete_entry).await?;
Source

pub async fn read_all_entries(&self) -> Result<Vec<LogEntry>, WalError>

Read all log entries from the WAL for recovery.

This method reads and parses all entries from the WAL file(s) in the configured format. It’s typically used during database recovery to replay operations. The method automatically detects the format (binary or JSON Lines) and parses entries accordingly.

For binary format, entries are parsed by finding checksum boundaries. For JSON Lines format, entries are parsed line by line.

§Returns

Returns a Result containing a vector of all LogEntry instances found in the WAL, or a WalError if reading or parsing fails.

§Errors
  • WalError::Io - If file operations fail
  • WalError::Serialization - If entry parsing fails
§Examples
use std::path::PathBuf;

use sentinel_wal::{WalConfig, WalManager};

let config = WalConfig::default();
let wal = WalManager::new(PathBuf::from("data/app.wal"), config).await?;

// Read all entries for recovery
let entries = wal.read_all_entries().await?;

println!("Found {} entries in WAL", entries.len());
for entry in entries {
    println!(
        "Entry: {:?} on {} in collection {}",
        entry.entry_type,
        entry.document_id_str(),
        entry.collection_str()
    );
}
Source

pub fn stream_entries( &self, ) -> impl Stream<Item = Result<LogEntry, WalError>> + Send + 'static

Stream log entries from the WAL file.

This method provides a streaming interface to read WAL entries without loading the entire file into memory. It’s more memory-efficient than read_all_entries() for large WAL files. The stream automatically handles format detection and parsing.

For binary format, entries are streamed by reading length prefixes. For JSON Lines format, entries are streamed line by line.

§Returns

Returns a Stream that yields Result<LogEntry> items. The stream will yield Ok(entry) for successfully parsed entries and Err(error) for parsing failures.

§Examples
use std::path::PathBuf;

use sentinel_wal::{WalConfig, WalManager};
use futures::StreamExt;

let config = WalConfig::default();
let wal = WalManager::new(PathBuf::from("data/app.wal"), config).await?;

// Stream entries for processing
let mut stream = wal.stream_entries();
use futures::pin_mut;
pin_mut!(stream);

let mut count = 0;
while let Some(result) = stream.next().await {
    match result {
        Ok(entry) => {
            count += 1;
            println!("Processed entry {}: {:?}", count, entry.entry_type);
        },
        Err(e) => {
            eprintln!("Error reading entry: {}", e);
        },
    }
}

println!("Total entries processed: {}", count);
Source

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

Perform a checkpoint operation on the WAL.

A checkpoint ensures that all pending WAL entries are durably written to disk and creates a recovery point. This is different from truncation - checkpointing preserves the WAL for potential future recovery while marking a safe recovery point.

The checkpoint process:

  1. Flushes any buffered writes to disk
  2. Ensures file metadata is synchronized
  3. Records the checkpoint position for recovery
§Returns

Returns Ok(()) on successful checkpoint, or a WalError if the operation fails.

§Errors
  • WalError::Io - If file synchronization operations fail
§Examples
use std::path::PathBuf;

use sentinel_wal::{EntryType, LogEntry, WalConfig, WalManager};

let config = WalConfig::default();
let wal = WalManager::new(PathBuf::from("data/app.wal"), config).await?;

// Write some entries
let entry = LogEntry::new(
    EntryType::Insert,
    "users".to_string(),
    "user-123".to_string(),
    None,
);
wal.write_entry(entry).await?;

// Create a checkpoint
wal.checkpoint().await?;

// At this point, all entries are safely on disk
// and can be recovered from if needed
Source

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

Get the current size of the WAL file in bytes.

This method returns the size of the WAL file on disk, which can be used to monitor file growth and determine if rotation is needed based on the configured max_file_size limit.

§Returns

Returns a Result containing the file size in bytes, or a WalError if the metadata cannot be read.

§Errors
  • WalError::Io - If file metadata operations fail
§Examples
use std::path::PathBuf;

use sentinel_wal::{WalConfig, WalManager};

let config = WalConfig {
    max_file_size: Some(10 * 1024 * 1024), // 10MB
    ..Default::default()
};
let wal =
    WalManager::new(PathBuf::from("data/app.wal"), config.clone()).await?;

let size = wal.size().await?;
println!("WAL file size: {} bytes", size);

if let Some(max_size) = config.max_file_size {
    if size >= max_size {
        println!("WAL file should be rotated");
    }
}
Source

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

Get the number of entries in the WAL.

This returns the count of entries that have been written to the WAL. Note that this may not reflect the current state if entries have been checkpointed or if the WAL has been rotated.

§Returns

Returns the number of entries written to the WAL.

§Examples
use std::path::PathBuf;

use sentinel_wal::{WalConfig, WalManager};

let wal = WalManager::new(PathBuf::from("data.wal"), WalConfig::default())
    .await?;

let count = wal.entries_count().await?;
println!("WAL has {} entries", count);

Trait Implementations§

Source§

impl Debug for WalManager

Source§

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

Formats the value using the given formatter. 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<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> 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> 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 = 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

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