commonware_storage/index/partitioned/
unordered.rs1#[commonware_macros::stability(ALPHA)]
4use crate::index::partitioned::{PartitionRange, Partitioned};
5use crate::{
6 index::{
7 Unordered as UnorderedTrait, partitioned::partition_index_and_sub_key,
8 unordered::Index as UnorderedIndex,
9 },
10 translator::Translator,
11};
12use commonware_runtime::Metrics;
13
14pub struct Index<T: Translator, V: Send + Sync, const P: usize> {
19 partitions: Vec<UnorderedIndex<T, V>>,
20}
21
22impl<T: Translator, V: Send + Sync, const P: usize> Index<T, V, P> {
23 pub fn new(ctx: impl Metrics, translator: T) -> Self {
25 let partition_count = 1 << (P * 8);
26 let mut partitions = Vec::with_capacity(partition_count);
27 for i in 0..partition_count {
28 partitions.push(UnorderedIndex::new(
29 ctx.child("partition").with_attribute("index", i),
30 translator.clone(),
31 ));
32 }
33
34 Self { partitions }
35 }
36
37 fn get_partition<'a>(&self, key: &'a [u8]) -> (&UnorderedIndex<T, V>, &'a [u8]) {
39 let (i, sub_key) = partition_index_and_sub_key::<P>(key);
40
41 (&self.partitions[i], sub_key)
42 }
43
44 fn get_partition_mut<'a>(&mut self, key: &'a [u8]) -> (&mut UnorderedIndex<T, V>, &'a [u8]) {
47 let (i, sub_key) = partition_index_and_sub_key::<P>(key);
48
49 (&mut self.partitions[i], sub_key)
50 }
51}
52
53#[commonware_macros::stability(ALPHA)]
54impl<T: Translator, V: Send + Sync + 'static, const P: usize> Partitioned for Index<T, V, P> {
55 type Range = RangeIndex<T, V, P>;
56
57 fn partition_count(&self) -> usize {
58 self.partitions.len()
59 }
60
61 fn partition_of(key: &[u8]) -> usize {
62 partition_index_and_sub_key::<P>(key).0
63 }
64
65 fn new_range(&self, offset: usize, count: usize) -> RangeIndex<T, V, P> {
68 let partitions = (0..count)
69 .map(|i| self.partitions[offset + i].empty())
70 .collect();
71 RangeIndex { partitions, offset }
72 }
73
74 fn install_range(&mut self, worker: RangeIndex<T, V, P>) {
76 let lo = worker.offset;
77 for (local, slot) in worker.partitions.into_iter().enumerate() {
78 self.partitions[lo + local].absorb(slot);
79 }
80 }
81}
82
83#[commonware_macros::stability(ALPHA)]
89pub(crate) struct RangeIndex<T: Translator, V: Send + Sync, const P: usize> {
90 partitions: Vec<UnorderedIndex<T, V>>,
92
93 offset: usize,
95}
96
97#[commonware_macros::stability(ALPHA)]
98impl<T: Translator, V: Send + Sync, const P: usize> PartitionRange for RangeIndex<T, V, P> {
99 type Value = V;
100 type Cursor<'a>
101 = <UnorderedIndex<T, V> as UnorderedTrait>::Cursor<'a>
102 where
103 Self: 'a;
104
105 fn get_mut(&mut self, key: &[u8]) -> Option<Self::Cursor<'_>> {
106 let (i, sub) = partition_index_and_sub_key::<P>(key);
107 self.partitions[i - self.offset].get_mut(sub)
108 }
109
110 fn get_mut_or_insert(&mut self, key: &[u8], value: V) -> Option<Self::Cursor<'_>> {
111 let (i, sub) = partition_index_and_sub_key::<P>(key);
112 self.partitions[i - self.offset].get_mut_or_insert(sub, value)
113 }
114
115 fn for_each_value(&self, mut f: impl FnMut(&V)) {
116 for partition in &self.partitions {
117 partition.for_each_value(&mut f);
118 }
119 }
120}
121
122impl<T: Translator, V: Send + Sync, const P: usize> super::super::Factory for Index<T, V, P> {
123 type Translator = T;
124
125 fn new(ctx: impl commonware_runtime::Metrics, translator: T) -> Self {
126 Self::new(ctx, translator)
127 }
128}
129
130impl<T: Translator, V: Send + Sync, const P: usize> UnorderedTrait for Index<T, V, P> {
131 type Value = V;
132 type Cursor<'a>
133 = <UnorderedIndex<T, V> as UnorderedTrait>::Cursor<'a>
134 where
135 Self: 'a;
136
137 fn get<'a>(&'a self, key: &[u8]) -> impl Iterator<Item = &'a Self::Value> + 'a
138 where
139 Self::Value: 'a,
140 {
141 let (partition, sub_key) = self.get_partition(key);
142
143 partition.get(sub_key)
144 }
145
146 fn get_mut<'a>(&'a mut self, key: &[u8]) -> Option<Self::Cursor<'a>> {
147 let (partition, sub_key) = self.get_partition_mut(key);
148
149 partition.get_mut(sub_key)
150 }
151
152 fn get_mut_or_insert<'a>(
153 &'a mut self,
154 key: &[u8],
155 value: Self::Value,
156 ) -> Option<Self::Cursor<'a>> {
157 let (partition, sub_key) = self.get_partition_mut(key);
158
159 partition.get_mut_or_insert(sub_key, value)
160 }
161
162 fn insert(&mut self, key: &[u8], value: Self::Value) {
163 let (partition, sub_key) = self.get_partition_mut(key);
164
165 partition.insert(sub_key, value);
166 }
167
168 fn insert_and_retain(
169 &mut self,
170 key: &[u8],
171 value: Self::Value,
172 should_retain: impl Fn(&Self::Value) -> bool,
173 ) {
174 let (partition, sub_key) = self.get_partition_mut(key);
175
176 partition.insert_and_retain(sub_key, value, should_retain);
177 }
178
179 fn remove(&mut self, key: &[u8]) {
180 let (partition, sub_key) = self.get_partition_mut(key);
181
182 partition.remove(sub_key);
183 }
184
185 #[cfg(test)]
186 fn keys(&self) -> usize {
187 let mut keys = 0;
189 for partition in &self.partitions {
190 keys += partition.keys();
191 }
192
193 keys
194 }
195
196 #[cfg(test)]
197 fn items(&self) -> usize {
198 let mut items = 0;
200 for partition in &self.partitions {
201 items += partition.items();
202 }
203
204 items
205 }
206
207 #[cfg(test)]
208 fn pruned(&self) -> usize {
209 let mut pruned = 0;
211 for partition in &self.partitions {
212 pruned += partition.pruned();
213 }
214
215 pruned
216 }
217}
218
219#[cfg(test)]
220mod tests {
221 use super::*;
222 use crate::{index::Cursor as _, translator::OneCap};
223 use commonware_macros::test_traced;
224 use commonware_runtime::{Runner as _, Supervisor as _, deterministic};
225
226 fn new_index(ctx: impl Metrics) -> Index<OneCap, u64, 1> {
229 Index::new(ctx, OneCap)
230 }
231
232 #[test_traced]
236 fn test_range_for_each_value_visits_all_values_once() {
237 deterministic::Runner::default().start(|context| async move {
238 let full = new_index(context.child("full"));
239
240 let mut worker = full.new_range(0x80, 2);
243 assert!(worker.get_mut_or_insert(&[0x80, 0x01, 0xAA], 1).is_none());
244 assert!(worker.get_mut_or_insert(&[0x80, 0x01, 0xBB], 2).is_some());
245 {
246 let mut cursor = worker.get_mut(&[0x80, 0x01, 0xBB]).unwrap();
247 cursor.next();
248 cursor.insert(2);
249 }
250 assert!(worker.get_mut_or_insert(&[0x80, 0x02], 3).is_none());
251 assert!(worker.get_mut_or_insert(&[0x81, 0x07], 4).is_none());
252
253 let mut seen = Vec::new();
254 worker.for_each_value(|v| seen.push(*v));
255 seen.sort_unstable();
256 assert_eq!(seen, vec![1, 2, 3, 4]);
257 });
258 }
259
260 #[test_traced]
265 fn test_install_range_nonzero_offset() {
266 deterministic::Runner::default().start(|context| async move {
267 let mut full = new_index(context.child("full"));
268
269 let mut worker = full.new_range(0x80, 2);
272 assert!(worker.get_mut_or_insert(&[0x80, 0x01], 1).is_none());
273 assert!(worker.get_mut_or_insert(&[0x80, 0x02], 2).is_none());
274 assert!(worker.get_mut_or_insert(&[0x81, 0x07], 3).is_none());
275
276 {
280 let mut cursor = worker.get_mut_or_insert(&[0x80, 0x01, 0xFF], 4).unwrap();
281 while cursor.next().is_some() {}
282 cursor.insert(4);
283 }
284
285 full.install_range(worker);
288 assert_eq!(full.keys(), 3);
289 assert_eq!(full.items(), 4);
290 assert_eq!(
291 full.get(&[0x80, 0x01]).copied().collect::<Vec<_>>(),
292 vec![1, 4]
293 );
294 assert_eq!(
295 full.get(&[0x80, 0x02]).copied().collect::<Vec<_>>(),
296 vec![2]
297 );
298 assert_eq!(
299 full.get(&[0x81, 0x07]).copied().collect::<Vec<_>>(),
300 vec![3]
301 );
302 });
303 }
304
305 #[test_traced]
309 fn test_worker_prunes_count_live() {
310 deterministic::Runner::default().start(|context| async move {
311 let mut full = new_index(context.child("full"));
312 assert_eq!(full.pruned(), 0);
313
314 let mut worker = full.new_range(0, full.partition_count());
318 assert!(worker.get_mut_or_insert(&[0x10, 0x01], 1).is_none());
319 {
320 let mut cursor = worker.get_mut_or_insert(&[0x10, 0x01, 0xFF], 2).unwrap();
321 while cursor.next().is_some() {}
322 cursor.insert(2);
323 }
324 {
325 let mut cursor = worker.get_mut(&[0x10, 0x01]).unwrap();
326 while cursor.next().is_some() {
327 cursor.delete();
328 }
329 }
330 assert_eq!(full.pruned(), 2);
331
332 full.install_range(worker);
334 assert_eq!(full.pruned(), 2);
335 assert_eq!(full.keys(), 0);
336 assert_eq!(full.items(), 0);
337 });
338 }
339}