moka/sync_base/
key_lock.rs
1use std::{
2 hash::{BuildHasher, Hash},
3 sync::Arc,
4};
5
6use crate::{cht::SegmentedHashMap, common::concurrent::arc::MiniArc};
7
8use parking_lot::{Mutex, MutexGuard};
9
10const LOCK_MAP_NUM_SEGMENTS: usize = 64;
11
12type LockMap<K, S> = SegmentedHashMap<Arc<K>, MiniArc<Mutex<()>>, S>;
13
14pub(crate) struct KeyLock<'a, K, S>
16where
17 K: Eq + Hash,
18 S: BuildHasher,
19{
20 map: &'a LockMap<K, S>,
21 key: Arc<K>,
22 hash: u64,
23 lock: MiniArc<Mutex<()>>,
24}
25
26impl<K, S> Drop for KeyLock<'_, K, S>
27where
28 K: Eq + Hash,
29 S: BuildHasher,
30{
31 fn drop(&mut self) {
32 if MiniArc::count(&self.lock) <= 2 {
33 self.map.remove_if(
34 self.hash,
35 |k| k == &self.key,
36 |_k, v| MiniArc::count(v) <= 2,
37 );
38 }
39 }
40}
41
42impl<'a, K, S> KeyLock<'a, K, S>
43where
44 K: Eq + Hash,
45 S: BuildHasher,
46{
47 fn new(map: &'a LockMap<K, S>, key: &Arc<K>, hash: u64, lock: MiniArc<Mutex<()>>) -> Self {
48 Self {
49 map,
50 key: Arc::clone(key),
51 hash,
52 lock,
53 }
54 }
55
56 pub(crate) fn lock(&self) -> MutexGuard<'_, ()> {
57 self.lock.lock()
58 }
59}
60
61pub(crate) struct KeyLockMap<K, S> {
62 locks: LockMap<K, S>,
63}
64
65impl<K, S> KeyLockMap<K, S>
66where
67 K: Eq + Hash,
68 S: BuildHasher,
69{
70 pub(crate) fn with_hasher(hasher: S) -> Self {
71 Self {
72 locks: SegmentedHashMap::with_num_segments_and_hasher(LOCK_MAP_NUM_SEGMENTS, hasher),
73 }
74 }
75
76 pub(crate) fn key_lock(&self, key: &Arc<K>) -> KeyLock<'_, K, S> {
77 let hash = self.locks.hash(key);
78 let kl = MiniArc::new(Mutex::new(()));
79 match self
80 .locks
81 .insert_if_not_present(Arc::clone(key), hash, kl.clone())
82 {
83 None => KeyLock::new(&self.locks, key, hash, kl),
84 Some(existing_kl) => KeyLock::new(&self.locks, key, hash, existing_kl),
85 }
86 }
87}
88
89#[cfg(test)]
90impl<K, S> KeyLockMap<K, S> {
91 pub(crate) fn is_empty(&self) -> bool {
92 self.locks.len() == 0
93 }
94}