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