use std::sync::Arc;
use std::thread;
use std::time::Duration;
use tensorlogic_adapters::{DomainInfo, LockWithTimeout, LockedSymbolTable};
fn main() -> anyhow::Result<()> {
println!("=== TensorLogic Adapters: Concurrent Schema Access ===\n");
example_basic_locking()?;
example_concurrent_readers()?;
example_reader_writer_pattern()?;
example_transactions()?;
example_lock_timeouts()?;
example_lock_statistics()?;
Ok(())
}
fn example_basic_locking() -> anyhow::Result<()> {
println!("--- Example 1: Basic Read/Write Locking ---");
let table = LockedSymbolTable::new();
{
println!("Acquiring write lock...");
let mut guard = table.write();
guard.add_domain(DomainInfo::new("User", 1000))?;
guard.add_domain(DomainInfo::new("Role", 10))?;
println!("Added 2 domains");
}
{
println!("Acquiring read lock...");
let guard = table.read();
println!("Schema has {} domains", guard.domains.len());
for (name, domain) in &guard.domains {
println!(" - {}: cardinality {}", name, domain.cardinality);
}
}
println!();
Ok(())
}
fn example_concurrent_readers() -> anyhow::Result<()> {
println!("--- Example 2: Multiple Concurrent Readers ---");
let table = Arc::new(LockedSymbolTable::new());
{
let mut guard = table.write();
for i in 0..5 {
guard.add_domain(DomainInfo::new(format!("Domain{}", i), 100))?;
}
}
println!("Spawning 5 concurrent readers...");
let mut handles = vec![];
for reader_id in 0..5 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
let guard = table_clone.read();
println!(
" Reader {}: Read {} domains",
reader_id,
guard.domains.len()
);
thread::sleep(Duration::from_millis(50));
println!(" Reader {}: Done", reader_id);
}));
}
for handle in handles {
handle.join().expect("unwrap");
}
println!("All readers completed successfully\n");
Ok(())
}
fn example_reader_writer_pattern() -> anyhow::Result<()> {
println!("--- Example 3: Reader-Writer Pattern ---");
let table = Arc::new(LockedSymbolTable::new());
{
let mut guard = table.write();
guard.add_domain(DomainInfo::new("User", 1000))?;
}
let mut handles = vec![];
for reader_id in 0..3 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
for iteration in 0..3 {
let guard = table_clone.read();
println!(
" Reader {} (iteration {}): {} domains",
reader_id,
iteration,
guard.domains.len()
);
thread::sleep(Duration::from_millis(20));
}
}));
}
for writer_id in 0..2 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
for iteration in 0..2 {
let mut guard = table_clone.write();
let domain_name = format!("WriterDomain_{}_{}", writer_id, iteration);
guard
.add_domain(DomainInfo::new(&domain_name, 100))
.expect("unwrap");
println!(
" Writer {} (iteration {}): Added {}",
writer_id, iteration, domain_name
);
thread::sleep(Duration::from_millis(30));
}
}));
}
for handle in handles {
handle.join().expect("unwrap");
}
{
let guard = table.read();
println!("Final schema has {} domains", guard.domains.len());
}
println!();
Ok(())
}
fn example_transactions() -> anyhow::Result<()> {
println!("--- Example 4: Transactions with Commit/Rollback ---");
let table = LockedSymbolTable::new();
println!("Transaction 1: Adding domains with commit");
{
let mut txn = table.begin_transaction();
txn.execute(|t| {
t.add_domain(DomainInfo::new("User", 1000)).expect("unwrap");
t.add_domain(DomainInfo::new("Post", 5000)).expect("unwrap");
Ok(())
})?;
txn.commit();
println!(" ✓ Transaction committed");
}
{
let guard = table.read();
println!(" Schema has {} domains", guard.domains.len());
}
println!("\nTransaction 2: Attempting to add domains then rollback");
{
let mut txn = table.begin_transaction();
txn.execute(|t| {
t.add_domain(DomainInfo::new("Comment", 10000))
.expect("unwrap");
t.add_domain(DomainInfo::new("Tag", 500)).expect("unwrap");
Ok(())
})?;
println!(" Added 2 domains in transaction");
txn.rollback();
println!(" ✗ Transaction rolled back");
}
{
let guard = table.read();
println!(" Schema still has {} domains", guard.domains.len());
assert!(!guard.domains.contains_key("Comment"));
}
println!("\nTransaction 3: Auto-rollback on drop");
{
let mut txn = table.begin_transaction();
txn.execute(|t| {
t.add_domain(DomainInfo::new("AutoRollback", 100))
.expect("unwrap");
Ok(())
})?;
println!(" Added domain but not committing");
}
{
let guard = table.read();
println!(" Schema still has {} domains", guard.domains.len());
assert!(!guard.domains.contains_key("AutoRollback"));
}
println!();
Ok(())
}
fn example_lock_timeouts() -> anyhow::Result<()> {
println!("--- Example 5: Lock Timeout Handling ---");
let table = Arc::new(LockedSymbolTable::new());
println!("Thread 1: Acquiring write lock...");
let table_clone = Arc::clone(&table);
let handle = thread::spawn(move || {
let _write_guard = table_clone.write();
println!(" Thread 1: Got write lock, holding for 100ms");
thread::sleep(Duration::from_millis(100));
println!(" Thread 1: Releasing write lock");
});
thread::sleep(Duration::from_millis(10));
println!("Thread 2: Attempting to acquire write lock with 50ms timeout...");
let result = table.write_timeout(Duration::from_millis(50));
if result.is_none() {
println!(" ✗ Thread 2: Timeout - could not acquire lock");
} else {
println!(" ✓ Thread 2: Got lock (unexpected!)");
}
handle.join().expect("unwrap");
println!("Thread 2: Attempting to acquire write lock with 200ms timeout...");
let result = table.write_timeout(Duration::from_millis(200));
if result.is_some() {
println!(" ✓ Thread 2: Successfully acquired lock after Thread 1 released");
}
println!();
Ok(())
}
fn example_lock_statistics() -> anyhow::Result<()> {
println!("--- Example 6: Lock Statistics Monitoring ---");
let table = Arc::new(LockedSymbolTable::new());
{
let mut guard = table.write();
guard.add_domain(DomainInfo::new("User", 1000))?;
}
println!("Performing concurrent operations...");
let mut handles = vec![];
for i in 0..5 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
for _ in 0..3 {
let _guard = table_clone.read();
thread::sleep(Duration::from_millis(10 * i));
}
}));
}
for i in 0..3 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
for j in 0..2 {
let mut guard = table_clone.write();
guard
.add_domain(DomainInfo::new(format!("Domain_{}_{}", i, j), 100))
.expect("unwrap");
thread::sleep(Duration::from_millis(15));
}
}));
}
for _ in 0..3 {
let table_clone = Arc::clone(&table);
handles.push(thread::spawn(move || {
for _ in 0..5 {
let _ = table_clone.try_read();
thread::sleep(Duration::from_millis(5));
}
}));
}
for handle in handles {
handle.join().expect("unwrap");
}
let stats = table.stats();
println!("\n=== Lock Statistics ===");
println!("Read locks acquired: {}", stats.read_locks);
println!("Write locks acquired: {}", stats.write_locks);
println!("Read contentions: {}", stats.read_contentions);
println!("Write contentions: {}", stats.write_contentions);
println!("Average read wait: {:.2}ms", stats.avg_read_wait_ms());
println!("Average write wait: {:.2}ms", stats.avg_write_wait_ms());
println!(
"Read contention rate: {:.2}%",
stats.read_contention_rate() * 100.0
);
println!(
"Write contention rate: {:.2}%",
stats.write_contention_rate() * 100.0
);
println!("Transactions started: {}", stats.transactions_started);
println!("Transactions committed: {}", stats.transactions_committed);
println!(
"Transactions rolled back: {}",
stats.transactions_rolled_back
);
println!(
"Transaction commit rate: {:.2}%",
stats.commit_rate() * 100.0
);
println!("\nResetting statistics...");
table.reset_stats();
let stats_after_reset = table.stats();
println!("Read locks after reset: {}", stats_after_reset.read_locks);
println!();
Ok(())
}