use ourdb::{OurDB, OurDBConfig, OurDBSetArgs}; use std::path::PathBuf; use std::time::Instant; fn main() -> Result<(), ourdb::Error> { // Create a temporary directory for the database let db_path = std::env::temp_dir().join("ourdb_advanced_example"); std::fs::create_dir_all(&db_path)?; println!("Creating database at: {}", db_path.display()); // Demonstrate key-value mode (non-incremental) key_value_mode_example(&db_path)?; // Demonstrate incremental mode incremental_mode_example(&db_path)?; // Demonstrate performance benchmarking performance_benchmark(&db_path)?; // Clean up (optional) if std::env::var("KEEP_DB").is_err() { std::fs::remove_dir_all(&db_path)?; println!("Cleaned up database directory"); } else { println!("Database kept at: {}", db_path.display()); } Ok(()) } fn key_value_mode_example(base_path: &PathBuf) -> Result<(), ourdb::Error> { println!("\n=== Key-Value Mode Example ==="); let db_path = base_path.join("key_value"); std::fs::create_dir_all(&db_path)?; // Create a new database with key-value mode (non-incremental) let config = OurDBConfig { path: db_path, incremental_mode: false, file_size: Some(1024 * 1024), // 1MB for testing keysize: Some(2), // Small key size for demonstration reset: None, // Don't reset existing database }; let mut db = OurDB::new(config)?; // In key-value mode, we must provide IDs explicitly let custom_ids = [100, 200, 300, 400, 500]; // Store data with custom IDs for (i, &id) in custom_ids.iter().enumerate() { let data = format!("Record with custom ID {}", id); db.set(OurDBSetArgs { id: Some(id), data: data.as_bytes(), })?; println!("Stored record {} with custom ID: {}", i + 1, id); } // Retrieve data by custom IDs for &id in &custom_ids { let retrieved = db.get(id)?; println!( "Retrieved ID {}: {}", id, String::from_utf8_lossy(&retrieved) ); } // Update and track history let id_to_update = custom_ids[2]; // ID 300 for i in 1..=3 { let updated_data = format!("Updated record {} (version {})", id_to_update, i); db.set(OurDBSetArgs { id: Some(id_to_update), data: updated_data.as_bytes(), })?; println!("Updated ID {} (version {})", id_to_update, i); } // Get history for the updated record let history = db.get_history(id_to_update, 5)?; println!("History for ID {} (most recent first):", id_to_update); for (i, entry) in history.iter().enumerate() { println!(" Version {}: {}", i, String::from_utf8_lossy(entry)); } db.close()?; println!("Key-value mode example completed"); Ok(()) } fn incremental_mode_example(base_path: &PathBuf) -> Result<(), ourdb::Error> { println!("\n=== Incremental Mode Example ==="); let db_path = base_path.join("incremental"); std::fs::create_dir_all(&db_path)?; // Create a new database with incremental mode let config = OurDBConfig { path: db_path, incremental_mode: true, file_size: Some(1024 * 1024), // 1MB for testing keysize: Some(3), // 3-byte keys reset: None, // Don't reset existing database }; let mut db = OurDB::new(config)?; // In incremental mode, IDs are auto-generated let mut assigned_ids = Vec::new(); // Store multiple records and collect assigned IDs for i in 1..=5 { let data = format!("Auto-increment record {}", i); let id = db.set(OurDBSetArgs { id: None, data: data.as_bytes(), })?; assigned_ids.push(id); println!("Stored record {} with auto-assigned ID: {}", i, id); } // Check next ID let next_id = db.get_next_id()?; println!("Next ID to be assigned: {}", next_id); // Retrieve all records for &id in &assigned_ids { let retrieved = db.get(id)?; println!( "Retrieved ID {}: {}", id, String::from_utf8_lossy(&retrieved) ); } db.close()?; println!("Incremental mode example completed"); Ok(()) } fn performance_benchmark(base_path: &PathBuf) -> Result<(), ourdb::Error> { println!("\n=== Performance Benchmark ==="); let db_path = base_path.join("benchmark"); std::fs::create_dir_all(&db_path)?; // Create a new database let config = OurDBConfig { path: db_path, incremental_mode: true, file_size: Some(1024 * 1024), // 10MB keysize: Some(4), // 4-byte keys reset: None, // Don't reset existing database }; let mut db = OurDB::new(config)?; // Number of operations for the benchmark let num_operations = 1000; let data_size = 100; // bytes per record // Prepare test data let test_data = vec![b'A'; data_size]; // Benchmark write operations println!("Benchmarking {} write operations...", num_operations); let start = Instant::now(); let mut ids = Vec::with_capacity(num_operations); for _ in 0..num_operations { let id = db.set(OurDBSetArgs { id: None, data: &test_data, })?; ids.push(id); } let write_duration = start.elapsed(); let writes_per_second = num_operations as f64 / write_duration.as_secs_f64(); println!( "Write performance: {:.2} ops/sec ({:.2} ms/op)", writes_per_second, write_duration.as_secs_f64() * 1000.0 / num_operations as f64 ); // Benchmark read operations println!("Benchmarking {} read operations...", num_operations); let start = Instant::now(); for &id in &ids { let _ = db.get(id)?; } let read_duration = start.elapsed(); let reads_per_second = num_operations as f64 / read_duration.as_secs_f64(); println!( "Read performance: {:.2} ops/sec ({:.2} ms/op)", reads_per_second, read_duration.as_secs_f64() * 1000.0 / num_operations as f64 ); // Benchmark update operations println!("Benchmarking {} update operations...", num_operations); let start = Instant::now(); for &id in &ids { db.set(OurDBSetArgs { id: Some(id), data: &test_data, })?; } let update_duration = start.elapsed(); let updates_per_second = num_operations as f64 / update_duration.as_secs_f64(); println!( "Update performance: {:.2} ops/sec ({:.2} ms/op)", updates_per_second, update_duration.as_secs_f64() * 1000.0 / num_operations as f64 ); db.close()?; println!("Performance benchmark completed"); Ok(()) }