Skip to main content

ClockCache

Struct ClockCache 

Source
pub struct ClockCache<K, V>
where K: Eq + Hash,
{ /* private fields */ }
Expand description

An implementation of a concurrent Clock cache.

The Clock algorithm is an efficient $O(1)$ approximation of Least Recently Used (LRU). It uses a circular “clock hand” logic to iterate over slots and evict entries that haven’t been recently accessed.

§Concurrency Model

This implementation is lock-free for reads and uses fine-grained atomic state transitions for concurrent writes and evictions.

  • Tag-based Synchronization: Each slot is protected by an AtomicU64 tag that combines a versioned index, a frequency bit (Hot/Cold), and a “Busy” bit.
  • Memory Safety: Uses Epoch-based Reclamation (via crossbeam-epoch) to ensure safe destruction of evicted entries while other threads hold references.

Implementations§

Source§

impl<K, V> ClockCache<K, V>
where K: Eq + Hash,

Source

pub fn new(capacity: usize, metrics_config: MetricsConfig) -> Self

Creates a new Clock cache with a fixed capacity.

§Initialization Logic
  1. Slots: Allocates a contiguous block of memory for capacity slots. Each slot is wrapped in CachePadded to eliminate L1 cache-line contention between concurrent readers and writers.
  2. Index Pool: Initializes the MPMC RingQueue. Note: The pool is populated with all available slot indices (0..capacity) immediately. This “cold start” state treats every slot as vacant and ready for the first wave of insertions.
  3. Metrics: Sets up sharded atomic counters for tracking hits, misses, and eviction latency without creating a global bottleneck.
Source

pub fn get<Q>(&self, key: &Q, context: &ThreadContext) -> Option<Ref<K, V>>
where Key<K>: Borrow<Q>, Q: Eq + Hash + ?Sized,

Retrieves an entry from the cache.

Uses an Acquire load on the slot tag to synchronize with the Release store of the last writer. If the entry is Cold, it is upgraded to Hot via a compare_exchange to protect it from the next eviction cycle.

Source

pub fn insert( &self, entry: Entry<K, V>, context: &ThreadContext, quota: &mut RequestQuota, )

Inserts a new entry or updates an existing one.

If the key is missing, the thread initiates the Eviction Loop:

  1. Pops an index from the index_pool.
  2. If the slot is Hot: Decrements frequency and pushes it back (Second Chance).
  3. If the slot is Cold: Claims the slot using a Busy bit, swaps the entry, and updates the IndexTable.
§Memory Ordering Logic
  1. Claiming: AcqRel on the tag ensures exclusive access to the slot.
  2. Writing: Relaxed store on the entry is safe because it is guarded by the surrounding Tag barriers.
  3. Publishing: Release store on the final Tag makes the new entry visible to all concurrent readers.
Source

pub fn remove<Q>(&self, key: &Q, context: &ThreadContext) -> bool
where Key<K>: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes an entry from the cache and resets its physical slot.

This operation performs a two-stage teardown:

  1. Logical Removal: Atomically removes the key from the index_table.
  2. Physical Invalidation: Transitions the associated slot’s Tag to a reset/vacant state via a compare_exchange loop.
§Synchronization
  • Tag Match: If the Tag no longer matches the expected index or hash (due to a concurrent eviction), the method returns true immediately, as the target entry is already gone.
  • Reset: A successful tag.reset() ensures that any “in-flight” get requests observing this slot will see a signature mismatch and return None.
§Memory Reclamation

Note that while the Tag is reset, the Entry itself remains in the slot and the index is not pushed back to the index_pool. The physical memory is reclaimed by the insert logic when the Clock hand eventually encounters this reset slot.

§Parameters
  • key: The key to be removed.
  • context: The thread context for backoff coordination during contention.
§Returns

Returns true if the entry was found and successfully invalidated.

Trait Implementations§

Source§

impl<K, V> CacheEngine<K, V> for ClockCache<K, V>
where K: Eq + Hash,

Source§

fn get<Q>(&self, key: &Q, context: &ThreadContext) -> Option<Ref<K, V>>
where Key<K>: Borrow<Q>, Q: Eq + Hash + ?Sized,

Retrieves a protected reference to a cached value. Read more
Source§

fn insert( &self, entry: Entry<K, V>, context: &ThreadContext, quota: &mut RequestQuota, )

Inserts a key-value pair into the cache. Read more
Source§

fn remove<Q>(&self, key: &Q, context: &ThreadContext) -> bool
where Key<K>: Borrow<Q>, Q: Eq + Hash + ?Sized,

Removes an entry from the cache. Read more
Source§

fn capacity(&self) -> usize

Returns the total number of slots allocated for the cache.
Source§

fn metrics(&self) -> MetricsSnapshot

Returns a snapshot of internal cache statistics.
Source§

impl<K, V> Drop for ClockCache<K, V>
where K: Eq + Hash,

Source§

fn drop(&mut self)

Executes the destructor for this type. Read more

Auto Trait Implementations§

§

impl<K, V> !Freeze for ClockCache<K, V>

§

impl<K, V> !RefUnwindSafe for ClockCache<K, V>

§

impl<K, V> Send for ClockCache<K, V>
where V: Send + Sync, K: Sync + Send,

§

impl<K, V> Sync for ClockCache<K, V>
where V: Send + Sync, K: Sync + Send,

§

impl<K, V> Unpin for ClockCache<K, V>

§

impl<K, V> UnsafeUnpin for ClockCache<K, V>

§

impl<K, V> !UnwindSafe for ClockCache<K, V>

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Pointable for T

Source§

const ALIGN: usize

The alignment of pointer.
Source§

type Init = T

The type for initializers.
Source§

unsafe fn init(init: <T as Pointable>::Init) -> usize

Initializes a with the given initializer. Read more
Source§

unsafe fn deref<'a>(ptr: usize) -> &'a T

Dereferences the given pointer. Read more
Source§

unsafe fn deref_mut<'a>(ptr: usize) -> &'a mut T

Mutably dereferences the given pointer. Read more
Source§

unsafe fn drop(ptr: usize)

Drops the object pointed to by the given pointer. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V