use sieve_cache::{ShardedSieveCache, SyncSieveCache};
use std::sync::{Arc, Barrier};
use std::thread;
use std::time::Duration;
const NUM_THREADS: usize = 8;
const OPERATIONS_PER_THREAD: usize = 5000;
const CACHE_CAPACITY: usize = 1000;
const SHARDED_CACHE_SHARDS: usize = 16;
#[test]
fn test_sync_cache_concurrent_operations() {
let cache = Arc::new(SyncSieveCache::new(CACHE_CAPACITY).unwrap());
let barrier = Arc::new(Barrier::new(NUM_THREADS));
for i in 0..100 {
cache.insert(format!("init_key{}", i), i);
}
let mut handles = Vec::with_capacity(NUM_THREADS);
for thread_id in 0..NUM_THREADS {
let cache_clone = Arc::clone(&cache);
let barrier_clone = Arc::clone(&barrier);
let handle = thread::spawn(move || {
barrier_clone.wait();
for i in 0..OPERATIONS_PER_THREAD {
let op = i % 5;
let key = format!("key{}_{}", thread_id, i % 200);
match op {
0 => {
cache_clone.insert(key, i);
}
1 => {
let _ = cache_clone.get(&key);
}
2 => {
let _ = cache_clone.remove(&key);
}
3 => {
cache_clone.get_mut(&key, |value| {
*value += 1;
});
}
4 => {
if i % 1000 == 0 {
match i % 3 {
0 => {
cache_clone.for_each_value(|value| {
*value += 1;
});
}
1 => {
cache_clone.for_each_entry(|(key, value)| {
if key.contains("_50") {
*value *= 2;
}
});
}
2 => {
cache_clone.retain_batch(|key, _| {
!key.contains(&format!("_{}", thread_id))
});
}
_ => unreachable!(),
}
}
}
_ => unreachable!(),
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let len = cache.len();
println!("SyncSieveCache final size: {}", len);
cache.insert("final_key".to_string(), 999);
assert_eq!(cache.get(&"final_key".to_string()), Some(999));
}
#[test]
fn test_sharded_cache_concurrent_operations() {
let cache =
Arc::new(ShardedSieveCache::with_shards(CACHE_CAPACITY, SHARDED_CACHE_SHARDS).unwrap());
let barrier = Arc::new(Barrier::new(NUM_THREADS));
for i in 0..100 {
cache.insert(format!("init_key{}", i), i);
}
let mut handles = Vec::with_capacity(NUM_THREADS);
for thread_id in 0..NUM_THREADS {
let cache_clone = Arc::clone(&cache);
let barrier_clone = Arc::clone(&barrier);
let handle = thread::spawn(move || {
barrier_clone.wait();
for i in 0..OPERATIONS_PER_THREAD {
let op = i % 5;
let key = format!("key{}_{}", thread_id, i % 200);
match op {
0 => {
cache_clone.insert(key, i);
}
1 => {
let _ = cache_clone.get(&key);
}
2 => {
let _ = cache_clone.remove(&key);
}
3 => {
cache_clone.get_mut(&key, |value| {
*value += 1;
});
}
4 => {
if i % 1000 == 0 {
match i % 3 {
0 => {
cache_clone.for_each_value(|value| {
*value += 1;
});
}
1 => {
cache_clone.for_each_entry(|(key, value)| {
if key.contains("_50") {
*value *= 2;
}
});
}
2 => {
cache_clone
.retain(|key, _| !key.contains(&format!("_{}", thread_id)));
}
_ => unreachable!(),
}
}
}
_ => unreachable!(),
}
}
});
handles.push(handle);
}
for handle in handles {
handle.join().unwrap();
}
let len = cache.len();
println!("ShardedSieveCache final size: {}", len);
cache.insert("final_key".to_string(), 999);
assert_eq!(cache.get(&"final_key".to_string()), Some(999));
}
#[test]
fn test_retain_race_conditions() {
let cache = Arc::new(SyncSieveCache::new(CACHE_CAPACITY).unwrap());
for i in 0..500 {
cache.insert(format!("key{}", i), i);
}
let cache_clone1 = Arc::clone(&cache);
let modifier = thread::spawn(move || {
for i in 0..50 {
for j in 0..500 {
let key = format!("key{}", j);
cache_clone1.get_mut(&key, |value| {
*value += 1;
});
}
for j in 0..10 {
let new_key = format!("new_key{}_{}", i, j);
cache_clone1.insert(new_key, j);
}
thread::sleep(Duration::from_millis(1));
}
});
let cache_clone2 = Arc::clone(&cache);
let retainer = thread::spawn(move || {
for i in 0..10 {
if i % 2 == 0 {
cache_clone2.retain(|key, value| {
(*value % 2 == 0) || !key.contains("new")
});
} else {
cache_clone2.retain_batch(|key, value| {
(*value % 2 == 1) || !key.contains("new")
});
}
thread::sleep(Duration::from_millis(5));
}
});
modifier.join().unwrap();
retainer.join().unwrap();
let len = cache.len();
println!("Cache size after retain race test: {}", len);
cache.insert("after_race_test".to_string(), 1000);
assert_eq!(cache.get(&"after_race_test".to_string()), Some(1000));
}
#[test]
fn test_with_lock_operation() {
let cache = Arc::new(SyncSieveCache::new(100).unwrap());
cache.insert("key1".to_string(), 1);
cache.with_lock(|inner_cache| {
inner_cache.insert("key2".to_string(), 2);
});
assert!(!cache.is_empty());
}
#[test]
fn test_nested_get_during_mut() {
let cache = Arc::new(SyncSieveCache::new(100).unwrap());
cache.insert("key1".to_string(), 1);
cache.insert("key2".to_string(), 2);
cache.get_mut(&"key1".to_string(), |val| {
*val += 1;
let _ = cache.get(&"key2".to_string());
});
assert!(!cache.is_empty());
}
#[test]
fn test_get_mut_operation() {
let cache = Arc::new(SyncSieveCache::new(100).unwrap());
cache.insert("key1".to_string(), 1);
cache.get_mut(&"key1".to_string(), |val| {
*val += 1;
});
assert!(!cache.is_empty());
}