pub struct Prefetcher { /* private fields */ }Expand description
Thread-safe prefetch manager with configurable lookahead window.
This struct encapsulates the prefetch configuration and computes which blocks should be speculatively loaded following a given access. It maintains minimal state (just the window size) and relies on atomic operations for thread safety.
§Thread Safety
Prefetcher is fully thread-safe and can be shared across threads via Arc<Prefetcher>.
The window size is stored as an AtomicU32, allowing lock-free reads and updates.
Multiple threads can concurrently call get_prefetch_targets without contention.
§Performance
- Memory footprint: 8 bytes (one
AtomicU32) - Computation cost: O(window_size) per call to
get_prefetch_targets - Contention: None (lock-free atomic operations)
§Examples
use hexz_core::cache::prefetch::Prefetcher;
let prefetcher = Prefetcher::new(4);
let targets = prefetcher.get_prefetch_targets(10);
assert_eq!(targets, vec![11, 12, 13, 14]);Implementations§
Source§impl Prefetcher
impl Prefetcher
Sourcepub fn new(window_size: u32) -> Self
pub fn new(window_size: u32) -> Self
Constructs a new prefetcher with a fixed lookahead window.
The window size determines how many blocks ahead of the current access should be prefetched. A value of 0 disables prefetching entirely, which is appropriate for random access workloads or low-latency storage backends.
§Arguments
window_size- Number of blocks to prefetch ahead of the current access. Typical values range from 4 (local storage) to 32 (high-latency cloud backends). Must fit inu32(practical limit is much lower, usually < 256).
§Returns
Returns a new Prefetcher instance configured with the specified window size.
§Performance
- Time complexity: O(1)
- Memory allocation: 8 bytes
§Examples
use hexz_core::cache::prefetch::Prefetcher;
// Aggressive prefetching for high-latency S3 backend
let s3_prefetcher = Prefetcher::new(16);
// Conservative prefetching for local SSD
let ssd_prefetcher = Prefetcher::new(2);
// Disable prefetching for random access workload
let no_prefetch = Prefetcher::new(0);
assert!(no_prefetch.get_prefetch_targets(100).is_empty());Sourcepub fn try_start(&self) -> bool
pub fn try_start(&self) -> bool
Attempts to acquire the in-flight guard. Returns true if this caller
won the race and should spawn a prefetch thread. The caller must call
clear_in_flight when the prefetch completes.
Sourcepub fn spawn_count(&self) -> u64
pub fn spawn_count(&self) -> u64
Returns the total number of prefetch operations started since construction.
Sourcepub fn clear_in_flight(&self)
pub fn clear_in_flight(&self)
Clears the in-flight flag, allowing the next read to spawn a prefetch.
Sourcepub fn get_prefetch_targets(&self, current_block: u64) -> Vec<u64>
pub fn get_prefetch_targets(&self, current_block: u64) -> Vec<u64>
Computes the block indices that should be speculatively prefetched.
Given the index of a block currently being accessed, this method returns a
contiguous sequence of block indices that immediately follow it. The caller
(typically File) is responsible for scheduling the actual I/O operations
to load these blocks into the cache.
The returned vector contains exactly window_size consecutive block indices,
starting from current_block + 1 and ending at current_block + window_size.
If prefetching is disabled (window_size == 0), returns an empty vector.
§Arguments
current_block- Zero-based index of the block being actively read. This value is used as the anchor point for computing the prefetch range.
§Returns
Returns Vec<u64> containing the block indices to prefetch:
- Non-empty:
[current_block + 1, current_block + 2, ..., current_block + window_size] - Empty: If
window_size == 0(prefetching disabled)
§Performance
- Time complexity: O(window_size) to allocate and populate the vector
- Space complexity: O(window_size) for the returned vector
- Typical cost: < 1 µs for window_size ≤ 32
§Integer Overflow
This method performs saturating addition to avoid panics if current_block
is near u64::MAX. However, in practice, block indices are bounded by the
snapshot’s logical size, which is typically far below u64::MAX.
§Examples
§Standard Prefetch
use hexz_core::cache::prefetch::Prefetcher;
let prefetcher = Prefetcher::new(5);
let targets = prefetcher.get_prefetch_targets(42);
assert_eq!(targets, vec![43, 44, 45, 46, 47]);§Disabled Prefetch
use hexz_core::cache::prefetch::Prefetcher;
let prefetcher = Prefetcher::new(0);
let targets = prefetcher.get_prefetch_targets(100);
assert!(targets.is_empty());§Boundary Case
use hexz_core::cache::prefetch::Prefetcher;
let prefetcher = Prefetcher::new(1);
let targets = prefetcher.get_prefetch_targets(999);
assert_eq!(targets, vec![1000]);§Integration Notes
The caller must handle:
- Bounds checking: Ensure prefetch targets do not exceed the stream’s logical size (number of blocks in the snapshot)
- Cache lookup: Skip prefetching blocks already present in the cache
- I/O scheduling: Issue async or background reads for the target blocks
- Error handling: Prefetch failures should not impact the foreground read
See File::read_at_into_uninit for a reference implementation.
Trait Implementations§
Auto Trait Implementations§
impl !Freeze for Prefetcher
impl RefUnwindSafe for Prefetcher
impl Send for Prefetcher
impl Sync for Prefetcher
impl Unpin for Prefetcher
impl UnsafeUnpin for Prefetcher
impl UnwindSafe for Prefetcher
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