Skip to main content

Cache

Trait Cache 

Source
pub trait Cache:
    Send
    + Sync
    + 'static {
    // Required methods
    fn get<'life0, 'life1, 'async_trait>(
        &'life0 self,
        key: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn set<'life0, 'life1, 'async_trait>(
        &'life0 self,
        key: &'life1 str,
        value: Vec<u8>,
        ttl: Option<Duration>,
    ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn delete<'life0, 'life1, 'async_trait>(
        &'life0 self,
        key: &'life1 str,
    ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn increment<'life0, 'life1, 'async_trait>(
        &'life0 self,
        key: &'life1 str,
        by: i64,
    ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait;
    fn clear<'life0, 'async_trait>(
        &'life0 self,
    ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait;

    // Provided methods
    fn set_if_absent<'life0, 'life1, 'async_trait>(
        &'life0 self,
        _key: &'life1 str,
        _value: Vec<u8>,
    ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn set_if_absent_with_ttl<'life0, 'life1, 'async_trait>(
        &'life0 self,
        _key: &'life1 str,
        _value: Vec<u8>,
        _ttl: Duration,
    ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn increment_with_expiry<'life0, 'life1, 'async_trait>(
        &'life0 self,
        _key: &'life1 str,
        _by: i64,
        _ttl: Duration,
    ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait { ... }
    fn admit_marker<'life0, 'life1, 'life2, 'async_trait>(
        &'life0 self,
        req: &'life1 AdmitMarker<'life2>,
    ) -> Pin<Box<dyn Future<Output = Result<Admission, CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait { ... }
    fn invalidate_marker<'life0, 'life1, 'life2, 'life3, 'async_trait>(
        &'life0 self,
        marker: &'life1 str,
        epoch_key: &'life2 str,
        epoch: &'life3 [u8],
        ttl: Duration,
    ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
       where Self: 'async_trait,
             'life0: 'async_trait,
             'life1: 'async_trait,
             'life2: 'async_trait,
             'life3: 'async_trait { ... }
}
Expand description

Byte-oriented cache with optional per-entry time-to-live.

Keys are UTF-8 strings. Values are opaque bytes; JSON helpers live on CacheExt. increment follows Redis INCRBY: a missing key is treated as 0, and a stored value that is not a decimal integer is an error.

§Contract for backends and external adapters

Only get, set, delete, increment and clear are required. The atomic creation methods (set_if_absent and set_if_absent_with_ttl) are provided methods, so adding them never breaks an existing implementation. The legacy set_if_absent default returns CacheError::Backend (“atomic insertion is unsupported”); the default of set_if_absent_with_ttl returns CacheError::Unsupported. Callers that need atomic creation (RouteCache generation markers) treat that error as “bypass”: they serve the origin and store nothing. They never emulate creation with get followed by set, which would let two creators both win and let a delayed writer overwrite a newer value.

An atomic creation method must make the liveness check, the insertion and the expiry deadline one indivisible step: exactly one of any set of concurrent creators of a missing or expired key observes Ok(true), and a cancelled call either created the entry with its full TTL or created nothing. See docs/CACHE.md for the generation-expiry contract built on this primitive.

Required Methods§

Source

fn get<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Fetch key. Ok(None) when the key is missing or has expired.

Source

fn set<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, value: Vec<u8>, ttl: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Store value at key. ttl of None means the entry does not expire.

Source

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Remove key. Ok(true) when a live entry was removed.

Source

fn increment<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, by: i64, ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Add by to the integer stored at key (Redis INCRBY).

A missing key starts at 0. by may be negative. The stored form is the decimal representation of the new value, with no expiry when the key is created by this call; an existing key keeps its expiry.

Source

fn clear<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Remove every entry this cache is responsible for.

Provided Methods§

Source

fn set_if_absent<'life0, 'life1, 'async_trait>( &'life0 self, _key: &'life1 str, _value: Vec<u8>, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Atomically create a nonexpiring entry only when no live entry exists.

Args: key: Entry identity. value: Opaque value to store on successful creation.

Returns: Whether this call created the entry. Backends without atomic insertion report a capability error; RouteCache then bypasses.

Source

fn set_if_absent_with_ttl<'life0, 'life1, 'async_trait>( &'life0 self, _key: &'life1 str, _value: Vec<u8>, _ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Atomically create an expiring entry only when no live entry exists.

The liveness check, insertion and expiry deadline are one atomic step. An existing entry that has already expired counts as absent and is replaced. A losing creator leaves the winner’s value and deadline untouched.

TTL granularity is one millisecond. A ttl that is not a whole number of milliseconds is rounded up, so a sub-millisecond TTL lives for one millisecond and an entry never expires earlier than requested. A zero ttl is rejected rather than treated as “already expired”, because an entry that cannot be observed is never useful as a marker and several stores treat zero as “no expiry”.

Args: key: Entry identity. value: Opaque value to store on successful creation. ttl: Positive lifetime, rounded up to whole milliseconds.

Returns: Whether this call created the entry.

§Errors

CacheError::InvalidTtl for a zero ttl or one above the portable limit (i64::MAX / 2 milliseconds), never clamped, checked before the key is examined. CacheError::SizeLimit when the entry is refused by byte admission. CacheError::Unsupported from the default implementation: backends that cannot create and expire atomically must keep it, not emulate it.

Source

fn increment_with_expiry<'life0, 'life1, 'async_trait>( &'life0 self, _key: &'life1 str, _by: i64, _ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Atomically add by to a counter and give it an expiry when it has none.

A missing or expired key starts at 0. The increment and the expiry are one indivisible step: a key that exists without a deadline (including one created by this call) receives ttl, while a key that already has a deadline keeps it. Separate increment and expiry calls are not equivalent: if the key expires or is evicted between them, INCRBY recreates it without a TTL, a permanent counter. ttl follows the rules of set_if_absent_with_ttl: rounded up to whole milliseconds, zero and values above i64::MAX / 2 milliseconds rejected.

Returns: The counter value after the increment.

§Errors

CacheError::InvalidTtl, CacheError::NotInteger, and CacheError::Unsupported from the default implementation: backends that cannot do this atomically must keep it. RouteCache uses it for its admission budget and, when unsupported, bypasses.

Source

fn admit_marker<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, req: &'life1 AdmitMarker<'life2>, ) -> Pin<Box<dyn Future<Output = Result<Admission, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Admit a route-cache generation marker (provided; overriding is an optimisation, never a requirement).

The default runs the generic sequence from the primitives above: create the marker with set_if_absent_with_ttl, count it with increment_with_expiry only when this call created it, delete it again when over budget, then compare the epoch. An adapter lacking either primitive therefore fails with CacheError::Unsupported before any budget is spent and without leaving a marker behind. Backends that can do the whole thing atomically (the bundled ones) override it: one lock for MemoryCache, one server-side script for Redis, whose window follows the server clock. See docs/CACHE.md.

§Errors

Backend failures, and CacheError::Unsupported from the defaults of the primitives.

Source

fn invalidate_marker<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, marker: &'life1 str, epoch_key: &'life2 str, epoch: &'life3 [u8], ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Replace the invalidation epoch and delete a marker (provided).

The default does set with ttl, then delete. Backends override it to make the pair one atomic backend call (the bundled ones do).

§Errors

Backend failures.

Dyn Compatibility§

This trait is dyn compatible.

In older versions of Rust, dyn compatibility was called "object safety".

Implementations on Foreign Types§

Source§

impl<T: Cache + ?Sized> Cache for Arc<T>

Source§

fn get<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<Option<Vec<u8>>, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn set<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, value: Vec<u8>, ttl: Option<Duration>, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn set_if_absent<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, value: Vec<u8>, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn set_if_absent_with_ttl<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, value: Vec<u8>, ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn delete<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<bool, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn increment<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, by: i64, ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn clear<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Source§

fn increment_with_expiry<'life0, 'life1, 'async_trait>( &'life0 self, key: &'life1 str, by: i64, ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<i64, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Source§

fn admit_marker<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, req: &'life1 AdmitMarker<'life2>, ) -> Pin<Box<dyn Future<Output = Result<Admission, CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Source§

fn invalidate_marker<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, marker: &'life1 str, epoch_key: &'life2 str, epoch: &'life3 [u8], ttl: Duration, ) -> Pin<Box<dyn Future<Output = Result<(), CacheError>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Implementors§