Skip to main content

codetether_agent/session/index/
cache_mut.rs

1//! Mutation methods for [`SummaryIndex`].
2//!
3//! Separated from the struct definition for SRP — these methods
4//! modify the cache tree and maintain LRU ordering.
5
6use super::cache::SummaryIndex;
7use super::types::{MAX_CACHED_SUMMARIES, SummaryNode, SummaryRange};
8
9impl SummaryIndex {
10    /// Insert a node, maintaining LRU ordering and evicting if over budget.
11    pub fn insert(&mut self, range: SummaryRange, node: SummaryNode) -> Option<SummaryNode> {
12        self.touch_lru(range);
13        let prev = self.tree.insert(range, node);
14        self.evict_if_over_budget();
15        prev
16    }
17
18    /// Hot-path hook for `Session::add_message`.
19    ///
20    /// Drops every cached summary whose range covers `idx`.
21    pub fn append(&mut self, idx: usize) {
22        let to_drop: Vec<SummaryRange> = self
23            .tree
24            .keys()
25            .filter(|r| r.contains(idx))
26            .copied()
27            .collect();
28        for r in &to_drop {
29            self.tree.remove(r);
30        }
31        self.lru_order.retain(|r| !to_drop.contains(r));
32        if !to_drop.is_empty() {
33            self.generation = self.generation.wrapping_add(1);
34        }
35    }
36
37    /// Drop ranges whose `end > idx` (compaction/reset).
38    pub fn invalidate_after(&mut self, idx: usize) {
39        let to_drop: Vec<SummaryRange> =
40            self.tree.keys().filter(|r| r.end > idx).copied().collect();
41        for r in &to_drop {
42            self.tree.remove(r);
43        }
44        self.lru_order.retain(|r| !to_drop.contains(r));
45        if !to_drop.is_empty() {
46            self.generation = self.generation.wrapping_add(1);
47        }
48    }
49
50    /// Move `range` to most-recently-used position.
51    pub(super) fn touch_lru(&mut self, range: SummaryRange) {
52        self.lru_order.retain(|r| *r != range);
53        self.lru_order.push(range);
54    }
55
56    /// Evict oldest entries exceeding [`MAX_CACHED_SUMMARIES`].
57    fn evict_if_over_budget(&mut self) {
58        while self.tree.len() > MAX_CACHED_SUMMARIES {
59            if let Some(oldest) = self.lru_order.first().copied() {
60                self.tree.remove(&oldest);
61                self.lru_order.remove(0);
62            } else {
63                break;
64            }
65        }
66    }
67}