pub struct TaggedCache<C: CacheStore> { /* private fields */ }Expand description
Cache with tag-based invalidation support.
The tag -> member-key index (and its reverse, key -> tags) is persisted in
the backing CacheStore itself under reserved keys — it is NOT kept in
a local, per-process map. That means the index is visible to every
instance sharing the same backing store (e.g. every app process pointed at
the same Redis), so a key tagged by one instance can be looked up and
invalidated by another.
§Atomicity caveat (concurrent race)
Index updates go through CacheStore::set_add / CacheStore::set_remove /
CacheStore::set_members. Only backends that override these with a
native set type — RedisCache does, via SADD/SREM/SMEMBERS — update
the index atomically (see CacheStore::supports_atomic_sets). Other
backends (e.g. InMemoryCache, MemcachedCache) fall back to the
trait’s default, non-atomic read-modify-write, so concurrent
set_with_tags/invalidate_tag calls against the SAME tag from
different instances can race and lose an update. For distributed
deployments, wrap a RedisCache (or another backend that overrides the
set primitives) if you need that guarantee. Self::new logs a warning
once, at construction time, when the backing store doesn’t support
atomic sets.
§Partial-failure caveat (sequential, non-transactional updates)
Separately from the concurrent-race caveat above: Self::set_with_tags,
Self::delete, and Self::invalidate_tags each issue several
independent set_add/set_remove/delete calls in sequence. If an
early call in one of these sequences succeeds and a later one fails, the
tag index (and its reverse index) can end up partially updated —
inconsistent with the cached value, or inconsistent with itself (e.g. a
key’s reverse-index tag set can end up not matching the forward tag ->
keys sets it’s actually a member of). There is currently no automatic
rollback or reconciliation for this case: a failed call may need to be
retried or the affected tag(s)/key(s) reconciled manually. A best-effort
warning is logged when this happens (see the calls guarded by
warn_on_partial_failure in the implementation) so operators at least
get a signal, but the index itself is not repaired automatically.
§Reserved key namespace
The tag index’s bookkeeping keys (tag_set_key/key_tags_set_key/
TAG_INDEX_KEY) all begin with the reserved prefix
"__armature_" and live in the SAME keyspace as caller-supplied keys —
both go through the same backing CacheStore, with only key_prefix
(from CacheConfig) applied identically to both. A caller-supplied key
that happens to start with "__armature_" would therefore collide with
this reserved bookkeeping keyspace (e.g. writing to
__armature_tag__:users would clobber the “users” tag’s member set).
This prefix is forbidden for caller-supplied keys: Self::set_with_tags,
Self::get, and Self::delete all reject a key starting with
"__armature_" with a CacheError::Config, rather than silently
allowing the collision.
Implementations§
Source§impl<C: CacheStore> TaggedCache<C>
impl<C: CacheStore> TaggedCache<C>
Sourcepub fn new(cache: Arc<C>) -> Self
pub fn new(cache: Arc<C>) -> Self
Create new tagged cache
Checks CacheStore::supports_atomic_sets on cache and logs a
warning once, here at construction time, when the backing store does
NOT support atomic sets — see the struct-level “Atomicity caveat”
docs for what that means for concurrent tag-index updates.
§Examples
use armature_cache::*;
let cache = RedisCache::new(config).await?;
let tagged = TaggedCache::new(Arc::new(cache));Sourcepub async fn delete(&self, key: &str) -> CacheResult<()>
pub async fn delete(&self, key: &str) -> CacheResult<()>
Delete a specific key
Sourcepub async fn invalidate_tag(&self, tag: &str) -> CacheResult<()>
pub async fn invalidate_tag(&self, tag: &str) -> CacheResult<()>
Sourcepub async fn get_keys_by_tag(&self, tag: &str) -> CacheResult<Vec<String>>
pub async fn get_keys_by_tag(&self, tag: &str) -> CacheResult<Vec<String>>
Get all keys with a specific tag
Get all tags for a specific key
Get all registered tags (tags currently carrying at least one member).