dualcache_ff/componant/
storage.rs1use std::{boxed::Box, vec::Vec};
2
3use ::core::sync::atomic::{AtomicU64, AtomicPtr, Ordering};
4use core::ptr;
5
6pub struct Node<K, V> {
8 pub key: K,
9 pub value: V,
10 pub expire_at: u32,
12 pub g_idx: u32,
14}
15
16pub struct Cache<K, V> {
23 pub(crate) index_mask: usize,
24 pub(crate) index: Box<[AtomicU64]>,
25 pub(crate) nodes: Box<[AtomicPtr<Node<K, V>>]>,
26}
27
28unsafe impl<K: Send, V: Send> Send for Cache<K, V> {}
29unsafe impl<K: Send + Sync, V: Send + Sync> Sync for Cache<K, V> {}
30
31impl<K, V> Cache<K, V> {
32 pub fn new(capacity: usize) -> Self {
33 let index_size = (capacity * 2).next_power_of_two();
34 let mut index = Vec::with_capacity(index_size);
35 for _ in 0..index_size {
36 index.push(AtomicU64::new(0));
37 }
38
39 let mut nodes = Vec::with_capacity(capacity);
40 for _ in 0..capacity {
41 nodes.push(AtomicPtr::new(ptr::null_mut()));
42 }
43
44 Self {
45 index_mask: index_size - 1,
46 index: index.into_boxed_slice(),
47 nodes: nodes.into_boxed_slice(),
48 }
49 }
50
51 #[inline(always)]
52 pub fn index_probe(&self, hash: u64, tag: u16) -> Option<usize> {
53 let mut idx = hash as usize & self.index_mask;
54 for _ in 0..16 {
55 let entry = self.index[idx].load(Ordering::Acquire);
56 if entry == 0 {
57 return None;
58 }
59 if entry != u64::MAX && (entry >> 48) as u16 == tag {
60 return Some((entry & 0x0000_FFFF_FFFF_FFFF) as usize);
61 }
62 idx = (idx + 1) & self.index_mask;
63 }
64 None
65 }
66
67 #[inline(always)]
68 pub fn index_store(&self, hash: u64, tag: u16, entry: u64) {
69 let mut idx = hash as usize & self.index_mask;
70 for i in 0..16 {
71 let prev = self.index[idx].load(Ordering::Acquire);
72 if prev == 0 || prev == u64::MAX || (prev >> 48) == (tag as u64) {
73 self.index[idx].store(entry, Ordering::Release);
74 return;
75 }
76 if i == 15 {
77 self.index[hash as usize & self.index_mask].store(entry, Ordering::Release);
78 }
79 idx = (idx + 1) & self.index_mask;
80 }
81 }
82
83 #[inline(always)]
84 pub fn index_remove(&self, hash: u64, tag: u16, g_idx: usize) {
85 let mut idx = hash as usize & self.index_mask;
86 for _ in 0..16 {
87 let entry = self.index[idx].load(Ordering::Acquire);
88 if entry == 0 {
89 return;
90 }
91 if entry != u64::MAX
92 && (entry >> 48) as u16 == tag
93 && (entry & 0x0000_FFFF_FFFF_FFFF) == (g_idx as u64)
94 {
95 self.index[idx].store(u64::MAX, Ordering::Release);
96 return;
97 }
98 idx = (idx + 1) & self.index_mask;
99 }
100 }
101
102 #[inline(always)]
103 pub fn index_clear_at(&self, idx: usize) {
104 self.index[idx].store(0, Ordering::Relaxed);
105 }
106
107 #[inline(always)]
108 pub fn index_len(&self) -> usize {
109 self.index.len()
110 }
111
112 #[inline(always)]
113 pub fn node_get_full(&self, idx: usize, key: &K, current_epoch: u32) -> Option<V>
114 where
115 K: Eq,
116 V: Clone,
117 {
118 let ptr = self.nodes[idx].load(Ordering::Acquire);
119 if ptr.is_null() {
120 return None;
121 }
122 let node = unsafe { &*ptr };
124 if node.key == *key {
125 if node.expire_at > 0 && node.expire_at < current_epoch {
126 return None;
127 }
128 Some(node.value.clone())
129 } else {
130 None
131 }
132 }
133
134 pub fn clear(&self) {
135 for i in 0..self.index.len() {
136 self.index[i].store(0, Ordering::Relaxed);
137 }
138 for i in 0..self.nodes.len() {
139 self.nodes[i].store(ptr::null_mut(), Ordering::Release);
140 }
141 }
142}
143
144impl<K, V> Drop for Cache<K, V> {
145 fn drop(&mut self) {
146 for node_ptr in self.nodes.iter() {
147 let ptr = node_ptr.swap(ptr::null_mut(), Ordering::Relaxed);
148 if !ptr.is_null() {
149 unsafe {
150 let _ = Box::from_raw(ptr);
151 }
152 }
153 }
154 }
155}