commonware_storage/qmdb/keyless/sync/
mod.rs1use crate::{
2 Context,
3 journal::{
4 authenticated,
5 contiguous::{Contiguous as _, Mutable},
6 },
7 merkle::{
8 Family, Location,
9 full::{self, Merkle},
10 },
11 qmdb::{
12 self,
13 any::value::ValueEncoding,
14 keyless::{CompactDb, Keyless, Metrics, Operation, operation::Codec},
15 sync,
16 },
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, V, C, H, S> sync::Database for Keyless<F, E, V, C, H, S>
25where
26 F: Family,
27 E: Context,
28 V: ValueEncoding + Codec,
29 C: Mutable<Item = Operation<F, V>> + sync::Journal<F, Context = E, Op = Operation<F, V>>,
30 C::Config: Clone + Send,
31 H: Hasher,
32 S: Strategy,
33 Operation<F, V>: EncodeShared,
34{
35 type Family = F;
36 type Op = Operation<F, V>;
37 type Journal = C;
38 type Hasher = H;
39 type Config = super::Config<C::Config, S>;
40 type Digest = H::Digest;
41 type Context = E;
42
43 async fn from_sync_result(
59 context: Self::Context,
60 config: Self::Config,
61 log: Self::Journal,
62 pinned_nodes: Option<Vec<Self::Digest>>,
63 range: NonEmptyRange<Location<F>>,
64 apply_batch_size: NonZeroU64,
65 ) -> Result<Self, qmdb::Error<F>> {
66 let hasher = qmdb::hasher::<H>();
67
68 let merkle = Merkle::<F, _, _, S>::init_sync(
69 context.child("merkle"),
70 full::SyncConfig {
71 config: config.merkle.clone(),
72 range: range.clone(),
73 pinned_nodes,
74 },
75 )
76 .await?;
77
78 let journal = authenticated::Journal::<F, _, _, _, S>::from_components(
79 merkle,
80 log,
81 hasher,
82 apply_batch_size.get(),
83 )
84 .await?;
85
86 let (last_commit_loc, inactivity_floor_loc) = {
87 let bounds = journal.bounds();
88 let loc = bounds
89 .end
90 .checked_sub(1)
91 .ok_or(qmdb::Error::HistoricalFloorPruned(Location::new(
92 bounds.end,
93 )))?;
94 let floor =
95 qmdb::find_inactivity_floor_at::<F, _>(&journal, Location::new(bounds.end)).await?;
96 (Location::new(loc), floor)
97 };
98 let inactive_peaks = F::inactive_peaks(last_commit_loc + 1, inactivity_floor_loc);
99 let root = journal.root(inactive_peaks)?;
100
101 let metrics = Metrics::new(context);
102 let db = Self {
103 journal,
104 root,
105 last_commit_loc,
106 inactivity_floor_loc,
107 metrics,
108 };
109 db.update_metrics();
110
111 db.sync().await
112 }
113
114 async fn persist_sync_result(self) -> Result<Self, qmdb::Error<F>> {
115 Ok(self)
116 }
117
118 async fn local_pinned_nodes(
119 context: Self::Context,
120 config: &Self::Config,
121 target: &sync::Target<F, Self::Digest>,
122 journal: &Self::Journal,
123 ) -> Result<Option<Vec<Self::Digest>>, qmdb::Error<F>> {
124 if target.range.start() == Location::new(0)
125 || !sync::journal_covers_range(journal.bounds(), &target.range)
126 {
127 return Ok(None);
128 }
129
130 let inactivity_floor =
133 qmdb::find_inactivity_floor_at::<F, _>(journal, target.range.end()).await?;
134
135 sync::local_pinned_nodes::<F, _, H, S>(
136 context,
137 config.merkle.clone(),
138 target,
139 inactivity_floor,
140 )
141 .await
142 }
143
144 fn root(&self) -> Self::Digest {
145 self.root()
146 }
147}
148
149impl<F, E, V, H, Cfg, S> sync::Database for CompactDb<F, E, V, H, Cfg, S>
150where
151 F: Family,
152 E: Context,
153 V: ValueEncoding + Codec,
154 H: Hasher,
155 S: Strategy,
156 Operation<F, V>: EncodeShared,
157 Operation<F, V>: Read<Cfg = Cfg>,
158 Cfg: Clone + Send + Sync + 'static,
159{
160 type Family = F;
161 type Op = Operation<F, V>;
162 type Journal = sync::journal::Memory<F, E, Operation<F, V>>;
163 type Config = super::CompactConfig<Cfg, S>;
164 type Digest = H::Digest;
165 type Context = E;
166 type Hasher = H;
167
168 async fn from_sync_result(
169 context: Self::Context,
170 config: Self::Config,
171 log: Self::Journal,
172 pinned_nodes: Option<Vec<Self::Digest>>,
173 range: NonEmptyRange<Location<F>>,
174 _apply_batch_size: NonZeroU64,
175 ) -> Result<Self, qmdb::Error<F>> {
176 crate::qmdb::compact::from_sync_result(
177 context,
178 config,
179 log,
180 pinned_nodes,
181 range,
182 Self::init_from_sync,
183 )
184 .await
185 }
186
187 async fn persist_sync_result(self) -> Result<Self, qmdb::Error<F>> {
188 self.sync().await
189 }
190
191 async fn local_pinned_nodes(
192 _context: Self::Context,
193 _config: &Self::Config,
194 _target: &sync::Target<F, Self::Digest>,
195 _journal: &Self::Journal,
196 ) -> Result<Option<Vec<Self::Digest>>, qmdb::Error<F>> {
197 Ok(None)
198 }
199
200 fn root(&self) -> Self::Digest {
201 self.root()
202 }
203}
204
205#[cfg(test)]
206mod tests;