feoxdb/lib.rs
1//! # FeOxDB - High-Performance Embedded Key-Value Store
2//!
3// Copyright 2025 Mehran Toosi
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17//! FeOxDB is an ultra-fast embedded key-value database designed for sub-microsecond latency.
18//!
19//! ## Performance
20//!
21//! View the latest benchmark results at: <https://feoxdb.com/benchmarks.html>
22//!
23//! ## Features
24//!
25//! - **Ultra-Low Latency**: <300ns GET operations, <600ns INSERT operations
26//! - **Lock-Free Operations**: Uses DashMap and SkipList for concurrent access
27//! - **io_uring Support** (Linux): Kernel-bypass I/O for maximum throughput with minimal syscalls
28//! - **Flexible Storage**: Memory-only or persistent modes with async I/O
29//! - **JSON Patch Support**: RFC 6902 compliant partial updates for JSON values
30//! - **Atomic Operations**: Increment/decrement counters atomically
31//! - **CLOCK Cache**: Efficient cache eviction algorithm
32//! - **Write Buffering**: Batched writes with sharded buffers to reduce contention
33//! - **Statistics**: Real-time performance metrics and monitoring
34//!
35//! ## ACID Properties and Durability
36//!
37//! FeOxDB provides ACI properties with relaxed durability:
38//!
39//! - **Atomicity**: ✅ Individual operations are atomic via Arc-wrapped records
40//! - **Consistency**: ✅ Timestamp-based conflict resolution ensures consistency
41//! - **Isolation**: ✅ Lock-free reads and sharded writes provide operation isolation
42//! - **Durability**: ⚠️ Write-behind logging with bounded data loss window
43//!
44//! ### Durability Trade-offs
45//!
46//! FeOxDB trades full durability for extreme performance:
47//! - **Write-behind buffering**: Flushes every 100ms or when buffers fill (1024 entries or 16MB per shard)
48//! - **Worst-case data loss**:
49//! - **Time window**: `100ms + 16MB / 4KB_random_write_QD1_throughput`
50//! - **Data at risk**: `16MB × num_shards` (e.g., 64MB for 4 shards, 128MB for 8 shards)
51//! - Workers write in parallel, so time doesn't multiply with shards
52//! - Example (50MB/s 4KB random QD1): 420ms window, up to 64MB at risk (4 shards)
53//! - Example (200MB/s 4KB random QD1): 180ms window, up to 64MB at risk (4 shards)
54//! - **Memory-only mode**: No durability, maximum performance
55//! - **Explicit flush**: Call `store.flush()` to synchronously write all buffered data (blocks until fsync completes)
56//!
57//! ## Quick Start
58//!
59//! ### Memory-Only Mode (Fastest)
60//! ```rust
61//! use feoxdb::FeoxStore;
62//!
63//! # fn main() -> feoxdb::Result<()> {
64//! // Create an in-memory store
65//! let store = FeoxStore::new(None)?;
66//!
67//! // Insert a key-value pair
68//! store.insert(b"key", b"value")?;
69//!
70//! // Retrieve the value
71//! let value = store.get(b"key")?;
72//! assert_eq!(value, b"value");
73//!
74//! // Delete the key
75//! store.delete(b"key")?;
76//! # Ok(())
77//! # }
78//! ```
79//!
80//! ### Persistent Mode
81//! ```no_run
82//! use feoxdb::FeoxStore;
83//!
84//! # fn main() -> feoxdb::Result<()> {
85//! // Create a persistent store
86//! let store = FeoxStore::new(Some("/path/to/data.feox".to_string()))?;
87//!
88//! // Operations are automatically persisted
89//! store.insert(b"persistent_key", b"persistent_value")?;
90//!
91//! // Flush to disk
92//! store.flush();
93//! # Ok(())
94//! # }
95//! ```
96//!
97//! ### Using the Builder Pattern
98//! ```rust
99//! use feoxdb::FeoxStore;
100//!
101//! # fn main() -> feoxdb::Result<()> {
102//! let store = FeoxStore::builder()
103//! .max_memory(1024 * 1024 * 1024) // 1GB limit
104//! .hash_bits(20) // 1M hash buckets
105//! .build()?;
106//! # Ok(())
107//! # }
108//! ```
109//!
110//! ### Range Queries and Store Operations
111//! ```rust
112//! use feoxdb::FeoxStore;
113//!
114//! # fn main() -> feoxdb::Result<()> {
115//! let store = FeoxStore::new(None)?;
116//!
117//! // Insert sorted keys
118//! store.insert(b"user:001", b"Mehran")?;
119//! store.insert(b"user:002", b"Bob")?;
120//! store.insert(b"user:003", b"Charlie")?;
121//!
122//! // Range query (both start and end are inclusive)
123//! let results = store.range_query(b"user:001", b"user:003", 10)?;
124//! assert_eq!(results.len(), 3); // Returns user:001, user:002, user:003
125//!
126//! // Check existence
127//! assert!(store.contains_key(b"user:001"));
128//!
129//! // Get store metrics
130//! assert_eq!(store.len(), 3);
131//! println!("Memory usage: {} bytes", store.memory_usage());
132//! # Ok(())
133//! # }
134//! ```
135//!
136//! ### JSON Patch Operations (RFC 6902)
137//! ```no_run
138//! use feoxdb::FeoxStore;
139//!
140//! # fn main() -> feoxdb::Result<()> {
141//! let store = FeoxStore::new(None)?;
142//!
143//! // Insert a JSON document
144//! let initial_json = br#"{
145//! "name": "Mehran",
146//! "age": 30,
147//! "scores": [85, 90, 95]
148//! }"#;
149//! store.insert(b"user:123", initial_json)?;
150//!
151//! // Apply a JSON Patch to modify specific fields
152//! let patch = br#"[
153//! {"op": "replace", "path": "/age", "value": 31},
154//! {"op": "add", "path": "/email", "value": "[email protected]"},
155//! {"op": "add", "path": "/scores/-", "value": 100}
156//! ]"#;
157//!
158//! store.json_patch(b"user:123", patch)?;
159//!
160//! // The document is now updated with the patches applied
161//! let updated = store.get(b"user:123")?;
162//! # Ok(())
163//! # }
164//! ```
165//!
166//! ### Atomic Counter Operations
167//! ```rust
168//! use feoxdb::FeoxStore;
169//!
170//! # fn main() -> feoxdb::Result<()> {
171//! let store = FeoxStore::new(None)?;
172//!
173//! // Initialize a counter (must be 8-byte i64 value)
174//! let zero: i64 = 0;
175//! store.insert(b"counter:visits", &zero.to_le_bytes())?;
176//!
177//! // Increment atomically
178//! let new_value = store.atomic_increment(b"counter:visits", 1)?;
179//! assert_eq!(new_value, 1);
180//!
181//! // Increment by 5
182//! let new_value = store.atomic_increment(b"counter:visits", 5)?;
183//! assert_eq!(new_value, 6);
184//!
185//! // Decrement by 2
186//! let new_value = store.atomic_increment(b"counter:visits", -2)?;
187//! assert_eq!(new_value, 4);
188//! # Ok(())
189//! # }
190//! ```
191//!
192//! ## Timestamps and Consistency
193//!
194//! FeOxDB uses timestamps for conflict resolution and consistency:
195//!
196//! ```rust
197//! # use feoxdb::FeoxStore;
198//! # fn main() -> feoxdb::Result<()> {
199//! # let store = FeoxStore::new(None)?;
200//! // Insert with explicit timestamp
201//! store.insert_with_timestamp(b"key", b"value_v1", Some(100))?;
202//!
203//! // Update with higher timestamp succeeds
204//! store.insert_with_timestamp(b"key", b"value_v2", Some(200))?;
205//!
206//! // Update with lower timestamp fails
207//! let result = store.insert_with_timestamp(b"key", b"value_v3", Some(150));
208//! assert!(result.is_err()); // OlderTimestamp error
209//! # Ok(())
210//! # }
211//! ```
212//!
213//! ## Performance and Benchmarking
214//!
215//! Run benchmarks to verify performance on your hardware:
216//!
217//! ```bash
218//! # Criterion benchmarks for detailed latency analysis
219//! cargo bench
220//!
221//! # Throughput test (100k operations, 100 byte values)
222//! cargo run --release --example performance_test 100000 100
223//!
224//! # Deterministic test for reproducible results
225//! cargo run --release --example deterministic_test 100000 100
226//! ```
227//!
228//! Typical results on M3 Max:
229//!
230//! | Operation | Latency (Memory Mode) | Throughput |
231//! |-----------|----------------------|------------|
232//! | GET | ~200-260ns | 2.1M ops/sec |
233//! | INSERT | ~700ns | 850K ops/sec |
234//! | DELETE | ~290ns | 1.1M ops/sec |
235//! | Mixed (80/20) | ~290ns | 3.1M ops/sec |
236//!
237//! ## Architecture Overview
238//!
239//! FeOxDB uses a lock-free, multi-tier architecture optimized for modern multi-core CPUs:
240//!
241//! ### Lock-Free Data Structures
242//! - **Hash Table**: DashMap provides lock-free concurrent hash map with sharded locks
243//! - **Ordered Index**: Crossbeam SkipList enables lock-free sorted traversal
244//! - **Atomic Operations**: All metadata updates use atomic primitives in hot path
245//!
246//! ### Async Write-Behind Logging
247//! - **Sharded Write Buffers**: Multiple write buffers with thread-consistent assignment to reduce contention
248//! - **Batched Writes**: Writes are buffered and flushed asynchronously in batches
249//! - **io_uring Integration**: On Linux, uses kernel-bypass I/O for minimal syscall overhead
250//! - **Write Coalescing**: Multiple updates to the same key are automatically coalesced
251//!
252//! ### Storage Tiers
253//! 1. **In-Memory Layer**: Hot data in DashMap with O(1) access
254//! 2. **Write Buffer**: Sharded buffers with thread-local affinity for write batching
255//! 3. **Persistent Storage**: Sector-aligned async I/O with write-ahead logging
256//! 4. **Cache Layer**: CLOCK algorithm keeps frequently accessed data in memory
257//!
258//! ### Free Space Management
259//!
260//! FeOxDB uses a dual RB-tree structure for managing disk space:
261//! - One tree sorted by size for best-fit allocation
262//! - One tree sorted by address for efficient merging
263//! - Automatic coalescing of adjacent free blocks
264//! - O(log n) allocation and deallocation
265//! - Zero external fragmentation through immediate merging
266//!
267//! ## Thread Safety
268//!
269//! All operations are thread-safe and can be called concurrently:
270//!
271//! ```rust
272//! # use feoxdb::FeoxStore;
273//! # use std::sync::Arc;
274//! # use std::thread;
275//! # fn main() -> feoxdb::Result<()> {
276//! let store = Arc::new(FeoxStore::new(None)?);
277//! let mut handles = vec![];
278//!
279//! for i in 0..10 {
280//! let store_clone = Arc::clone(&store);
281//! handles.push(thread::spawn(move || {
282//! let key = format!("key_{}", i);
283//! store_clone.insert(key.as_bytes(), b"value").unwrap();
284//! }));
285//! }
286//!
287//! for handle in handles {
288//! handle.join().unwrap();
289//! }
290//! # Ok(())
291//! # }
292//! ```
293
294pub mod constants;
295pub mod core;
296pub mod error;
297pub mod stats;
298pub mod storage;
299pub mod utils;
300
301pub use core::store::{FeoxStore, StoreBuilder, StoreConfig};
302pub use error::{FeoxError, Result};
303pub use stats::Statistics;
304
305#[cfg(test)]
306mod tests;