Skip to main content

lean_ctx/core/context_kernel/
ctx_read_dedup.rs

1//! Thin content-deduplication bridge for the ctx_read hot path.
2
3use super::dedup_wiring::{self, DedupAction};
4
5/// Read-specific snapshot of content-deduplication statistics.
6#[derive(Debug, Clone, Default, serde::Serialize)]
7pub struct ReadDedupSummary {
8    /// Number of reads checked for duplicate content.
9    pub total_reads: usize,
10    /// Number of reads replaced with unchanged-content stubs.
11    pub dedup_hits: usize,
12    /// Estimated tokens avoided by deduplicated reads.
13    pub tokens_saved: usize,
14    /// Fraction of checked reads replaced with stubs.
15    pub hit_rate: f64,
16}
17
18/// Returns whether content deduplication should run for a ctx_read mode.
19#[must_use]
20pub fn should_dedup(mode: &str) -> bool {
21    super::kernel_config::is_enabled()
22        && super::kernel_config::is_feature_enabled("content_dedup")
23        && mode != "raw"
24}
25
26/// Returns an unchanged-content stub when a prior delivery matches.
27///
28/// Returns `None` (deliver full content) when the kernel master switch is
29/// disabled, when the `content_dedup` feature is off, or when the content
30/// has not been seen before.
31#[must_use]
32pub fn try_dedup(path: &str, content: &str) -> Option<String> {
33    if !super::kernel_config::is_enabled() {
34        return None;
35    }
36    match dedup_wiring::check_content(path, content) {
37        DedupAction::DeliverStub { stub } => Some(stub),
38        DedupAction::DeliverFull | DedupAction::DeliverModified => None,
39    }
40}
41/// Invalidates deduplication state after a file write.
42pub fn on_file_write(path: &str) {
43    dedup_wiring::invalidate(path);
44}
45
46/// Returns read-specific cumulative content-deduplication statistics.
47#[must_use]
48pub fn dedup_summary() -> ReadDedupSummary {
49    let stats = dedup_wiring::dedup_stats();
50    ReadDedupSummary {
51        total_reads: stats.total_checks,
52        dedup_hits: stats.cache_hits,
53        tokens_saved: stats.tokens_saved,
54        hit_rate: stats.hit_rate,
55    }
56}
57
58/// Clears content-deduplication state and statistics.
59pub fn reset() {
60    dedup_wiring::reset_dedup();
61}
62
63#[cfg(test)]
64mod tests {
65    use std::sync::MutexGuard;
66
67    use super::{dedup_summary, on_file_write, reset, should_dedup, try_dedup};
68    use crate::core::context_kernel::kernel_config::{
69        KERNEL_TEST_LOCK, KernelFeatures, reset_features, update_features,
70    };
71
72    fn isolated() -> MutexGuard<'static, ()> {
73        let guard = KERNEL_TEST_LOCK
74            .lock()
75            .unwrap_or_else(std::sync::PoisonError::into_inner);
76        reset_features();
77        crate::core::context_kernel::dedup_wiring::reset_dedup();
78        reset();
79        guard
80    }
81
82    #[test]
83    fn should_dedup_respects_config() {
84        let _guard = isolated();
85        let features = KernelFeatures {
86            enabled: false,
87            ..KernelFeatures::default()
88        };
89        update_features(features);
90        assert!(!should_dedup("full"));
91    }
92
93    #[test]
94    fn should_dedup_raw_mode_false() {
95        let _guard = isolated();
96        assert!(!should_dedup("raw"));
97        assert!(should_dedup("full"));
98    }
99
100    #[test]
101    fn try_dedup_new_file_none() {
102        let _guard = isolated();
103        assert_eq!(try_dedup("new.rs", "content"), None);
104    }
105
106    #[test]
107    fn try_dedup_repeated_file_some() {
108        let _guard = isolated();
109        assert_eq!(try_dedup("repeat.rs", "content"), None);
110        let stub = try_dedup("repeat.rs", "content");
111        assert!(stub.is_some());
112        assert!(stub.is_some_and(|value| value.contains("repeat.rs unchanged")));
113    }
114
115    #[test]
116    fn on_write_invalidates() {
117        let _guard = isolated();
118        assert_eq!(try_dedup("written.rs", "content"), None);
119        assert!(try_dedup("written.rs", "content").is_some());
120        on_file_write("written.rs");
121        assert_eq!(try_dedup("written.rs", "content"), None);
122    }
123
124    #[test]
125    fn summary_tracks_reads() {
126        let _guard = isolated();
127        assert_eq!(try_dedup("a.rs", "one"), None);
128        assert!(try_dedup("a.rs", "one").is_some());
129        assert!(try_dedup("a.rs", "one").is_some());
130        assert_eq!(try_dedup("b.rs", "two"), None);
131        assert!(try_dedup("b.rs", "two").is_some());
132
133        let summary = dedup_summary();
134        assert_eq!(summary.total_reads, 5);
135        assert_eq!(summary.dedup_hits, 3);
136        assert!((summary.hit_rate - 0.6).abs() < f64::EPSILON);
137    }
138}