Skip to main content

greplm_core/
io_backend.rs

1//! Ingest read path.
2//!
3//! Reading thousands of small source files is dominated by per-file syscall
4//! overhead, not bandwidth, so the goal is high effective queue depth (many
5//! reads in flight) rather than exotic zero-copy. The portable backend achieves
6//! that with a rayon worker pool over buffered reads; the page cache keeps
7//! re-reads (and the watch loop) cheap. An io_uring backend can be slotted in on
8//! Linux behind the `io-uring` feature.
9
10use std::path::Path;
11
12use crate::error::{Error, Result};
13
14/// Abstraction over how file bytes are pulled in during indexing.
15pub trait IoBackend: Send + Sync {
16    /// Read the full contents of a file.
17    fn read(&self, path: &Path) -> Result<Vec<u8>>;
18
19    /// Human-readable backend name (for `status`).
20    fn name(&self) -> &'static str;
21}
22
23/// Portable backend: a plain buffered read. Concurrency is supplied by the
24/// caller running `read` from many rayon worker threads at once.
25#[derive(Debug, Default, Clone, Copy)]
26pub struct RayonBackend;
27
28impl IoBackend for RayonBackend {
29    fn read(&self, path: &Path) -> Result<Vec<u8>> {
30        std::fs::read(path).map_err(|e| Error::io(path, e))
31    }
32
33    fn name(&self) -> &'static str {
34        "rayon"
35    }
36}
37
38#[cfg(all(feature = "io-uring", target_os = "linux"))]
39mod uring {
40    use super::*;
41
42    /// Linux io_uring backend (registered buffers + SQPOLL planned). Currently a
43    /// thin placeholder that defers to a buffered read so the feature compiles
44    /// and can be filled in without changing call sites.
45    #[derive(Debug, Default, Clone, Copy)]
46    pub struct UringBackend;
47
48    impl IoBackend for UringBackend {
49        fn read(&self, path: &Path) -> Result<Vec<u8>> {
50            std::fs::read(path).map_err(|e| Error::io(path, e))
51        }
52
53        fn name(&self) -> &'static str {
54            "io_uring"
55        }
56    }
57}
58
59/// Select a backend based on configuration and build features.
60pub fn default_backend() -> Box<dyn IoBackend> {
61    Box::new(RayonBackend)
62}