Skip to main content

decdn_cache/policy/
lru.rs

1//! Behavior-preserving default policies: recency eviction, unconditional admit.
2use super::{
3    AdmissionContext, AdmissionDecision, AdmissionPolicy, EvictionContext, EvictionPlan,
4    EvictionPolicy, Segment,
5};
6use crate::Hash;
7
8/// Evicts by last access, oldest first, until the sweep reaches
9/// `target_bytes` or spends its budget. Promotes nothing.
10///
11/// Equal recencies — every blob that carries the open-time recency seed shares
12/// one instant — release largest first, so the sweep reaches its target in
13/// fewer releases.
14#[derive(Debug, Default, Clone, Copy)]
15pub struct LruEviction;
16
17impl EvictionPolicy for LruEviction {
18    fn plan(&self, ctx: &EvictionContext<'_>) -> EvictionPlan {
19        let size = |h: &Hash| ctx.sizes.get(h).copied().unwrap_or(0);
20        let mut ordered: Vec<(Hash, std::time::Instant)> =
21            ctx.candidates.iter().map(|(h, t)| (*h, *t)).collect();
22        // Oldest access first; equal recencies largest first.
23        ordered.sort_by(|a, b| a.1.cmp(&b.1).then_with(|| size(&b.0).cmp(&size(&a.0))));
24        let mut evict = Vec::new();
25        let mut freed = 0u64;
26        for (h, _) in ordered {
27            if ctx.total_bytes.saturating_sub(freed) <= ctx.target_bytes {
28                break;
29            }
30            if evict.len() as u64 >= ctx.budget {
31                break;
32            }
33            freed = freed.saturating_add(ctx.sizes.get(&h).copied().unwrap_or(0));
34            evict.push(h);
35        }
36        EvictionPlan {
37            evict,
38            promote: Vec::new(),
39        }
40    }
41}
42
43/// Stores every miss, straight into [`Segment::Main`]. The default admission
44/// policy, and the one that makes the segment map inert.
45#[derive(Debug, Default, Clone, Copy)]
46pub struct AlwaysAdmit;
47
48impl AdmissionPolicy for AlwaysAdmit {
49    fn admit(&self, _ctx: &AdmissionContext) -> AdmissionDecision {
50        AdmissionDecision::Store {
51            segment: Segment::Main,
52        }
53    }
54}
55
56#[cfg(test)]
57mod tests;