1use super::{Config, Error};
2use crate::{Context, SyncCompletion};
3use commonware_codec::{Codec, FixedSize, ReadExt};
4use commonware_cryptography::{Crc32, crc32};
5use commonware_runtime::{
6 Blob, BufMut, Error as RError, Handle, IoBufMut, ReadOptions, WriteOptions,
7 telemetry::metrics::{Counter, Gauge, GaugeExt, MetricsExt as _},
8};
9use commonware_utils::Span;
10use futures::{FutureExt as _, future::try_join_all};
11use std::collections::{BTreeMap, BTreeSet, HashMap};
12use tracing::{debug, warn};
13
14const BLOB_NAMES: [&[u8]; 2] = [b"left", b"right"];
16
17struct Info {
19 start: usize,
20 length: usize,
21}
22
23impl Info {
24 const fn new(start: usize, length: usize) -> Self {
26 Self { start, length }
27 }
28}
29
30struct Wrapper<B: Blob, K: Span> {
32 blob: B,
33 version: u64,
34 lengths: HashMap<K, Info>,
35 modified: BTreeSet<K>,
36 data: IoBufMut,
37}
38
39impl<B: Blob, K: Span> Wrapper<B, K> {
40 const fn new(blob: B, version: u64, lengths: HashMap<K, Info>, data: IoBufMut) -> Self {
42 Self {
43 blob,
44 version,
45 lengths,
46 modified: BTreeSet::new(),
47 data,
48 }
49 }
50
51 fn empty(blob: B) -> Self {
53 Self {
54 blob,
55 version: 0,
56 lengths: HashMap::new(),
57 modified: BTreeSet::new(),
58 data: IoBufMut::default(),
59 }
60 }
61}
62
63struct State<B: Blob, K: Span> {
65 cursor: usize,
66 next_version: u64,
67 key_order_changed: u64,
68 blobs: [Wrapper<B, K>; 2],
69 pending: Option<SyncCompletion>,
74}
75
76struct Inner<E: Context, K: Span, V: Codec> {
78 context: E,
79
80 map: BTreeMap<K, V>,
81 partition: String,
82 state: State<E::Blob, K>,
83
84 sync_overwrites: Counter,
85 sync_rewrites: Counter,
86 keys: Gauge,
87}
88
89enum Loaded<B: Blob, K: Span, V> {
91 Valid(BTreeMap<K, V>, Wrapper<B, K>),
93 Invalid(B),
95}
96
97impl<E: Context, K: Span, V: Codec> Inner<E, K, V> {
98 async fn init(context: E, cfg: Config<V::Cfg>) -> Result<Self, Error> {
100 let (left_blob, left_len) = context.open(&cfg.partition, BLOB_NAMES[0]).await?;
102 let (right_blob, right_len) = context.open(&cfg.partition, BLOB_NAMES[1]).await?;
103
104 let left = Self::load(&context, &cfg.codec_config, 0, left_blob, left_len).await?;
108 let right = Self::load(&context, &cfg.codec_config, 1, right_blob, right_len).await?;
109 if matches!((&left, &right), (Loaded::Invalid(_), Loaded::Invalid(_))) {
110 return Err(Error::Corruption(
111 "both metadata copies failed validation".into(),
112 ));
113 }
114 let (left_map, left_wrapper) = Self::normalize(left).await?;
115 let (right_map, right_wrapper) = Self::normalize(right).await?;
116
117 let mut map = left_map;
119 let mut cursor = 0;
120 let mut version = left_wrapper.version;
121 if right_wrapper.version > left_wrapper.version {
122 cursor = 1;
123 map = right_map;
124 version = right_wrapper.version;
125 }
126 let next_version = version.checked_add(1).expect("version overflow");
127
128 let sync_rewrites =
130 context.counter("sync_rewrites", "number of syncs that rewrote all data");
131 let sync_overwrites = context.counter(
132 "sync_overwrites",
133 "number of syncs that modified existing data",
134 );
135 let keys = context.gauge("keys", "number of tracked keys");
136
137 let _ = keys.try_set(map.len());
139 Ok(Self {
140 context,
141
142 map,
143 partition: cfg.partition,
144 state: State {
145 cursor,
146 next_version,
147 key_order_changed: next_version, blobs: [left_wrapper, right_wrapper],
149 pending: None,
150 },
151
152 sync_rewrites,
153 sync_overwrites,
154 keys,
155 })
156 }
157
158 async fn load(
159 context: &E,
160 codec_config: &V::Cfg,
161 index: usize,
162 blob: E::Blob,
163 len: u64,
164 ) -> Result<Loaded<E::Blob, K, V>, Error> {
165 if len == 0 {
167 return Ok(Loaded::Valid(BTreeMap::new(), Wrapper::empty(blob)));
169 }
170
171 let len: usize = len.try_into().expect("blob too large for platform");
174 let buf = blob
175 .read_at(0, len, ReadOptions::DONT_CACHE)
176 .await?
177 .coalesce_with_pool(context.storage_buffer_pool());
178
179 if buf.len() < 8 + crc32::Digest::SIZE {
183 warn!(blob = index, len = buf.len(), "blob is too short");
184 return Ok(Loaded::Invalid(blob));
185 }
186
187 let checksum_index = buf.len() - crc32::Digest::SIZE;
189 let stored_checksum =
190 u32::from_be_bytes(buf.as_ref()[checksum_index..].try_into().unwrap());
191 let computed_checksum = Crc32::checksum(&buf.as_ref()[..checksum_index]);
192 if stored_checksum != computed_checksum {
193 warn!(
194 blob = index,
195 stored = stored_checksum,
196 computed = computed_checksum,
197 "checksum mismatch"
198 );
199 return Ok(Loaded::Invalid(blob));
200 }
201
202 let version = u64::from_be_bytes(buf.as_ref()[..8].try_into().unwrap());
204
205 let mut data = BTreeMap::new();
210 let mut lengths = HashMap::new();
211 let mut cursor = u64::SIZE;
212 while cursor < checksum_index {
213 let key = K::read(&mut buf.as_ref()[cursor..].as_ref())
215 .expect("unable to read key from blob");
216 cursor += key.encode_size();
217
218 let value = V::read_cfg(&mut buf.as_ref()[cursor..].as_ref(), codec_config)
220 .expect("unable to read value from blob");
221 lengths.insert(key.clone(), Info::new(cursor, value.encode_size()));
222 cursor += value.encode_size();
223 data.insert(key, value);
224 }
225
226 Ok(Loaded::Valid(
228 data,
229 Wrapper::new(blob, version, lengths, buf),
230 ))
231 }
232
233 async fn normalize(
235 copy: Loaded<E::Blob, K, V>,
236 ) -> Result<(BTreeMap<K, V>, Wrapper<E::Blob, K>), Error> {
237 match copy {
238 Loaded::Valid(map, wrapper) => Ok((map, wrapper)),
239 Loaded::Invalid(blob) => {
240 blob.resize(0).await?;
241 blob.sync().await?;
242 Ok((BTreeMap::new(), Wrapper::empty(blob)))
243 }
244 }
245 }
246
247 fn get(&self, key: &K) -> Option<&V> {
249 self.map.get(key)
250 }
251
252 fn get_mut(&mut self, key: &K) -> Option<&mut V> {
254 let value = self.map.get_mut(key)?;
256
257 let cursor = self.state.cursor;
261 self.state.blobs[cursor].modified.insert(key.clone());
262 self.state.blobs[1 - cursor].modified.insert(key.clone());
263
264 Some(value)
265 }
266
267 fn clear(&mut self) {
269 self.map.clear();
271
272 self.state.key_order_changed = self.state.next_version;
274 self.keys.set(0);
275 }
276
277 fn put(&mut self, key: K, value: V) -> Option<V> {
279 let previous = self.map.insert(key.clone(), value);
281
282 if previous.is_some() {
286 let cursor = self.state.cursor;
287 self.state.blobs[cursor].modified.insert(key.clone());
288 self.state.blobs[1 - cursor].modified.insert(key);
289 } else {
290 self.state.key_order_changed = self.state.next_version;
291 }
292 let _ = self.keys.try_set(self.map.len());
293 previous
294 }
295
296 fn upsert(&mut self, key: K, f: impl FnOnce(&mut V))
298 where
299 V: Default,
300 {
301 if let Some(value) = self.get_mut(&key) {
302 f(value);
304 } else {
305 let mut value = V::default();
307 f(&mut value);
308 self.put(key, value);
309 }
310 }
311
312 fn remove(&mut self, key: &K) -> Option<V> {
314 let past = self.map.remove(key);
316
317 if past.is_some() {
319 self.state.key_order_changed = self.state.next_version;
320 }
321 let _ = self.keys.try_set(self.map.len());
322
323 past
324 }
325
326 fn keys(&self) -> impl Iterator<Item = &K> {
328 self.map.keys()
329 }
330
331 fn retain(&mut self, mut f: impl FnMut(&K, &V) -> bool) {
333 let old_len = self.map.len();
335 self.map.retain(|k, v| f(k, v));
336 let new_len = self.map.len();
337
338 if new_len != old_len {
340 self.state.key_order_changed = self.state.next_version;
341 let _ = self.keys.try_set(self.map.len());
342 }
343 }
344
345 async fn wait_for_pending(&mut self) -> Result<(), RError> {
347 let Some(completion) = &self.state.pending else {
351 return Ok(());
352 };
353 completion.clone().await?;
354 self.state.pending = None;
355 Ok(())
356 }
357
358 async fn sync(&mut self) -> Result<(), RError> {
360 self.wait_for_pending().await?;
361 self.write_next_version(false).await?;
362 Ok(())
363 }
364
365 async fn start_sync(&mut self) -> Result<Handle<()>, RError> {
367 self.wait_for_pending().await?;
368 self.write_next_version(true).await
369 }
370
371 async fn write_next_version(&mut self, pipelined: bool) -> Result<Handle<()>, RError> {
373 let cursor = self.state.cursor;
375 let next_version = self.state.next_version;
376 let key_order_changed = self.state.key_order_changed;
377
378 let past_version = self.state.blobs[cursor].version;
384 let next_next_version = next_version.checked_add(1).expect("version overflow");
385
386 let target_cursor = 1 - cursor;
388
389 if key_order_changed < past_version && self.state.blobs[target_cursor].modified.is_empty() {
394 return Ok(Handle::ready(Ok(())));
395 }
396
397 self.state.cursor = target_cursor;
399 self.state.next_version = next_next_version;
400
401 let target = &mut self.state.blobs[target_cursor];
403
404 let mut overwrite = true;
408 if key_order_changed < past_version {
409 for key in target.modified.iter() {
410 let info = target.lengths.get(key).expect("key must exist");
411 let new_value = self.map.get(key).expect("key must exist");
412 if info.length == new_value.encode_size() {
413 let start = info.start;
415 let end = start + info.length;
416 let mut buf = &mut target.data.as_mut()[start..end];
417 new_value.write(&mut buf);
418 } else {
419 overwrite = false;
421 break;
422 }
423 }
424 } else {
425 overwrite = false;
427 }
428
429 if overwrite {
431 (&mut target.data.as_mut()[0..u64::SIZE]).put_u64(next_version);
433
434 let checksum_index = target.data.len() - crc32::Digest::SIZE;
436 let checksum = Crc32::checksum(&target.data.as_ref()[..checksum_index]);
437 (&mut target.data.as_mut()[checksum_index..]).put_u32(checksum);
438
439 let data = std::mem::take(&mut target.data).freeze();
443
444 let writes = target
447 .modified
448 .iter()
449 .map(|key| {
450 let info = target.lengths.get(key).expect("key must exist");
451 let start = info.start;
452 let end = start + info.length;
453 target.blob.write_at(
454 start as u64,
455 data.slice(start..end),
456 WriteOptions::DONT_CACHE,
457 )
458 })
459 .chain([
460 target
461 .blob
462 .write_at(0, data.slice(0..u64::SIZE), WriteOptions::DONT_CACHE),
463 target.blob.write_at(
464 checksum_index as u64,
465 data.slice(checksum_index..checksum_index + crc32::Digest::SIZE),
466 WriteOptions::DONT_CACHE,
467 ),
468 ]);
469 try_join_all(writes).await?;
470 let sync = if pipelined {
471 Some(target.blob.start_sync().await)
472 } else {
473 target.blob.sync().await?;
474 None
475 };
476
477 target.modified.clear();
479
480 target.version = next_version;
482 target.data = data.into_mut_with_pool(self.context.storage_buffer_pool());
483 self.sync_overwrites.inc();
484 return Ok(self.record_pending(sync));
485 }
486
487 target.modified.clear();
489
490 let mut lengths = HashMap::with_capacity(self.map.len());
494 let mut next_data_len = u64::SIZE + crc32::Digest::SIZE;
495 for (key, value) in &self.map {
496 let value_len = value.encode_size();
497 lengths.insert(key.clone(), Info::new(0, value_len));
498 next_data_len += key.encode_size() + value_len;
499 }
500
501 let target_data_len = target.data.len();
504
505 let mut next_data = if target.data.capacity() >= next_data_len {
507 let mut data = std::mem::take(&mut target.data);
508 data.clear();
509 data
510 } else {
511 self.context.storage_buffer_pool().alloc(next_data_len)
512 };
513 next_data.put_u64(next_version);
514
515 for (key, value) in &self.map {
517 key.write(&mut next_data);
518 let info = lengths.get_mut(key).expect("key must exist");
519 info.start = next_data.len();
520 value.write(&mut next_data);
521 }
522 next_data.put_u32(Crc32::checksum(next_data.as_ref()));
523
524 let next_data = next_data.freeze();
526 let shrinking = next_data.len() < target_data_len;
527
528 let sync = if pipelined {
531 target
532 .blob
533 .write_at(0, next_data.clone(), WriteOptions::DONT_CACHE)
534 .await?;
535 if shrinking {
536 target.blob.resize(next_data.len() as u64).await?;
537 }
538 Some(target.blob.start_sync().await)
539 } else if shrinking {
540 target
541 .blob
542 .write_at(0, next_data.clone(), WriteOptions::DONT_CACHE)
543 .await?;
544 target.blob.resize(next_data.len() as u64).await?;
545 target.blob.sync().await?;
546 None
547 } else {
548 target
551 .blob
552 .write_at(
553 0,
554 next_data.clone(),
555 WriteOptions::SYNC | WriteOptions::DONT_CACHE,
556 )
557 .await?;
558 None
559 };
560
561 target.version = next_version;
563 target.lengths = lengths;
564 target.data = next_data.into_mut_with_pool(self.context.storage_buffer_pool());
565
566 self.sync_rewrites.inc();
567 Ok(self.record_pending(sync))
568 }
569
570 fn record_pending(&mut self, sync: Option<Handle<()>>) -> Handle<()> {
572 let Some(sync) = sync else {
573 return Handle::ready(Ok(()));
574 };
575 let completion: SyncCompletion = sync.boxed().shared();
576 let handle = Handle::from_future(completion.clone());
577 self.state.pending = Some(completion);
578 handle
579 }
580
581 async fn destroy(mut self) -> Result<(), Error> {
583 if let Some(pending) = self.state.pending.take() {
584 let _ = pending.await;
585 }
586 let state = self.state;
587 for (i, wrapper) in state.blobs.into_iter().enumerate() {
588 drop(wrapper.blob);
589 self.context
590 .remove(&self.partition, Some(BLOB_NAMES[i]))
591 .await?;
592 debug!(blob = i, "destroyed blob");
593 }
594 match self.context.remove(&self.partition, None).await {
595 Ok(()) => {}
596 Err(RError::PartitionMissing(_)) => {
597 }
599 Err(err) => return Err(Error::Runtime(err)),
600 }
601 Ok(())
602 }
603}
604
605pub struct Metadata<E: Context, K: Span, V: Codec>(Box<Inner<E, K, V>>);
610
611impl<E: Context, K: Span, V: Codec> std::fmt::Debug for Metadata<E, K, V> {
612 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
613 f.debug_struct("Metadata")
614 .field("keys", &self.0.map.len())
615 .finish_non_exhaustive()
616 }
617}
618
619impl<E: Context, K: Span, V: Codec> Metadata<E, K, V> {
620 pub async fn init(context: E, cfg: Config<V::Cfg>) -> Result<Self, Error> {
622 Ok(Self(Box::new(Inner::init(context, cfg).await?)))
623 }
624
625 pub fn get(&self, key: &K) -> Option<&V> {
627 self.0.get(key)
628 }
629
630 pub fn get_mut(&mut self, key: &K) -> Option<&mut V> {
632 self.0.get_mut(key)
633 }
634
635 pub fn clear(&mut self) {
638 self.0.clear();
639 }
640
641 pub fn put(&mut self, key: K, value: V) -> Option<V> {
647 self.0.put(key, value)
648 }
649
650 pub async fn put_sync(mut self, key: K, value: V) -> Result<Self, Error> {
655 self.0.put(key, value);
656 self.0.sync().await?;
657 Ok(self)
658 }
659
660 pub fn upsert(&mut self, key: K, f: impl FnOnce(&mut V))
662 where
663 V: Default,
664 {
665 self.0.upsert(key, f);
666 }
667
668 pub async fn upsert_sync(mut self, key: K, f: impl FnOnce(&mut V)) -> Result<Self, Error>
670 where
671 V: Default,
672 {
673 self.0.upsert(key, f);
674 self.0.sync().await?;
675 Ok(self)
676 }
677
678 pub fn remove(&mut self, key: &K) -> Option<V> {
680 self.0.remove(key)
681 }
682
683 pub fn keys(&self) -> impl Iterator<Item = &K> {
685 self.0.keys()
686 }
687
688 pub fn retain(&mut self, f: impl FnMut(&K, &V) -> bool) {
690 self.0.retain(f);
691 }
692
693 pub async fn sync(mut self) -> Result<Self, Error> {
695 self.0.sync().await?;
696 Ok(self)
697 }
698
699 pub async fn start_sync(mut self) -> Result<(Self, Handle<()>), Error> {
707 let handle = self.0.start_sync().await?;
708 Ok((self, handle))
709 }
710
711 pub async fn destroy(self) -> Result<(), Error> {
713 self.0.destroy().await
714 }
715}