sc_transaction_pool/graph/
tracked_map.rs1use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
20use std::{
21 collections::HashMap,
22 sync::{
23 atomic::{AtomicIsize, Ordering as AtomicOrdering},
24 Arc,
25 },
26};
27
28pub trait Size {
30 fn size(&self) -> usize;
31}
32
33#[derive(Debug)]
37pub struct TrackedMap<K, V> {
38 index: Arc<RwLock<HashMap<K, V>>>,
39 bytes: AtomicIsize,
40 length: AtomicIsize,
41}
42
43impl<K, V> Default for TrackedMap<K, V> {
44 fn default() -> Self {
45 Self { index: Arc::new(HashMap::default().into()), bytes: 0.into(), length: 0.into() }
46 }
47}
48
49impl<K, V> TrackedMap<K, V> {
50 pub fn len(&self) -> usize {
52 std::cmp::max(self.length.load(AtomicOrdering::Relaxed), 0) as usize
53 }
54
55 pub fn bytes(&self) -> usize {
57 std::cmp::max(self.bytes.load(AtomicOrdering::Relaxed), 0) as usize
58 }
59
60 pub fn read(&self) -> TrackedMapReadAccess<K, V> {
62 TrackedMapReadAccess { inner_guard: self.index.read() }
63 }
64
65 pub fn write(&self) -> TrackedMapWriteAccess<K, V> {
67 TrackedMapWriteAccess {
68 inner_guard: self.index.write(),
69 bytes: &self.bytes,
70 length: &self.length,
71 }
72 }
73}
74
75impl<K: Clone, V: Clone> TrackedMap<K, V> {
76 pub fn clone_map(&self) -> HashMap<K, V> {
78 self.index.read().clone()
79 }
80}
81
82pub struct TrackedMapReadAccess<'a, K, V> {
83 inner_guard: RwLockReadGuard<'a, HashMap<K, V>>,
84}
85
86impl<'a, K, V> TrackedMapReadAccess<'a, K, V>
87where
88 K: Eq + std::hash::Hash,
89{
90 pub fn contains_key(&self, key: &K) -> bool {
92 self.inner_guard.contains_key(key)
93 }
94
95 pub fn get(&self, key: &K) -> Option<&V> {
97 self.inner_guard.get(key)
98 }
99
100 pub fn values(&self) -> std::collections::hash_map::Values<K, V> {
102 self.inner_guard.values()
103 }
104}
105
106pub struct TrackedMapWriteAccess<'a, K, V> {
107 bytes: &'a AtomicIsize,
108 length: &'a AtomicIsize,
109 inner_guard: RwLockWriteGuard<'a, HashMap<K, V>>,
110}
111
112impl<'a, K, V> TrackedMapWriteAccess<'a, K, V>
113where
114 K: Eq + std::hash::Hash,
115 V: Size,
116{
117 pub fn insert(&mut self, key: K, val: V) -> Option<V> {
119 let new_bytes = val.size();
120 self.bytes.fetch_add(new_bytes as isize, AtomicOrdering::Relaxed);
121 self.length.fetch_add(1, AtomicOrdering::Relaxed);
122 self.inner_guard.insert(key, val).inspect(|old_val| {
123 self.bytes.fetch_sub(old_val.size() as isize, AtomicOrdering::Relaxed);
124 self.length.fetch_sub(1, AtomicOrdering::Relaxed);
125 })
126 }
127
128 pub fn remove(&mut self, key: &K) -> Option<V> {
130 let val = self.inner_guard.remove(key);
131 if let Some(size) = val.as_ref().map(Size::size) {
132 self.bytes.fetch_sub(size as isize, AtomicOrdering::Relaxed);
133 self.length.fetch_sub(1, AtomicOrdering::Relaxed);
134 }
135 val
136 }
137
138 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
140 self.inner_guard.get_mut(key)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146
147 use super::*;
148
149 impl Size for i32 {
150 fn size(&self) -> usize {
151 *self as usize / 10
152 }
153 }
154
155 #[test]
156 fn basic() {
157 let map = TrackedMap::default();
158 map.write().insert(5, 10);
159 map.write().insert(6, 20);
160
161 assert_eq!(map.bytes(), 3);
162 assert_eq!(map.len(), 2);
163
164 map.write().insert(6, 30);
165
166 assert_eq!(map.bytes(), 4);
167 assert_eq!(map.len(), 2);
168
169 map.write().remove(&6);
170 assert_eq!(map.bytes(), 1);
171 assert_eq!(map.len(), 1);
172 }
173}