1use crate::{
2 Context,
3 archive::{Error, Identifier, immutable::Config},
4 freezer::{self, Checkpoint, Cursor, Freezer},
5 metadata::{self, Metadata},
6 ordinal::{self, Ordinal},
7};
8use commonware_codec::{CodecShared, EncodeSize, FixedSize, Read, ReadExt, Write};
9use commonware_runtime::{
10 Buf, BufMut,
11 telemetry::metrics::{Counter, MetricsExt as _},
12};
13use commonware_utils::{Array, bitmap::BitMap, sequence::prefixed_u64::U64};
14use futures::{TryFutureExt as _, try_join};
15use std::collections::BTreeMap;
16use tracing::debug;
17
18const FREEZER_PREFIX: u8 = 0;
20
21const ORDINAL_PREFIX: u8 = 1;
23
24#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
26enum Record {
27 Freezer(Checkpoint),
28 Ordinal(Option<BitMap>),
29}
30
31impl Record {
32 fn freezer(&self) -> &Checkpoint {
34 match self {
35 Self::Freezer(checkpoint) => checkpoint,
36 _ => panic!("incorrect record"),
37 }
38 }
39
40 fn ordinal(&self) -> &Option<BitMap> {
42 match self {
43 Self::Ordinal(indices) => indices,
44 _ => panic!("incorrect record"),
45 }
46 }
47}
48
49impl Write for Record {
50 fn write(&self, buf: &mut impl BufMut) {
51 match self {
52 Self::Freezer(checkpoint) => {
53 buf.put_u8(0);
54 checkpoint.write(buf);
55 }
56 Self::Ordinal(indices) => {
57 buf.put_u8(1);
58 indices.write(buf);
59 }
60 }
61 }
62}
63
64impl Read for Record {
65 type Cfg = ();
66 fn read_cfg(buf: &mut impl Buf, _: &Self::Cfg) -> Result<Self, commonware_codec::Error> {
67 let tag = u8::read(buf)?;
68 match tag {
69 0 => Ok(Self::Freezer(Checkpoint::read(buf)?)),
70 1 => Ok(Self::Ordinal(Option::<BitMap>::read_cfg(
71 buf,
72 &(usize::MAX as u64),
73 )?)),
74 _ => Err(commonware_codec::Error::InvalidEnum(tag)),
75 }
76 }
77}
78
79impl EncodeSize for Record {
80 fn encode_size(&self) -> usize {
81 1 + match self {
82 Self::Freezer(_) => Checkpoint::SIZE,
83 Self::Ordinal(indices) => indices.encode_size(),
84 }
85 }
86}
87
88struct Inner<E: Context, K: Array, V: CodecShared> {
90 items_per_section: u64,
92
93 metadata: Metadata<E, U64, Record>,
95
96 freezer: Freezer<E, K, V>,
98
99 ordinal: Ordinal<E, Cursor>,
101
102 gets: Counter,
104 has: Counter,
105 syncs: Counter,
106}
107
108impl<E: Context, K: Array, V: CodecShared> Inner<E, K, V> {
109 async fn init(context: E, cfg: Config<V::Cfg>) -> Result<Self, Error> {
111 let metadata = Metadata::<E, U64, Record>::init(
113 context.child("metadata"),
114 metadata::Config {
115 partition: cfg.metadata_partition,
116 codec_config: (),
117 },
118 )
119 .await?;
120
121 let freezer_key = U64::new(FREEZER_PREFIX, 0);
124 let checkpoint = metadata.get(&freezer_key).map(|freezer| *freezer.freezer());
125
126 let freezer = Freezer::init(
130 context.child("freezer"),
131 freezer::Config {
132 key_partition: cfg.freezer_key_partition,
133 key_write_buffer: cfg.freezer_key_write_buffer,
134 key_page_cache: cfg.freezer_key_page_cache,
135 value_partition: cfg.freezer_value_partition,
136 value_compression: cfg.freezer_value_compression,
137 value_write_buffer: cfg.freezer_value_write_buffer,
138 value_target_size: cfg.freezer_value_target_size,
139 table_partition: cfg.freezer_table_partition,
140 table_initial_size: cfg.freezer_table_initial_size,
141 table_resize_frequency: cfg.freezer_table_resize_frequency,
142 table_resize_chunk_size: cfg.freezer_table_resize_chunk_size,
143 table_replay_buffer: cfg.replay_buffer,
144 codec_config: cfg.codec_config,
145 },
146 checkpoint,
147 )
148 .await?;
149
150 let sections = metadata
153 .keys()
154 .filter(|k| k.prefix() == ORDINAL_PREFIX)
155 .collect::<Vec<_>>();
156 let mut section_bits = BTreeMap::new();
157 for section in sections {
158 let bits = metadata.get(section).unwrap().ordinal();
160
161 let section = section.value();
163 section_bits.insert(section, bits);
164 }
165
166 let ordinal = Ordinal::init(
170 context.child("ordinal"),
171 ordinal::Config {
172 partition: cfg.ordinal_partition,
173 items_per_blob: cfg.items_per_section,
174 write_buffer: cfg.ordinal_write_buffer,
175 replay_buffer: cfg.replay_buffer,
176 },
177 Some(section_bits),
178 )
179 .await?;
180
181 let gets = context.counter("gets", "Number of gets performed");
183 let has = context.counter("has", "Number of has performed");
184 let syncs = context.counter("syncs", "Number of syncs called");
185
186 Ok(Self {
187 items_per_section: cfg.items_per_section.get(),
188 metadata,
189 freezer,
190 ordinal,
191 gets,
192 has,
193 syncs,
194 })
195 }
196
197 async fn get_index(&self, index: u64) -> Result<Option<V>, Error> {
199 let Some(cursor) = self.ordinal.get(index).await? else {
201 return Ok(None);
202 };
203
204 let result = self
206 .freezer
207 .get(freezer::Identifier::Cursor(cursor))
208 .await?;
209
210 Ok(result)
212 }
213
214 async fn get_key(&self, key: &K) -> Result<Option<V>, Error> {
216 let result = self.freezer.get(freezer::Identifier::Key(key)).await?;
218
219 Ok(result)
221 }
222
223 fn initialize_section(&mut self, section: u64) {
225 let bits = BitMap::zeroes(self.items_per_section);
227
228 let key = U64::new(ORDINAL_PREFIX, section);
230 self.metadata.put(key, Record::Ordinal(Some(bits)));
231 debug!(section, "initialized section");
232 }
233}
234
235impl<E: Context, K: Array, V: CodecShared> Inner<E, K, V> {
236 async fn put(mut self: Box<Self>, index: u64, key: K, data: V) -> Result<Box<Self>, Error> {
238 if self.ordinal.has(index) {
240 return Ok(self);
241 }
242
243 let section = index / self.items_per_section;
245 let ordinal_key = U64::new(ORDINAL_PREFIX, section);
246 if self.metadata.get(&ordinal_key).is_none() {
247 self.initialize_section(section);
248 }
249 let record = self.metadata.get_mut(&ordinal_key).unwrap();
250
251 let done = if let Record::Ordinal(Some(bits)) = record {
253 bits.set(index % self.items_per_section, true);
254 bits.count_ones() == self.items_per_section
255 } else {
256 false
257 };
258 if done {
259 *record = Record::Ordinal(None);
260 }
261
262 let cursor;
264 (self.freezer, cursor) = self.freezer.put(key, data).await?;
265
266 self.ordinal = self.ordinal.put(index, cursor).await?;
268
269 Ok(self)
270 }
271
272 async fn get(&self, identifier: Identifier<'_, K>) -> Result<Option<V>, Error> {
274 self.gets.inc();
275
276 match identifier {
277 Identifier::Index(index) => self.get_index(index).await,
278 Identifier::Key(key) => self.get_key(key).await,
279 }
280 }
281
282 async fn has(&self, identifier: Identifier<'_, K>) -> Result<bool, Error> {
284 self.has.inc();
285
286 match identifier {
287 Identifier::Index(index) => Ok(self.ordinal.has(index)),
288 Identifier::Key(key) => Ok(self.freezer.has(key).await?),
289 }
290 }
291
292 async fn sync(mut self: Box<Self>) -> Result<Box<Self>, Error> {
294 self.syncs.inc();
295
296 let ((freezer, checkpoint), ordinal) = try_join!(
298 self.freezer.sync().map_err(Error::from),
299 self.ordinal.sync().map_err(Error::from)
300 )?;
301 self.freezer = freezer;
302 self.ordinal = ordinal;
303
304 let freezer_key = U64::new(FREEZER_PREFIX, 0);
307 self.metadata = self
308 .metadata
309 .put_sync(freezer_key, Record::Freezer(checkpoint))
310 .await?;
311
312 Ok(self)
313 }
314
315 fn next_gap(&self, index: u64) -> (Option<u64>, Option<u64>) {
317 self.ordinal.next_gap(index)
318 }
319
320 fn missing_items(&self, index: u64, max: usize) -> Vec<u64> {
322 self.ordinal.missing_items(index, max)
323 }
324
325 fn ranges(&self) -> impl Iterator<Item = (u64, u64)> {
327 self.ordinal.ranges()
328 }
329
330 fn ranges_from(&self, from: u64) -> impl Iterator<Item = (u64, u64)> {
332 self.ordinal.ranges_from(from)
333 }
334
335 fn first_index(&self) -> Option<u64> {
337 self.ordinal.first_index()
338 }
339
340 fn last_index(&self) -> Option<u64> {
342 self.ordinal.last_index()
343 }
344
345 async fn destroy(self) -> Result<(), Error> {
347 self.ordinal.destroy().await?;
349
350 self.freezer.destroy().await?;
352
353 self.metadata.destroy().await?;
355
356 Ok(())
357 }
358}
359
360pub struct Archive<E: Context, K: Array, V: CodecShared>(Box<Inner<E, K, V>>);
365
366impl<E: Context, K: Array, V: CodecShared> std::fmt::Debug for Archive<E, K, V> {
367 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
368 f.debug_struct("Archive")
369 .field("first_index", &self.0.first_index())
370 .field("last_index", &self.0.last_index())
371 .finish_non_exhaustive()
372 }
373}
374
375impl<E: Context, K: Array, V: CodecShared> Archive<E, K, V> {
376 pub async fn init(context: E, cfg: Config<V::Cfg>) -> Result<Self, Error> {
378 Ok(Self(Box::new(Inner::init(context, cfg).await?)))
379 }
380}
381
382impl<E: Context, K: Array, V: CodecShared> crate::archive::Archive for Archive<E, K, V> {
383 type Key = K;
384 type Value = V;
385
386 async fn put(mut self, index: u64, key: K, data: V) -> Result<Self, Error> {
387 self.0 = self.0.put(index, key, data).await?;
388 Ok(self)
389 }
390
391 async fn get(&self, identifier: Identifier<'_, K>) -> Result<Option<V>, Error> {
392 self.0.get(identifier).await
393 }
394
395 async fn has(&self, identifier: Identifier<'_, K>) -> Result<bool, Error> {
396 self.0.has(identifier).await
397 }
398
399 async fn sync(mut self) -> Result<Self, Error> {
400 self.0 = self.0.sync().await?;
401 Ok(self)
402 }
403
404 fn next_gap(&self, index: u64) -> (Option<u64>, Option<u64>) {
405 self.0.next_gap(index)
406 }
407
408 fn missing_items(&self, index: u64, max: usize) -> Vec<u64> {
409 self.0.missing_items(index, max)
410 }
411
412 fn ranges(&self) -> impl Iterator<Item = (u64, u64)> {
413 self.0.ranges()
414 }
415
416 fn ranges_from(&self, from: u64) -> impl Iterator<Item = (u64, u64)> {
417 self.0.ranges_from(from)
418 }
419
420 fn first_index(&self) -> Option<u64> {
421 self.0.first_index()
422 }
423
424 fn last_index(&self) -> Option<u64> {
425 self.0.last_index()
426 }
427
428 async fn destroy(self) -> Result<(), Error> {
429 self.0.destroy().await
430 }
431}
432
433#[cfg(all(test, feature = "arbitrary"))]
434mod conformance {
435 use super::*;
436 use commonware_codec::conformance::CodecConformance;
437
438 commonware_conformance::conformance_tests! {
439 CodecConformance<Record>
440 }
441}