DiskCache

Struct DiskCache 

Source
pub struct DiskCache {
    pub(super) cache_dir: PathBuf,
    pub(super) write_gc_lock: Arc<RwLock<()>>,
    pub(crate) index_walk: Arc<Semaphore>,
}
Expand description

Content-addressable disk cache.

Fields§

§cache_dir: PathBuf§write_gc_lock: Arc<RwLock<()>>§index_walk: Arc<Semaphore>

One remove_by_key_prefix at a time, process-wide.

The removal walks the whole index twice, and the second walk holds write_gc_lock.write_owned() for its duration. tokio’s RwLock is write-preferring, so overlapping removals starve every cache write in the process, and a walk costs exactly the same for a key nothing was ever stored under. Lives on the cache, not on Admission, so every caller gets the bound without learning it exists, and the permit is carried INTO both blocking closures the same way the GC guard is: a permit held by the async fn would be released when a client drops the request mid-walk, while the walk itself runs on.

Implementations§

Source§

impl DiskCache

Source

pub async fn new(cache_dir: &str) -> Self

Create a new cache in the specified directory.

Source

pub fn generate_key(data: &[u8]) -> String

Generate a cache key from file content (SHA256 hash).

Source

pub async fn get<T: DeserializeOwned>( &self, key: &str, ) -> Result<Option<T>, ApiError>

Get a cached value by key.

Source

pub async fn set<T: Serialize>( &self, key: &str, value: &T, ) -> Result<(), ApiError>

Set a cached value.

Serializes and then delegates to Self::set_bytes, so there is exactly one body that takes the write_gc_lock read guard around a cacache::write – the invariant cannot drift between the two entry points.

Source

pub async fn has(&self, key: &str) -> Result<bool, ApiError>

Whether the index holds an entry for key. An index lookup only: the content is not read, so this is the cheap pre-filter, never the decision a reader acts on.

Ok(false) is “absent”; a lookup that FAILS is an error, not an absence, so a caller answering 404 on false still answers a broken cache store with 500 CACHE_ERROR (#5750 review). cacache::metadata answers Ok(None) for a key it has no entry for.

Source

pub async fn remove(&self, key: &str) -> Result<(), ApiError>

Remove a cached entry.

Source

pub async fn clear(&self) -> Result<(), ApiError>

Clear all cached entries.

Source

pub async fn get_bytes(&self, key: &str) -> Result<Option<Vec<u8>>, ApiError>

Get raw bytes from cache (for Parquet responses).

Source

pub async fn set_bytes(&self, key: &str, data: &[u8]) -> Result<(), ApiError>

Set raw bytes in cache.

Source

pub async fn stats(&self) -> Result<CacheStats, ApiError>

Cache-wide entry count and total content size in bytes, for the /api/v1/metrics gauges (issue #3636). Sums Metadata::size across every index entry; entries sharing a deduplicated content blob are each counted once (as stored), matching what remove_by_key_prefix treats as “still referenced”.

Source§

impl DiskCache

Source

pub async fn remove_by_key_prefix( &self, key_prefix: &str, ) -> Result<usize, ApiError>

Remove every index entry whose key is key_prefix itself or starts with "{key_prefix}-" (issue #3636). One source file fans out into several entries under the same hash prefix – the plain request key, the -json-v2, -parquet-vN, -parquet-metadata-v4 and -symbolic-v1 variants, each combination of opening-filter and quality suffix – and DELETE /api/v1/cache/{key} (handed the file hash its cache_key resolves to) is meant to drop all of them for that file in one call.

The underlying store is content-addressable: two different source files can produce byte-identical output (the issue’s example is two different IFCs that both emit an empty symbolic-data payload) and then share one content blob across two index entries. So this removes INDEX ENTRIES first – an index-only removal (cacache::remove) is exactly the operation the issue’s own hand-pruning experiment found safe: leaving a blob temporarily orphaned makes it unreachable but never makes a surviving entry read as corrupt, whereas removing a blob a live index entry still points at does (their write-up reproduced the resulting 500s). Only once every matching index entry is gone does this walk the remaining index and drop content blobs that nothing references any more; a blob still referenced by an unrelated entry is left alone.

Returns the number of index entries removed. Zero is a normal, successful result for a prefix nothing was ever cached under, or that already had its entries removed – deleting an absent entry is a no-op, not an error, so a retried or duplicate DELETE stays safe.

Trait Implementations§

Source§

impl Clone for DiskCache

Source§

fn clone(&self) -> DiskCache

Returns a duplicate of the value. Read more
1.0.0 · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for DiskCache

Source§

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

Formats the value using the given formatter. 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
§

impl<U> As for U

§

fn as_<T>(self) -> T
where T: CastFrom<U>,

Casts self to type T. The semantics of numeric casting with the as operator are followed, so <T as As>::as_::<U> can be used in the same way as T as U for numeric conversions. 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> 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.

§

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

§

fn from_ref(input: &T) -> T

Converts to this type from a reference to the input type.
§

impl<T> Instrument for T

§

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

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

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
§

impl<T> Pointable for T

§

const ALIGN: usize

The alignment of pointer.
§

type Init = T

The type for initializers.
§

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

Initializes a with the given initializer. Read more
§

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

Dereferences the given pointer. Read more
§

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

Mutably dereferences the given pointer. Read more
§

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
§

impl<SS, SP> SupersetOf<SS> for SP
where SS: SubsetOf<SP>,

§

fn to_subset(&self) -> Option<SS>

The inverse inclusion map: attempts to construct self from the equivalent element of its superset. Read more
§

fn is_in_subset(&self) -> bool

Checks if self is actually part of its subset T (and can be converted to it).
§

fn to_subset_unchecked(&self) -> SS

Use with care! Same as self.to_subset but without any property checks. Always succeeds.
§

fn from_subset(element: &SS) -> SP

The inclusion map: converts self to the equivalent element of its superset.
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.
§

impl<T> WithSubscriber for T

§

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
§

fn with_current_subscriber(self) -> WithDispatch<Self>

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

impl<A, B, T> HttpServerConnExec<A, B> for T
where B: Body,