pub struct FileBackend { /* private fields */ }Expand description
A storage backend implementation backed by a local file.
This struct wraps a standard std::fs::File handle. It provides thread-safe
access to the underlying file data by utilizing system calls that accept
an explicit offset, thereby bypassing the stateful file pointer. This design
eliminates the need for a Mutex around the file handle during read operations.
Implementations§
Source§impl FileBackend
impl FileBackend
Sourcepub fn new(path: &Path) -> Result<Self>
pub fn new(path: &Path) -> Result<Self>
Opens a snapshot file and prepares it for concurrent reads.
This constructor performs two operations:
- Opens the file at
pathin read-only mode (O_RDONLY) - Queries file metadata via
fstat(2)to cache the file size
The file size is cached to avoid repeated stat system calls. The backend
assumes the file is immutable (snapshot semantics) and will not change
size during its lifetime.
§Parameters
path: Filesystem path to the snapshot file (absolute or relative)
§Returns
Ok(FileBackend): Successfully opened and initializedErr(Error::Io): If the file cannot be opened or metadata cannot be read
§Errors
Common error conditions:
- File not found (
ENOENT): Path does not exist - Permission denied (
EACCES): Insufficient permissions to read file - Invalid path (
ENOTDIR): A path component is not a directory - Device errors: Disk I/O failure during open or stat
§Examples
use hexz_core::store::local::FileBackend;
use std::path::Path;
// Absolute path
let backend = FileBackend::new(Path::new("/var/data/snapshot.hxz"))?;
// Relative path
let backend = FileBackend::new(Path::new("./snapshots/test.hxz"))?;
// Error handling
match FileBackend::new(Path::new("/nonexistent.hxz")) {
Ok(_) => println!("Success"),
Err(e) => eprintln!("Failed to open: {}", e),
}Trait Implementations§
Source§impl Debug for FileBackend
impl Debug for FileBackend
Source§impl StorageBackend for FileBackend
impl StorageBackend for FileBackend
Source§fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes>
fn read_exact(&self, offset: u64, len: usize) -> Result<Bytes>
Reads exactly len bytes starting at offset using position-independent I/O.
This method uses pread(2) semantics (via FileExt::read_exact_at) to read
data at an explicit offset without modifying any file descriptor state. This
enables safe concurrent reads from multiple threads without coordination.
§Parameters
offset: Absolute byte offset from the start of the file (0-indexed)len: Number of bytes to read (must not causeoffset + lento exceed file size)
§Returns
Ok(Bytes): A buffer containing exactlylenbytes of dataErr(Error::Io): If the read fails or reaches unexpected EOF
§Errors
This method returns an error in the following cases:
- Unexpected EOF (
ErrorKind::UnexpectedEof):offset + len > file_size - I/O errors: Disk read failure, filesystem corruption, device disconnected
- Invalid offset: Requesting beyond addressable range (rare on 64-bit systems)
§Performance
- Time complexity: O(len) for data copying, O(1) for offset calculation
- Syscalls: 1
pread(2)call - Allocations: 1 heap allocation of
lenbytes - Page cache: Benefits from OS caching; repeated reads of the same range may be served from memory without disk I/O
§Concurrency
This method is safe to call concurrently from multiple threads. Each call operates on an independent offset and does not affect other reads.
§Examples
use hexz_core::store::local::FileBackend;
use hexz_core::store::StorageBackend;
use std::path::Path;
let backend = FileBackend::new(Path::new("/data/snapshot.hxz"))?;
// Read first 512 bytes (header)
let header = backend.read_exact(0, 512)?;
assert_eq!(header.len(), 512);
// Read 4KB block at offset 1MB
let block = backend.read_exact(1024 * 1024, 4096)?;
assert_eq!(block.len(), 4096);
// Error: reading beyond file boundary
let file_size = backend.len();
assert!(backend.read_exact(file_size, 1).is_err());Source§fn len(&self) -> u64
fn len(&self) -> u64
Returns the total file size in bytes.
This value is cached during construction via File::metadata() and remains
constant for the lifetime of the backend. The file is assumed to be immutable
(snapshot semantics); modifying the file externally while the backend is
active results in undefined behavior.
§Returns
The file size in bytes as of the time FileBackend::new() was called.
§Performance
This method is a simple field access with no system calls (O(1)).
§Examples
use hexz_core::store::local::FileBackend;
use hexz_core::store::StorageBackend;
use std::path::Path;
let backend = FileBackend::new(Path::new("/data/snapshot.hxz"))?;
let size = backend.len();
println!("Snapshot size: {} bytes ({} MB)", size, size / 1024 / 1024);Auto Trait Implementations§
impl Freeze for FileBackend
impl RefUnwindSafe for FileBackend
impl Send for FileBackend
impl Sync for FileBackend
impl Unpin for FileBackend
impl UnsafeUnpin for FileBackend
impl UnwindSafe for FileBackend
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Instrument for T
impl<T> Instrument for T
Source§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
Source§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more