Struct Bitask

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

A Bitcask-style key-value store implementation.

Bitcask is an append-only log-structured storage engine that maintains an in-memory index (keydir) mapping keys to their most recent value locations on disk.

§Features

  • Single-writer, multiple-reader architecture
  • Process-safe file locking
  • Append-only log structure
  • In-memory key directory
  • Automatic log rotation at 4MB

§Thread Safety

The database ensures process-level safety through file locking, but is not thread-safe internally. Concurrent access from multiple threads requires appropriate synchronization mechanisms at the application level.

§Examples

Basic usage:

use bitask::Bitask;

let mut db = bitask::db::Bitask::open("my_db")?;

// Store a value
db.put(b"key".to_vec(), b"value".to_vec())?;

// Retrieve a value
let value = db.ask(b"key")?;
assert_eq!(value, b"value");

// Remove a value
db.remove(b"key".to_vec())?;

§File Structure

  • Active file: <timestamp>.active.log - Current file being written to
  • Sealed files: <timestamp>.log - Immutable files after rotation
  • Lock file: db.lock - Ensures single-writer access

§Log Rotation

Files are automatically rotated when they reach 4MB in size. When rotation occurs:

  1. Current active file is renamed from .active.log to .log
  2. New active file is created with current timestamp
  3. All existing data remains accessible

Implementations§

Source§

impl Bitask

Source

pub fn open(path: impl AsRef<Path>) -> Result<Self, Error>

Opens a Bitcask database at the specified path with exclusive write access.

Creates a new database if one doesn’t exist at the specified path. Uses file system locks to ensure only one writer exists across all processes.

§Parameters
  • path - Path where the database files will be stored
§Returns

Returns a new Bitask instance if successful.

§Errors

Returns an Error if:

§Examples
let mut db = bitask::db::Bitask::open("my_db")?;
Source

pub fn ask(&mut self, key: &[u8]) -> Result<Vec<u8>, Error>

Retrieves the value associated with the given key.

Performs an O(1) lookup in the in-memory index followed by a single disk read.

§Parameters
  • key - The key to look up
§Returns

Returns the value as a Vec<u8> if the key exists.

§Errors

Returns an Error if:

§Examples
if let Ok(value) = db.ask(b"my_key") {
    println!("Found value: {:?}", value);
}
Source

pub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) -> Result<(), Error>

Stores a key-value pair in the database.

If the key already exists, it will be updated with the new value. The operation is atomic and durable (synced to disk).

Performance: Requires one disk write (append-only) and one in-memory index update. May trigger file rotation if the active file exceeds size limit (4MB).

§Parameters
  • key - The key to store
  • value - The value to associate with the key
§Returns

Returns () if the operation was successful.

§Errors

Returns an Error if:

§Examples
db.put(b"my_key".to_vec(), b"my_value".to_vec())?;
Source

pub fn remove(&mut self, key: Vec<u8>) -> Result<(), Error>

Removes a key-value pair from the database.

The operation is atomic and durable. Even if the key doesn’t exist, a tombstone entry is written to ensure the removal is persisted.

Performance: Requires one disk write (append-only) and one in-memory index update.

§Parameters
  • key - The key to remove
§Returns

Returns () if the operation was successful.

§Errors

Returns an Error if:

§Examples
db.remove(b"my_key".to_vec())?;
Source

pub fn compact(&mut self) -> Result<(), Error>

Compacts the database by removing obsolete entries and merging files.

This process:

  1. Identifies immutable files (not including active file)
  2. Creates a new compacted file with only latest entries
  3. Removes old files after successful compaction

Performance: Requires reading all immutable files and writing live entries to a new file. Memory usage remains constant as entries are processed sequentially.

§Returns

Returns () if compaction was successful.

§Errors

Returns an Error if:

§Examples
// After many operations, compact to reclaim space
db.compact()?;

Trait Implementations§

Source§

impl Debug for Bitask

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Drop for Bitask

Source§

fn drop(&mut self)

Cleans up resources when the database is dropped.

Removes the physical lock file from the filesystem to allow future database instances to acquire the write lock.

Auto Trait Implementations§

§

impl Freeze for Bitask

§

impl RefUnwindSafe for Bitask

§

impl Send for Bitask

§

impl Sync for Bitask

§

impl Unpin for Bitask

§

impl UnwindSafe for Bitask

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.