reifydb-transaction 0.9.3

Transaction management and concurrency control for ReifyDB
Documentation
// SPDX-License-Identifier: Apache-2.0
// Copyright (c) 2026 ReifyDB

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!");
}