omega_cache/core/thread_context.rs
1use crate::core::backoff::Backoff;
2use std::cell::UnsafeCell;
3
4/// `ThreadContext` maintains the long-lived, persistent contention state of a
5/// specific thread as it interacts with a specific cache instance.
6///
7/// Unlike a request-scoped budget (quota), `ThreadContext` acts as the "Thread Memory."
8/// It tracks historical contention via [`Backoff`], allowing the thread to adapt its
9/// timing based on how "hot" the cache has been in recent operations.
10///
11/// ### Safety and Thread Locality
12/// This struct is explicitly **!Send** and **!Sync**.
13///
14/// It uses [`UnsafeCell`] to provide interior mutability with zero runtime overhead.
15/// This is only safe when the context is stored in a way that guarantees exclusive
16/// access by a single thread (e.g., inside a `ThreadLocal` ). The non-thread-safe
17/// markers ensure this state cannot accidentally leak or be shared across thread boundaries.
18pub struct ThreadContext {
19 backoff: UnsafeCell<Backoff>,
20}
21
22impl ThreadContext {
23 /// Creates a new `ThreadContext` with the provided backoff policy.
24 ///
25 /// Usually initialized lazily when a thread first interacts with a cache instance.
26 #[inline(always)]
27 pub fn new(backoff: Backoff) -> Self {
28 Self {
29 backoff: UnsafeCell::new(backoff),
30 }
31 }
32
33 /// Signals hardware-level contention and triggers a thread yield.
34 ///
35 /// This should be called when an atomic operation (like a CAS) fails.
36 /// It increases the internal frustration level and performs a hardware-friendly
37 /// stall (e.g., `spin_loop` or `yield`) based on the persistent backoff state.
38 #[inline(always)]
39 pub fn wait(&self) {
40 unsafe { &mut *self.backoff.get() }.wait();
41 }
42
43 /// Signals a successful operation, allowing the thread-local "heat" to dissipate.
44 ///
45 /// This should be called after a successful operation. It decays the
46 /// persistent frustration level, ensuring that subsequent calls from
47 /// this thread are not unnecessarily throttled.
48 #[inline(always)]
49 pub fn decay(&self) {
50 unsafe { &mut *self.backoff.get() }.wait();
51 }
52}
53
54impl Default for ThreadContext {
55 #[inline(always)]
56 fn default() -> Self {
57 const DEFAULT_LIMIT: usize = 32;
58
59 Self {
60 backoff: UnsafeCell::new(Backoff::linear(DEFAULT_LIMIT)),
61 }
62 }
63}