Skip to content

Commit

Permalink
persistence: complete storage provider functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
dr-orlovsky committed Aug 29, 2024
1 parent c0f6a6c commit 48594c2
Show file tree
Hide file tree
Showing 4 changed files with 156 additions and 67 deletions.
33 changes: 12 additions & 21 deletions src/persistence/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ pub struct MemStash {

#[getter(skip)]
#[strict_type(skip)]
store_provider: Option<Box<dyn StoreProvider<Object = Self>>>,
store_provider: Option<Box<dyn StoreProvider<Self>>>,

schemata: TinyOrdMap<SchemaId, SchemaIfaces>,
ifaces: TinyOrdMap<IfaceId, Iface>,
Expand Down Expand Up @@ -473,7 +473,7 @@ pub struct MemState {

#[getter(skip)]
#[strict_type(skip)]
store_provider: Option<Box<dyn StoreProvider<Object = Self>>>,
store_provider: Option<Box<dyn StoreProvider<Self>>>,

witnesses: LargeOrdMap<XWitnessId, WitnessOrd>,
contracts: TinyOrdMap<ContractId, MemContractState>,
Expand Down Expand Up @@ -1178,7 +1178,7 @@ pub struct MemIndex {

#[getter(skip)]
#[strict_type(skip)]
store_provider: Option<Box<dyn StoreProvider<Object = Self>>>,
store_provider: Option<Box<dyn StoreProvider<Self>>>,

op_bundle_index: MediumOrdMap<OpId, BundleId>,
bundle_contract_index: MediumOrdMap<BundleId, ContractId>,
Expand Down Expand Up @@ -1458,10 +1458,7 @@ mod store {
use crate::persistence::{MemIndex, MemStash, MemState, StoreError, StoreProvider};

impl Stored for MemStash {
fn new_stored(
provider: impl StoreProvider<Object = Self> + 'static,
autosave: bool,
) -> Self {
fn new_stored(provider: impl StoreProvider<Self> + 'static, autosave: bool) -> Self {
Self {
dirty: true,
autosave,
Expand All @@ -1471,7 +1468,7 @@ mod store {
}

fn load(
provider: impl StoreProvider<Object = Self> + 'static,
provider: impl StoreProvider<Self> + 'static,
autosave: bool,
) -> Result<Self, StoreError> {
let mut me = provider.load()?;
Expand All @@ -1484,7 +1481,7 @@ mod store {

fn autosave(&mut self) { self.autosave = true; }

fn make_stored(&mut self, provider: impl StoreProvider<Object = Self> + 'static) -> bool {
fn make_stored(&mut self, provider: impl StoreProvider<Self> + 'static) -> bool {
let res = self.store_provider.is_some();
self.store_provider = Some(Box::new(provider));
self.dirty = true;
Expand All @@ -1502,10 +1499,7 @@ mod store {
}

impl Stored for MemState {
fn new_stored(
provider: impl StoreProvider<Object = Self> + 'static,
autosave: bool,
) -> Self {
fn new_stored(provider: impl StoreProvider<Self> + 'static, autosave: bool) -> Self {
Self {
dirty: true,
autosave,
Expand All @@ -1515,7 +1509,7 @@ mod store {
}

fn load(
provider: impl StoreProvider<Object = Self> + 'static,
provider: impl StoreProvider<Self> + 'static,
autosave: bool,
) -> Result<Self, StoreError> {
let mut me = provider.load()?;
Expand All @@ -1528,7 +1522,7 @@ mod store {

fn autosave(&mut self) { self.autosave = true; }

fn make_stored(&mut self, provider: impl StoreProvider<Object = Self> + 'static) -> bool {
fn make_stored(&mut self, provider: impl StoreProvider<Self> + 'static) -> bool {
let res = self.store_provider.is_some();
self.store_provider = Some(Box::new(provider));
self.dirty = true;
Expand All @@ -1546,10 +1540,7 @@ mod store {
}

impl Stored for MemIndex {
fn new_stored(
provider: impl StoreProvider<Object = Self> + 'static,
autosave: bool,
) -> Self {
fn new_stored(provider: impl StoreProvider<Self> + 'static, autosave: bool) -> Self {
Self {
dirty: true,
autosave,
Expand All @@ -1559,7 +1550,7 @@ mod store {
}

fn load(
provider: impl StoreProvider<Object = Self> + 'static,
provider: impl StoreProvider<Self> + 'static,
autosave: bool,
) -> Result<Self, StoreError> {
let mut me = provider.load()?;
Expand All @@ -1572,7 +1563,7 @@ mod store {

fn autosave(&mut self) { self.autosave = true; }

fn make_stored(&mut self, provider: impl StoreProvider<Object = Self> + 'static) -> bool {
fn make_stored(&mut self, provider: impl StoreProvider<Self> + 'static) -> bool {
let res = self.store_provider.is_some();
self.store_provider = Some(Box::new(provider));
self.dirty = true;
Expand Down
2 changes: 1 addition & 1 deletion src/persistence/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub use stock::{
ComposeError, ConsignError, ContractIfaceError, FasciaError, InputError as StockInputError,
Stock, StockError, StockErrorAll, StockErrorMem, UpdateRes,
};
pub use store::{StoreError, StoreProvider, Stored};
pub use store::{StockStoreProvider, StoreError, StoreProvider, Stored};

pub trait StoreTransaction {
type TransactionErr: std::error::Error;
Expand Down
59 changes: 21 additions & 38 deletions src/persistence/stock.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use super::{
IndexWriteProvider, MemIndex, MemStash, MemState, PersistedState, SchemaIfaces, Stash,
StashDataError, StashError, StashInconsistency, StashProvider, StashReadProvider,
StashWriteProvider, State, StateError, StateInconsistency, StateProvider, StateReadProvider,
StateWriteProvider, StoreProvider, StoreTransaction, Stored,
StateWriteProvider, StockStoreProvider, StoreError, StoreProvider, StoreTransaction, Stored,
};
use crate::containers::{
AnchorSet, AnchoredBundles, Batch, BuilderSeal, BundledWitness, Consignment, ContainerVer,
Expand Down Expand Up @@ -381,30 +381,15 @@ where
H: Stored,
I: Stored,
{
pub fn new_stored(
stash_provider: impl StoreProvider<Object = S> + 'static,
state_provider: impl StoreProvider<Object = H> + 'static,
index_provider: impl StoreProvider<Object = I> + 'static,
autosave: bool,
) -> Self {
let stash = S::new_stored(stash_provider, autosave);
let state = H::new_stored(state_provider, autosave);
let index = I::new_stored(index_provider, autosave);

Stock::with(stash, state, index)
}

pub fn load(
stash_provider: impl StoreProvider<Object = S> + 'static,
state_provider: impl StoreProvider<Object = H> + 'static,
index_provider: impl StoreProvider<Object = I> + 'static,
autosave: bool,
) -> Result<Self, String> {
let stash = S::load(stash_provider, autosave)?;
let state = H::load(state_provider, autosave)?;
let index = I::load(index_provider, autosave)?;

Ok(Stock::with(stash, state, index))
pub fn load<P>(provider: P, autosave: bool) -> Result<Self, StoreError>
where P: StoreProvider<Self> + 'static {
let mut stock = provider.load()?;
if autosave {
stock.stash.as_provider_mut().autosave();
stock.state.as_provider_mut().autosave();
stock.index.as_provider_mut().autosave();
}
Ok(stock)
}

pub fn autosave(&mut self) {
Expand All @@ -419,21 +404,12 @@ where
self.as_index_provider().is_dirty()
}

pub fn make_stored(
&mut self,
stash_provider: impl StoreProvider<Object = S> + 'static,
state_provider: impl StoreProvider<Object = H> + 'static,
index_provider: impl StoreProvider<Object = I> + 'static,
) -> bool {
let _1 = self.stash.as_provider_mut().make_stored(stash_provider);
let _2 = self.state.as_provider_mut().make_stored(state_provider);
let _3 = self.index.as_provider_mut().make_stored(index_provider);
assert_eq!(_1, _2);
assert_eq!(_2, _3);
_1
pub fn make_stored<P>(&mut self, provider: P) -> bool
where P: StockStoreProvider<S, H, I> + 'static {
provider.make_stored(self)
}

pub fn store(&self) -> Result<(), String> {
pub fn store(&self) -> Result<(), StoreError> {
self.as_stash_provider().store()?;
self.as_state_provider().store()?;
self.as_index_provider().store()?;
Expand All @@ -458,6 +434,13 @@ impl<S: StashProvider, H: StateProvider, P: IndexProvider> Stock<S, H, P> {
#[doc(hidden)]
pub fn as_index_provider(&self) -> &P { self.index.as_provider() }

#[doc(hidden)]
pub fn as_stash_provider_mut(&mut self) -> &mut S { self.stash.as_provider_mut() }
#[doc(hidden)]
pub fn as_state_provider_mut(&mut self) -> &mut H { self.state.as_provider_mut() }
#[doc(hidden)]
pub fn as_index_provider_mut(&mut self) -> &mut P { self.index.as_provider_mut() }

pub fn ifaces(&self) -> Result<impl Iterator<Item = IfaceInfo> + '_, StockError<S, H, P>> {
let names = self
.stash
Expand Down
129 changes: 122 additions & 7 deletions src/persistence/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ use std::error::Error;
use std::fmt::Debug;

use amplify::confinement;
use strict_encoding::{DeserializeError, SerializeError};

use crate::persistence::{IndexProvider, StashProvider, StateProvider, Stock};

#[derive(Debug, Display, Error)]
#[display(inner)]
Expand All @@ -32,23 +35,135 @@ impl From<confinement::Error> for StoreError {
fn from(err: confinement::Error) -> Self { Self(Box::new(err)) }
}

pub trait StoreProvider: Send + Debug {
type Object;
impl From<SerializeError> for StoreError {
fn from(err: SerializeError) -> Self { Self(Box::new(err)) }
}

impl From<DeserializeError> for StoreError {
fn from(err: DeserializeError) -> Self { Self(Box::new(err)) }
}

pub trait StockStoreProvider<S: StashProvider, H: StateProvider, I: IndexProvider>:
StoreProvider<Stock<S, H, I>>
{
fn make_stored(&self, stock: &mut Stock<S, H, I>) -> bool;
}

fn load(&self) -> Result<Self::Object, StoreError>;
fn store(&self, object: &Self::Object) -> Result<(), StoreError>;
pub trait StoreProvider<T>: Send + Debug {
fn load(&self) -> Result<T, StoreError>;
fn store(&self, object: &T) -> Result<(), StoreError>;
}

pub trait Stored: Sized {
fn new_stored(provider: impl StoreProvider<Object = Self> + 'static, autosave: bool) -> Self;
fn new_stored(provider: impl StoreProvider<Self> + 'static, autosave: bool) -> Self;
fn load(
provider: impl StoreProvider<Object = Self> + 'static,
provider: impl StoreProvider<Self> + 'static,
autosave: bool,
) -> Result<Self, StoreError>;

fn is_dirty(&self) -> bool;
fn autosave(&mut self);
fn make_stored(&mut self, provider: impl StoreProvider<Object = Self> + 'static) -> bool;
fn make_stored(&mut self, provider: impl StoreProvider<Self> + 'static) -> bool;

fn store(&self) -> Result<(), StoreError>;
}

#[cfg(feature = "fs")]
mod fs {
use std::path::PathBuf;

use amplify::confinement::U32 as U32MAX;
use strict_encoding::{StrictDeserialize, StrictSerialize};

use super::*;
use crate::persistence::{MemIndex, MemStash, MemState, Stock, Stored};

impl StoreProvider<MemStash> for PathBuf {
fn load(&self) -> Result<MemStash, StoreError> {
Ok(MemStash::strict_deserialize_from_file::<U32MAX>(&self)?)
}

fn store(&self, object: &MemStash) -> Result<(), StoreError> {
object.strict_serialize_to_file::<U32MAX>(&self)?;
Ok(())
}
}

impl StoreProvider<MemState> for PathBuf {
fn load(&self) -> Result<MemState, StoreError> {
Ok(MemState::strict_deserialize_from_file::<U32MAX>(&self)?)
}

fn store(&self, object: &MemState) -> Result<(), StoreError> {
object.strict_serialize_to_file::<U32MAX>(&self)?;
Ok(())
}
}

impl StoreProvider<MemIndex> for PathBuf {
fn load(&self) -> Result<MemIndex, StoreError> {
Ok(MemIndex::strict_deserialize_from_file::<U32MAX>(&self)?)
}

fn store(&self, object: &MemIndex) -> Result<(), StoreError> {
object.strict_serialize_to_file::<U32MAX>(&self)?;
Ok(())
}
}

impl StoreProvider<Stock> for PathBuf {
fn load(&self) -> Result<Stock, StoreError> {
let mut filename = self.to_owned();
filename.push("stash.dat");
let stash: MemStash = filename.load()?;

let mut filename = self.to_owned();
filename.push("state.dat");
let state: MemState = filename.load()?;

let mut filename = self.to_owned();
filename.push("index.dat");
let index: MemIndex = filename.load()?;

Ok(Stock::with(stash, state, index))
}

fn store(&self, stock: &Stock) -> Result<(), StoreError> {
// TODO: Revert files on failure

let mut filename = self.to_owned();
filename.push("stash.dat");
filename.store(stock.as_stash_provider())?;

let mut filename = self.to_owned();
filename.push("state.dat");
filename.store(stock.as_state_provider())?;

let mut filename = self.to_owned();
filename.push("index.dat");
filename.store(stock.as_index_provider())?;

Ok(())
}
}

impl StockStoreProvider<MemStash, MemState, MemIndex> for PathBuf {
fn make_stored(&self, stock: &mut Stock<MemStash, MemState, MemIndex>) -> bool {
let mut filename = self.to_owned();
filename.push("stash.dat");
let _1 = stock.as_stash_provider_mut().make_stored(filename);

let mut filename = self.to_owned();
filename.push("state.dat");
let _2 = stock.as_state_provider_mut().make_stored(filename);

let mut filename = self.to_owned();
filename.push("index.dat");
let _3 = stock.as_index_provider_mut().make_stored(filename);

assert_eq!(_1, _2);
assert_eq!(_2, _3);
_1
}
}
}

0 comments on commit 48594c2

Please sign in to comment.