Skip to main content

RangeCache

Struct RangeCache 

Source
pub struct RangeCache { /* private fields */ }
Expand description

Range-aware read cache over an origin object store.

§Cache invalidation

This cache assumes object keys are write-once and content-addressed: a given key always maps to the same bytes for the lifetime of the object. The size and block caches therefore carry no TTL, etag, or generation in their keys and are never invalidated. Overwriting an existing key with different content would cause stale size/block data to be served indefinitely. This is safe for micromegas lake objects (blocks, parquet) which are never overwritten; do not point this cache at a mutable namespace.

§In-flight map and priority

Concurrent fetches of the same block or size are collapsed via an in-flight map (FetchScheduler): the first caller to ask for a key becomes its owner and issues the origin request (spawned as a detached task, so a cancelled caller never strands the others waiting on it); every other concurrent caller joins and observes the same result. Contiguous missing blocks the owner controls are coalesced into one origin.get_range per run. Every origin GET is either Demand or Prefetch priority; a demand caller joining a prefetch-priority fetch promotes it (see own_or_join), so a late demand read is never stuck behind unrelated prefetch traffic.

Implementations§

Source§

impl RangeCache

Source

pub fn new( origin: Arc<dyn ObjectStore>, backend: Arc<dyn RangeCacheBackend>, block_size: u64, ns: String, total_fetch_permits: usize, demand_reserved_fetch_permits: usize, max_coalesced_get_bytes: u64, promote_whole_batch: bool, ) -> Self

Source

pub fn with_prefix_labels(self, labels: Arc<[&'static str]>) -> Self

Attach a prefix classifier for the dimensioned hit-rate/request metrics: labels are the server’s configured allowed_prefixes, leaked to 'static once at startup by the caller (bounded, low-cardinality, set once). Every request key is then longest-prefix-matched against labels (see classify); a key matching none classifies as metric_tags::PREFIX_OTHER.

RangeCache::new itself leaves this empty (every key classifies as "other"), so its existing callers/tests compile unmodified; only object_cache_srv.rs opts in.

Source

pub fn classify(&self, key: &str) -> &'static str

The prefix label key falls under (e.g. "blobs", "views", per the server’s configured allowed_prefixes), or metric_tags::PREFIX_OTHER if it matches none. See with_prefix_labels.

Source

pub fn fetch_budget_stats(&self) -> (usize, usize, usize, usize)

(shared_available, shared_total, prefetch_available, prefetch_total) – the fetch-permit budget’s current occupancy, for the saturation sampler.

Source

pub fn inflight_len(&self) -> usize

Number of keys (blocks or size() heads) currently in flight to origin, for the saturation sampler.

Source

pub fn backend_disk_stats(&self) -> Option<BackendDiskStats>

Backend disk write-path counters (None for a backend with no disk tier), for the saturation sampler’s per-second foyer disk gauges.

Source

pub fn block_size(&self) -> u64

Size in bytes of one cache block. Every distinct block a request touches is fetched and held whole, so callers gating memory (e.g. the server’s cross-request budget) need this to account for amplification from small scattered ranges.

Source

pub fn size(&self, key: &str) -> impl Future<Output = Result<u64>>

Source

pub fn stream_ranges( &self, key: &str, ranges: Vec<Range<u64>>, caller: StreamRangesCaller, ) -> impl Future<Output = Result<impl Stream<Item = Result<Bytes>> + Send + 'static>>

Stream the bytes for ranges (each half-open [start, end)) without materializing more than a couple of DEMAND_WINDOW_BLOCKS windows of blocks at a time, regardless of how large the ranges are in total.

Upfront validation — the size() lookup and every range’s out-of-bounds check — runs before the stream is constructed and returned, so 404/416-shaped errors surface synchronously to the caller with proper status codes; only a failure after that point (a mid-stream fetch_blocks error, e.g. the origin going down) is yielded as the stream’s terminal Err item. A degenerate start >= end range is validated like any other (its end is still checked against file_size) but yields no bytes.

Yields a flat, ordered sequence of chunks: ranges are processed in the order given and each range’s bytes are emitted contiguously (possibly split into several Bytes chunks at window boundaries) before the next range’s bytes begin. There is no cross-range block dedup — a block shared by two ranges is fetched once per range it appears in, though a repeat is always a backend hit or an in-flight join, never a second origin GET (see own_or_join).

caller selects which of the two distinct error counters (range_cache_get_range_error / range_cache_get_ranges_error) this call emits on validation failure or a mid-stream fetch error, so get_range/get_ranges (and the two HTTP handlers, which call this directly) keep emitting the metric they always have.

Source

pub fn stream_ranges_with_size( &self, key: &str, ranges: Vec<Range<u64>>, file_size: u64, caller: StreamRangesCaller, ) -> impl Future<Output = Result<impl Stream<Item = Result<Bytes>> + Send + 'static>>

Like stream_ranges, but for a caller that already resolved file_size itself (e.g. get_range_handler, which needs it up front for range validation): skips the redundant self.size() call, so a cache hit doesn’t fire range_cache_size_backend_hit a second time per call.

Source

pub fn get_range( &self, key: &str, range: Range<u64>, ) -> impl Future<Output = Result<Bytes>>

Source

pub fn get_range_with_size( &self, key: &str, file_size: u64, range: Range<u64>, ) -> impl Future<Output = Result<Bytes>>

Like get_range, but for a caller that already resolved file_size itself, skipping the redundant self.size() call inside stream_ranges (see stream_ranges_with_size).

Source

pub fn get_ranges( &self, key: &str, ranges: &[Range<u64>], ) -> impl Future<Output = Result<Vec<Bytes>>>

Source

pub fn get_ranges_with_size( &self, key: &str, file_size: u64, ranges: &[Range<u64>], ) -> impl Future<Output = Result<Vec<Bytes>>>

Like get_ranges, but for a caller that already resolved file_size itself (see stream_ranges_with_size).

Source

pub async fn prefetch_ranges( &self, key: &str, ranges: &[Range<u64>], ) -> Result<()>

Warm the cache for ranges at Prefetch priority without returning any bytes. The HTTP surface for this (endpoint + client method) is #1198; this is the priority-carrying core it builds on. Public (rather than crate-private) so integration tests under tests/ — which compile as a separate crate — can exercise the promotion behavior described in the fetch-rework plan.

Source

pub async fn prefetch_blocks( &self, key: &str, file_size: u64, indices: &[u64], ) -> Result<()>

Warm the cache for the given block indices at Prefetch priority.

Trait Implementations§

Source§

impl Clone for RangeCache

Source§

fn clone(&self) -> RangeCache

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. 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<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T> Scope for T

Source§

fn with<F, R>(self, f: F) -> R
where Self: Sized, F: FnOnce(Self) -> R,

Scoped with ownership.
Source§

fn with_ref<F, R>(&self, f: F) -> R
where F: FnOnce(&Self) -> R,

Scoped with reference.
Source§

fn with_mut<F, R>(&mut self, f: F) -> R
where F: FnOnce(&mut Self) -> R,

Scoped with mutable reference.
Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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> Value for T
where T: Send + Sync + 'static,

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