232 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			232 lines
		
	
	
		
			6.8 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
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(())
 | 
						|
}
 |