use std::sync::Arc;
use std::thread;
use tiny_counter::{EventStore, TimeUnit};
fn main() {
println!("=== Concurrent Access Examples ===\n");
println!("1. Recording from multiple threads:");
let store = Arc::new(EventStore::new());
let mut handles = vec![];
for thread_id in 0..5 {
let store = Arc::clone(&store);
let handle = thread::spawn(move || {
for _ in 0..100 {
store.record("concurrent_event");
}
println!(" Thread {} recorded 100 events", thread_id);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let total = store
.query("concurrent_event")
.last_days(1)
.sum()
.unwrap_or(0);
println!(" Total events recorded: {} (expected 500)\n", total);
println!("2. Querying from multiple threads:");
let store = Arc::new(EventStore::new());
store.record_count("shared_data", 1000);
let mut handles = vec![];
for thread_id in 0..3 {
let store = Arc::clone(&store);
let handle = thread::spawn(move || {
let count = store.query("shared_data").last_days(7).sum().unwrap_or(0);
println!(" Thread {} read: {} events", thread_id, count);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
println!("\n3. Race condition prevention with reservations:");
let store = Arc::new(EventStore::new());
let mut handles = vec![];
for thread_id in 0..20 {
let store = Arc::clone(&store);
let handle = thread::spawn(move || {
let result = store
.limit()
.at_most("limited_api", 10, TimeUnit::Hours)
.reserve("limited_api");
match result {
Ok(reservation) => {
reservation.commit();
(thread_id, true)
}
Err(_) => (thread_id, false),
}
});
handles.push(handle);
}
let mut successes = 0;
let mut failures = 0;
for handle in handles {
let (thread_id, success) = handle.join().unwrap();
if success {
successes += 1;
println!(" Thread {}: ✓ Reserved slot", thread_id);
} else {
failures += 1;
}
}
println!(" Total: {} succeeded, {} failed", successes, failures);
println!(" (Expected: exactly 10 succeeded, 10 failed)\n");
println!("4. Producer-consumer pattern:");
let store = Arc::new(EventStore::new());
let producer_store = Arc::clone(&store);
let producer = thread::spawn(move || {
for i in 0..50 {
producer_store.record("message");
if (i + 1) % 10 == 0 {
println!(" Producer: Sent {} messages", i + 1);
}
thread::sleep(std::time::Duration::from_millis(10));
}
});
let consumer_store = Arc::clone(&store);
let consumer = thread::spawn(move || {
thread::sleep(std::time::Duration::from_millis(100));
let mut last_count = 0;
for _ in 0..5 {
let count = consumer_store
.query("message")
.last_days(1)
.sum()
.unwrap_or(0);
let new_messages = count - last_count;
if new_messages > 0 {
println!(
" Consumer: Processed {} messages (total: {})",
new_messages, count
);
}
last_count = count;
thread::sleep(std::time::Duration::from_millis(100));
}
});
producer.join().unwrap();
consumer.join().unwrap();
println!("\n5. Concurrent updates to different events:");
let store = Arc::new(EventStore::new());
let mut handles = vec![];
let events = ["event_a", "event_b", "event_c", "event_d"];
for (thread_id, event_name) in events.iter().enumerate() {
let store = Arc::clone(&store);
let event_name = event_name.to_string();
let handle = thread::spawn(move || {
for _ in 0..25 {
store.record(&event_name);
}
println!(" Thread {} recorded 25 {} events", thread_id, event_name);
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let total = store
.query_many(&["event_a", "event_b", "event_c", "event_d"])
.last_days(1)
.sum()
.unwrap_or(0);
println!(
" Total events across all types: {} (expected 100)\n",
total
);
println!("6. Stress test (100 threads, 10 events each):");
let store = Arc::new(EventStore::new());
let mut handles = vec![];
for _ in 0..100 {
let store = Arc::clone(&store);
let handle = thread::spawn(move || {
for _ in 0..10 {
store.record("stress_test");
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let final_count = store.query("stress_test").last_days(1).sum().unwrap_or(0);
println!(" Final count: {} (expected 1000)", final_count);
if final_count == 1000 {
println!(" ✓ No events lost to race conditions");
} else {
println!(" ✗ Lost {} events", 1000 - final_count);
}
println!("\n✓ Concurrent access complete!");
}