use std::{sync::Arc, thread::spawn, time::Instant};
use reifydb_codec::{key::serializer::KeySerializer, row::bytes::EncodedBytes};
use reifydb_core::{interface::catalog::id::QueueId, key::queue::QueueDeduplicationKey};
use reifydb_transaction::multi::transaction::MultiTransaction;
use reifydb_value::util::cowvec::CowVec;
trait KeyBytes {
fn key_bytes(&self) -> Vec<u8>;
}
impl KeyBytes for i32 {
fn key_bytes(&self) -> Vec<u8> {
let mut ser = KeySerializer::new();
ser.extend_i32(*self);
ser.finish().as_slice().to_vec()
}
}
impl KeyBytes for String {
fn key_bytes(&self) -> Vec<u8> {
let mut ser = KeySerializer::new();
ser.extend_str(self);
ser.finish().as_slice().to_vec()
}
}
macro_rules! as_key {
($key:expr) => {{ QueueDeduplicationKey::new(QueueId(1), $key.key_bytes().iter().map(|b| !b).collect::<Vec<u8>>()) }};
}
macro_rules! as_values {
($val:expr) => {{ EncodedBytes(CowVec::new($val.key_bytes())) }};
}
pub fn oracle_performance_benchmark() {
println!("=== Oracle Performance Benchmark ===\n");
let test_sizes = vec![1000, 5000, 10000, 25000];
for &num_txns in &test_sizes {
println!("Testing with {} transactions...", num_txns);
let engine = MultiTransaction::testing();
let start = Instant::now();
for i in 0..num_txns {
let mut tx = engine.begin_command().unwrap();
let key = as_key!(format!("key_{}", i));
let value = as_values!(format!("value_{}", i));
tx.set(&key, value).unwrap();
tx.commit(vec![]).unwrap();
}
let duration = start.elapsed();
let tps = num_txns as f64 / duration.as_secs_f64();
println!(" {} transactions in {:?}", num_txns, duration);
println!(" {:.0} TPS (transactions per second)", tps);
println!(" {:.2} μs per transaction\n", duration.as_micros() as f64 / num_txns as f64);
}
}
pub fn concurrent_oracle_benchmark() {
println!("=== Concurrent Oracle Performance Benchmark ===\n");
let test_configs = vec![(10, 1000), (50, 500), (100, 250), (1000, 50)];
for &(num_threads, txns_per_thread) in &test_configs {
let total_txns = num_threads * txns_per_thread;
println!(
"Testing {} threads × {} transactions = {} total...",
num_threads, txns_per_thread, total_txns
);
let engine = Arc::new(MultiTransaction::testing());
let start = Instant::now();
let mut handles = vec![];
for thread_id in 0..num_threads {
let engine_clone = engine.clone();
let handle = spawn(move || {
let base_key = thread_id * txns_per_thread;
for i in 0..txns_per_thread {
let mut tx = engine_clone.begin_command().unwrap();
let key = as_key!(base_key + i);
let value = as_values!(i);
tx.set(&key, value).unwrap();
tx.commit(vec![]).unwrap();
}
});
handles.push(handle);
}
for handle in handles {
handle.join().expect("Task panicked");
}
let duration = start.elapsed();
let tps = total_txns as f64 / duration.as_secs_f64();
println!(" {} total transactions in {:?}", total_txns, duration);
println!(" {:.0} TPS (transactions per second)", tps);
println!(" {:.2} μs per transaction\n", duration.as_micros() as f64 / total_txns as f64);
}
}
pub fn conflict_detection_benchmark() {
println!("=== Conflict Detection Performance Benchmark ===\n");
let engine = MultiTransaction::testing();
for i in 0..1000 {
let mut tx = engine.begin_command().unwrap();
let key = as_key!(format!("shared_key_{}", i % 100));
let value = as_values!(i);
tx.set(&key, value).unwrap();
tx.commit(vec![]).unwrap();
}
println!("Pre-populated with 1000 transactions across 100 keys");
let num_conflict_txns = 10000;
let start = Instant::now();
let mut conflicts = 0;
for i in 0..num_conflict_txns {
let mut tx = engine.begin_command().unwrap();
let key = as_key!(format!("shared_key_{}", i % 100));
let value = as_values!(i + 1000);
tx.set(&key, value).unwrap();
match tx.commit(vec![]) {
Ok(_) => {}
Err(e) if e.code == "TXN_001" => {
conflicts += 1;
}
Err(e) => panic!("Unexpected error: {:?}", e),
};
}
let duration = start.elapsed();
let tps = num_conflict_txns as f64 / duration.as_secs_f64();
println!(" {} transactions with potential conflicts in {:?}", num_conflict_txns, duration);
println!(
" {} actual conflicts detected ({:.1}%)",
conflicts,
conflicts as f64 / num_conflict_txns as f64 * 100.0
);
println!(" {:.0} TPS (transactions per second)", tps);
println!(" {:.2} μs per transaction", duration.as_micros() as f64 / num_conflict_txns as f64);
}
fn main() {
println!("🚀 ReifyDB Oracle Performance Benchmarks\n");
oracle_performance_benchmark();
println!("\n{}\n", "=".repeat(60));
concurrent_oracle_benchmark();
println!("\n{}\n", "=".repeat(60));
conflict_detection_benchmark();
println!("\n✅ All benchmarks completed!");
}