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 runtime;
60pub mod utils;
61
62/// Local file-based storage backends.
63///
64/// Provides `StorageBackend` implementations that read directly from local
65/// files or memory-mapped regions.
66///
67/// - `FileBackend`: Traditional file I/O using `pread(2)` system calls
68/// - `MmapBackend`: Memory-mapped file access leveraging the OS page cache
69///
70/// ## Choosing a Backend
71///
72/// | Scenario | Recommended Backend | Rationale |
73/// |----------|-------------------|-----------|
74/// | Sequential scans | `FileBackend` | Lower kernel overhead, predictable I/O scheduling |
75/// | Random access with locality | `MmapBackend` | OS page cache provides transparent prefetch and caching |
76/// | Small files (<100MB) | `MmapBackend` | Entire file likely stays resident, near-zero overhead |
77/// | Large files (>1GB) with sparse access | `FileBackend` | Avoids address space fragmentation, explicit control |
78/// | Containers/restricted environments | `FileBackend` | No special kernel capabilities required |
79///
80/// ## Thread Safety
81///
82/// Both backends are fully thread-safe:
83/// - `FileBackend` uses offset-based I/O (`pread`) that bypasses file cursor state
84/// - `MmapBackend` wraps the memory map in `Arc<Mmap>` for safe shared access
85pub mod local;
86
87/// HTTP storage backends (blocking and async).
88///
89/// Enables reading snapshots served over HTTP using range requests.
90///
91/// The `HttpBackend` type wraps the `reqwest` async client in an embedded Tokio runtime,
92/// allowing synchronous callers to use HTTP without managing an async runtime.
93pub mod http;
94
95/// S3-compatible object storage backends.
96///
97/// Allows snapshots to be stored and accessed from S3 or S3-like object
98/// stores while still presenting the `StorageBackend` abstraction.
99///
100/// The `S3Backend` type wraps the `rust-s3` async client in an embedded Tokio runtime,
101/// providing a synchronous interface for snapshot access.
102pub mod s3;