You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
- remove the inherent `ttl`/`set_ttl`/`unset_ttl`/`refresh_on_hit`/`set_refresh_on_hit`
on `ShardedTtlCacheBase`/`ShardedLruTtlCacheBase`; the runtime TTL controls live only
on `ConcurrentCacheTtl`, matching the redis/redb stores and the single-owner `CacheTtl`
- add `per_shard_initial_capacity` to `ShardedUnboundCacheBuilder`,
`ShardedTtlCacheBuilder`, and `ShardedExpiringCacheBuilder` (per-shard preallocation
hint, counterpart of the single-owner `initial_capacity`)
- add `ExpiringLruCache::retain`, matching `LruTtlCache::retain`; document the shared
retain contract (LRU iteration, expired entries removed regardless of the predicate,
survivor recency preserved) on all three LRU stores
- document that `set_max_size` shrinks evict strictly by LRU recency, ignoring TTL/expiry
state (rustdoc, CHANGELOG, migration guide)
- migration guide: cover the `disk_directory` -> `disk_dir` builder rename and the
sharded TTL-control trait move; add both to the VERIFY error index
- register the `resilience` example in Cargo.toml with required-features; fix its header
run command to the minimal feature set
- CHANGELOG: `RedbCacheBuildError` keeps a derived `Debug` (drop it from the
manual-impl claim)
- lib.rs: use the compiling `dyn ConcurrentCached<K, V, Error = E>` form in the
`cache_get_or_set_with` doc
- tests: cover all inert `sync_writes_buckets` modes in the ui test; add
concurrent-resize stress tests for `ShardedLruTtlCache` and `ShardedExpiringLruCache`;
pin the new builder hint and retain behavior
- specs: mark design 0022/0026 implemented; record the sharded trait matrix, runtime
resize, and buckets guard; correct the redb builder and trait enumerations
Copy file name to clipboardExpand all lines: CHANGELOG.md
+6-3Lines changed: 6 additions & 3 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -5,11 +5,14 @@
5
5
### Breaking Changes
6
6
7
7
-`#[cached]` rejects an explicit `sync_writes_buckets` when `sync_writes` is not `"by_key"` with a pointed compile error. The value was previously accepted and silently ignored (buckets only exist on the `by_key` path); `#[once]` already rejected the same inert combination.
8
-
-`RedbCacheBuilder::disk_directory` renamed to `disk_dir`, matching the `disk_dir` attribute on `#[concurrent_cached]`. Breaking only vs the 3.0 rcs (the method did not exist in 2.x under either name).
8
+
-`RedbCacheBuilder::disk_directory` renamed to `disk_dir`, matching the `disk_dir` attribute on `#[concurrent_cached]`. The 2.x builder method was `DiskCacheBuilder::disk_directory`; see the [migration guide](docs/migrations/2.0-to-3.0.md#69-disk_directory-builder-method-renamed-to-disk_dir).
9
+
- The inherent `ttl` / `set_ttl` / `unset_ttl` / `refresh_on_hit` / `set_refresh_on_hit` methods on `ShardedTtlCacheBase` / `ShardedLruTtlCacheBase` are removed; the runtime TTL controls live only on `ConcurrentCacheTtl` (same names and signatures, still `&self`). This makes the concurrent family uniform: `RedisCache`, `AsyncRedisCache`, and `RedbCache` already exposed them only through the trait, and the single-owner stores went through the same change for `CacheTtl` in rc.1. Builder setters are unaffected. Import the trait (or `cached::prelude::*`) at call sites; see the [migration guide](docs/migrations/2.0-to-3.0.md#70-sharded-ttl-stores-inherent-ttlset_ttlunset_ttlrefresh_on_hitset_refresh_on_hit-removed-use-concurrentcachettl).
9
10
10
11
### Added
11
12
12
-
-`ShardedLruCacheBase`, `ShardedLruTtlCacheBase`, and `ShardedExpiringLruCacheBase` (and their default-hasher aliases) now support runtime capacity resizing via `set_max_size(&self, usize) -> Option<usize>` and `try_set_max_size(&self, usize) -> Result<Option<usize>, SetMaxSizeError>`. Shrinking evicts LRU-excess entries per shard, fires `on_evict`, and increments the eviction counter; the same ceiling-division-plus-16-per-shard-floor policy the builders use is applied; resize is not atomic across shards (matches the documented `set_ttl` behavior).
13
+
-`ShardedLruCacheBase`, `ShardedLruTtlCacheBase`, and `ShardedExpiringLruCacheBase` (and their default-hasher aliases) now support runtime capacity resizing via `set_max_size(&self, usize) -> Option<usize>` and `try_set_max_size(&self, usize) -> Result<Option<usize>, SetMaxSizeError>`. Shrinking evicts LRU-excess entries per shard strictly by recency (expired-but-recent entries survive a shrink; only `evict()` sweeps by TTL/expiry), fires `on_evict`, and increments the eviction counter; the same ceiling-division-plus-16-per-shard-floor policy the builders use is applied; resize is not atomic across shards (matches the documented `set_ttl` behavior).
14
+
-`per_shard_initial_capacity` on `ShardedUnboundCacheBuilder`, `ShardedTtlCacheBuilder`, and `ShardedExpiringCacheBuilder`: a per-shard preallocation hint, the sharded counterpart of the single-owner builders' `initial_capacity` (total preallocation is `shards x per_shard_initial_capacity`).
15
+
-`ExpiringLruCache::retain(keep)`: removes entries that are expired or fail the predicate, firing `on_evict` and counting evictions, matching `LruTtlCache::retain`. The `retain` docs on all three LRU stores now spell out the shared contract: iteration is over the LRU entries, expired entries are removed without consulting the predicate (expiry-aware stores only), and survivor recency order is unchanged.
13
16
- New runnable example `examples/resilience.rs` covering `sync_writes = "by_key"`, `result_fallback`, and `force_refresh`.
14
17
15
18
### Changed
@@ -46,7 +49,7 @@
46
49
-`RedbCache` default-directory resolution self-heals a pre-existing cache directory with legacy permissions. A directory created by an earlier `cached` version was created with the process umask (0775 under the umask-002 user-private-group default of Debian/Ubuntu) and permanently failed the security validation with "I/O error preparing the disk cache directory"; the app-derived candidate is now tightened to 0700 and re-validated (the chmod only succeeds for the owner, so an attacker-owned or symlinked directory still falls through to the next candidate instead of aborting).
47
50
-`ShardedExpiringLruCache::cache_set` evaluates the displaced entry's `is_expired()` exactly once, under the shard write lock. It previously evaluated twice (once inside the lock for the eviction counter, once outside for `on_evict` and the return value), so a value crossing the expiry threshold between the two calls fired `on_evict` without counting the eviction. The other sharded expiring stores already evaluated once.
48
51
-`RedisCacheBuildError::MissingConnectionString` redacts the env-var value carried by `std::env::VarError::NotUnicode`. The raw value is the connection string itself (credentials included) and was printed by both `Display` and `Debug`.
-`RedisCacheBuildError` uses a manual `Debug` impl, matching `RedisCacheError` / `RedbCacheError`(`RedbCacheBuildError` keeps its derived `Debug`; it carries no redactable value).
50
53
-`make examples` actually runs the registered examples again: the per-example targets are `.PHONY`, and make skips implicit-rule search for phony targets, so the `examples/basic/%` / `examples/redis/%` pattern rules silently expanded to nothing and only the two explicitly-ruled examples (`wasm`, `redis-async-async-std`) ran. The rules are now static pattern rules, `expires_per_key` and `struct_method` are registered, and the expansion guard checks every registered example expands to its own run command.
Copy file name to clipboardExpand all lines: docs/migrations/2.0-to-3.0.md
+44-1Lines changed: 44 additions & 1 deletion
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -1035,7 +1035,9 @@ in a hot path), recreate the cache with the same builder settings instead of cal
1035
1035
-`ConcurrentCloneCached::cache_peek_with_expiry_status` (and the `CloneCached` equivalent) — a read that returns the cached value along with its expiry status without renewing the TTL, updating LRU recency, or incrementing hit/miss counters. This is now a *required* method (see breaking change #16); the built-in sharded and in-memory expiry stores implement it with a genuine side-effect-free read.
1036
1036
-`in_impl = true` macro attribute — cache a method inside an `impl` block (the cache static is emitted in the method body); a `self` receiver is allowed and excluded from the key. The `_prime_cache` companion is not generated for `in_impl` methods.
1037
1037
-`LruCache::set_max_size` / `try_set_max_size`, `LruTtlCache::set_max_size` / `try_set_max_size`, `ExpiringLruCache::set_max_size` / `try_set_max_size` — resize a live LRU-backed cache (evicts LRU entries when shrinking). All three `try_set_max_size` methods return `Result<Option<usize>, cached::SetMaxSizeError>` where the inner value is the previous bound (same shape as `set_max_size`; `ZeroSize` on a zero argument).
1038
-
-`ShardedLruCache::set_max_size` / `try_set_max_size`, `ShardedLruTtlCache::set_max_size` / `try_set_max_size`, `ShardedExpiringLruCache::set_max_size` / `try_set_max_size` (and the `*Base` generic forms) — runtime capacity resize on the sharded LRU stores. Shrinking evicts LRU-excess entries per shard, fires `on_evict`, and increments the eviction counter; the same ceiling-division-plus-16-per-shard-floor policy the builders use is applied. Resize is not atomic across shards (matches the documented `set_ttl` behavior). Return type matches the non-sharded `set_max_size` / `try_set_max_size`.
1038
+
-`ShardedLruCache::set_max_size` / `try_set_max_size`, `ShardedLruTtlCache::set_max_size` / `try_set_max_size`, `ShardedExpiringLruCache::set_max_size` / `try_set_max_size` (and the `*Base` generic forms) — runtime capacity resize on the sharded LRU stores. Shrinking evicts LRU-excess entries per shard strictly by recency (TTL/expiry state is ignored; call `evict()` first to sweep expired entries preferentially), fires `on_evict`, and increments the eviction counter; the same ceiling-division-plus-16-per-shard-floor policy the builders use is applied. Resize is not atomic across shards (matches the documented `set_ttl` behavior). Return type matches the non-sharded `set_max_size` / `try_set_max_size`.
1039
+
-`per_shard_initial_capacity(n)` on `ShardedUnboundCacheBuilder`, `ShardedTtlCacheBuilder`, and `ShardedExpiringCacheBuilder` — per-shard preallocation hint, the sharded counterpart of the single-owner builders' `initial_capacity` (total preallocation is `shards * per_shard_initial_capacity`). The LRU-bounded sharded builders size their shards from `max_size` / `per_shard_max_size` and do not take a separate hint.
1040
+
-`ExpiringLruCache::retain(keep)` — removes entries that are expired or fail the predicate, firing `on_evict` and counting evictions; matches `LruTtlCache::retain`. `LruCache::retain` (no expiry dimension) removes solely on the predicate.
1039
1041
-`RedisCache` / `AsyncRedisCache` now implement `cache_clear` / `async_cache_clear` (namespace-scoped `SCAN` + `DEL`); `cache_reset` / `async_cache_reset` delegate to them (redis tracks no in-memory metrics).
1040
1042
- Reference arguments (`&T`, `Option<&T>`) now form the default macro key without a `convert`.
1041
1043
-`Expires::expires_at(&self) -> Option<cached::time::Instant>` -- default trait method returning the value's expiry instant when tracked (`None` by default / when unknown). Advisory/observability only; `is_expired()` remains the authoritative liveness check. Existing `impl Expires` blocks (which provide only `is_expired`) get the default for free. The instant type is the crate's `time::Instant` (`web_time` on wasm, `std` elsewhere), not `std::time::Instant`; a custom override must use that type.
### 70. Sharded TTL stores: inherent `ttl`/`set_ttl`/`unset_ttl`/`refresh_on_hit`/`set_refresh_on_hit` removed; use `ConcurrentCacheTtl`
1487
+
1488
+
The runtime TTL controls on the sharded TTL-capable stores (`ShardedTtlCache`,
1489
+
`ShardedLruTtlCache` and their `*Base` forms) are no longer inherent methods; they live only on
1490
+
the [`ConcurrentCacheTtl`] trait (same names, same signatures, still `&self`). This makes the
1491
+
concurrent family uniform: `RedisCache`, `AsyncRedisCache`, and `RedbCache` already exposed
1492
+
these controls only through `ConcurrentCacheTtl`. The single-owner counterpart is #20
1493
+
(`TtlCache` / `LruTtlCache` via `CacheTtl`). Builder setters (`.ttl(...)`,
1494
+
`.refresh_on_hit(...)`) are unaffected.
1495
+
1496
+
Detection: `no method named set_ttl` (or `ttl`/`unset_ttl`/`refresh_on_hit`/`set_refresh_on_hit`)
1497
+
`found for struct ShardedTtlCacheBase`/`ShardedLruTtlCacheBase` -- the compiler suggests the
1498
+
trait import.
1499
+
1500
+
Action:
1501
+
```rust
1502
+
// Before -- inherent methods, no import needed
1503
+
cache.set_ttl(Duration::from_secs(30));
1504
+
// After -- same call, trait must be in scope
1505
+
usecached::ConcurrentCacheTtl; // or `use cached::prelude::*;`
1506
+
cache.set_ttl(Duration::from_secs(30));
1507
+
```
1508
+
1468
1509
## Required Cargo.toml change
1469
1510
1470
1511
```toml
@@ -1535,4 +1576,6 @@ has a breaking change this major, see #51).
1535
1576
- a `match` arm on `RedisCacheBuildError::Build(BuildError::MissingRequired(..))` for `"ttl"` is now unreachable → remove the arm; set `.ttl(Duration)` explicitly if you need expiry (#65).
1536
1577
- a `#[concurrent_cached(disk = true, cache_prefix_block = ...)]` annotation that previously compiled → remove `cache_prefix_block`; disk stores key by redb table name, set via `name = "..."` (#66).
1537
1578
-`` `sync_writes_buckets` only applies to `sync_writes = "by_key"` `` → add `sync_writes = "by_key"` to opt into per-key locking, or remove `sync_writes_buckets` to keep no-synchronization behavior (#68).
1579
+
-`no method named disk_directory` on a `RedbCacheBuilder` → renamed to `disk_dir` (#69).
1580
+
-`no method named set_ttl`/`ttl`/`unset_ttl`/`refresh_on_hit`/`set_refresh_on_hit` on a `ShardedTtlCache`/`ShardedLruTtlCache` value → `use cached::ConcurrentCacheTtl;` or the prelude (#70).
1538
1581
-`cargo test` — no behavior changes beyond the above; disk caches will be empty on first run after upgrade (format change). The default `#[cached]` write behavior is unchanged from 2.x (no synchronization); `sync_writes = "by_key"` is an opt-in (#39).
0 commit comments