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:
- Current active file is renamed from
.active.log
to.log
- New active file is created with current timestamp
- All existing data remains accessible
Implementations§
Source§impl Bitask
impl Bitask
Sourcepub fn open(path: impl AsRef<Path>) -> Result<Self, Error>
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:
- Another process has write access (
Error::WriterLock
) - Filesystem operations fail (
Error::Io
) - No active file is found when opening existing DB (
Error::ActiveFileNotFound
)
§Examples
let mut db = bitask::db::Bitask::open("my_db")?;
Sourcepub fn ask(&mut self, key: &[u8]) -> Result<Vec<u8>, Error>
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:
- The key is empty (
Error::InvalidEmptyKey
) - The key doesn’t exist (
Error::KeyNotFound
) - The data file is missing (
Error::FileNotFound
) - IO operations fail (
Error::Io
)
§Examples
if let Ok(value) = db.ask(b"my_key") {
println!("Found value: {:?}", value);
}
Sourcepub fn put(&mut self, key: Vec<u8>, value: Vec<u8>) -> Result<(), Error>
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 storevalue
- The value to associate with the key
§Returns
Returns ()
if the operation was successful.
§Errors
Returns an Error
if:
- The key is empty (
Error::InvalidEmptyKey
) - The value is empty (
Error::InvalidEmptyValue
) - IO operations fail (
Error::Io
)
§Examples
db.put(b"my_key".to_vec(), b"my_value".to_vec())?;
Sourcepub fn remove(&mut self, key: Vec<u8>) -> Result<(), Error>
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:
- The key is empty (
Error::InvalidEmptyKey
) - IO operations fail (
Error::Io
)
§Examples
db.remove(b"my_key".to_vec())?;
Sourcepub fn compact(&mut self) -> Result<(), Error>
pub fn compact(&mut self) -> Result<(), Error>
Compacts the database by removing obsolete entries and merging files.
This process:
- Identifies immutable files (not including active file)
- Creates a new compacted file with only latest entries
- 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:
- IO operations fail (
Error::Io
) - File operations fail (
Error::FileNotFound
)
§Examples
// After many operations, compact to reclaim space
db.compact()?;