iroh_blobs/
store.rs

1//! Implementations of blob stores
2use crate::{BlobFormat, Hash, HashAndFormat};
3
4#[cfg(feature = "fs-store")]
5mod bao_file;
6pub mod mem;
7mod mutable_mem_storage;
8pub mod readonly_mem;
9
10#[cfg(feature = "fs-store")]
11pub mod fs;
12
13mod traits;
14use tracing::warn;
15pub use traits::*;
16
17/// Create a 16 byte unique ID.
18fn new_uuid() -> [u8; 16] {
19    use rand::Rng;
20    rand::thread_rng().gen::<[u8; 16]>()
21}
22
23/// Create temp file name based on a 16 byte UUID.
24fn temp_name() -> String {
25    format!("{}.temp", hex::encode(new_uuid()))
26}
27
28#[derive(Debug, Default, Clone)]
29struct TempCounters {
30    /// number of raw temp tags for a hash
31    raw: u64,
32    /// number of hash seq temp tags for a hash
33    hash_seq: u64,
34}
35
36impl TempCounters {
37    fn counter(&mut self, format: BlobFormat) -> &mut u64 {
38        match format {
39            BlobFormat::Raw => &mut self.raw,
40            BlobFormat::HashSeq => &mut self.hash_seq,
41        }
42    }
43
44    fn inc(&mut self, format: BlobFormat) {
45        let counter = self.counter(format);
46        *counter = counter.checked_add(1).unwrap();
47    }
48
49    fn dec(&mut self, format: BlobFormat) {
50        let counter = self.counter(format);
51        *counter = counter.saturating_sub(1);
52    }
53
54    fn is_empty(&self) -> bool {
55        self.raw == 0 && self.hash_seq == 0
56    }
57}
58
59#[derive(Debug, Clone, Default)]
60struct TempCounterMap(std::collections::BTreeMap<Hash, TempCounters>);
61
62impl TempCounterMap {
63    fn inc(&mut self, value: &HashAndFormat) {
64        let HashAndFormat { hash, format } = value;
65        self.0.entry(*hash).or_default().inc(*format)
66    }
67
68    fn dec(&mut self, value: &HashAndFormat) {
69        let HashAndFormat { hash, format } = value;
70        let Some(counters) = self.0.get_mut(hash) else {
71            warn!("Decrementing non-existent temp tag");
72            return;
73        };
74        counters.dec(*format);
75        if counters.is_empty() {
76            self.0.remove(hash);
77        }
78    }
79
80    fn contains(&self, hash: &Hash) -> bool {
81        self.0.contains_key(hash)
82    }
83
84    fn keys(&self) -> impl Iterator<Item = HashAndFormat> {
85        let mut res = Vec::new();
86        for (k, v) in self.0.iter() {
87            if v.raw > 0 {
88                res.push(HashAndFormat::raw(*k));
89            }
90            if v.hash_seq > 0 {
91                res.push(HashAndFormat::hash_seq(*k));
92            }
93        }
94        res.into_iter()
95    }
96}