Skip to main content

arctic/concurrent/smr/
no_op.rs

1use core::cell::Cell;
2use core::marker::PhantomData;
3use core::num::NonZeroU64;
4use core::sync::atomic::AtomicU32;
5use core::sync::atomic::Ordering;
6
7use crate::Key;
8use crate::concurrent::Smr;
9use crate::concurrent::Value;
10use crate::concurrent::smr;
11
12thread_local! {
13    static GARBAGE_LOCAL: Cell<u32> = const { Cell::new(0) };
14}
15
16static GARBAGE_GLOBAL: AtomicU32 = AtomicU32::new(0);
17
18// FIXME: configurable?
19const GARBAGE_THRESHOLD: u32 = 256;
20
21/// Dummy backend for safe memory reclamation that leaks all retired allocations.
22///
23/// Should only be used for benchmarking purposes.
24#[derive(Default)]
25pub struct NoOp;
26
27impl<K: Key, V: Value> Smr<K, V> for NoOp {
28    type Guard<'g>
29        = Guard<(), V>
30    where
31        V: 'g,
32        Self: 'g;
33
34    fn guard<'g>(&'g self, _: K::Read<'_>) -> Self::Guard<'g>
35    where
36        V: 'g,
37    {
38        Guard::default()
39    }
40
41    fn garbage(&self) -> u32 {
42        GARBAGE_GLOBAL.load(Ordering::Relaxed)
43    }
44}
45
46/// Guard type for [`NoOp`] SMR backend.
47pub struct Guard<G, V> {
48    _guard: PhantomData<G>,
49    _value: PhantomData<V>,
50}
51
52impl<G, V> Default for Guard<G, V> {
53    fn default() -> Self {
54        Self {
55            _guard: PhantomData,
56            _value: PhantomData,
57        }
58    }
59}
60
61impl<G, V: Value> smr::Guard<V> for Guard<G, V> {
62    unsafe fn retire_node(&mut self, _bits: usize, _node: NonZeroU64) {
63        if cfg!(feature = "stat-garbage") {
64            GARBAGE_LOCAL.set(GARBAGE_LOCAL.get() + 1);
65
66            if GARBAGE_LOCAL.get() > GARBAGE_THRESHOLD {
67                GARBAGE_GLOBAL.fetch_add(GARBAGE_THRESHOLD, Ordering::Relaxed);
68                GARBAGE_LOCAL.set(0);
69            }
70        }
71    }
72
73    unsafe fn retire_value(&mut self, _value: u64) {
74        if cfg!(feature = "stat-garbage") {
75            GARBAGE_LOCAL.set(GARBAGE_LOCAL.get() + 1);
76
77            if GARBAGE_LOCAL.get() > GARBAGE_THRESHOLD {
78                GARBAGE_GLOBAL.fetch_add(GARBAGE_THRESHOLD, Ordering::Relaxed);
79                GARBAGE_LOCAL.set(0);
80            }
81        }
82    }
83}
84
85impl<G, V: Value> From<G> for Guard<G, V> {
86    #[inline]
87    fn from(_: G) -> Self {
88        Self::default()
89    }
90}