use crate::fs::inode_table::InodeTable;
use crate::fs::policy::Policy;
use std::path::{Path, PathBuf};
use std::sync::RwLock;
use std::sync::RwLockReadGuard;
use std::sync::atomic::{AtomicU64, Ordering};
use std::time::{SystemTime, UNIX_EPOCH};
pub struct PolicyFreshnessGuard {
policy: RwLock<Policy>,
inodes: RwLock<InodeTable>,
root: PathBuf,
last_check: AtomicU64,
check_interval_secs: AtomicU64,
}
impl PolicyFreshnessGuard {
pub fn new(root: &Path) -> Self {
Self {
policy: RwLock::new(Policy::load(root)),
inodes: RwLock::new(InodeTable::new(root)),
root: root.to_path_buf(),
last_check: AtomicU64::new(0),
check_interval_secs: AtomicU64::new(1),
}
}
pub fn with_check_interval(root: &Path, interval_secs: u64) -> Self {
Self {
policy: RwLock::new(Policy::load(root)),
inodes: RwLock::new(InodeTable::new(root)),
root: root.to_path_buf(),
last_check: AtomicU64::new(0),
check_interval_secs: AtomicU64::new(interval_secs),
}
}
pub fn set_check_interval(&self, interval_secs: u64) {
self.check_interval_secs
.store(interval_secs, Ordering::Relaxed);
}
pub fn ensure_fresh(&self) -> bool {
let now_secs = now_unix_secs();
let last = self.last_check.load(Ordering::Relaxed);
let interval = self.check_interval_secs.load(Ordering::Relaxed);
if interval > 0 && now_secs < last.wrapping_add(interval) {
return false;
}
{
let policy = self
.policy
.read()
.expect("policy RwLock poisoned — fatal process state");
if !policy.has_config_changed() {
self.last_check.store(now_secs, Ordering::Relaxed);
return false;
}
}
{
let mut policy = self
.policy
.write()
.expect("policy RwLock poisoned — fatal process state");
if policy.check_and_reload() {
self.inodes
.write()
.expect("inodes RwLock poisoned — fatal process state")
.evict_prefix(&self.root);
self.last_check.store(now_secs, Ordering::Relaxed);
return true;
}
}
self.last_check.store(now_secs, Ordering::Relaxed);
false
}
#[inline]
pub fn policy_read(&self) -> RwLockReadGuard<'_, Policy> {
self.policy
.read()
.expect("policy RwLock poisoned — fatal process state")
}
#[inline]
pub fn policy_write(&self) -> std::sync::RwLockWriteGuard<'_, Policy> {
self.policy
.write()
.expect("policy RwLock poisoned — fatal process state")
}
#[inline]
pub fn inodes_read(&self) -> RwLockReadGuard<'_, InodeTable> {
self.inodes
.read()
.expect("inodes RwLock poisoned — fatal process state")
}
#[inline]
pub fn inodes_write(&self) -> std::sync::RwLockWriteGuard<'_, InodeTable> {
self.inodes
.write()
.expect("inodes RwLock poisoned — fatal process state")
}
}
fn now_unix_secs() -> u64 {
SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(0)
}