197 lines
5.8 KiB
Rust
197 lines
5.8 KiB
Rust
// 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<BackendType> {
|
|
vec![BackendType::Redb, BackendType::Sled]
|
|
}
|
|
}
|
|
|
|
/// Wrapper for benchmark backends with automatic cleanup
|
|
pub struct BenchmarkBackend {
|
|
pub storage: Arc<dyn StorageBackend>,
|
|
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<Self, Box<dyn std::error::Error>> {
|
|
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<Self, Box<dyn std::error::Error>> {
|
|
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<Self, Box<dyn std::error::Error>> {
|
|
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<dyn std::error::Error>> {
|
|
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<dyn std::error::Error>> {
|
|
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<String>)]) -> Result<(), Box<dyn std::error::Error>> {
|
|
for (key, elements) in data {
|
|
self.storage.rpush(key, elements.clone())?;
|
|
}
|
|
Ok(())
|
|
}
|
|
|
|
/// Clear all data from the backend
|
|
pub fn clear(&self) -> Result<(), Box<dyn std::error::Error>> {
|
|
self.storage.flushdb()?;
|
|
Ok(())
|
|
}
|
|
|
|
/// Get the number of keys in the database
|
|
pub fn dbsize(&self) -> Result<i64, Box<dyn std::error::Error>> {
|
|
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<BenchmarkBackend, Box<dyn std::error::Error>> {
|
|
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<BenchmarkBackend, Box<dyn std::error::Error>> {
|
|
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<BenchmarkBackend, Box<dyn std::error::Error>> {
|
|
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);
|
|
}
|
|
} |