Add per item access count#6
Open
fsdvh wants to merge 20 commits into
Open
Conversation
### Summary
- Adds `try_read` / `try_write` to the internal `RwLock` wrapper, normalizing
`WouldBlock` to `None` and panicking on poison (matching the blocking variants' behavior).
- Introduces a `LockContention` error type returned by all non-blocking operations
when the target shard lock cannot be acquired immediately.
- Adds non-blocking counterparts for all major cache operations on `Cache`:
- `try_contains_key` — returns `Result<bool, LockContention>`
- `try_get` — returns `Result<Option<Val>, LockContention>`
- `try_peek` — returns `Result<Option<Val>, LockContention>`
- `try_remove` — returns `Result<Option<(Key, Val)>, LockContention>`
- `try_insert` / `try_insert_with_lifecycle` — returns `Result<(), (Key, Val)>` /
`Result<L::RequestState, (Key, Val)>` (key+value returned on contention so the
caller can retry or discard)
- All read-path methods return `Err(LockContention)` on contention; write-path insert
methods return `Err((key, val))` so the caller can retry or discard without losing data.
* extend lifecycle trait with on_evict_(cold|hot) * default impl for on_evict * Address Copilot review on PR arthurprs#117 - Fix hot/cold misclassification in handle_insert_overweight: capture the evicted entry's ResidentState before remove_internal so cold evictions aren't reported as hot. - Reword on_evict deprecation note to accurately describe per-method fallback (each new method delegates to on_evict independently). - Document rejection-style behavior on on_evict_hot: items that never enter the cache (oversized inserts and oversized placeholder values) are reported as hot. - Migrate DefaultLifecycle (sync and unsync) and the eviction_listener example to implement on_evict_hot/on_evict_cold directly. * Lifecycle: drop on_evict deprecation; route overweight rejections to cold - on_evict stays as a provided method with an empty default body (no deprecation). on_evict_hot/on_evict_cold default to delegating to it, so existing impls keep working and new impls can override just the hot/cold methods when they want to distinguish. - Route oversized inserts and oversized placeholder rejections through on_evict_cold (they never entered any queue). - Revert DefaultLifecycle (sync/unsync) and the eviction_listener example to the simple on_evict form. * Cross-reference rejection routing on on_evict and on_evict_hot docs --------- Co-authored-by: Deniz <DenizUgur@users.noreply.github.com> Co-authored-by: Arthur Silva <arthurprs@gmail.com>
* fix: memory leak in dropping uninserted guard * fix * Add regression tests for placeholder slot reuse on guard drop Cover the two documented cases where a placeholder is removed/replaced while a guard is still outstanding (overwrite insert, and remove + slot reuse). Both panicked under the original unconditional entries.remove and pass with the fix that only frees the slot when the placeholder is still present. --------- Co-authored-by: Arthur Silva <arthurprs@gmail.com>
`std::mem::size_of` was only added to the prelude in Rust 1.80, but the declared MSRV is 1.71. It was used unqualified in linked_slab.rs, breaking builds for downstream crates on Rust < 1.80. Qualify the call as `std::mem::size_of` (matching shard.rs) and add an `msrv` CI job that runs `cargo msrv verify` so this regression is caught in the future. Fixes arthurprs#118
reserve() only grew the hash table, not the LinkedSlab Vec that holds the actual entries. Under a large insert burst, that Vec doubled and memcpy'd hundreds of MB while the shard write lock was held, stalling all concurrent readers on that shard (issue arthurprs#119). Now reserve() also pre-allocates the slab, sized for the requested entries plus the bounded ghost-key space (capacity_non_resident) instead of a fixed 50% guess.
The previous reserve() unconditionally added the full per-shard capacity_non_resident as ghost headroom. On a cache with a large estimated_items_capacity, a small reserve(n) call would then allocate the entire ghost cap (potentially gigabytes), not space for n entries. Cap the ghost term at additional: n insertions evict at most n residents into ghosts, and ghosts are also bounded by capacity_non_resident, so min(additional, capacity_non_resident) is the true upper bound. Full pre-loads (additional >= cap) are unchanged; small reserves no longer over-allocate.
…rthurprs#124) * Reshape lifecycle API: Default-built RequestState threaded by &mut BREAKING (0.7.0). Collapses the growing per-operation variant cross-product. - `Lifecycle::RequestState` now requires `Default`; `begin_request` and `end_request` are removed. State is built via `Default` and finalized by its own `Drop` (which releases evicted items outside the shard lock). - The `*_with_lifecycle` methods now take `&mut L::RequestState` (returning `()` / `Result<(), _>`) instead of returning the state, so one state can be threaded through several ops to batch eviction work or inspect evicted items. This supersedes the `_with_state` proposal in arthurprs#122. - Drops the now-vestigial `&L` plumbing from the placeholder machinery and the unused `Cache::lifecycle` field; shards keep their own clones for the hooks. * Drop RequestState outside the lock in set_capacity set_capacity created and dropped its own RequestState inside the shard method, so when called via Cache::set_capacity (shard.write().set_capacity) the evicted items were released while the write lock was still held — contradicting the documented Drop-after-lock contract. Take &mut lcs from the caller instead, so it drops after the lock guard. Also use Default::default() consistently instead of L::RequestState::default(). * Document lcs/lock drop ordering in set_capacity
…s, document stats overhead
- Fold record_item_hit{,_mut} into arity-overloaded record_hit{,_mut}
arms so each resident hit-site records both counters in one call.
- Re-enable entry_overhead under the stats feature; assert the real
per-cache sizes (sync unchanged, unsync +8 via discriminant niche).
- Document the stats feature's per-entry size and per-hit/miss cost.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.