mod lru_cache_chirho;
pub use lru_cache_chirho::{LruCacheChirho, CacheStatsChirho};
use std::sync::Arc;
use std::sync::atomic::{AtomicU64, Ordering};
#[derive(Debug, Clone, Hash, PartialEq, Eq)]
pub struct VerseCacheKeyChirho {
pub module_chirho: String,
pub book_chirho: u8,
pub chapter_chirho: u16,
pub verse_chirho: u16,
pub options_hash_chirho: u64,
}
impl VerseCacheKeyChirho {
pub fn new_chirho(
module_chirho: &str,
book_chirho: u8,
chapter_chirho: u16,
verse_chirho: u16,
options_hash_chirho: u64,
) -> Self {
Self {
module_chirho: module_chirho.to_string(),
book_chirho,
chapter_chirho,
verse_chirho,
options_hash_chirho,
}
}
}
#[derive(Debug, Default)]
pub struct AtomicCacheStatsChirho {
hits_chirho: AtomicU64,
misses_chirho: AtomicU64,
evictions_chirho: AtomicU64,
}
impl AtomicCacheStatsChirho {
pub fn new_chirho() -> Self {
Self::default()
}
pub fn record_hit_chirho(&self) {
self.hits_chirho.fetch_add(1, Ordering::Relaxed);
}
pub fn record_miss_chirho(&self) {
self.misses_chirho.fetch_add(1, Ordering::Relaxed);
}
pub fn record_eviction_chirho(&self) {
self.evictions_chirho.fetch_add(1, Ordering::Relaxed);
}
pub fn snapshot_chirho(&self) -> CacheStatsChirho {
CacheStatsChirho {
hits_chirho: self.hits_chirho.load(Ordering::Relaxed),
misses_chirho: self.misses_chirho.load(Ordering::Relaxed),
evictions_chirho: self.evictions_chirho.load(Ordering::Relaxed),
}
}
pub fn reset_chirho(&self) {
self.hits_chirho.store(0, Ordering::Relaxed);
self.misses_chirho.store(0, Ordering::Relaxed);
self.evictions_chirho.store(0, Ordering::Relaxed);
}
}
pub struct CachedModuleChirho<M> {
module_chirho: M,
cache_chirho: Arc<std::sync::RwLock<LruCacheChirho<VerseCacheKeyChirho, String>>>,
stats_chirho: Arc<AtomicCacheStatsChirho>,
}
impl<M> CachedModuleChirho<M> {
pub fn new_chirho(module_chirho: M, cache_size_chirho: usize) -> Self {
Self {
module_chirho,
cache_chirho: Arc::new(std::sync::RwLock::new(
LruCacheChirho::new_chirho(cache_size_chirho)
)),
stats_chirho: Arc::new(AtomicCacheStatsChirho::new_chirho()),
}
}
pub fn module_chirho(&self) -> &M {
&self.module_chirho
}
pub fn module_mut_chirho(&mut self) -> &mut M {
&mut self.module_chirho
}
pub fn stats_chirho(&self) -> CacheStatsChirho {
self.stats_chirho.snapshot_chirho()
}
pub fn reset_stats_chirho(&self) {
self.stats_chirho.reset_chirho();
}
pub fn clear_cache_chirho(&self) {
let mut cache_chirho = self.cache_chirho.write().unwrap();
cache_chirho.clear_chirho();
}
pub fn get_cached_chirho(&self, key_chirho: &VerseCacheKeyChirho) -> Option<String> {
let mut cache_chirho = self.cache_chirho.write().unwrap();
if let Some(value_chirho) = cache_chirho.get_chirho(key_chirho) {
self.stats_chirho.record_hit_chirho();
Some(value_chirho.clone())
} else {
self.stats_chirho.record_miss_chirho();
None
}
}
pub fn put_cached_chirho(&self, key_chirho: VerseCacheKeyChirho, value_chirho: String) {
let mut cache_chirho = self.cache_chirho.write().unwrap();
if cache_chirho.put_chirho(key_chirho, value_chirho).is_some() {
self.stats_chirho.record_eviction_chirho();
}
}
}
impl<M: Clone> Clone for CachedModuleChirho<M> {
fn clone(&self) -> Self {
Self {
module_chirho: self.module_chirho.clone(),
cache_chirho: self.cache_chirho.clone(),
stats_chirho: self.stats_chirho.clone(),
}
}
}
#[cfg(test)]
mod tests_chirho {
use super::*;
#[test]
fn test_verse_cache_key_chirho() {
let key1_chirho = VerseCacheKeyChirho::new_chirho("KJV", 1, 1, 1, 0);
let key2_chirho = VerseCacheKeyChirho::new_chirho("KJV", 1, 1, 1, 0);
let key3_chirho = VerseCacheKeyChirho::new_chirho("KJV", 1, 1, 2, 0);
assert_eq!(key1_chirho, key2_chirho);
assert_ne!(key1_chirho, key3_chirho);
}
#[test]
fn test_atomic_stats_chirho() {
let stats_chirho = AtomicCacheStatsChirho::new_chirho();
stats_chirho.record_hit_chirho();
stats_chirho.record_hit_chirho();
stats_chirho.record_miss_chirho();
let snapshot_chirho = stats_chirho.snapshot_chirho();
assert_eq!(snapshot_chirho.hits_chirho, 2);
assert_eq!(snapshot_chirho.misses_chirho, 1);
}
#[test]
fn test_cached_module_basic_chirho() {
let module_chirho = "test_module";
let cached_chirho = CachedModuleChirho::new_chirho(module_chirho, 100);
let key_chirho = VerseCacheKeyChirho::new_chirho("KJV", 1, 1, 1, 0);
assert!(cached_chirho.get_cached_chirho(&key_chirho).is_none());
cached_chirho.put_cached_chirho(key_chirho.clone(), "Genesis 1:1 text".to_string());
let result_chirho = cached_chirho.get_cached_chirho(&key_chirho);
assert_eq!(result_chirho, Some("Genesis 1:1 text".to_string()));
}
#[test]
fn test_cached_module_stats_chirho() {
let cached_chirho = CachedModuleChirho::new_chirho("module", 10);
let key_chirho = VerseCacheKeyChirho::new_chirho("KJV", 1, 1, 1, 0);
cached_chirho.get_cached_chirho(&key_chirho);
let stats_chirho = cached_chirho.stats_chirho();
assert_eq!(stats_chirho.misses_chirho, 1);
assert_eq!(stats_chirho.hits_chirho, 0);
cached_chirho.put_cached_chirho(key_chirho.clone(), "text".to_string());
cached_chirho.get_cached_chirho(&key_chirho);
let stats_chirho = cached_chirho.stats_chirho();
assert_eq!(stats_chirho.hits_chirho, 1);
}
}