dualcache_ff/componant/
arena.rs1#![allow(clippy::missing_safety_doc)]
2use ::core::sync::atomic::{AtomicUsize, Ordering};
3use core::cell::UnsafeCell;
4use core::mem::MaybeUninit;
5
6pub const NULL_INDEX: u32 = u32::MAX;
7
8pub struct Arena<K, V, const N: usize> {
10 nodes: [UnsafeCell<MaybeUninit<Node<K, V>>>; N],
11 next_free: [::core::sync::atomic::AtomicU32; N],
12 free_head: AtomicUsize, }
14
15unsafe impl<K: Send, V: Send, const N: usize> Send for Arena<K, V, N> {}
17unsafe impl<K: Sync, V: Sync, const N: usize> Sync for Arena<K, V, N> {}
18
19pub struct Node<K, V> {
20 pub key: K,
21 pub value: V,
22}
23
24impl<K, V, const N: usize> Default for Arena<K, V, N> {
25 fn default() -> Self {
26 Self::new()
27 }
28}
29
30impl<K, V, const N: usize> Arena<K, V, N> {
31 pub const fn new() -> Self {
32 let mut next_free = [const { ::core::sync::atomic::AtomicU32::new(0) }; N];
33 let mut i = 0;
34 while i < N - 1 {
35 next_free[i] = ::core::sync::atomic::AtomicU32::new((i + 1) as u32);
36 i += 1;
37 }
38 next_free[N - 1] = ::core::sync::atomic::AtomicU32::new(NULL_INDEX);
39
40 let nodes: [UnsafeCell<MaybeUninit<Node<K, V>>>; N] = unsafe {
42 core::mem::MaybeUninit::uninit().assume_init()
43 };
44
45 Self {
46 nodes,
47 next_free,
48 free_head: AtomicUsize::new(0), }
50 }
51
52 #[allow(clippy::not_unsafe_ptr_arg_deref)]
57 pub fn alloc(&self, key: K, value: V, node: *mut crate::componant::qsbr::ThreadStateNode) -> Option<usize> {
58 let local_free = unsafe { &mut *(*node).local_free.get() };
59 if let Some(idx) = local_free.pop() {
60 unsafe {
61 (*self.nodes[idx as usize].get()).write(Node { key, value });
62 }
63 return Some(idx as usize);
64 }
65
66
67
68 let mut head = self.free_head.load(Ordering::Acquire);
70 loop {
71 let index = (head & 0xFFFFFFFF) as u32;
72 if index == NULL_INDEX {
73 return None; }
75
76 let mut curr = index;
78 let mut count = 1;
79 while count < 64 {
80 let next = self.next_free[curr as usize].load(Ordering::Relaxed);
81 if next == NULL_INDEX {
82 break;
83 }
84 curr = next;
85 count += 1;
86 }
87
88 let next_after_batch = self.next_free[curr as usize].load(Ordering::Relaxed);
89 let tag = head >> 32;
90 let new_head = (tag.wrapping_add(1) << 32) | (next_after_batch as usize);
91
92 match self.free_head.compare_exchange_weak(head, new_head, Ordering::AcqRel, Ordering::Acquire) {
93 Ok(_) => {
94 let mut p = self.next_free[index as usize].load(Ordering::Relaxed);
97 for _ in 1..count {
98 let _ = local_free.push(p);
99 p = self.next_free[p as usize].load(Ordering::Relaxed);
100 }
101
102 unsafe {
103 (*self.nodes[index as usize].get()).write(Node { key, value });
104 }
105 return Some(index as usize);
106 }
107 Err(h) => {
108 head = h;
109 ::core::hint::spin_loop();
110 }
111 }
112 }
113 }
114
115 pub unsafe fn free(&self, index: usize) { unsafe {
118 self.drop_node(index);
119 self.free_raw(index);
120 }}
121
122 pub unsafe fn drop_node(&self, index: usize) {
124 unsafe {
125 core::ptr::drop_in_place((*self.nodes[index].get()).as_mut_ptr());
126 }
127 }
128
129 pub fn set_next_free(&self, index: u32, next: u32) {
130 self.next_free[index as usize].store(next, Ordering::Relaxed);
131 }
132
133 pub unsafe fn free_batch(&self, head_idx: u32, tail_idx: u32) {
135 let mut head = self.free_head.load(Ordering::Relaxed);
136 loop {
137 let next = (head & 0xFFFFFFFF) as u32;
138 self.next_free[tail_idx as usize].store(next, Ordering::Relaxed);
139 let tag = head >> 32;
140 let new_head = (tag.wrapping_add(1) << 32) | (head_idx as usize);
141
142 if self.free_head.compare_exchange_weak(head, new_head, Ordering::AcqRel, Ordering::Acquire).is_ok() {
143 return;
144 } else {
145 head = self.free_head.load(Ordering::Relaxed);
146 ::core::hint::spin_loop();
147 }
148 }
149 }
150
151 pub unsafe fn free_raw(&self, index: usize) { unsafe {
153 self.free_batch(index as u32, index as u32);
154 }}
155
156 #[inline(always)]
159 pub unsafe fn get(&self, index: usize) -> &Node<K, V> {
160 unsafe {
161 &*((*self.nodes[index].get()).as_ptr())
162 }
163 }
164
165 #[allow(clippy::mut_from_ref)]
166 pub unsafe fn get_mut(&self, index: usize) -> &mut Node<K, V> {
167 unsafe {
168 &mut *((*self.nodes[index].get()).as_mut_ptr())
169 }
170 }
171}
172
173#[cfg(test)]
174mod tests {
175 use super::*;
176 use std::sync::Arc;
177 use std::thread;
178
179 #[test]
180 fn test_arena_default() {
181 let arena = Arena::<u64, u64, 100>::new();
182 let mut dummy_node = crate::componant::qsbr::ThreadStateNode::new();
183 let dummy_ptr = &mut dummy_node as *mut _;
184 assert!(arena.alloc(1, 10, dummy_ptr).is_some());
185 }
186
187 #[test]
188 fn test_arena_cas_retries() {
189 let arena = Arc::new(Arena::<u64, u64, 1000>::new());
190 let mut handles = vec![];
191
192 for i in 0..10 {
193 let arena_clone = arena.clone();
194 handles.push(thread::spawn(move || {
195 let mut dummy_node = crate::componant::qsbr::ThreadStateNode::new();
196 let dummy_ptr = &mut dummy_node as *mut _;
197 let mut idxs = vec![];
198 for _ in 0..50 {
199 if let Some(idx) = arena_clone.alloc(i, i * 10, dummy_ptr) {
200 idxs.push(idx);
201 }
202 }
203 for idx in idxs {
204 unsafe { arena_clone.free(idx); }
205 }
206 }));
207 }
208 for handle in handles {
209 handle.join().unwrap();
210 }
211 }
212 #[test]
213 fn test_arena_oom() {
214 let arena = Arena::<u64, u64, 4>::new();
215 let node = {
216 let node = std::boxed::Box::into_raw(std::boxed::Box::new(crate::componant::qsbr::ThreadStateNode::new()));
217 crate::componant::qsbr::register_node(node, 0, ::core::ptr::null(), None);
218 node
219 };
220 assert!(arena.alloc(1, 1, node).is_some());
221 assert!(arena.alloc(2, 2, node).is_some());
222 assert!(arena.alloc(3, 3, node).is_some());
223 assert!(arena.alloc(4, 4, node).is_some());
224 assert!(arena.alloc(5, 5, node).is_none()); }
226}