// benches/common/backends.rs use herodb::storage::Storage; use herodb::storage_sled::SledStorage; use herodb::storage_trait::StorageBackend; use std::sync::Arc; use tempfile::TempDir; /// Backend type identifier #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BackendType { Redb, Sled, } impl BackendType { pub fn name(&self) -> &'static str { match self { BackendType::Redb => "redb", BackendType::Sled => "sled", } } pub fn all() -> Vec { vec![BackendType::Redb, BackendType::Sled] } } /// Wrapper for benchmark backends with automatic cleanup pub struct BenchmarkBackend { pub storage: Arc, pub backend_type: BackendType, _temp_dir: TempDir, // Kept for automatic cleanup } impl BenchmarkBackend { /// Create a new redb backend for benchmarking pub fn new_redb() -> Result> { let temp_dir = TempDir::new()?; let db_path = temp_dir.path().join("bench.db"); let storage = Storage::new(db_path, false, None)?; Ok(Self { storage: Arc::new(storage), backend_type: BackendType::Redb, _temp_dir: temp_dir, }) } /// Create a new sled backend for benchmarking pub fn new_sled() -> Result> { let temp_dir = TempDir::new()?; let db_path = temp_dir.path().join("bench.sled"); let storage = SledStorage::new(db_path, false, None)?; Ok(Self { storage: Arc::new(storage), backend_type: BackendType::Sled, _temp_dir: temp_dir, }) } /// Create a backend of the specified type pub fn new(backend_type: BackendType) -> Result> { match backend_type { BackendType::Redb => Self::new_redb(), BackendType::Sled => Self::new_sled(), } } /// Get the backend name for display pub fn name(&self) -> &'static str { self.backend_type.name() } /// Pre-populate the backend with test data pub fn populate_strings(&self, data: &[(String, String)]) -> Result<(), Box> { for (key, value) in data { self.storage.set(key.clone(), value.clone())?; } Ok(()) } /// Pre-populate with hash data pub fn populate_hashes(&self, data: &[(String, Vec<(String, String)>)]) -> Result<(), Box> { for (key, fields) in data { self.storage.hset(key, fields.clone())?; } Ok(()) } /// Pre-populate with list data pub fn populate_lists(&self, data: &[(String, Vec)]) -> Result<(), Box> { for (key, elements) in data { self.storage.rpush(key, elements.clone())?; } Ok(()) } /// Clear all data from the backend pub fn clear(&self) -> Result<(), Box> { self.storage.flushdb()?; Ok(()) } /// Get the number of keys in the database pub fn dbsize(&self) -> Result> { Ok(self.storage.dbsize()?) } } /// Helper function to create and populate a backend for read benchmarks pub fn setup_populated_backend( backend_type: BackendType, num_keys: usize, value_size: usize, ) -> Result> { use super::DataGenerator; let backend = BenchmarkBackend::new(backend_type)?; let mut generator = DataGenerator::new(42); let data = generator.generate_string_pairs(num_keys, value_size); backend.populate_strings(&data)?; Ok(backend) } /// Helper function to create and populate a backend with hash data pub fn setup_populated_backend_hashes( backend_type: BackendType, num_hashes: usize, fields_per_hash: usize, value_size: usize, ) -> Result> { use super::DataGenerator; let backend = BenchmarkBackend::new(backend_type)?; let mut generator = DataGenerator::new(42); let data = generator.generate_hash_data(num_hashes, fields_per_hash, value_size); backend.populate_hashes(&data)?; Ok(backend) } /// Helper function to create and populate a backend with list data pub fn setup_populated_backend_lists( backend_type: BackendType, num_lists: usize, elements_per_list: usize, element_size: usize, ) -> Result> { use super::DataGenerator; let backend = BenchmarkBackend::new(backend_type)?; let mut generator = DataGenerator::new(42); let data = generator.generate_list_data(num_lists, elements_per_list, element_size); backend.populate_lists(&data)?; Ok(backend) } #[cfg(test)] mod tests { use super::*; #[test] fn test_backend_creation() { let redb = BenchmarkBackend::new_redb(); assert!(redb.is_ok()); let sled = BenchmarkBackend::new_sled(); assert!(sled.is_ok()); } #[test] fn test_backend_populate() { let backend = BenchmarkBackend::new_redb().unwrap(); let data = vec![ ("key1".to_string(), "value1".to_string()), ("key2".to_string(), "value2".to_string()), ]; backend.populate_strings(&data).unwrap(); assert_eq!(backend.dbsize().unwrap(), 2); } #[test] fn test_backend_clear() { let backend = BenchmarkBackend::new_redb().unwrap(); let data = vec![("key1".to_string(), "value1".to_string())]; backend.populate_strings(&data).unwrap(); assert_eq!(backend.dbsize().unwrap(), 1); backend.clear().unwrap(); assert_eq!(backend.dbsize().unwrap(), 0); } }