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§
Sourcefn 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 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.
Sourcefn 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 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.
Sourcefn 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 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.
Sourcefn 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 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.
Provided Methods§
Sourcefn 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<'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.
Sourcefn 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 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.
Sourcefn 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 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.
Sourcefn 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 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.
Sourcefn 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,
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".