# `AshCache.CacheVersion`
[🔗](https://github.com/Undeadlol1/ash_cache/blob/v0.1.0/lib/ash_cache/cache_version.ex#L1)

Per-resource cache version counter, stored in the same store
as the cached entries.

Every cache key embeds the resource's current cache version, so bumping the
counter makes every previously cached entry unreachable in O(1) — the
invalidation strategy for writes. Orphaned entries age out via their TTL.

The one rule everything here follows: **a cache version value is used once
and never comes back.** Old entries can only be reached again through
their old cache version, so as long as no old value returns, no old entry
does — whatever the store loses, evicts or restarts.

Every value is 128 random bits, never a count. A count read-then-incremented
would let two writers both write N+1, and a reader that derived its key
between their commits could cache data missing the second write under a
cache version that never changes again. A count, or a node-local unique
integer, also starts over: after a node restart against a store that
outlived it (Redis), or after the store lost the counter. Random values
repeat neither.

A missing counter — a fresh store, or one that lost it to eviction, a
restart, or a server leaving a distributed cache — is therefore not zero
but a brand-new value, written back so later reads share it. Two readers
finding it missing at once on one server share one new value (see
`AshCache.Coalesce`); on two servers each may write its own, the last write
wins and the other's entries are merely wasted. Neither is an old value.

A bump writes a new value. If the store refuses, the bump deletes the
counter instead, which makes the next read pick a new value; only when the
store refuses both does the bump report an error. A store *error* on read
answers a fresh value that is never written, so every key misses while the
store is unhealthy — a burst of reads, never stale data.

The counter is still stored with `never_evict: true` and `ttl: :infinity`, so a
store that drops entries to stay within a bound keeps it: losing it is
safe, but costs every cached read of the resource.

# `bump`

```elixir
@spec bump(atom(), module()) :: :ok | {:error, term()}
```

# `current`

```elixir
@spec current(atom(), module()) :: term()
```

An opaque value: equal between two calls only while no write happened in between.

# `for_key`

```elixir
@spec for_key(atom(), module(), [module()]) :: term()
```

The version part of a cache key: the resource's own version, plus the
version of each resource in its `clear_when_changed` list. A write to a
listed resource changes that resource's version, in its own store, so
keying on it clears this resource's entries too.

---

*Consult [api-reference.md](api-reference.md) for complete listing*
