Skip to main content

hexz_core/store/
mod.rs

1//! Storage backends for snapshot byte access.
2//!
3//! Implements the `StorageBackend` trait for local files, HTTP (blocking and
4//! async), memory-mapped files, and S3-compatible object storage. Higher
5//! layers use these backends to fetch raw bytes without caring about the
6//! transport.
7
8use bytes::Bytes;
9use hexz_common::Result;
10use std::fmt::Debug;
11
12/// Abstract interface for all byte-addressable snapshot storage backends.
13///
14/// **Architectural intent:** Decouples the snapshot decoding logic from the
15/// physical storage medium so that files, HTTP endpoints, memory maps, or
16/// object stores can be swapped without changing higher layers.
17///
18/// **Constraints:** Implementations must be thread-safe (`Send + Sync`) and
19/// provide stable, random-access reads over an immutable byte region whose
20/// length does not change during the lifetime of the backend.
21///
22/// **Side effects:** Individual calls may perform disk or network I/O and may
23/// block the calling thread; callers are responsible for scheduling behavior.
24pub trait StorageBackend: Send + Sync + Debug {
25    /// Reads exactly `len` bytes starting at `offset` from the underlying store.
26    ///
27    /// **Architectural intent:** Provides the minimal primitive needed by the
28    /// format layer to fetch headers, indices, and compressed blocks.
29    ///
30    /// **Constraints:** `offset + len` must not exceed `self.len()`; callers
31    /// should treat short reads or I/O errors as fatal for the current
32    /// operation.
33    ///
34    /// **Side effects:** May perform synchronous I/O and allocate a new
35    /// `Bytes` buffer per call; repeated small reads can be expensive.
36    fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes>;
37
38    /// Returns the total logical size of the underlying snapshot in bytes.
39    ///
40    /// **Architectural intent:** Allows upper layers to validate range
41    /// requests and compute offsets into the header and index regions.
42    ///
43    /// **Constraints:** The length is assumed to be immutable for the lifetime
44    /// of the backend; changing it concurrently is undefined behavior.
45    fn len(&self) -> u64;
46
47    /// Returns `true` if the underlying store has zero length.
48    ///
49    /// **Architectural intent:** Convenience helper to avoid repeated `len()`
50    /// comparisons in call sites that need to quickly reject empty inputs.
51    ///
52    /// **Constraints:** Equivalent to `self.len() == 0`; implementations
53    /// should not override the default semantics.
54    fn is_empty(&self) -> bool {
55        self.len() == 0
56    }
57}
58
59pub mod utils;
60
61/// Local file-based storage backends.
62///
63/// Provides `StorageBackend` implementations that read directly from local
64/// files or memory-mapped regions.
65///
66/// - `FileBackend`: Traditional file I/O using `pread(2)` system calls
67/// - `MmapBackend`: Memory-mapped file access leveraging the OS page cache
68///
69/// ## Choosing a Backend
70///
71/// | Scenario | Recommended Backend | Rationale |
72/// |----------|-------------------|-----------|
73/// | Sequential scans | `FileBackend` | Lower kernel overhead, predictable I/O scheduling |
74/// | Random access with locality | `MmapBackend` | OS page cache provides transparent prefetch and caching |
75/// | Small files (<100MB) | `MmapBackend` | Entire file likely stays resident, near-zero overhead |
76/// | Large files (>1GB) with sparse access | `FileBackend` | Avoids address space fragmentation, explicit control |
77/// | Containers/restricted environments | `FileBackend` | No special kernel capabilities required |
78///
79/// ## Thread Safety
80///
81/// Both backends are fully thread-safe:
82/// - `FileBackend` uses offset-based I/O (`pread`) that bypasses file cursor state
83/// - `MmapBackend` wraps the memory map in `Arc<Mmap>` for safe shared access
84pub mod local;
85
86/// HTTP storage backends (blocking and async).
87///
88/// Enables reading snapshots served over HTTP using range requests.
89///
90/// The `HttpBackend` type wraps the `reqwest` async client in an embedded Tokio runtime,
91/// allowing synchronous callers to use HTTP without managing an async runtime.
92pub mod http;
93
94/// S3-compatible object storage backends.
95///
96/// Allows snapshots to be stored and accessed from S3 or S3-like object
97/// stores while still presenting the `StorageBackend` abstraction.
98///
99/// The `S3Backend` type wraps the `rust-s3` async client in an embedded Tokio runtime,
100/// providing a synchronous interface for snapshot access.
101pub mod s3;