Skip to main content

keyhog_scanner/engine/
scan.rs

1use super::scan_inner_profile::{
2    scan_inner_prof_enabled, SCAN_INNER_CALLS, SCAN_PHASE1_NS, SCAN_PREPARE_NS,
3};
4use super::*;
5
6impl CompiledScanner {
7    /// Capture the effective decode policy consumed by this scanner.
8    pub fn decode_workload_plan(&self) -> crate::decode::DecodeWorkloadPlan {
9        crate::decode::DecodeWorkloadPlan::from_compiled_limits(
10            self.config.max_decode_depth,
11            self.config.max_decode_bytes,
12            self.detector_plans.decode_transforms_arc(),
13            self.detector_plans.decoder_plan_arc(),
14        )
15    }
16
17    #[cfg(feature = "decode")]
18    #[inline]
19    pub(crate) fn chunk_needs_decode_postprocess(&self, chunk: &keyhog_core::Chunk) -> bool {
20        self.config.max_decode_depth > 0
21            && chunk.data.len() <= self.config.max_decode_bytes
22            && crate::decode::decoder_admission(
23                chunk,
24                self.detector_plans.decode_transforms(),
25                self.detector_plans.decoder_plan(),
26            ) != crate::decode::DecodeAdmission::Impossible
27    }
28
29    #[cfg(not(feature = "decode"))]
30    #[inline]
31    pub(crate) fn chunk_needs_decode_postprocess(&self, _chunk: &keyhog_core::Chunk) -> bool {
32        false
33    }
34
35    pub(crate) fn scan_inner(
36        &self,
37        chunk: &Chunk,
38        backend: crate::hw_probe::ScanBackend,
39        deadline: Option<std::time::Instant>,
40        route: crate::ScanExecutionRoute,
41    ) -> crate::error::Result<Vec<RawMatch>> {
42        if crate::deadline::expired(deadline) {
43            return Ok(Vec::new());
44        }
45        // KH-116: Record scan metrics atomically
46        crate::telemetry::record_file_scanned(chunk.data.len());
47        if backend.is_gpu() {
48            crate::telemetry::record_gpu_dispatch();
49        }
50        let prof = scan_inner_prof_enabled();
51        let t0 = prof.then(std::time::Instant::now);
52        let prepared = self.prepare_chunk(chunk);
53        if let Some(t) = t0 {
54            SCAN_PREPARE_NS.fetch_add(
55                t.elapsed().as_nanos() as u64,
56                std::sync::atomic::Ordering::Relaxed,
57            );
58        }
59        if crate::deadline::expired(deadline) {
60            return Ok(Vec::new());
61        }
62        let t1 = prof.then(std::time::Instant::now);
63        let triggered = self.collect_triggered_patterns_for_backend(&chunk.data, backend)?;
64        if let Some(t) = t1 {
65            SCAN_PHASE1_NS.fetch_add(
66                t.elapsed().as_nanos() as u64,
67                std::sync::atomic::Ordering::Relaxed,
68            );
69            SCAN_INNER_CALLS.fetch_add(1, std::sync::atomic::Ordering::Relaxed);
70        }
71        if crate::deadline::expired(deadline) {
72            return Ok(Vec::new());
73        }
74        self.scan_prepared_with_triggered(
75            prepared, &triggered, deadline, None, None, None, None, route,
76        )
77    }
78}