Skip to main content

dark_std/sync/
map_btree.rs

1use crate::lock::{SyncLock, SyncLockGuard};
2use serde::{Deserializer, Serialize, Serializer};
3use std::borrow::Borrow;
4use std::cell::UnsafeCell;
5use std::collections::{
6    btree_map::IntoIter as MapIntoIter, btree_map::Iter as MapIter,
7    btree_map::IterMut as MapIterMut, BTreeMap,
8};
9use std::fmt::{Debug, Display, Formatter};
10use std::hash::Hash;
11use std::ops::{Deref, DerefMut};
12use std::sync::atomic::{AtomicBool, Ordering};
13use std::sync::Arc;
14
15use super::entry::{Entry, Retired};
16use super::snapshot::AtomicSnapshot;
17
18/// A concurrent BTreeMap with a Go `sync.Map`-style read/dirty architecture:
19///
20/// - `read`: an immutable snapshot, atomically published. `get` / `iter` /
21///   `Index` read it lock-free.
22/// - `dirty`: the canonical, mutable map, guarded by `lock`.
23///
24/// Every slot is an `Arc<Entry<V>>` shared between the snapshot and `dirty`.
25/// The entry holds an atomic pointer to the value, so updating an existing key
26/// swaps the pointer in place (O(1)) — no snapshot rebuild — and readers
27/// always see the latest value. New keys and removals are published lazily
28/// (tracked by the `amended` flag). Snapshots and retired values are kept
29/// alive until the map is dropped, so references returned by `get` stay valid.
30pub struct SyncBtreeMap<K: Eq + Hash, V> {
31    dirty: UnsafeCell<BTreeMap<K, Arc<Entry<V>>>>,
32    lock: SyncLock,
33    amended: AtomicBool,
34    read: AtomicSnapshot<BTreeMap<K, Arc<Entry<V>>>>,
35    retired: Retired<V>,
36}
37
38/// Safety: `dirty` is only ever accessed under `lock`; the `read` snapshot is
39/// immutable once published; values behind entries are immutable once
40/// published and swapped out atomically; retired values and retired snapshots
41/// are kept alive until the map is dropped, so references derived from `get`
42/// remain valid for the lifetime of `&self`.
43unsafe impl<K: Eq + Hash, V> Send for SyncBtreeMap<K, V> {}
44unsafe impl<K: Eq + Hash, V> Sync for SyncBtreeMap<K, V> {}
45
46impl<K, V> std::ops::Index<&K> for SyncBtreeMap<K, V>
47where
48    K: Eq + Hash + Ord + Clone,
49{
50    type Output = V;
51
52    fn index(&self, index: &K) -> &Self::Output {
53        self.get(index).expect("key not found")
54    }
55}
56
57impl<K: Eq + Hash, V> SyncBtreeMap<K, V>
58where
59    K: Eq + Hash,
60{
61    pub fn new_arc() -> Arc<Self> {
62        Arc::new(Self::new())
63    }
64
65    pub fn new() -> Self {
66        Self {
67            dirty: UnsafeCell::new(BTreeMap::new()),
68            lock: Default::default(),
69            amended: AtomicBool::new(false),
70            read: AtomicSnapshot::new(BTreeMap::new()),
71            retired: Retired::new(),
72        }
73    }
74
75    pub fn with_capacity(_capacity: usize) -> Self {
76        Self::new()
77    }
78
79    pub fn with_map(map: BTreeMap<K, V>) -> Self
80    where
81        K: Ord,
82    {
83        let dirty = map
84            .into_iter()
85            .map(|(k, v)| (k, Arc::new(Entry::new(v))))
86            .collect();
87        Self {
88            read: AtomicSnapshot::new(BTreeMap::new()),
89            dirty: UnsafeCell::new(dirty),
90            lock: Default::default(),
91            amended: AtomicBool::new(true),
92            retired: Retired::new(),
93        }
94    }
95
96    /// Publish the current `dirty` map as a fresh immutable snapshot.
97    ///
98    /// The caller must hold `lock` (or have exclusive `&mut` access).
99    fn promote(&self)
100    where
101        K: Clone,
102    {
103        let dirty = unsafe { &*self.dirty.get() };
104        self.read.publish(dirty.clone());
105        // After publishing, `read` reflects `dirty`: nothing is pending.
106        self.amended.store(false, Ordering::Release);
107    }
108
109    pub fn insert(&self, k: K, v: V) -> Option<V>
110    where
111        K: Ord + Clone,
112        V: Clone,
113    {
114        let g = self.lock.lock();
115        let m = unsafe { &mut *self.dirty.get() };
116        if let Some(entry) = m.get(&k) {
117            // Update: swap the value in place (O(1)). The shared entry lets
118            // readers observe the new value without a snapshot rebuild.
119            let old = entry.swap(v);
120            let old_value = unsafe { (*old).clone() };
121            self.retired.push(old);
122            drop(g);
123            return Some(old_value);
124        }
125        // New key: leave it for lazy promotion and mark `amended`.
126        m.insert(k, Arc::new(Entry::new(v)));
127        self.amended.store(true, Ordering::Release);
128        drop(g);
129        None
130    }
131
132    pub fn insert_mut(&mut self, k: K, v: V) -> Option<V>
133    where
134        K: Ord + Clone,
135        V: Clone,
136    {
137        self.insert(k, v)
138    }
139
140    pub fn remove(&self, k: &K) -> Option<V>
141    where
142        K: Ord + Clone,
143        V: Clone,
144    {
145        let g = self.lock.lock();
146        let m = unsafe { &mut *self.dirty.get() };
147        if let Some(entry) = m.remove(k) {
148            // Clone the value out; the entry (and its value) stays alive in the
149            // retired snapshot published below.
150            let v = entry.load().clone();
151            // Refresh the snapshot so `get` no longer serves the removed key.
152            self.promote();
153            drop(g);
154            return Some(v);
155        }
156        drop(g);
157        None
158    }
159
160    pub fn remove_mut(&mut self, k: &K) -> Option<V>
161    where
162        K: Ord + Clone,
163        V: Clone,
164    {
165        self.remove(k)
166    }
167
168    pub fn len(&self) -> usize {
169        if !self.amended.load(Ordering::Acquire) {
170            return self.read.load().len();
171        }
172        let g = self.lock.lock();
173        let r = unsafe { (&*self.dirty.get()).len() };
174        drop(g);
175        r
176    }
177
178    pub fn is_empty(&self) -> bool {
179        if !self.amended.load(Ordering::Acquire) {
180            return self.read.load().is_empty();
181        }
182        let g = self.lock.lock();
183        let r = unsafe { (&*self.dirty.get()).is_empty() };
184        drop(g);
185        r
186    }
187
188    pub fn clear(&self)
189    where
190        K: Eq + Hash + Clone,
191    {
192        let g = self.lock.lock();
193        unsafe { (&mut *self.dirty.get()).clear() };
194        self.promote();
195        drop(g);
196    }
197
198    pub fn clear_mut(&mut self)
199    where
200        K: Eq + Hash + Clone,
201    {
202        self.clear()
203    }
204
205    pub fn shrink_to_fit(&self) {}
206
207    pub fn shrink_to_fit_mut(&mut self) {}
208
209    pub fn from(map: BTreeMap<K, V>) -> Self
210    where
211        K: Eq + Hash + Ord,
212    {
213        let s = Self::with_map(map);
214        s
215    }
216
217    /// Returns a reference to the value corresponding to the key.
218    ///
219    /// The key may be any borrowed form of the map's key type, but
220    /// [`Hash`] and [`Eq`] on the borrowed form *must* match those for
221    /// the key type.
222    ///
223    /// Reads are lock-free: the value is served from the immutable `read`
224    /// snapshot through a shared entry, so updates are visible immediately.
225    /// If the key was added to `dirty` since the last snapshot was published,
226    /// a fresh snapshot is published first.
227    ///
228    /// # Examples
229    ///
230    /// ```
231    /// use dark_std::sync::{SyncBtreeMap};
232    ///
233    /// let mut map = SyncBtreeMap::new();
234    /// map.insert_mut(1, "a");
235    /// assert_eq!(*map.get(&1).unwrap(), "a");
236    /// assert_eq!(map.get(&2).is_none(), true);
237    /// ```
238    #[inline]
239    pub fn get<Q: ?Sized>(&self, k: &Q) -> Option<&V>
240    where
241        K: Borrow<Q> + Ord + Clone,
242        Q: Hash + Eq + Ord,
243    {
244        if let Some(entry) = self.read.load().get(k) {
245            return Some(entry.load());
246        }
247        // If nothing was written to `dirty` since the last snapshot was
248        // published, a snapshot miss is a real miss: no lock is needed.
249        if !self.amended.load(Ordering::Acquire) {
250            return None;
251        }
252        // Snapshot miss: the key may have been written to `dirty` without a
253        // snapshot refresh yet (lazy promotion). Publish a fresh snapshot and
254        // serve from it so the reference points into immutable, retained
255        // storage instead of the lock-guarded `dirty` map.
256        let g = self.lock.lock();
257        let found = unsafe { (&*self.dirty.get()).contains_key(k) };
258        if found {
259            self.promote();
260        }
261        drop(g);
262        if found {
263            self.read.load().get(k).map(|e| e.load())
264        } else {
265            None
266        }
267    }
268
269    /// Returns a mutable handle to the value for `k`, implemented with
270    /// copy-on-write: the value is cloned, the handle mutates the clone, and
271    /// the result is swapped back into the shared entry (O(1)) when the handle
272    /// is dropped. Concurrent readers may observe the pre-mutation value until
273    /// the handle is dropped.
274    #[inline]
275    pub fn get_mut(&self, k: &K) -> Option<BtreeMapRefMut<'_, K, V>>
276    where
277        K: Hash + Eq + Clone + Ord,
278        V: Clone,
279    {
280        let g = self.lock.lock();
281        let dirty = unsafe { &*self.dirty.get() };
282        let value = dirty.get(k)?.load().clone();
283        drop(g);
284        Some(BtreeMapRefMut {
285            k: k.clone(),
286            m: self,
287            value: Some(value),
288        })
289    }
290
291    #[inline]
292    pub fn contains_key(&self, x: &K) -> bool
293    where
294        K: PartialEq + Ord,
295    {
296        if self.read.load().contains_key(x) {
297            return true;
298        }
299        if !self.amended.load(Ordering::Acquire) {
300            return false;
301        }
302        let g = self.lock.lock();
303        let r = unsafe { (&*self.dirty.get()).contains_key(x) };
304        drop(g);
305        r
306    }
307
308    /// Iterate over the current contents. A fresh snapshot is published first,
309    /// so all entries written so far are visible.
310    pub fn iter(&self) -> Iter<'_, K, V>
311    where
312        K: Clone,
313    {
314        let g = self.lock.lock();
315        self.promote();
316        drop(g);
317        Iter {
318            inner: self.read.load().iter(),
319        }
320    }
321
322    pub fn iter_mut(&self) -> IterMut<'_, K, V>
323    where
324        K: Clone,
325        V: Clone,
326    {
327        let m = unsafe { &mut *self.dirty.get() };
328        IterMut {
329            m: self,
330            _g: self.lock.lock(),
331            inner: Some(m.iter_mut()),
332        }
333    }
334
335    pub fn into_iter(self) -> MapIntoIter<K, V>
336    where
337        K: Ord,
338    {
339        self.into_inner().into_iter()
340    }
341
342    pub fn into_inner(self) -> BTreeMap<K, V>
343    where
344        K: Ord,
345    {
346        // Move `dirty` out; the remaining fields (snapshots, retired values,
347        // lock) are dropped normally at the end of this function.
348        let dirty = self.dirty.into_inner();
349        dirty
350            .into_iter()
351            .map(|(k, entry)| (k, entry.take()))
352            .collect()
353    }
354}
355
356/// Iterator over `(&K, &V)`, served from the immutable snapshot.
357pub struct Iter<'a, K, V> {
358    inner: MapIter<'a, K, Arc<Entry<V>>>,
359}
360
361impl<'a, K, V> Iterator for Iter<'a, K, V> {
362    type Item = (&'a K, &'a V);
363
364    fn next(&mut self) -> Option<Self::Item> {
365        self.inner.next().map(|(k, e)| (k, e.load()))
366    }
367}
368
369impl<'a, K, V> ExactSizeIterator for Iter<'a, K, V> {
370    fn len(&self) -> usize {
371        self.inner.len()
372    }
373}
374
375/// Mutable iterator over `(&K, &mut V)`. Entries shared with snapshots are
376/// replaced with fresh unique ones; mutations are published when the iterator
377/// is dropped.
378pub struct IterMut<'a, K: Eq + Hash + Clone, V: Clone> {
379    m: &'a SyncBtreeMap<K, V>,
380    _g: SyncLockGuard<'a>,
381    inner: Option<MapIterMut<'a, K, Arc<Entry<V>>>>,
382}
383
384impl<'a, K: Eq + Hash + Clone, V: Clone> Drop for IterMut<'a, K, V> {
385    fn drop(&mut self) {
386        // Drop the `&mut` borrows into `dirty` first, then publish the
387        // mutations into a fresh snapshot. The lock (`_g`) is still held.
388        self.inner.take();
389        self.m.promote();
390    }
391}
392
393impl<'a, K: Eq + Hash + Clone, V: Clone> Iterator for IterMut<'a, K, V> {
394    type Item = (&'a K, &'a mut V);
395
396    fn next(&mut self) -> Option<Self::Item> {
397        let (k, entry) = self.inner.as_mut().unwrap().next()?;
398        // Make the entry uniquely owned so we can hand out `&mut V`.
399        if Arc::get_mut(entry).is_none() {
400            let current = entry.load().clone();
401            *entry = Arc::new(Entry::new(current));
402        }
403        Some((k, Arc::get_mut(entry).unwrap().get_mut()))
404    }
405}
406
407impl<'a, K: Eq + Hash + Clone, V: Clone> ExactSizeIterator for IterMut<'a, K, V> {
408    fn len(&self) -> usize {
409        self.inner.as_ref().unwrap().len()
410    }
411}
412
413pub struct BtreeMapRefMut<'a, K: Eq + Hash + Ord + Clone, V: Clone> {
414    k: K,
415    m: &'a SyncBtreeMap<K, V>,
416    value: Option<V>,
417}
418
419impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> Drop for BtreeMapRefMut<'a, K, V> {
420    fn drop(&mut self) {
421        if let Some(v) = self.value.take() {
422            let g = self.m.lock.lock();
423            let dirty = unsafe { &mut *self.m.dirty.get() };
424            match dirty.get_mut(&self.k) {
425                Some(entry) => {
426                    let old = entry.swap(v);
427                    self.m.retired.push(old);
428                }
429                // The key was removed while the handle was held: keep the
430                // mutation by re-inserting it.
431                None => {
432                    dirty.insert(self.k.clone(), Arc::new(Entry::new(v)));
433                    self.m.amended.store(true, Ordering::Release);
434                }
435            }
436            drop(g);
437        }
438    }
439}
440
441impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> Deref for BtreeMapRefMut<'_, K, V> {
442    type Target = V;
443
444    fn deref(&self) -> &Self::Target {
445        self.value.as_ref().unwrap()
446    }
447}
448
449impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> DerefMut for BtreeMapRefMut<'_, K, V> {
450    fn deref_mut(&mut self) -> &mut Self::Target {
451        self.value.as_mut().unwrap()
452    }
453}
454
455impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> Debug for BtreeMapRefMut<'_, K, V>
456where
457    V: Debug,
458{
459    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
460        self.value.as_ref().unwrap().fmt(f)
461    }
462}
463
464impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> Display for BtreeMapRefMut<'_, K, V>
465where
466    V: Display,
467{
468    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
469        self.value.as_ref().unwrap().fmt(f)
470    }
471}
472
473impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> PartialEq<Self> for BtreeMapRefMut<'_, K, V>
474where
475    V: Eq,
476{
477    fn eq(&self, other: &Self) -> bool {
478        self.value
479            .as_ref()
480            .unwrap()
481            .eq(&other.value.as_ref().unwrap())
482    }
483}
484
485impl<'a, K: Eq + Hash + Ord + Clone, V: Clone> Eq for BtreeMapRefMut<'_, K, V> where V: Eq {}
486
487impl<'a, K: Clone, V> IntoIterator for &'a SyncBtreeMap<K, V>
488where
489    K: Eq + Hash,
490{
491    type Item = (&'a K, &'a V);
492    type IntoIter = Iter<'a, K, V>;
493
494    fn into_iter(self) -> Self::IntoIter {
495        self.iter()
496    }
497}
498
499impl<K: Eq + Hash + Ord, V> IntoIterator for SyncBtreeMap<K, V> {
500    type Item = (K, V);
501    type IntoIter = MapIntoIter<K, V>;
502
503    fn into_iter(self) -> Self::IntoIter {
504        self.into_iter()
505    }
506}
507
508impl<K: Eq + Hash + Ord, V> From<BTreeMap<K, V>> for SyncBtreeMap<K, V> {
509    fn from(arg: BTreeMap<K, V>) -> Self {
510        Self::from(arg)
511    }
512}
513
514impl<K, V> serde::Serialize for SyncBtreeMap<K, V>
515where
516    K: Eq + Hash + Serialize + Ord,
517    V: Serialize,
518{
519    fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
520    where
521        S: Serializer,
522    {
523        use serde::ser::SerializeMap;
524        let g = self.lock.lock();
525        let dirty = unsafe { &*self.dirty.get() };
526        let mut m = serializer.serialize_map(Some(dirty.len()))?;
527        for (k, e) in dirty.iter() {
528            m.serialize_entry(k, e.load())?;
529        }
530        drop(g);
531        m.end()
532    }
533}
534
535impl<'de, K, V> serde::Deserialize<'de> for SyncBtreeMap<K, V>
536where
537    K: Eq + Hash + Ord + serde::Deserialize<'de>,
538    V: serde::Deserialize<'de>,
539{
540    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
541    where
542        D: Deserializer<'de>,
543    {
544        let m = BTreeMap::deserialize(deserializer)?;
545        Ok(Self::from(m))
546    }
547}
548
549impl<K: Eq + Hash, V> Debug for SyncBtreeMap<K, V>
550where
551    K: Eq + Hash + Debug,
552    V: Debug,
553{
554    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
555        let g = self.lock.lock();
556        let r = unsafe { (&*self.dirty.get()).fmt(f) };
557        drop(g);
558        r
559    }
560}
561
562impl<K: Eq + Hash, V> Display for SyncBtreeMap<K, V>
563where
564    K: Eq + Hash + Display,
565    V: Display,
566{
567    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
568        use std::fmt::Pointer;
569        let g = self.lock.lock();
570        let r = unsafe { (&*self.dirty.get()).fmt(f) };
571        drop(g);
572        r
573    }
574}
575
576pub struct BtreeIter<'a, K, V> {
577    inner: MapIter<'a, K, *const V>,
578}
579
580impl<'a, K, V> Iterator for BtreeIter<'a, K, V> {
581    type Item = (&'a K, &'a V);
582
583    fn next(&mut self) -> Option<Self::Item> {
584        match self.inner.next() {
585            None => None,
586            Some((k, v)) => Some((k, unsafe { v.as_ref().unwrap() })),
587        }
588    }
589}
590
591impl<K: Clone + Eq + Hash + Ord, V: Clone> Clone for SyncBtreeMap<K, V> {
592    fn clone(&self) -> Self {
593        let g = self.lock.lock();
594        let dirty = unsafe { &*self.dirty.get() };
595        let m = dirty
596            .iter()
597            .map(|(k, e)| (k.clone(), e.load().clone()))
598            .collect();
599        drop(g);
600        SyncBtreeMap::from(m)
601    }
602}
603
604impl<K: Eq + Hash, V> Default for SyncBtreeMap<K, V> {
605    fn default() -> Self {
606        SyncBtreeMap::new()
607    }
608}