pub struct FeoxStore { /* private fields */ }
Expand description
High-performance embedded key-value store.
FeoxStore
provides ultra-fast key-value storage with optional persistence.
It uses lock-free data structures for concurrent access and achieves
sub-microsecond latencies for most operations.
§Thread Safety
All methods are thread-safe and can be called concurrently from multiple threads.
Implementations§
Source§impl FeoxStore
impl FeoxStore
Sourcepub fn new(device_path: Option<String>) -> Result<Self>
pub fn new(device_path: Option<String>) -> Result<Self>
Create a new FeoxStore with default configuration
Sourcepub fn with_config(config: StoreConfig) -> Result<Self>
pub fn with_config(config: StoreConfig) -> Result<Self>
Create a new FeoxStore with custom configuration
Sourcepub fn builder() -> StoreBuilder
pub fn builder() -> StoreBuilder
Create a builder for configuring FeoxStore.
§Example
use feoxdb::FeoxStore;
let store = FeoxStore::builder()
.max_memory(2_000_000_000)
.build()?;
Sourcepub fn insert(&self, key: &[u8], value: &[u8]) -> Result<()>
pub fn insert(&self, key: &[u8], value: &[u8]) -> Result<()>
Insert or update a key-value pair.
§Arguments
key
- The key to insert (max 65KB)value
- The value to store (max 4GB)timestamp
- Optional timestamp for conflict resolution. IfNone
, uses current time.
§Returns
Returns Ok(())
if successful.
§Errors
InvalidKey
- Key is empty or too largeInvalidValue
- Value is too largeOlderTimestamp
- Timestamp is not newer than existing recordOutOfMemory
- Memory limit exceeded
§Example
store.insert(b"user:123", b"{\"name\":\"Mehran\"}")?;
§Performance
- Memory mode: ~800ns
- Persistent mode: ~1µs (buffered write)
Sourcepub fn insert_with_timestamp(
&self,
key: &[u8],
value: &[u8],
timestamp: Option<u64>,
) -> Result<()>
pub fn insert_with_timestamp( &self, key: &[u8], value: &[u8], timestamp: Option<u64>, ) -> Result<()>
Insert or update a key-value pair with explicit timestamp.
This is the advanced version that allows manual timestamp control for
conflict resolution. Most users should use insert()
instead.
§Arguments
key
- The key to insert (max 65KB)value
- The value to store (max 4GB)timestamp
- Optional timestamp for conflict resolution. IfNone
, uses current time.
§Errors
OlderTimestamp
- Timestamp is not newer than existing record
Sourcepub fn get(&self, key: &[u8]) -> Result<Vec<u8>>
pub fn get(&self, key: &[u8]) -> Result<Vec<u8>>
Retrieve a value by key.
§Arguments
key
- The key to look upexpected_size
- Optional expected value size for validation
§Returns
Returns the value as a Vec<u8>
if found.
§Errors
KeyNotFound
- Key does not existInvalidKey
- Key is invalidSizeMismatch
- Value size doesn’t match expected sizeIoError
- Failed to read from disk (persistent mode)
§Example
let value = store.get(b"key")?;
assert_eq!(value, b"value");
§Performance
- Memory mode: ~100ns
- Persistent mode (cached): ~150ns
- Persistent mode (disk read): ~500ns
Sourcepub fn delete(&self, key: &[u8]) -> Result<()>
pub fn delete(&self, key: &[u8]) -> Result<()>
Delete a key-value pair.
§Arguments
key
- The key to deletetimestamp
- Optional timestamp for conflict resolution
§Returns
Returns Ok(())
if the key was deleted.
§Errors
KeyNotFound
- Key does not existOlderTimestamp
- Timestamp is not newer than existing record
§Example
store.delete(b"temp")?;
§Performance
- Memory mode: ~300ns
- Persistent mode: ~400ns
Sourcepub fn delete_with_timestamp(
&self,
key: &[u8],
timestamp: Option<u64>,
) -> Result<()>
pub fn delete_with_timestamp( &self, key: &[u8], timestamp: Option<u64>, ) -> Result<()>
Delete a key-value pair with explicit timestamp.
This is the advanced version that allows manual timestamp control.
Most users should use delete()
instead.
§Arguments
key
- The key to deletetimestamp
- Optional timestamp. IfNone
, uses current time.
§Errors
OlderTimestamp
- Timestamp is not newer than existing record
Sourcepub fn json_patch(&self, key: &[u8], patch: &[u8]) -> Result<()>
pub fn json_patch(&self, key: &[u8], patch: &[u8]) -> Result<()>
Apply a JSON patch to a value.
Uses RFC 6902 JSON Patch format to modify specific fields in a JSON document. Both the existing value and the patch must be valid JSON.
§Arguments
key
- The key containing the JSON document to patchpatch
- JSON Patch operations in RFC 6902 formattimestamp
- Optional timestamp for conflict resolution
§Returns
Returns Ok(())
if the update was applied.
§Errors
KeyNotFound
- Key does not existOlderTimestamp
- Timestamp is not newer than existing recordJsonPatchError
- Invalid JSON document or patch format
§Example
// Insert initial JSON value
let initial = br#"{"name":"Alice","age":30}"#;
store.insert(b"user:1", initial)?;
// Apply JSON patch to update age
let patch = br#"[{"op":"replace","path":"/age","value":31}]"#;
store.json_patch(b"user:1", patch)?;
// Value now has age updated to 31
let updated = store.get(b"user:1")?;
assert_eq!(updated.len(), initial.len()); // Same length, just age changed
Sourcepub fn json_patch_with_timestamp(
&self,
key: &[u8],
patch: &[u8],
timestamp: Option<u64>,
) -> Result<()>
pub fn json_patch_with_timestamp( &self, key: &[u8], patch: &[u8], timestamp: Option<u64>, ) -> Result<()>
Apply JSON patch with explicit timestamp.
This is the advanced version that allows manual timestamp control.
Most users should use json_patch()
instead.
§Arguments
key
- The key whose value to patchpatch
- JSON Patch array (RFC 6902)timestamp
- Optional timestamp. IfNone
, uses current time.
§Errors
OlderTimestamp
- Timestamp is not newer than existing record
Sourcepub fn range_query(
&self,
start_key: &[u8],
end_key: &[u8],
limit: usize,
) -> Result<Vec<(Vec<u8>, Vec<u8>)>>
pub fn range_query( &self, start_key: &[u8], end_key: &[u8], limit: usize, ) -> Result<Vec<(Vec<u8>, Vec<u8>)>>
Perform a range query on the store.
Returns all key-value pairs where the key is >= start_key
and <= end_key
.
Both bounds are inclusive.
§Arguments
start_key
- Inclusive lower boundend_key
- Inclusive upper boundlimit
- Maximum number of results to return
§Returns
Returns a vector of (key, value) pairs in sorted order.
§Example
store.insert(b"user:001", b"Alice")?;
store.insert(b"user:002", b"Bob")?;
store.insert(b"user:003", b"Charlie")?;
store.insert(b"user:004", b"David")?;
// Get users 001 through 003 (inclusive)
let results = store.range_query(b"user:001", b"user:003", 10)?;
assert_eq!(results.len(), 3);
Sourcepub fn atomic_increment(&self, key: &[u8], delta: i64) -> Result<i64>
pub fn atomic_increment(&self, key: &[u8], delta: i64) -> Result<i64>
Atomically increment a numeric counter.
The value must be stored as an 8-byte little-endian i64. If the key doesn’t exist, it will be created with the given delta value. If it exists, the value will be incremented atomically.
§Value Format
The value MUST be exactly 8 bytes representing a little-endian i64.
Use i64::to_le_bytes()
to create the initial value:
let zero: i64 = 0;
store.insert(b"counter", &zero.to_le_bytes())?;
§Arguments
key
- The key of the counterdelta
- The amount to increment by (can be negative for decrement)timestamp
- Optional timestamp for conflict resolution
§Returns
Returns the new value after incrementing.
§Errors
InvalidOperation
- Existing value is not exactly 8 bytes (not a valid i64)OlderTimestamp
- Timestamp is not newer than existing record
§Example
// Initialize counter with proper binary format
let initial: i64 = 0;
store.insert(b"visits", &initial.to_le_bytes())?;
// Increment atomically
let val = store.atomic_increment(b"visits", 1)?;
assert_eq!(val, 1);
// Increment by 5
let val = store.atomic_increment(b"visits", 5)?;
assert_eq!(val, 6);
// Decrement by 2
let val = store.atomic_increment(b"visits", -2)?;
assert_eq!(val, 4);
// Or create new counter directly (starts at delta value)
let downloads = store.atomic_increment(b"downloads", 100)?;
assert_eq!(downloads, 100);
Sourcepub fn atomic_increment_with_timestamp(
&self,
key: &[u8],
delta: i64,
timestamp: Option<u64>,
) -> Result<i64>
pub fn atomic_increment_with_timestamp( &self, key: &[u8], delta: i64, timestamp: Option<u64>, ) -> Result<i64>
Atomically increment/decrement with explicit timestamp.
This is the advanced version that allows manual timestamp control.
Most users should use atomic_increment()
instead.
§Arguments
key
- The key to increment/decrementdelta
- Amount to add (negative to decrement)timestamp
- Optional timestamp. IfNone
, uses current time.
§Errors
OlderTimestamp
- Timestamp is not newer than existing record
Sourcepub fn get_size(&self, key: &[u8]) -> Result<usize>
pub fn get_size(&self, key: &[u8]) -> Result<usize>
Get the size of a value without loading it.
Useful for checking value size before loading large values from disk.
§Arguments
key
- The key to check
§Returns
Returns the size in bytes of the value.
§Errors
KeyNotFound
- Key does not exist
§Example
store.insert(b"large_file", &vec![0u8; 1_000_000])?;
// Check size before loading
let size = store.get_size(b"large_file")?;
assert_eq!(size, 1_000_000);
Sourcepub fn flush_all(&self)
pub fn flush_all(&self)
Force flush all pending writes to disk.
In persistent mode, ensures all buffered writes are flushed to disk. In memory-only mode, this is a no-op.
§Example
let store = FeoxStore::new(Some("/path/to/data.feox".to_string()))?;
store.insert(b"important", b"data")?;
store.flush_all(); // Ensure data is persisted
Sourcepub fn contains_key(&self, key: &[u8]) -> bool
pub fn contains_key(&self, key: &[u8]) -> bool
Check if a key exists
Sourcepub fn memory_usage(&self) -> usize
pub fn memory_usage(&self) -> usize
Get memory usage statistics
Sourcepub fn stats(&self) -> StatsSnapshot
pub fn stats(&self) -> StatsSnapshot
Get statistics snapshot