Skip to content

Add entry/entry_async API for atomic cache access#109

Open
arthurprs wants to merge 1 commit intomasterfrom
entry-api
Open

Add entry/entry_async API for atomic cache access#109
arthurprs wants to merge 1 commit intomasterfrom
entry-api

Conversation

@arthurprs
Copy link
Owner

@arthurprs arthurprs commented Mar 12, 2026

Add entry() / entry_async() methods that take a FnOnce(&Key, &mut Val) -> EntryAction<T> closure for atomic inspect-and-act patterns under a write lock, with weight recalculation on Retain.

  • EntryAction<T> enum: Retain(T), Remove, ReplaceWithGuard
  • EntryResult<T> enum: Retained(T), Removed(K, V), Replaced(PlaceholderGuard, V), Vacant(PlaceholderGuard), Timeout
  • Placeholder deduplication: concurrent callers for the same key wait (blocking or async) and retry with the loaded value
  • Panic-safe weight accounting via WeightGuard drop guard

Closes #73, closes #77

@arthurprs arthurprs force-pushed the entry-api branch 5 times, most recently from d836942 to d6a388f Compare March 13, 2026 15:19
@arthurprs arthurprs requested a review from Copilot March 13, 2026 15:24
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new closure-based “inspect and act” entry API to the cache, enabling atomic keep/remove/replace decisions for existing entries while preserving placeholder-based single-loader semantics (sync + async), addressing the upsert/replace use cases in #73 and #77.

Changes:

  • Introduces entry/entry_async (read-lock fast path) and entry_mut/entry_mut_async (write-lock, in-place mutation + weight recalculation) returning EntryResult.
  • Adds shard support for entry_or_placeholder, get_key_value, and renames placeholder upsert helper to get_or_placeholder.
  • Expands documentation and adds extensive unit + shuttle concurrency tests for the new APIs.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
src/sync.rs Adds new entry APIs (sync + async) and many tests exercising actions, placeholder waiting, and timeouts
src/shard.rs Adds shard-level EntryOrPlaceholder, entry_or_placeholder, and get_key_value helper; renames placeholder helper
src/sync_placeholder.rs Adds OccupiedAction/EntryResult, refactors placeholder join logic, and exposes wait_for_placeholder for reuse
src/unsync.rs Updates to renamed shard placeholder helper and fixes docstrings
src/shuttle_tests.rs Adds shuttle stress/race tests covering new entry APIs
src/lib.rs Documents the new entry API family in crate-level docs and fixes wording
src/options.rs Fixes doc typo (OptionOptions)
README.md Documents entry/entry_mut API and fixes minor wording

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +323 to +326
let start = *timeout_start.get_or_insert_with(Instant::now);
#[cfg(not(fuzzing))]
thread::park_timeout(remaining);
timeout = Some(remaining.saturating_sub(start.elapsed()));
*timeout = Some(remaining.saturating_sub(start.elapsed()));
src/sync.rs Outdated
Comment on lines +574 to +589
// Read-lock fast path: if key exists and callback returns Keep, we're done
// without ever taking a write lock.
{
let shard_guard = shard.read();
if let Some((k, v)) = shard_guard.get_key_value(hash, key) {
match on_occupied(k, v) {
OccupiedAction::Keep(t) => return EntryResult::Value(t),
OccupiedAction::Remove | OccupiedAction::Replace => {
// Need write lock — fall through
}
}
}
}

// Write-lock path: re-call callback for authoritative decision, or handle
// vacant/placeholder cases.
src/sync.rs Outdated
Comment on lines +640 to +647
{
let shard_guard = shard.read();
if let Some((k, v)) = shard_guard.get_key_value(hash, key) {
match on_occupied(k, v) {
OccupiedAction::Keep(t) => return EntryResult::Value(t),
OccupiedAction::Remove | OccupiedAction::Replace => {}
}
}
src/shard.rs Outdated
Comment on lines +1195 to +1201
// Create placeholder in the same slot
let shared = Plh::new(hash, idx);
let (entry, _) = self.entries.get_mut(idx).unwrap();
*entry = Entry::Placeholder(Placeholder {
key: key.to_owned(),
hot: state,
shared: shared.clone(),
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds new entry/entry_mut (and async variants) to the sync cache, enabling atomic “inspect-and-act” operations on existing entries (keep/remove/replace) while preserving placeholder-based single-loader deduplication on misses.

Changes:

  • Introduces entry() / entry_async() with a read-lock “Keep” fast path and write-lock fallback for Remove/Replace.
  • Introduces entry_mut() / entry_mut_async() for in-place mutation under a write lock with post-callback weight recalculation.
  • Adds shard-level support (get_key_value, entry_or_placeholder) and expands docs/tests (including Shuttle concurrency tests) to cover the new API.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/sync.rs Adds the public entry* APIs, exports new enums, and adds extensive unit tests.
src/sync_placeholder.rs Adds EntryResult/OccupiedAction types and factors out placeholder waiting logic for reuse by entry*.
src/shard.rs Adds get_key_value, renames placeholder helper, and implements entry_or_placeholder to support entry*.
src/unsync.rs Updates unsync code to use renamed placeholder helper.
src/shuttle_tests.rs Adds Shuttle concurrency tests covering entry_mut* and related wakeup races.
src/lib.rs Documentation updates referencing the new entry APIs and minor wording fixes.
src/options.rs Fixes a docstring typo (“Option” → “Options”).
README.md Documents the new entry / entry_mut API with an example and minor typo fix.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines 318 to 327
loop {
if let Some(remaining) = timeout {
if let Some(remaining) = *timeout {
if remaining.is_zero() {
return Self::join_timeout(lifecycle, shard, shared, parked_thread, &notified);
}
let start = *timeout_start.get_or_insert_with(Instant::now);
let start = Instant::now();
#[cfg(not(fuzzing))]
thread::park_timeout(remaining);
timeout = Some(remaining.saturating_sub(start.elapsed()));
*timeout = Some(remaining.saturating_sub(start.elapsed()));
} else {
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new closure-based entry / entry_mut API to the concurrent cache to support atomic “inspect-and-act” operations (keep/remove/replace) while preserving placeholder-based deduplication for cache misses and concurrent loaders.

Changes:

  • Added entry / entry_async (read-lock fast path for Keep) and entry_mut / entry_mut_async (in-place mutation under write lock with weight recalculation).
  • Introduced OccupiedAction<T> and EntryResult<T> enums and extended placeholder waiting to support timeout propagation across retries.
  • Refactored shard placeholder acquisition (get_or_placeholder) and added get_key_value plus extensive sync + shuttle concurrency tests and docs/README updates.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
src/sync.rs Adds the new public entry* APIs, wires them into shard/placeholder logic, and adds comprehensive tests.
src/sync_placeholder.rs Adds OccupiedAction/EntryResult, extends GuardResult, and refactors placeholder waiting with deadline reuse.
src/shard.rs Adds get_key_value, renames placeholder upsert to get_or_placeholder, and introduces entry_or_placeholder shard primitive.
src/unsync.rs Updates unsync placeholder acquisition to use the renamed shard API.
src/shuttle_tests.rs Adds shuttle-based concurrency tests for the new entry APIs (sync + async).
src/lib.rs Updates crate-level docs to mention the new entry APIs and fixes minor wording.
src/options.rs Minor doc comment correction.
README.md Documents the new entry API with an example and fixes minor wording.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new closure-based “inspect-and-act” entry API to the synchronous cache to enable atomic keep/remove/replace (and mutable in-place updates) while integrating with the existing placeholder/guard deduplication mechanism.

Changes:

  • Introduces entry / entry_async (shared ref callback with read-lock fast path) and entry_mut / entry_mut_async (mutable callback under write lock) plus OccupiedAction + EntryResult.
  • Refactors placeholder acquisition (upsert_placeholderget_or_placeholder) and adds shard helper get_key_value() to support the read-lock occupied fast path.
  • Expands tests substantially (including shuttle concurrency tests) and updates docs/README wording for the new API.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 3 comments.

Show a summary per file
File Description
src/sync.rs Implements new entry* APIs, integrates placeholder waiting/retry, and adds extensive unit + async tests.
src/shard.rs Adds OccupiedAction, EntryOrPlaceholder, entry_or_placeholder, and get_key_value() to support atomic entry operations.
src/sync_placeholder.rs Adds EntryResult, re-exports OccupiedAction, and updates placeholder wait logic to use a reusable deadline.
src/shuttle_tests.rs Adds shuttle tests for the new entry APIs and waker-change race coverage.
src/unsync.rs Updates unsync placeholder calls to the renamed get_or_placeholder API and fixes doc wording.
src/lib.rs Updates crate-level docs to mention the new entry API and fixes minor wording.
src/options.rs Fixes a doc typo (“Option” → “Options”).
README.md Mentions and demonstrates the new entry API; fixes minor wording.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@arthurprs arthurprs force-pushed the entry-api branch 3 times, most recently from 64522a3 to 3318018 Compare March 14, 2026 23:14
@arthurprs arthurprs requested a review from Copilot March 14, 2026 23:22
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds a new closure-based entry() / entry_async() API to the synchronous cache to support atomic inspect-and-act (keep/remove/replace) under a shard write lock, integrating with existing placeholder/guard deduplication for cache misses and concurrent loaders.

Changes:

  • Introduces Cache::entry / Cache::entry_async returning EntryResult, driven by OccupiedAction decisions made under a shard write lock.
  • Refactors placeholder join/wait logic (sync + async), including a !Unpin JoinFuture to safely store waiter notification pointers.
  • Updates shard internals to support entry-or-placeholder behavior and renames placeholder creation API (upsert_placeholderget_or_placeholder), plus doc/test updates.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/unsync.rs Renames placeholder API usage and fixes doc typos in the unsync cache.
src/sync_placeholder.rs Adds EntryResult/JoinResult, refactors join/wait mechanics, and makes JoinFuture pin-safe.
src/sync.rs Adds entry/entry_async, updates async guard behavior, adjusts re-exports, and adds extensive tests.
src/shuttle_tests.rs Adds Shuttle concurrency tests covering the new entry APIs and waker-change races.
src/shard.rs Adds OccupiedAction + shard-level entry_or_placeholder, introduces get_key_value, renames placeholder getter.
src/options.rs Fixes doc typo (OptionOptions).
src/lib.rs Updates crate-level docs to mention the new entry family and fixes wording.
README.md Documents the new entry API and fixes a wording typo in the example.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

@arthurprs arthurprs force-pushed the entry-api branch 3 times, most recently from c83ec93 to c249def Compare March 15, 2026 15:42
@arthurprs arthurprs requested a review from Copilot March 15, 2026 15:42
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR adds a new closure-based entry() / entry_async() API to the concurrent cache to support atomic inspect-and-act patterns under a shard write lock, integrating with the existing placeholder/guard mechanism for single-flight loading and adding tests/docs around the new behavior.

Changes:

  • Introduces EntryAction<T> / EntryResult<T> and implements Cache::entry + Cache::entry_async for atomic mutate/remove/replace-or-guard flows.
  • Refactors placeholder join/waiting code to support deduplication and async joining without cloning in the join future itself.
  • Updates docs/README and expands test coverage (including shuttle tests) for the new entry behavior and concurrency scenarios.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/unsync.rs Updates placeholder acquisition API name + minor doc fixes.
src/sync_placeholder.rs Adds EntryResult, refactors join/wait logic, makes join future !Unpin and internal.
src/sync.rs Exposes entry/entry_async, integrates placeholder waiting, adjusts exports.
src/shard.rs Adds EntryAction + shard-level entry_or_placeholder and weight guard logic.
src/shuttle_tests.rs Adds shuttle concurrency tests for entry/entry_async.
src/options.rs Fixes doc typo (OptionOptions).
src/lib.rs Documentation improvements mentioning entry API + typo fix.
README.md Documents new entry API and fixes typos.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

Comment on lines +1222 to +1226
let list_head = if state == ResidentState::Hot {
self.num_hot -= 1;
self.weight_hot -= old_weight;
&mut self.hot_head
} else {
src/sync.rs Outdated
pub use crate::sync_placeholder::{
EntryResult, GuardResult, EntryAction, PlaceholderGuard,
};
use crate::sync_placeholder::{JoinFuture, JoinResult};
@arthurprs arthurprs force-pushed the entry-api branch 3 times, most recently from d0e1fa6 to 55e7df7 Compare March 15, 2026 16:28
@arthurprs arthurprs requested a review from Copilot March 15, 2026 20:37
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new closure-based entry() / entry_async() API on the concurrent (sync) cache to support atomic “inspect-and-act” updates under a shard write lock, while preserving existing placeholder deduplication behavior and improving panic-safety for weight accounting.

Changes:

  • Add Cache::entry and Cache::entry_async with EntryAction/EntryResult to support retain/remove/replace-with-guard patterns.
  • Refactor placeholder join/wait logic (sync + async) to support retries and make async waiting pin-safe.
  • Adjust shard internals to support entry-or-placeholder operations and panic-safe weight recalculation; update docs/tests accordingly.

Reviewed changes

Copilot reviewed 8 out of 8 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
src/unsync.rs Renames placeholder upsert helper usage; minor doc fixes.
src/sync_placeholder.rs Adds EntryResult, refactors join/wait logic, and makes JoinFuture pin-stable for waiter pointer safety.
src/sync.rs Exposes entry/entry_async, updates async guard logic, and adds extensive tests.
src/shuttle_tests.rs Adds shuttle-based concurrency tests covering new entry APIs and waker-change races.
src/shard.rs Adds EntryAction + shard-level entry_or_placeholder, renames placeholder helper to get_or_placeholder, introduces panic-safe WeightGuard.
src/options.rs Small docs correction (“Options” vs “Option”).
src/lib.rs Docs updates mentioning the new entry API; minor wording fixes.
README.md Documents the new entry API with examples; minor wording fixes.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

You can also share your feedback on Copilot code review. Take the survey.

- Add `entry()` / `entry_async()` with `FnOnce(&Key, &mut Val) -> EntryAction<T>`
  for atomic inspect-and-act under a write lock
- `EntryAction<T>`: `Retain(T)`, `Remove`, `ReplaceWithGuard`
- `EntryResult<T>`: `Retained(T)`, `Removed(K, V)`, `Replaced(Guard, V)`, `Vacant(Guard)`, `Timeout`
- Placeholder deduplication: concurrent callers wait (blocking or async) and retry
- Panic-safe weight accounting via `WeightGuard` drop guard
- Shuttle concurrency tests and docs/README updates

Closes #73, closes #77
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Request: adding an update_with Request: upsert with asynchronous guard

2 participants