Skip to main content

FileBackend

Struct FileBackend 

Source
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

Source

pub fn new(path: &Path) -> Result<Self>

Opens a snapshot file and prepares it for concurrent reads.

This constructor performs two operations:

  1. Opens the file at path in read-only mode (O_RDONLY)
  2. 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 initialized
  • Err(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

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl StorageBackend for FileBackend

Source§

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 cause offset + len to exceed file size)
§Returns
  • Ok(Bytes): A buffer containing exactly len bytes of data
  • Err(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 len bytes
  • 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

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);
Source§

fn is_empty(&self) -> bool

Returns true if the underlying store has zero length. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts 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 more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts 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
Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V

Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more