#[derive(Clone, Copy, Debug)]
pub struct TierPolicy {
pub hot_min_score: u32,
pub warm_min_score: u32,
pub warm_bits: u8,
pub drift_pct_q8: u32,
pub group_len: u32,
}
impl Default for TierPolicy {
fn default() -> Self {
Self {
hot_min_score: 512,
warm_min_score: 64,
warm_bits: 7,
drift_pct_q8: 26,
group_len: 64,
}
}
}
impl TierPolicy {
pub fn select_bits(&self, access_count: u32, last_access_ts: u32, now_ts: u32) -> u8 {
let age = now_ts.wrapping_sub(last_access_ts).wrapping_add(1);
let score = access_count.saturating_mul(1024).wrapping_div(age);
if score >= self.hot_min_score {
8
} else if score >= self.warm_min_score {
self.warm_bits
} else {
3
}
}
pub fn drift_factor(&self) -> f32 {
1.0 + (self.drift_pct_q8 as f32) / 256.0
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_default_policy() {
let p = TierPolicy::default();
assert_eq!(p.hot_min_score, 512);
assert_eq!(p.warm_min_score, 64);
assert_eq!(p.warm_bits, 7);
assert_eq!(p.drift_pct_q8, 26);
assert_eq!(p.group_len, 64);
}
#[test]
fn test_tier_selection_hot() {
let p = TierPolicy::default();
assert_eq!(p.select_bits(100, 0, 9), 8);
}
#[test]
fn test_tier_selection_warm() {
let p = TierPolicy::default();
assert_eq!(p.select_bits(10, 0, 99), 7);
}
#[test]
fn test_tier_selection_cold() {
let p = TierPolicy::default();
assert_eq!(p.select_bits(1, 0, 999), 3);
}
#[test]
fn test_drift_factor() {
let p = TierPolicy::default();
let df = p.drift_factor();
assert!((df - 1.1015625).abs() < 1e-6);
}
#[test]
fn test_warm_bits_5() {
let p = TierPolicy {
warm_bits: 5,
..Default::default()
};
assert_eq!(p.select_bits(10, 0, 99), 5);
}
}