lock_free/
hashmap_fast.rs

1//! Ultra-fast lock-free HashMap using open addressing
2//! 
3//! This implementation uses linear probing with atomic operations
4//! for maximum performance on modern CPUs.
5
6use std::sync::atomic::{AtomicU64, AtomicPtr, Ordering};
7use std::ptr::null_mut;
8use std::hash::{Hash, Hasher};
9use std::collections::hash_map::DefaultHasher;
10use std::marker::PhantomData;
11
12/// Entry states
13const EMPTY: u64 = 0;
14const TOMBSTONE: u64 = 1;
15const OCCUPIED_FLAG: u64 = 2;
16
17/// Cache line size
18const CACHE_LINE: usize = 128;
19
20/// Default capacity (must be power of 2)
21const DEFAULT_CAPACITY: usize = 1024;
22
23/// Entry in the hashmap
24#[repr(align(64))]
25struct Entry<K, V> {
26    /// Combined hash and state (2 bits state, 62 bits hash)
27    hash_state: AtomicU64,
28    /// Key storage
29    key: AtomicPtr<K>,
30    /// Value storage  
31    value: AtomicPtr<V>,
32}
33
34impl<K, V> Entry<K, V> {
35    fn new() -> Self {
36        Self {
37            hash_state: AtomicU64::new(EMPTY),
38            key: AtomicPtr::new(null_mut()),
39            value: AtomicPtr::new(null_mut()),
40        }
41    }
42}
43
44/// Ultra-fast lock-free HashMap
45pub struct FastHashMap<K, V> {
46    /// Entry array
47    entries: Box<[Entry<K, V>]>,
48    /// Capacity mask (capacity - 1)
49    mask: usize,
50    /// Size counter
51    size: AtomicU64,
52    /// Type markers
53    _phantom: PhantomData<(K, V)>,
54}
55
56impl<K: Hash + Eq + Clone, V: Clone> FastHashMap<K, V> {
57    /// Create new hashmap
58    pub fn new() -> Self {
59        Self::with_capacity(DEFAULT_CAPACITY)
60    }
61
62    /// Create with specified capacity
63    pub fn with_capacity(capacity: usize) -> Self {
64        let capacity = capacity.next_power_of_two();
65        let mut entries = Vec::with_capacity(capacity);
66        
67        for _ in 0..capacity {
68            entries.push(Entry::new());
69        }
70        
71        Self {
72            entries: entries.into_boxed_slice(),
73            mask: capacity - 1,
74            size: AtomicU64::new(0),
75            _phantom: PhantomData,
76        }
77    }
78
79    /// Hash a key
80    #[inline]
81    fn hash_key(key: &K) -> u64 {
82        let mut hasher = DefaultHasher::new();
83        key.hash(&mut hasher);
84        hasher.finish()
85    }
86
87    /// Insert key-value pair
88    pub fn insert(&self, key: K, value: V) -> Option<V> {
89        let hash = Self::hash_key(&key);
90        let hash_with_flag = hash | OCCUPIED_FLAG;
91        let mut index = (hash as usize) & self.mask;
92        let start_index = index;
93        
94        loop {
95            let entry = &self.entries[index];
96            let current_hash = entry.hash_state.load(Ordering::Acquire);
97            
98            if current_hash == EMPTY || current_hash == TOMBSTONE {
99                // Try to claim this slot
100                match entry.hash_state.compare_exchange(
101                    current_hash,
102                    hash_with_flag,
103                    Ordering::AcqRel,
104                    Ordering::Acquire
105                ) {
106                    Ok(_) => {
107                        // We got it! Store key and value
108                        let key_ptr = Box::into_raw(Box::new(key));
109                        let value_ptr = Box::into_raw(Box::new(value));
110                        
111                        entry.key.store(key_ptr, Ordering::Release);
112                        entry.value.store(value_ptr, Ordering::Release);
113                        
114                        if current_hash == EMPTY {
115                            self.size.fetch_add(1, Ordering::Relaxed);
116                        }
117                        return None;
118                    }
119                    Err(_) => {
120                        // Someone else got it, continue
121                    }
122                }
123            } else if current_hash == hash_with_flag {
124                // Check if same key
125                let key_ptr = entry.key.load(Ordering::Acquire);
126                if !key_ptr.is_null() {
127                    let stored_key = unsafe { &*key_ptr };
128                    if stored_key == &key {
129                        // Update value
130                        let new_value_ptr = Box::into_raw(Box::new(value));
131                        let old_value_ptr = entry.value.swap(new_value_ptr, Ordering::AcqRel);
132                        
133                        if !old_value_ptr.is_null() {
134                            let old_value = unsafe { Box::from_raw(old_value_ptr) };
135                            return Some(*old_value);
136                        }
137                        return None;
138                    }
139                }
140            }
141            
142            // Linear probe to next slot
143            index = (index + 1) & self.mask;
144            
145            // Check if we've wrapped around completely
146            if index == start_index {
147                // Table is full, can't insert
148                return None;
149            }
150        }
151    }
152
153    /// Get value by key
154    pub fn get(&self, key: &K) -> Option<V> {
155        let hash = Self::hash_key(key);
156        let hash_with_flag = hash | OCCUPIED_FLAG;
157        let mut index = (hash as usize) & self.mask;
158        let start_index = index;
159        
160        loop {
161            let entry = &self.entries[index];
162            let current_hash = entry.hash_state.load(Ordering::Acquire);
163            
164            if current_hash == EMPTY {
165                return None;
166            }
167            
168            if current_hash == hash_with_flag {
169                let key_ptr = entry.key.load(Ordering::Acquire);
170                if !key_ptr.is_null() {
171                    let stored_key = unsafe { &*key_ptr };
172                    if stored_key == key {
173                        let value_ptr = entry.value.load(Ordering::Acquire);
174                        if !value_ptr.is_null() {
175                            let value = unsafe { &*value_ptr };
176                            return Some(value.clone());
177                        }
178                    }
179                }
180            }
181            
182            index = (index + 1) & self.mask;
183            if index == start_index {
184                return None;
185            }
186        }
187    }
188
189    /// Remove key-value pair
190    pub fn remove(&self, key: &K) -> Option<V> {
191        let hash = Self::hash_key(key);
192        let hash_with_flag = hash | OCCUPIED_FLAG;
193        let mut index = (hash as usize) & self.mask;
194        let start_index = index;
195        
196        loop {
197            let entry = &self.entries[index];
198            let current_hash = entry.hash_state.load(Ordering::Acquire);
199            
200            if current_hash == EMPTY {
201                return None;
202            }
203            
204            if current_hash == hash_with_flag {
205                let key_ptr = entry.key.load(Ordering::Acquire);
206                if !key_ptr.is_null() {
207                    let stored_key = unsafe { &*key_ptr };
208                    if stored_key == key {
209                        // Mark as tombstone
210                        match entry.hash_state.compare_exchange(
211                            hash_with_flag,
212                            TOMBSTONE,
213                            Ordering::AcqRel,
214                            Ordering::Acquire
215                        ) {
216                            Ok(_) => {
217                                // Remove key and value
218                                let key_ptr = entry.key.swap(null_mut(), Ordering::AcqRel);
219                                let value_ptr = entry.value.swap(null_mut(), Ordering::AcqRel);
220                                
221                                self.size.fetch_sub(1, Ordering::Relaxed);
222                                
223                                if !key_ptr.is_null() {
224                                    unsafe { let _ = Box::from_raw(key_ptr); }
225                                }
226                                
227                                if !value_ptr.is_null() {
228                                    let value = unsafe { Box::from_raw(value_ptr) };
229                                    return Some(*value);
230                                }
231                            }
232                            Err(_) => {
233                                // Someone else removed it
234                                return None;
235                            }
236                        }
237                    }
238                }
239            }
240            
241            index = (index + 1) & self.mask;
242            if index == start_index {
243                return None;
244            }
245        }
246    }
247
248    /// Check if key exists
249    pub fn contains_key(&self, key: &K) -> bool {
250        let hash = Self::hash_key(key);
251        let hash_with_flag = hash | OCCUPIED_FLAG;
252        let mut index = (hash as usize) & self.mask;
253        let start_index = index;
254        
255        loop {
256            let entry = &self.entries[index];
257            let current_hash = entry.hash_state.load(Ordering::Acquire);
258            
259            if current_hash == EMPTY {
260                return false;
261            }
262            
263            if current_hash == hash_with_flag {
264                let key_ptr = entry.key.load(Ordering::Acquire);
265                if !key_ptr.is_null() {
266                    let stored_key = unsafe { &*key_ptr };
267                    if stored_key == key {
268                        return true;
269                    }
270                }
271            }
272            
273            index = (index + 1) & self.mask;
274            if index == start_index {
275                return false;
276            }
277        }
278    }
279
280    /// Get number of elements
281    pub fn len(&self) -> usize {
282        self.size.load(Ordering::Relaxed) as usize
283    }
284
285    /// Check if empty
286    pub fn is_empty(&self) -> bool {
287        self.len() == 0
288    }
289}
290
291unsafe impl<K: Send, V: Send> Send for FastHashMap<K, V> {}
292unsafe impl<K: Send + Sync, V: Send + Sync> Sync for FastHashMap<K, V> {}
293
294impl<K, V> Drop for FastHashMap<K, V> {
295    fn drop(&mut self) {
296        for entry in self.entries.iter() {
297            let key_ptr = entry.key.load(Ordering::Acquire);
298            let value_ptr = entry.value.load(Ordering::Acquire);
299            
300            if !key_ptr.is_null() {
301                unsafe { let _ = Box::from_raw(key_ptr); }
302            }
303            
304            if !value_ptr.is_null() {
305                unsafe { let _ = Box::from_raw(value_ptr); }
306            }
307        }
308    }
309}