Skip to content

Commit 53dbfa6

Browse files
committed
docs
1 parent 5c33c83 commit 53dbfa6

5 files changed

Lines changed: 178 additions & 4 deletions

File tree

src/lib.rs

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
1-
// VelociDB library interface
2-
// Modern embedded database with MVCC, async I/O, and vectorized execution
1+
//! # VelociDB
2+
//!
3+
//! VelociDB is a high-performance, embedded database engine written in Rust.
4+
//! It features a modern architecture designed for NVMe storage and multi-core systems.
5+
//!
6+
//! ## Key Features
7+
//!
8+
//! - **MVCC**: Multi-Version Concurrency Control for non-blocking reads.
9+
//! - **Async I/O**: Built on `tokio` and `io_uring` (on Linux) for high throughput.
10+
//! - **SIMD Acceleration**: Vectorized execution for query processing.
11+
//! - **Persistent Memory**: Direct Access (DAX) support for PMEM.
12+
//!
13+
//! ## Quick Start
14+
//!
15+
//! ```rust,no_run
16+
//! use velocidb::Database;
17+
//!
18+
//! # fn main() -> anyhow::Result<()> {
19+
//! // Open a database (creates it if it doesn't exist)
20+
//! let db = Database::open("my_database.db")?;
21+
//!
22+
//! // Create a table
23+
//! db.execute("CREATE TABLE users (id INTEGER PRIMARY KEY, name TEXT, age INTEGER)")?;
24+
//!
25+
//! // Insert data
26+
//! db.execute("INSERT INTO users VALUES (1, 'Alice', 30)")?;
27+
//! db.execute("INSERT INTO users VALUES (2, 'Bob', 25)")?;
28+
//!
29+
//! // Query data
30+
//! let results = db.query("SELECT * FROM users WHERE age > 25")?;
31+
//!
32+
//! for row in results.rows {
33+
//! println!("Found user: {:?}", row.values);
34+
//! }
35+
//! # Ok(())
36+
//! # }
37+
//! ```
338
439
pub mod storage;
540
pub mod btree;

src/lockfree.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ pub struct LockFreePageCache {
1717
/// Current size
1818
size: AtomicUsize,
1919
/// Cache entries: page_id -> cached page
20-
/// Using Arc<RwLock> for the HashMap as a pragmatic hybrid approach
20+
/// Using `Arc<RwLock>` for the HashMap as a pragmatic hybrid approach
2121
/// The HashMap itself is behind a lock, but individual operations are fast
2222
entries: Arc<RwLock<HashMap<PageId, Arc<CachedPage>>>>,
2323
/// LRU tracking queue (lock-free)

src/storage.rs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -150,6 +150,15 @@ impl Drop for Pager {
150150
}
151151
}
152152

153+
/// The main database structure.
154+
///
155+
/// `Database` provides the primary interface for interacting with a VelociDB database.
156+
/// It handles storage management, transaction coordination, and query execution.
157+
///
158+
/// # Thread Safety
159+
///
160+
/// `Database` is thread-safe and can be shared across threads using `Arc`.
161+
/// Internally, it uses fine-grained locking to allow concurrent reads and writes.
153162
pub struct Database {
154163
pager: Arc<RwLock<Pager>>,
155164
btrees: Arc<RwLock<HashMap<String, Arc<RwLock<BTree>>>>>,
@@ -158,6 +167,25 @@ pub struct Database {
158167
}
159168

160169
impl Database {
170+
/// Opens a database at the specified path.
171+
///
172+
/// If the database file does not exist, it will be created.
173+
///
174+
/// # Arguments
175+
///
176+
/// * `path` - The path to the database file.
177+
///
178+
/// # Returns
179+
///
180+
/// Returns a `Result` containing an `Arc<Database>` on success.
181+
///
182+
/// # Example
183+
///
184+
/// ```rust,no_run
185+
/// use velocidb::Database;
186+
///
187+
/// let db = Database::open("my_database.db").unwrap();
188+
/// ```
161189
pub fn open<P: AsRef<Path>>(path: P) -> Result<Arc<Self>> {
162190
let pager = Arc::new(RwLock::new(Pager::new(path.as_ref())?));
163191
let btrees = Arc::new(RwLock::new(HashMap::new()));
@@ -421,6 +449,20 @@ impl Database {
421449
Ok(())
422450
}
423451

452+
/// Executes a SQL statement that does not return rows (e.g., CREATE, INSERT, UPDATE, DELETE).
453+
///
454+
/// # Arguments
455+
///
456+
/// * `sql` - The SQL statement to execute.
457+
///
458+
/// # Example
459+
///
460+
/// ```rust,no_run
461+
/// # use velocidb::Database;
462+
/// # let db = Database::open("test.db").unwrap();
463+
/// db.execute("CREATE TABLE items (id INTEGER, name TEXT)").unwrap();
464+
/// db.execute("INSERT INTO items VALUES (1, 'Item 1')").unwrap();
465+
/// ```
424466
pub fn execute(&self, sql: &str) -> Result<()> {
425467
let parser = Parser::new();
426468
let statement = parser.parse(sql)?;
@@ -446,6 +488,26 @@ impl Database {
446488
Ok(())
447489
}
448490

491+
/// Executes a SQL query that returns rows (e.g., SELECT).
492+
///
493+
/// # Arguments
494+
///
495+
/// * `sql` - The SQL query to execute.
496+
///
497+
/// # Returns
498+
///
499+
/// Returns a `Result` containing a `QueryResult` with the fetched rows and columns.
500+
///
501+
/// # Example
502+
///
503+
/// ```rust,no_run
504+
/// # use velocidb::Database;
505+
/// # let db = Database::open("test.db").unwrap();
506+
/// let results = db.query("SELECT * FROM items").unwrap();
507+
/// for row in results.rows {
508+
/// println!("{:?}", row.values);
509+
/// }
510+
/// ```
449511
pub fn query(&self, sql: &str) -> Result<QueryResult> {
450512
let parser = Parser::new();
451513
let statement = parser.parse(sql)?;
@@ -460,11 +522,16 @@ impl Database {
460522
executor.query(statement)
461523
}
462524

525+
/// Closes the database and flushes all changes to disk.
526+
///
527+
/// While `Database` implements `Drop` to automatically flush on cleanup,
528+
/// calling `close` explicitly allows handling any flush errors.
463529
pub fn close(&self) -> Result<()> {
464530
self.pager.write().flush()?;
465531
Ok(())
466532
}
467533

534+
/// Lists all tables in the database.
468535
pub fn list_tables(&self) -> Vec<String> {
469536
self.schema.read().list_tables()
470537
}

src/transaction.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,11 +13,15 @@ use std::sync::atomic::{AtomicU64, AtomicU8, Ordering};
1313
use std::sync::Arc;
1414
use std::time::Duration;
1515

16+
/// Represents the state of a transaction.
1617
#[derive(Debug, Clone, Copy, PartialEq)]
1718
#[repr(u8)]
1819
pub enum TransactionState {
20+
/// Transaction is active and can perform operations.
1921
Active = 0,
22+
/// Transaction has been committed successfully.
2023
Committed = 1,
24+
/// Transaction has been aborted/rolled back.
2125
Aborted = 2,
2226
}
2327

@@ -32,6 +36,10 @@ impl From<u8> for TransactionState {
3236
}
3337
}
3438

39+
/// A database transaction.
40+
///
41+
/// Transactions provide ACID guarantees for database operations.
42+
/// They are created by the `TransactionManager`.
3543
pub struct Transaction {
3644
id: TransactionId,
3745
// Use atomic instead of RwLock to eliminate lock contention
@@ -46,14 +54,19 @@ impl Transaction {
4654
}
4755
}
4856

57+
/// Returns the unique identifier of the transaction.
4958
pub fn id(&self) -> TransactionId {
5059
self.id
5160
}
5261

62+
/// Returns the current state of the transaction.
5363
pub fn state(&self) -> TransactionState {
5464
self.state.load(Ordering::Acquire).into()
5565
}
5666

67+
/// Commits the transaction.
68+
///
69+
/// This makes all changes made by the transaction permanent.
5770
pub fn commit(&self) -> Result<()> {
5871
// Use compare-exchange to ensure atomic state transition
5972
match self.state.compare_exchange(
@@ -72,6 +85,9 @@ impl Transaction {
7285
}
7386
}
7487

88+
/// Aborts the transaction.
89+
///
90+
/// This rolls back all changes made by the transaction.
7591
pub fn abort(&self) -> Result<()> {
7692
// Use compare-exchange to ensure atomic state transition
7793
match self.state.compare_exchange(
@@ -91,6 +107,7 @@ impl Transaction {
91107
}
92108
}
93109

110+
/// Manages the lifecycle of transactions.
94111
pub struct TransactionManager {
95112
next_txn_id: AtomicU64,
96113
active_transactions: RwLock<HashMap<TransactionId, Arc<Transaction>>>,
@@ -104,6 +121,7 @@ impl TransactionManager {
104121
}
105122
}
106123

124+
/// Begins a new transaction.
107125
pub fn begin(&self) -> Arc<Transaction> {
108126
let txn_id = self.next_txn_id.fetch_add(1, Ordering::SeqCst);
109127
let txn = Arc::new(Transaction::new(txn_id));
@@ -117,6 +135,7 @@ impl TransactionManager {
117135
txn
118136
}
119137

138+
/// Commits a transaction.
120139
pub fn commit(&self, txn: &Transaction) -> Result<()> {
121140
// LOCK ORDERING:
122141
// 1. Commit transaction state (atomic operation - no lock)
@@ -129,6 +148,7 @@ impl TransactionManager {
129148
Ok(())
130149
}
131150

151+
/// Aborts a transaction.
132152
pub fn abort(&self, txn: &Transaction) -> Result<()> {
133153
// LOCK ORDERING: Same as commit - state first (atomic), then active_transactions
134154
txn.abort()?;
@@ -138,10 +158,12 @@ impl TransactionManager {
138158
Ok(())
139159
}
140160

161+
/// Retrieves an active transaction by ID.
141162
pub fn get_transaction(&self, txn_id: TransactionId) -> Option<Arc<Transaction>> {
142163
self.active_transactions.read().get(&txn_id).cloned()
143164
}
144165

166+
/// Returns the number of currently active transactions.
145167
pub fn active_count(&self) -> usize {
146168
self.active_transactions.read().len()
147169
}
@@ -166,6 +188,7 @@ impl TransactionManager {
166188

167189
use dashmap::DashMap;
168190

191+
/// Manages locks on database resources (e.g., tables).
169192
pub struct LockManager {
170193
// Per-table lock entries using lock-free DashMap
171194
// This eliminates the single global lock bottleneck
@@ -178,9 +201,12 @@ struct LockEntry {
178201
lock_type: LockType,
179202
}
180203

204+
/// Types of locks available.
181205
#[derive(Debug, Clone, Copy, PartialEq)]
182206
pub enum LockType {
207+
/// Shared lock (allows concurrent readers).
183208
Shared,
209+
/// Exclusive lock (single writer, no readers).
184210
Exclusive,
185211
}
186212

0 commit comments

Comments
 (0)