use crate::mmr::Location; use std::{future::Future, ops::Range}; /// Journal of operations used by a [super::Database] pub trait Journal: Sized + Send { /// The context of the journal type Context; /// The configuration of the journal type Config; /// The type of operations in the journal type Op: Send; /// The error type returned by the journal type Error: std::error::Error + Send + 'static + Into; /// Create/open a journal for syncing the given range. /// /// The implementation must: /// - Reuse any on-disk data whose logical locations lie within the range. /// - Discard/ignore any data outside the range. /// - Report `size()` equal to the next location to be filled. fn new( context: Self::Context, config: Self::Config, range: Range, ) -> impl Future>; /// Discard all operations before the given location. /// /// If current `size() <= start`, initialize as empty at the given location. /// Otherwise prune data before the given location. fn resize(&mut self, start: Location) -> impl Future> + Send; /// Persist the journal. fn sync(&mut self) -> impl Future> + Send; /// Get the number of operations in the journal fn size(&self) -> impl Future + Send; /// Append an operation to the journal fn append(&mut self, op: Self::Op) -> impl Future> + Send; } impl Journal for crate::journal::contiguous::variable::Journal where E: commonware_runtime::Clock + commonware_runtime::Storage + commonware_runtime::Metrics, V: commonware_codec::CodecShared, { type Context = E; type Config = crate::journal::contiguous::variable::Config; type Op = V; type Error = crate::journal::Error; async fn new( context: Self::Context, config: Self::Config, range: Range, ) -> Result { Self::init_sync(context, config.clone(), *range.start..*range.end).await } async fn resize(&mut self, start: Location) -> Result<(), Self::Error> { if self.size() <= start { self.clear_to_size(*start).await } else { self.prune(*start).await.map(|_| ()) } } async fn sync(&mut self) -> Result<(), Self::Error> { Self::sync(self).await } async fn size(&self) -> u64 { Self::size(self) } async fn append(&mut self, op: Self::Op) -> Result<(), Self::Error> { Self::append(self, op).await.map(|_| ()) } } impl Journal for crate::journal::contiguous::fixed::Journal where E: commonware_runtime::Clock + commonware_runtime::Storage + commonware_runtime::Metrics, A: commonware_codec::CodecFixedShared, { type Context = E; type Config = crate::journal::contiguous::fixed::Config; type Op = A; type Error = crate::journal::Error; async fn new( context: Self::Context, config: Self::Config, range: Range, ) -> Result { assert!(!range.is_empty(), "range must not be empty"); let mut journal = Self::init(context, config).await?; let size = journal.size(); if size > *range.end { return Err(crate::journal::Error::ItemOutOfRange(size)); } if size <= *range.start { if *range.start != 0 { journal.clear_to_size(*range.start).await?; } } else { journal.prune(*range.start).await?; } Ok(journal) } async fn resize(&mut self, start: Location) -> Result<(), Self::Error> { if self.size() <= start { self.clear_to_size(*start).await } else { self.prune(*start).await.map(|_| ()) } } async fn sync(&mut self) -> Result<(), Self::Error> { Self::sync(self).await } async fn size(&self) -> u64 { Self::size(self) } async fn append(&mut self, op: Self::Op) -> Result<(), Self::Error> { Self::append(self, op).await.map(|_| ()) } }