use feoxdb::FeoxStore;
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Instant;
fn main() -> feoxdb::Result<()> {
println!("=== Compare-and-Swap Examples ===\n");
configuration_example()?;
state_machine_example()?;
optimistic_update_example()?;
Ok(())
}
fn configuration_example() -> feoxdb::Result<()> {
println!("1. Configuration Versioning");
println!(" Using CAS to safely update configuration:");
let store = FeoxStore::new(None)?;
let config_v1 = r#"{"timeout": 30, "retries": 3}"#;
store.insert(b"app_config", config_v1.as_bytes())?;
println!(" Initial config: {}", config_v1);
let config_v2 = r#"{"timeout": 60, "retries": 5}"#;
if store.compare_and_swap(b"app_config", config_v1.as_bytes(), config_v2.as_bytes())? {
println!(" ✓ Config updated to: {}", config_v2);
} else {
println!(" ✗ Config was modified by another process");
}
if store.compare_and_swap(b"app_config", config_v1.as_bytes(), config_v2.as_bytes())? {
println!(" ✓ Config updated again");
} else {
println!(" ✗ Update failed - config already changed");
}
println!();
Ok(())
}
fn state_machine_example() -> feoxdb::Result<()> {
println!("2. State Machine Transitions");
println!(" Using CAS to ensure valid state transitions:");
let store = Arc::new(FeoxStore::new(None)?);
store.insert(b"order:1234:status", b"PENDING")?;
let num_workers = 3;
let barrier = Arc::new(Barrier::new(num_workers));
let mut handles = vec![];
let start = Instant::now();
for worker_id in 0..num_workers {
let store_clone = Arc::clone(&store);
let barrier_clone = Arc::clone(&barrier);
handles.push(thread::spawn(move || -> feoxdb::Result<String> {
barrier_clone.wait();
if store_clone.compare_and_swap(b"order:1234:status", b"PENDING", b"PROCESSING")? {
println!(" Worker {} claimed the order", worker_id);
std::thread::sleep(std::time::Duration::from_millis(50));
store_clone.compare_and_swap(b"order:1234:status", b"PROCESSING", b"COMPLETED")?;
return Ok(format!("Worker {} completed the order", worker_id));
}
Ok(format!("Worker {} couldn't claim the order", worker_id))
}));
}
let results: Vec<String> = handles
.into_iter()
.map(|h| h.join().unwrap().unwrap())
.collect();
let elapsed = start.elapsed();
for result in results {
println!(" {}", result);
}
let final_status = store.get(b"order:1234:status")?;
println!(
" Final status: {}",
String::from_utf8_lossy(&final_status)
);
println!(" Time: {:.2}ms", elapsed.as_secs_f64() * 1000.0);
println!();
assert_eq!(final_status, b"COMPLETED");
Ok(())
}
fn optimistic_update_example() -> feoxdb::Result<()> {
println!("3. Optimistic Locking Pattern");
println!(" Updating user balance with retry logic:");
let store = FeoxStore::new(None)?;
store.insert(b"user:1234:balance", b"1000")?;
let deduct_balance = |amount: i32| -> feoxdb::Result<bool> {
const MAX_RETRIES: u32 = 3;
for attempt in 1..=MAX_RETRIES {
let current = store.get(b"user:1234:balance")?;
let balance: i32 = String::from_utf8_lossy(¤t).parse().unwrap();
if balance < amount {
println!(
" ✗ Insufficient funds (balance: {}, required: {})",
balance, amount
);
return Ok(false);
}
let new_balance = (balance - amount).to_string();
if store.compare_and_swap(b"user:1234:balance", ¤t, new_balance.as_bytes())? {
println!(
" ✓ Deducted {} (attempt {}), new balance: {}",
amount, attempt, new_balance
);
return Ok(true);
}
if attempt < MAX_RETRIES {
println!(" ↻ Retry {} - balance changed during read", attempt);
}
}
println!(" ✗ Failed after {} retries", MAX_RETRIES);
Ok(false)
};
deduct_balance(200)?;
deduct_balance(300)?;
deduct_balance(600)?;
println!();
Ok(())
}