Force cleanup of expired entries
(&self)
| 309 | |
| 310 | /// Force cleanup of expired entries |
| 311 | pub fn cleanup(&self) { |
| 312 | let mut entries = self.entries.write(); |
| 313 | let mut stats = self.stats.write(); |
| 314 | |
| 315 | let mut last_cleanup = self.last_cleanup.write(); |
| 316 | *last_cleanup = Instant::now(); |
| 317 | |
| 318 | let initial_count = entries.len(); |
| 319 | let mut removed_size = 0; |
| 320 | |
| 321 | entries.retain(|_key, entry| { |
| 322 | if entry.is_expired() { |
| 323 | removed_size += entry.size_bytes; |
| 324 | false |
| 325 | } else { |
| 326 | true |
| 327 | } |
| 328 | }); |
| 329 | |
| 330 | let removed_count = initial_count - entries.len(); |
| 331 | if removed_count > 0 { |
| 332 | stats.total_entries = entries.len(); |
| 333 | stats.total_size_bytes = stats.total_size_bytes.saturating_sub(removed_size); |
| 334 | stats.expired_evictions += removed_count as u64; |
| 335 | stats.cleanup_runs += 1; |
| 336 | |
| 337 | debug!("Cache cleanup: removed {} expired entries, freed {} bytes", |
| 338 | removed_count, removed_size); |
| 339 | |
| 340 | // Unregister memory usage |
| 341 | if removed_size > 0 { |
| 342 | global_memory_monitor().record_query_deallocation(removed_size as u64); |
| 343 | } |
| 344 | } |
| 345 | |
| 346 | drop(stats); |
| 347 | drop(entries); |
| 348 | |
| 349 | // Validate memory tracking consistency after cleanup |
| 350 | if !self.validate_memory_tracking() { |
| 351 | debug!("Memory tracking was inconsistent after cleanup, fixed automatically"); |
| 352 | } |
| 353 | } |
| 354 | |
| 355 | /// Check if cleanup should be performed |
| 356 | fn maybe_cleanup(&self) { |