#[cfg(any(test, feature = "test-traits"))] use crate::qmdb::any::traits::PersistableMutableLog; use crate::{ index::Unordered as Index, journal::contiguous::{Contiguous, Mutable, Reader}, kv, mmr::Location, qmdb::{ any::{ db::{AuthenticatedLog, Db}, ValueEncoding, }, build_snapshot_from_log, operation::{Committable, Key, Operation as OperationTrait}, Error, }, }; use commonware_codec::Codec; use commonware_cryptography::Hasher; use commonware_runtime::{Clock, Metrics, Storage}; pub mod fixed; pub mod variable; pub use crate::qmdb::any::operation::{update::Unordered as Update, Unordered as Operation}; impl< E: Storage + Clock + Metrics, K: Key, V: ValueEncoding, C: Contiguous>, I: Index, H: Hasher, > Db> where Operation: Codec, { /// Returns the value for `key` and its location, or None if the key is not active. pub(crate) async fn get_with_loc( &self, key: &K, ) -> Result, Error> { // Collect to avoid holding a borrow across await points (rust-lang/rust#100013). let locs: Vec = self.snapshot.get(key).copied().collect(); let reader = self.log.reader().await; for loc in locs { let op = reader.read(*loc).await?; match &op { Operation::Update(Update(k, value)) => { if k == key { return Ok(Some((value.clone(), loc))); } } _ => unreachable!("location {loc} does not reference update operation"), } } Ok(None) } /// Get the value of `key` in the db, or None if it has no value. pub async fn get(&self, key: &K) -> Result, Error> { self.get_with_loc(key) .await .map(|op| op.map(|(value, _)| value)) } } impl< E: Storage + Clock + Metrics, C: Mutable, O: OperationTrait + Codec + Committable + Send + Sync, I: Index, H: Hasher, U: Send + Sync, > Db { /// Returns an [Db] initialized directly from the given components. The log is /// replayed from `inactivity_floor_loc` to build the snapshot, and that value is used as the /// inactivity floor. The last operation is assumed to be a commit. pub(crate) async fn from_components( inactivity_floor_loc: Location, log: AuthenticatedLog, mut snapshot: I, ) -> Result { let (active_keys, last_commit_loc) = { let reader = log.reader().await; let active_keys = build_snapshot_from_log(inactivity_floor_loc, &reader, &mut snapshot, |_, _| {}) .await?; let last_commit_loc = Location::new( reader .bounds() .end .checked_sub(1) .expect("commit should exist"), ); assert!(reader.read(*last_commit_loc).await?.is_commit()); (active_keys, last_commit_loc) }; Ok(Self { log, inactivity_floor_loc, snapshot, last_commit_loc, active_keys, _update: core::marker::PhantomData, }) } } impl< E: Storage + Clock + Metrics, K: Key, V: ValueEncoding, C: Contiguous>, I: Index + Send + Sync + 'static, H: Hasher, > kv::Gettable for Db> where Operation: Codec, V::Value: Send + Sync, { type Key = K; type Value = V::Value; type Error = Error; async fn get(&self, key: &Self::Key) -> Result, Self::Error> { self.get(key).await } } #[cfg(any(test, feature = "test-traits"))] impl crate::qmdb::any::traits::DbAny for Db> where E: Storage + Clock + Metrics, K: Key, V: ValueEncoding + 'static, C: PersistableMutableLog>, I: Index + Send + Sync + 'static, H: Hasher, Operation: Codec, V::Value: Send + Sync, { type Digest = H::Digest; }