use graph_d::transaction::{IsolationLevel, LockableResource, TransactionManager};
use graph_d::Result;
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::{Duration, Instant};
fn main() -> Result<()> {
println!("=== Concurrent Transaction Demo ===\n");
demo_basic_locking()?;
demo_concurrent_reads()?;
demo_deadlock_prevention()?;
demo_lock_statistics()?;
Ok(())
}
fn demo_basic_locking() -> Result<()> {
println!("=== Basic Locking Demo ===");
let tx_manager = TransactionManager::new(IsolationLevel::ReadCommitted);
let mut tx1 = tx_manager.begin_concurrent();
let mut tx2 = tx_manager.begin_concurrent();
let node_resource = LockableResource::Node(1);
println!("Transaction {}: Acquiring read lock on Node 1", tx1.id());
tx1.read_lock(node_resource)?;
println!("Transaction {}: Acquiring read lock on Node 1", tx2.id());
tx2.read_lock(node_resource)?;
println!("Both transactions successfully acquired read locks");
println!("Transaction {}: Acquiring write lock on Node 2", tx1.id());
tx1.write_lock(LockableResource::Node(2))?;
println!("Transaction {}: Committing", tx1.id());
tx1.commit()?;
println!("Transaction {}: Committing", tx2.id());
tx2.commit()?;
println!("Basic locking demo completed successfully!\n");
Ok(())
}
fn demo_concurrent_reads() -> Result<()> {
println!("=== Concurrent Reads Demo ===");
let tx_manager = Arc::new(TransactionManager::new(IsolationLevel::ReadCommitted));
let num_readers = 5;
let barrier = Arc::new(Barrier::new(num_readers));
let mut handles = Vec::new();
for i in 0..num_readers {
let tx_manager = Arc::clone(&tx_manager);
let barrier = Arc::clone(&barrier);
let handle = thread::spawn(move || -> Result<()> {
let mut tx = tx_manager.begin_concurrent();
let node_resource = LockableResource::Node(100);
barrier.wait();
let start = Instant::now();
tx.read_lock(node_resource)?;
println!("Reader {}: Acquired read lock in {:?}", i, start.elapsed());
thread::sleep(Duration::from_millis(50));
tx.commit()?;
println!("Reader {i}: Released lock");
Ok(())
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap()?;
}
println!("All {num_readers} readers completed successfully!\n");
Ok(())
}
fn demo_deadlock_prevention() -> Result<()> {
println!("=== Deadlock Prevention Demo ===");
let tx_manager = Arc::new(TransactionManager::new(IsolationLevel::ReadCommitted));
let barrier = Arc::new(Barrier::new(2));
let tx_manager1 = Arc::clone(&tx_manager);
let tx_manager2 = Arc::clone(&tx_manager);
let barrier1 = Arc::clone(&barrier);
let barrier2 = Arc::clone(&barrier);
let handle1 = thread::spawn(move || -> Result<()> {
let mut tx = tx_manager1.begin_concurrent();
println!("Transaction {}: Acquiring write lock on Node 1", tx.id());
tx.write_lock(LockableResource::Node(1))?;
barrier1.wait();
thread::sleep(Duration::from_millis(100));
println!(
"Transaction {}: Trying to acquire write lock on Node 2",
tx.id()
);
match tx.write_lock(LockableResource::Node(2)) {
Ok(_) => {
println!("Transaction {}: Successfully acquired both locks", tx.id());
tx.commit()?;
}
Err(e) => {
println!(
"Transaction {}: Failed to acquire second lock: {}",
tx.id(),
e
);
tx.rollback()?;
return Err(e);
}
}
Ok(())
});
let handle2 = thread::spawn(move || -> Result<()> {
let mut tx = tx_manager2.begin_concurrent();
println!("Transaction {}: Acquiring write lock on Node 2", tx.id());
tx.write_lock(LockableResource::Node(2))?;
barrier2.wait();
thread::sleep(Duration::from_millis(100));
println!(
"Transaction {}: Trying to acquire write lock on Node 1",
tx.id()
);
match tx.write_lock(LockableResource::Node(1)) {
Ok(_) => {
println!("Transaction {}: Successfully acquired both locks", tx.id());
tx.commit()?;
}
Err(e) => {
println!(
"Transaction {}: Failed to acquire second lock: {}",
tx.id(),
e
);
tx.rollback()?;
return Err(e);
}
}
Ok(())
});
let result1 = handle1.join().unwrap();
let result2 = handle2.join().unwrap();
match (result1, result2) {
(Ok(_), Ok(_)) => println!("Both transactions completed successfully (no deadlock)"),
(Ok(_), Err(_)) => println!("Transaction 1 succeeded, Transaction 2 was aborted"),
(Err(_), Ok(_)) => println!("Transaction 2 succeeded, Transaction 1 was aborted"),
(Err(e1), Err(e2)) => {
println!("Both transactions failed - this might indicate a deadlock:");
println!(" Transaction 1 error: {e1}");
println!(" Transaction 2 error: {e2}");
}
}
println!("Deadlock prevention demo completed!\n");
Ok(())
}
fn demo_lock_statistics() -> Result<()> {
println!("=== Lock Statistics Demo ===");
let tx_manager = TransactionManager::new(IsolationLevel::ReadCommitted);
let stats = tx_manager.lock_statistics();
println!("Initial lock statistics:");
println!(" Active locks: {}", stats.total_active_locks);
println!(" Waiting requests: {}", stats.waiting_requests);
println!(" Locked resources: {}", stats.locked_resources);
let mut tx1 = tx_manager.begin_concurrent();
let mut tx2 = tx_manager.begin_concurrent();
let mut tx3 = tx_manager.begin_concurrent();
tx1.read_lock(LockableResource::Node(1))?;
tx1.write_lock(LockableResource::Node(2))?;
tx2.read_lock(LockableResource::Node(1))?; tx3.read_lock(LockableResource::Node(3))?;
let stats = tx_manager.lock_statistics();
println!("\nAfter acquiring locks:");
println!(" Active locks: {}", stats.total_active_locks);
println!(" Waiting requests: {}", stats.waiting_requests);
println!(" Locked resources: {}", stats.locked_resources);
tx1.commit()?;
tx2.commit()?;
tx3.commit()?;
let stats = tx_manager.lock_statistics();
println!("\nAfter committing all transactions:");
println!(" Active locks: {}", stats.total_active_locks);
println!(" Waiting requests: {}", stats.waiting_requests);
println!(" Locked resources: {}", stats.locked_resources);
println!("Lock statistics demo completed!\n");
Ok(())
}
#[allow(dead_code)]
fn demo_transaction_isolation() -> Result<()> {
println!("=== Transaction Isolation Demo ===");
let isolation_levels = vec![
IsolationLevel::ReadUncommitted,
IsolationLevel::ReadCommitted,
IsolationLevel::RepeatableRead,
IsolationLevel::Serializable,
];
for isolation_level in isolation_levels {
println!("Testing isolation level: {isolation_level:?}");
let tx_manager = TransactionManager::new(isolation_level);
let tx = tx_manager.begin_concurrent_with_isolation(isolation_level);
println!(
" Created transaction {} with isolation {:?}",
tx.id(),
tx.transaction.isolation_level()
);
}
println!("Transaction isolation demo completed!\n");
Ok(())
}