iroh_blobs/store/fs/
tables.rs1use std::collections::BTreeSet;
3
4use redb::{ReadableTable, TableDefinition, TableError};
5
6use super::{EntryState, PathOptions};
7use crate::{util::Tag, Hash, HashAndFormat};
8
9pub(super) const BLOBS_TABLE: TableDefinition<Hash, EntryState> = TableDefinition::new("blobs-0");
10
11pub(super) const TAGS_TABLE: TableDefinition<Tag, HashAndFormat> = TableDefinition::new("tags-0");
12
13pub(super) const INLINE_DATA_TABLE: TableDefinition<Hash, &[u8]> =
14 TableDefinition::new("inline-data-0");
15
16pub(super) const INLINE_OUTBOARD_TABLE: TableDefinition<Hash, &[u8]> =
17 TableDefinition::new("inline-outboard-0");
18
19pub(super) trait ReadableTables {
23 fn blobs(&self) -> &impl ReadableTable<Hash, EntryState>;
24 fn tags(&self) -> &impl ReadableTable<Tag, HashAndFormat>;
25 fn inline_data(&self) -> &impl ReadableTable<Hash, &'static [u8]>;
26 fn inline_outboard(&self) -> &impl ReadableTable<Hash, &'static [u8]>;
27}
28
29pub(super) struct Tables<'a> {
32 pub blobs: redb::Table<'a, Hash, EntryState>,
33 pub tags: redb::Table<'a, Tag, HashAndFormat>,
34 pub inline_data: redb::Table<'a, Hash, &'static [u8]>,
35 pub inline_outboard: redb::Table<'a, Hash, &'static [u8]>,
36 pub delete_after_commit: &'a mut DeleteSet,
37}
38
39#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
40pub(super) enum BaoFilePart {
41 Outboard,
42 Data,
43 Sizes,
44}
45
46impl<'txn> Tables<'txn> {
47 pub fn new(
48 tx: &'txn redb::WriteTransaction,
49 delete_after_commit: &'txn mut DeleteSet,
50 ) -> std::result::Result<Self, TableError> {
51 Ok(Self {
52 blobs: tx.open_table(BLOBS_TABLE)?,
53 tags: tx.open_table(TAGS_TABLE)?,
54 inline_data: tx.open_table(INLINE_DATA_TABLE)?,
55 inline_outboard: tx.open_table(INLINE_OUTBOARD_TABLE)?,
56 delete_after_commit,
57 })
58 }
59}
60
61impl ReadableTables for Tables<'_> {
62 fn blobs(&self) -> &impl ReadableTable<Hash, EntryState> {
63 &self.blobs
64 }
65 fn tags(&self) -> &impl ReadableTable<Tag, HashAndFormat> {
66 &self.tags
67 }
68 fn inline_data(&self) -> &impl ReadableTable<Hash, &'static [u8]> {
69 &self.inline_data
70 }
71 fn inline_outboard(&self) -> &impl ReadableTable<Hash, &'static [u8]> {
72 &self.inline_outboard
73 }
74}
75
76pub(super) struct ReadOnlyTables {
79 pub blobs: redb::ReadOnlyTable<Hash, EntryState>,
80 pub tags: redb::ReadOnlyTable<Tag, HashAndFormat>,
81 pub inline_data: redb::ReadOnlyTable<Hash, &'static [u8]>,
82 pub inline_outboard: redb::ReadOnlyTable<Hash, &'static [u8]>,
83}
84
85impl ReadOnlyTables {
86 pub fn new(tx: &redb::ReadTransaction) -> std::result::Result<Self, TableError> {
87 Ok(Self {
88 blobs: tx.open_table(BLOBS_TABLE)?,
89 tags: tx.open_table(TAGS_TABLE)?,
90 inline_data: tx.open_table(INLINE_DATA_TABLE)?,
91 inline_outboard: tx.open_table(INLINE_OUTBOARD_TABLE)?,
92 })
93 }
94}
95
96impl ReadableTables for ReadOnlyTables {
97 fn blobs(&self) -> &impl ReadableTable<Hash, EntryState> {
98 &self.blobs
99 }
100 fn tags(&self) -> &impl ReadableTable<Tag, HashAndFormat> {
101 &self.tags
102 }
103 fn inline_data(&self) -> &impl ReadableTable<Hash, &'static [u8]> {
104 &self.inline_data
105 }
106 fn inline_outboard(&self) -> &impl ReadableTable<Hash, &'static [u8]> {
107 &self.inline_outboard
108 }
109}
110
111#[derive(Debug, Default)]
113pub(super) struct DeleteSet(BTreeSet<(Hash, BaoFilePart)>);
114
115impl DeleteSet {
116 pub fn insert(&mut self, hash: Hash, parts: impl IntoIterator<Item = BaoFilePart>) {
118 for part in parts {
119 self.0.insert((hash, part));
120 }
121 }
122
123 pub fn remove(&mut self, hash: Hash, parts: impl IntoIterator<Item = BaoFilePart>) {
127 for part in parts {
128 self.0.remove(&(hash, part));
129 }
130 }
131
132 pub fn into_inner(self) -> BTreeSet<(Hash, BaoFilePart)> {
134 self.0
135 }
136
137 pub fn apply_and_clear(&mut self, options: &PathOptions) {
142 for (hash, to_delete) in &self.0 {
143 tracing::debug!("deleting {:?} for {hash}", to_delete);
144 let path = match to_delete {
145 BaoFilePart::Data => options.owned_data_path(hash),
146 BaoFilePart::Outboard => options.owned_outboard_path(hash),
147 BaoFilePart::Sizes => options.owned_sizes_path(hash),
148 };
149 if let Err(cause) = std::fs::remove_file(&path) {
150 if cause.kind() != std::io::ErrorKind::NotFound {
152 tracing::warn!(
153 "failed to delete {:?} {}: {}",
154 to_delete,
155 path.display(),
156 cause
157 );
158 }
159 }
160 }
161 self.0.clear();
162 }
163}