1use crate::{
2 Context,
3 index::unordered::Index,
4 journal::{authenticated, contiguous::Mutable},
5 merkle::{
6 Family, Location,
7 full::{self, Merkle},
8 },
9 qmdb::{
10 self, Error,
11 any::ValueEncoding,
12 immutable::{self, CompactDb, Metrics, Operation},
13 operation::Key,
14 sync,
15 },
16 translator::Translator,
17};
18use commonware_codec::{EncodeShared, Read};
19use commonware_cryptography::Hasher;
20use commonware_parallel::Strategy;
21use commonware_utils::range::NonEmptyRange;
22use std::num::NonZeroU64;
23
24impl<F, E, K, V, C, H, T, S> sync::Database for immutable::Immutable<F, E, K, V, C, H, T, S>
25where
26 F: Family,
27 E: Context,
28 K: Key,
29 V: ValueEncoding,
30 C: Mutable<Item = Operation<F, K, V>> + sync::Journal<F, Context = E, Op = Operation<F, K, V>>,
31 C::Item: EncodeShared,
32 C::Config: Clone + Send,
33 H: Hasher,
34 T: Translator,
35 S: Strategy,
36{
37 type Family = F;
38 type Op = Operation<F, K, V>;
39 type Journal = C;
40 type Hasher = H;
41 type Config = immutable::Config<T, C::Config, S>;
42 type Digest = H::Digest;
43 type Context = E;
44
45 async fn from_sync_result(
62 context: Self::Context,
63 db_config: Self::Config,
64 log: Self::Journal,
65 pinned_nodes: Option<Vec<Self::Digest>>,
66 range: NonEmptyRange<Location<F>>,
67 apply_batch_size: NonZeroU64,
68 ) -> Result<Self, Error<F>> {
69 let hasher = qmdb::hasher::<H>();
70
71 let merkle = Merkle::<F, _, _, S>::init_sync(
73 context.child("merkle"),
74 full::SyncConfig {
75 config: db_config.merkle_config.clone(),
76 range: range.clone(),
77 pinned_nodes,
78 },
79 )
80 .await?;
81
82 let journal = authenticated::Journal::<_, _, _, _, S>::from_components(
83 merkle,
84 log,
85 hasher,
86 apply_batch_size.get(),
87 )
88 .await?;
89
90 let mut snapshot: Index<T, Location<F>> =
91 Index::new(context.child("snapshot"), db_config.translator.clone());
92
93 let (last_commit_loc, inactivity_floor_loc) = {
94 let bounds = journal.journal.bounds();
95 let last_commit_loc = Location::<F>::new(
96 bounds
97 .end
98 .checked_sub(1)
99 .ok_or(Error::HistoricalFloorPruned(Location::new(bounds.end)))?,
100 );
101 let inactivity_floor_loc = crate::qmdb::find_inactivity_floor_at::<F, _>(
102 &journal.journal,
103 Location::new(bounds.end),
104 )
105 .await?;
106
107 immutable::build_snapshot(
111 inactivity_floor_loc,
112 &journal.journal,
113 &mut snapshot,
114 db_config.init_buffer,
115 )
116 .await?;
117
118 (last_commit_loc, inactivity_floor_loc)
119 };
120 let inactive_peaks = F::inactive_peaks(last_commit_loc + 1, inactivity_floor_loc);
121 let root = journal.root(inactive_peaks)?;
122
123 let metrics = Metrics::new(context);
124 let db = Self {
125 journal,
126 root,
127 snapshot,
128 last_commit_loc,
129 inactivity_floor_loc,
130 metrics,
131 };
132 db.update_metrics();
133
134 db.sync().await
135 }
136
137 async fn persist_sync_result(self) -> Result<Self, Error<F>> {
138 Ok(self)
139 }
140
141 async fn local_pinned_nodes(
142 context: Self::Context,
143 config: &Self::Config,
144 target: &sync::Target<F, Self::Digest>,
145 journal: &Self::Journal,
146 ) -> Result<Option<Vec<Self::Digest>>, Error<F>> {
147 if target.range.start() == Location::new(0)
148 || !sync::journal_covers_range(journal.bounds(), &target.range)
149 {
150 return Ok(None);
151 }
152
153 let inactivity_floor =
156 qmdb::find_inactivity_floor_at::<F, _>(journal, target.range.end()).await?;
157
158 sync::local_pinned_nodes::<F, _, H, S>(
159 context,
160 config.merkle_config.clone(),
161 target,
162 inactivity_floor,
163 )
164 .await
165 }
166
167 fn root(&self) -> Self::Digest {
168 self.root()
169 }
170}
171
172impl<F, E, K, V, H, Cfg, S> sync::Database for CompactDb<F, E, K, V, H, Cfg, S>
173where
174 F: Family,
175 E: Context,
176 K: Key,
177 V: ValueEncoding,
178 H: Hasher,
179 S: Strategy,
180 Operation<F, K, V>: EncodeShared,
181 Operation<F, K, V>: Read<Cfg = Cfg>,
182 Cfg: Clone + Send + Sync + 'static,
183{
184 type Family = F;
185 type Op = Operation<F, K, V>;
186 type Journal = sync::journal::Memory<F, E, Operation<F, K, V>>;
187 type Config = immutable::CompactConfig<Cfg, S>;
188 type Digest = H::Digest;
189 type Context = E;
190 type Hasher = H;
191
192 async fn from_sync_result(
193 context: Self::Context,
194 config: Self::Config,
195 log: Self::Journal,
196 pinned_nodes: Option<Vec<Self::Digest>>,
197 range: NonEmptyRange<Location<F>>,
198 _apply_batch_size: NonZeroU64,
199 ) -> Result<Self, Error<F>> {
200 crate::qmdb::compact::from_sync_result(
201 context,
202 config,
203 log,
204 pinned_nodes,
205 range,
206 Self::init_from_sync,
207 )
208 .await
209 }
210
211 async fn persist_sync_result(self) -> Result<Self, Error<F>> {
212 self.sync().await
213 }
214
215 async fn local_pinned_nodes(
216 _context: Self::Context,
217 _config: &Self::Config,
218 _target: &sync::Target<F, Self::Digest>,
219 _journal: &Self::Journal,
220 ) -> Result<Option<Vec<Self::Digest>>, Error<F>> {
221 Ok(None)
222 }
223
224 fn root(&self) -> Self::Digest {
225 self.root()
226 }
227}
228
229#[cfg(test)]
230mod tests;