commonware_storage/index/
unordered.rs1use crate::{
6 index::{
7 storage::{push_displaced, Cursor as CursorImpl, IndexEntry, Overflow, Values},
8 Cursor as CursorTrait, Unordered,
9 },
10 translator::Translator,
11};
12use commonware_runtime::{
13 telemetry::metrics::{Counter, Gauge, MetricsExt as _},
14 Metrics,
15};
16use std::collections::{
17 hash_map::{Entry, OccupiedEntry, VacantEntry},
18 HashMap,
19};
20
21const INITIAL_CAPACITY: usize = 256;
25
26impl<K: Send + Sync, V: Send + Sync> IndexEntry<V> for OccupiedEntry<'_, K, V> {
28 type Key = K;
29
30 fn key(&self) -> &K {
31 OccupiedEntry::key(self)
32 }
33
34 fn get_mut(&mut self) -> &mut V {
35 self.get_mut()
36 }
37
38 fn remove(self) {
39 OccupiedEntry::remove(self);
40 }
41}
42
43pub type Cursor<'a, K, V, S> = CursorImpl<'a, K, V, OccupiedEntry<'a, K, V>, S>;
45
46pub struct Index<T: Translator, V: Send + Sync> {
53 translator: T,
54 map: HashMap<T::Key, V, T>,
55 overflow: Overflow<T::Key, V, T>,
56
57 keys: Gauge,
58 items: Gauge,
59 pruned: Counter,
60}
61
62impl<T: Translator, V: Send + Sync> Index<T, V> {
63 fn create(keys: &Gauge, items: &Gauge, vacant: VacantEntry<'_, T::Key, V>, v: V) {
65 keys.inc();
66 items.inc();
67 vacant.insert(v);
68 }
69
70 pub fn new(ctx: impl Metrics, translator: T) -> Self {
72 Self {
73 translator: translator.clone(),
74 overflow: HashMap::with_hasher(translator.clone()),
75 map: HashMap::with_capacity_and_hasher(INITIAL_CAPACITY, translator),
76 keys: ctx.gauge("keys", "Number of translated keys in the index"),
77 items: ctx.gauge("items", "Number of items in the index"),
78 pruned: ctx.counter("pruned", "Number of items pruned"),
79 }
80 }
81}
82
83impl<T: Translator, V: Send + Sync> super::Factory<T> for Index<T, V> {
84 fn new(ctx: impl commonware_runtime::Metrics, translator: T) -> Self {
85 Self::new(ctx, translator)
86 }
87}
88
89impl<T: Translator, V: Send + Sync> Unordered for Index<T, V> {
90 type Value = V;
91 type Cursor<'a>
92 = Cursor<'a, T::Key, V, T>
93 where
94 Self: 'a;
95
96 fn get<'a>(&'a self, key: &[u8]) -> impl Iterator<Item = &'a V> + 'a
97 where
98 V: 'a,
99 {
100 let k = self.translator.transform(key);
101 Values::new(self.map.get(&k), &self.overflow, k)
102 }
103
104 fn get_mut<'a>(&'a mut self, key: &[u8]) -> Option<Self::Cursor<'a>> {
105 let k = self.translator.transform(key);
106 match self.map.entry(k) {
107 Entry::Occupied(entry) => Some(Cursor::<'_, T::Key, V, T>::new(
108 entry,
109 &mut self.overflow,
110 &self.keys,
111 &self.items,
112 &self.pruned,
113 )),
114 Entry::Vacant(_) => None,
115 }
116 }
117
118 fn get_mut_or_insert<'a>(&'a mut self, key: &[u8], value: V) -> Option<Self::Cursor<'a>> {
119 let k = self.translator.transform(key);
120 match self.map.entry(k) {
121 Entry::Occupied(entry) => Some(Cursor::<'_, T::Key, V, T>::new(
122 entry,
123 &mut self.overflow,
124 &self.keys,
125 &self.items,
126 &self.pruned,
127 )),
128 Entry::Vacant(entry) => {
129 Self::create(&self.keys, &self.items, entry, value);
130 None
131 }
132 }
133 }
134
135 fn insert(&mut self, key: &[u8], v: V) {
136 let k = self.translator.transform(key);
137 match self.map.entry(k) {
138 Entry::Occupied(mut entry) => {
139 let old = std::mem::replace(entry.get_mut(), v);
142 push_displaced(&mut self.overflow, k, old);
143 self.items.inc();
144 }
145 Entry::Vacant(entry) => {
146 Self::create(&self.keys, &self.items, entry, v);
147 }
148 }
149 }
150
151 fn insert_and_retain(&mut self, key: &[u8], value: V, should_retain: impl Fn(&V) -> bool) {
152 let k = self.translator.transform(key);
153 match self.map.entry(k) {
154 Entry::Occupied(mut entry) => {
155 #[allow(clippy::map_entry)]
157 if !self.overflow.contains_key(&k) {
158 match (should_retain(entry.get()), should_retain(&value)) {
159 (true, true) => {
161 self.overflow.insert(k, vec![value]);
162 self.items.inc();
163 }
164 (false, true) => {
166 *entry.get_mut() = value;
167 self.pruned.inc();
168 }
169 (false, false) => {
171 entry.remove();
172 self.keys.dec();
173 self.items.dec();
174 self.pruned.inc();
175 }
176 (true, false) => {}
178 }
179 return;
180 }
181
182 let mut cursor = Cursor::<'_, T::Key, V, T>::new(
184 entry,
185 &mut self.overflow,
186 &self.keys,
187 &self.items,
188 &self.pruned,
189 );
190
191 cursor.retain(&should_retain);
193
194 if should_retain(&value) {
196 cursor.insert(value);
197 }
198 }
199 Entry::Vacant(entry) => {
200 if should_retain(&value) {
202 Self::create(&self.keys, &self.items, entry, value);
203 }
204 }
205 }
206 }
207
208 fn remove(&mut self, key: &[u8]) {
209 let k = self.translator.transform(key);
210 if self.map.remove(&k).is_some() {
211 self.keys.dec();
213 self.items.dec();
214 self.pruned.inc();
215 if !self.overflow.is_empty() {
216 if let Some(chain) = self.overflow.remove(&k) {
217 self.items.dec_by(chain.len() as i64);
218 self.pruned.inc_by(chain.len() as u64);
219 }
220 }
221 }
222 }
223
224 #[cfg(test)]
225 fn keys(&self) -> usize {
226 self.map.len()
227 }
228
229 #[cfg(test)]
230 fn items(&self) -> usize {
231 self.items.get() as usize
232 }
233
234 #[cfg(test)]
235 fn pruned(&self) -> usize {
236 self.pruned.get() as usize
237 }
238}