Lock File Cache System
Overview
The Lock File Cache System provides comprehensive caching capabilities for Rhema’s lock file operations, optimizing performance for read-heavy workloads and providing persistent storage for frequently accessed data. The system integrates seamlessly with the existing lock file infrastructure and provides multiple caching strategies and invalidation methods.
Features
1. In-Memory Caching
- Fast access to frequently used lock file data
- Configurable size limits and eviction strategies
- Thread-safe concurrent access
- Automatic cleanup of expired entries
2. Persistent Caching
- Disk-based storage for cache persistence across sessions
- Configurable compression for space efficiency
- Automatic integrity verification with checksums
- Metadata tracking for cache management
3. Cache Invalidation Strategies
- Time-based expiration: Automatic cleanup of old entries
- LRU (Least Recently Used): Evict least recently accessed entries
- LFU (Least Frequently Used): Evict least frequently accessed entries
- Size-based eviction: Remove largest entries when space is needed
- Priority-based eviction: Respect entry priority levels
- Hybrid strategy: Combine multiple approaches for optimal performance
4. Performance Metrics
- Hit/miss ratio tracking
- Access time monitoring
- Memory usage statistics
- Cache efficiency scoring
- Performance optimization recommendations
5. Cache Warming
- Preload frequently accessed data
- Pattern-based warming strategies
- Dependency relationship analysis
- Time-based access pattern optimization
Architecture
Core Components
1. CacheEntry<T>
Represents a single cache entry with metadata:
pub struct CacheEntry<T> {
pub data: T, // Cached data
pub created_at: DateTime<Utc>, // Creation timestamp
pub last_accessed: DateTime<Utc>, // Last access time
pub access_count: u64, // Number of accesses
pub ttl: Option<u64>, // Time-to-live in seconds
pub checksum: String, // Integrity checksum
pub size_bytes: usize, // Approximate size
pub priority: u8, // Eviction priority
pub pinned: bool, // Whether entry is pinned
}2. InMemoryCache
Handles fast in-memory storage with configurable eviction strategies:
pub struct InMemoryCache {
entries: HashMap<String, CacheEntry<Vec<u8>>>,
access_order: VecDeque<String>,
config: CacheConfig,
stats: CacheStats,
last_cleanup: Instant,
}3. PersistentCache
Manages disk-based persistent storage:
pub struct PersistentCache {
cache_dir: PathBuf,
config: CacheConfig,
compression_enabled: bool,
}4. LockFileCache
Main cache manager that coordinates in-memory and persistent caches:
pub struct LockFileCache {
memory_cache: Arc<RwLock<InMemoryCache>>,
persistent_cache: Option<Arc<PersistentCache>>,
config: CacheConfig,
stats: Arc<Mutex<CacheStats>>,
}Cache Key Types
The system supports multiple cache key types for different lock file data:
pub enum CacheKey {
LockFile(PathBuf), // Lock file by repository path
Scope(PathBuf), // Scope by path
Dependency(String, String), // Dependency by path and constraint
ResolutionResult(Vec<String>), // Resolution result by dependencies
ValidationResult(String), // Validation result by checksum
PerformanceMetrics(String), // Performance metrics by operation
Custom(String), // Custom key
}Configuration
CacheConfig
pub struct CacheConfig {
pub max_size_bytes: usize, // Maximum cache size
pub default_ttl: Option<u64>, // Default time-to-live
pub invalidation_strategy: InvalidationStrategy,
pub enable_persistent: bool, // Enable persistent caching
pub persistent_cache_dir: Option<PathBuf>,
pub enable_compression: bool, // Enable compression
pub max_entries: usize, // Maximum number of entries
pub cleanup_interval: u64, // Cleanup interval in seconds
pub enable_stats: bool, // Enable statistics
pub enable_warming: bool, // Enable cache warming
pub warming_strategy: WarmingStrategy,
}Default Configuration
impl Default for CacheConfig {
fn default() -> Self {
Self {
max_size_bytes: 100 * 1024 * 1024, // 100MB
default_ttl: Some(3600), // 1 hour
invalidation_strategy: InvalidationStrategy::Hybrid,
enable_persistent: true,
persistent_cache_dir: None, // Uses .rhema/cache
enable_compression: true,
max_entries: 10000,
cleanup_interval: 300, // 5 minutes
enable_stats: true,
enable_warming: false,
warming_strategy: WarmingStrategy::None,
}
}
}Usage
Basic Usage
1. Initialize the Cache System
use rhema::lock::{LockSystem, CacheConfig, InvalidationStrategy};
// Initialize with default configuration
LockSystem::initialize()?;
// Or with custom configuration
let config = CacheConfig {
max_size_bytes: 50 * 1024 * 1024, // 50MB
default_ttl: Some(1800), // 30 minutes
invalidation_strategy: InvalidationStrategy::Lru,
enable_persistent: true,
..Default::default()
};
rhema::lock::init_global_cache(config)?;2. Cache Lock File Operations
The cache system automatically integrates with lock file operations:
// Generate lock file (automatically cached)
let lock_file = LockSystem::generate_lock_file(repo_path)?;
// Subsequent calls will use cached data if available
let cached_lock_file = LockSystem::generate_lock_file(repo_path)?;3. Manual Cache Operations
use rhema::lock::{get_global_cache, CacheKey};
let cache = get_global_cache()?;
// Store lock file in cache
cache.set_lock_file(repo_path, &lock_file, Some(3600))?;
// Retrieve from cache
if let Some(cached_lock) = cache.get_lock_file(repo_path)? {
println!("Using cached lock file");
}
// Store scope in cache
cache.set_scope(scope_path, &scope, Some(1800))?;
// Retrieve scope from cache
if let Some(cached_scope) = cache.get_scope(scope_path)? {
println!("Using cached scope");
}Advanced Usage
1. Custom Cache Keys
use rhema::lock::CacheKey;
// Create custom cache key
let key = CacheKey::Custom("my_custom_data".to_string());
// Store custom data
let custom_data = vec![1, 2, 3, 4, 5];
cache.set_serializable(&key, &custom_data, Some(3600), 5)?;
// Retrieve custom data
let retrieved: Option<Vec<u8>> = cache.get_serializable(&key)?;2. Cache Statistics and Monitoring
// Get cache statistics
let stats = LockSystem::get_cache_stats()?;
println!("Cache hit rate: {:.2}%", stats.hit_rate * 100.0);
println!("Total entries: {}", stats.total_entries);
println!("Total size: {} MB", stats.total_size_bytes / 1024 / 1024);
// Get performance report
let report = LockSystem::get_cache_performance_report()?;
println!("{}", report);3. Cache Management
// Clear all caches
LockSystem::clear_caches()?;
// Warm cache for a repository
LockSystem::warm_cache(repo_path)?;
// Optimize cache based on usage patterns
LockSystem::optimize_cache()?;4. Cache Warming Strategies
use rhema::lock::{CacheConfig, WarmingStrategy};
let config = CacheConfig {
enable_warming: true,
warming_strategy: WarmingStrategy::FrequentAccess,
..Default::default()
};
// Initialize cache with warming enabled
rhema::lock::init_global_cache(config)?;
// Warm cache for repository
LockSystem::warm_cache(repo_path)?;Integration with Lock File System
Automatic Integration
The cache system automatically integrates with the existing lock file operations:
- Lock File Generation: Generated lock files are automatically cached
- Scope Resolution: Resolved scopes are cached for future use
- Dependency Resolution: Resolved dependencies are cached
- Validation Results: Validation results are cached
Performance Benefits
- Faster Lock File Generation: Subsequent generations use cached data
- Reduced Dependency Resolution: Cached dependencies avoid re-resolution
- Improved Validation Performance: Cached validation results
- Better Resource Utilization: Persistent cache reduces memory pressure
Cache Invalidation Strategies
1. Time-based Expiration
let config = CacheConfig {
default_ttl: Some(3600), // 1 hour
invalidation_strategy: InvalidationStrategy::TimeBased,
..Default::default()
};2. LRU (Least Recently Used)
let config = CacheConfig {
invalidation_strategy: InvalidationStrategy::Lru,
max_entries: 1000,
..Default::default()
};3. LFU (Least Frequently Used)
let config = CacheConfig {
invalidation_strategy: InvalidationStrategy::Lfu,
max_entries: 1000,
..Default::default()
};4. Size-based Eviction
let config = CacheConfig {
invalidation_strategy: InvalidationStrategy::SizeBased,
max_size_bytes: 50 * 1024 * 1024, // 50MB
..Default::default()
};5. Priority-based Eviction
let config = CacheConfig {
invalidation_strategy: InvalidationStrategy::PriorityBased,
max_entries: 1000,
..Default::default()
};6. Hybrid Strategy
let config = CacheConfig {
invalidation_strategy: InvalidationStrategy::Hybrid,
max_size_bytes: 100 * 1024 * 1024, // 100MB
max_entries: 10000,
..Default::default()
};Performance Monitoring
Cache Statistics
pub struct CacheStats {
pub hits: u64, // Total cache hits
pub misses: u64, // Total cache misses
pub total_entries: usize, // Current entries
pub total_size_bytes: usize, // Current size
pub max_size_bytes: usize, // Maximum size
pub evictions: u64, // Number of evictions
pub expired_entries: u64, // Number of expired entries
pub avg_access_time_us: u64, // Average access time
pub hit_rate: f64, // Hit rate (0.0 to 1.0)
pub last_cleanup: Option<DateTime<Utc>>,
pub efficiency_score: f64, // Overall efficiency
}Performance Report
let report = LockSystem::get_cache_performance_report()?;
println!("{}", report);Example output:
Cache Performance Report:
- Hit Rate: 85.50%
- Total Entries: 1,234
- Total Size: 45 MB
- Average Access Time: 125 μs
- Evictions: 23
- Expired Entries: 12
- Efficiency Score: 0.92Best Practices
1. Configuration Optimization
- Memory-constrained environments: Use smaller cache sizes and enable compression
- High-performance requirements: Use larger cache sizes and disable compression
- Long-running processes: Enable persistent caching
- Short-lived processes: Use in-memory caching only
2. Cache Warming
- Development environments: Use
WarmingStrategy::FrequentAccess - Production environments: Use
WarmingStrategy::DependencyBased - CI/CD pipelines: Use
WarmingStrategy::AccessPattern
3. Invalidation Strategy Selection
- Read-heavy workloads: Use
InvalidationStrategy::Lru - Write-heavy workloads: Use
InvalidationStrategy::TimeBased - Mixed workloads: Use
InvalidationStrategy::Hybrid - Memory-constrained: Use
InvalidationStrategy::SizeBased
4. Monitoring and Maintenance
- Regularly monitor cache statistics
- Adjust configuration based on usage patterns
- Clear caches periodically to prevent stale data
- Use cache optimization features
Error Handling
The cache system provides comprehensive error handling:
use rhema::lock::get_global_cache;
match get_global_cache() {
Ok(cache) => {
// Use cache
let result = cache.get_lock_file(repo_path)?;
}
Err(RhemaError::CacheError(msg)) => {
// Handle cache-specific errors
eprintln!("Cache error: {}", msg);
}
Err(e) => {
// Handle other errors
eprintln!("Error: {}", e);
}
}Testing
The cache system includes comprehensive tests:
# Run cache integration tests
cargo test cache_integration_test
# Run specific cache tests
cargo test test_cache_initialization
cargo test test_cache_operations
cargo test test_cache_invalidation_strategiesTroubleshooting
Common Issues
-
Cache Not Working
- Ensure cache is initialized:
LockSystem::initialize()? - Check cache configuration
- Verify cache directory permissions
- Ensure cache is initialized:
-
Low Hit Rate
- Increase cache size
- Adjust TTL settings
- Enable cache warming
- Review invalidation strategy
-
High Memory Usage
- Reduce cache size
- Enable compression
- Use persistent caching
- Adjust cleanup interval
-
Slow Performance
- Check cache statistics
- Optimize cache configuration
- Enable cache warming
- Review access patterns
Debug Information
Enable debug logging to troubleshoot cache issues:
use log::LevelFilter;
// Set log level to debug
env_logger::Builder::new()
.filter_level(LevelFilter::Debug)
.init();Conclusion
The Lock File Cache System provides a robust, high-performance caching solution for Rhema’s lock file operations. With its flexible configuration options, multiple invalidation strategies, and comprehensive monitoring capabilities, it significantly improves performance for read-heavy workloads while maintaining data integrity and providing persistent storage options.
The system integrates seamlessly with the existing lock file infrastructure and provides both automatic and manual caching capabilities, making it suitable for a wide range of use cases from development environments to production systems.