From 14d37f74e35fc882dc6f43d5999f74e7220a56cb Mon Sep 17 00:00:00 2001 From: Dr Maxim Orlovsky Date: Fri, 9 Aug 2024 13:03:29 +0200 Subject: [PATCH] persistence: complete storage provider functionality --- src/persistence/memory.rs | 33 ++++------ src/persistence/mod.rs | 2 +- src/persistence/stock.rs | 59 ++++++----------- src/persistence/store.rs | 130 ++++++++++++++++++++++++++++++++++++-- 4 files changed, 157 insertions(+), 67 deletions(-) diff --git a/src/persistence/memory.rs b/src/persistence/memory.rs index aa9c47bc..9ff7fe02 100644 --- a/src/persistence/memory.rs +++ b/src/persistence/memory.rs @@ -84,7 +84,7 @@ pub struct MemStash { #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + store_provider: Option>>, schemata: TinyOrdMap, ifaces: TinyOrdMap, @@ -473,7 +473,7 @@ pub struct MemState { #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + store_provider: Option>>, witnesses: LargeOrdMap, contracts: TinyOrdMap, @@ -1190,7 +1190,7 @@ pub struct MemIndex { #[getter(skip)] #[strict_type(skip)] - store_provider: Option>>, + store_provider: Option>>, op_bundle_index: MediumOrdMap, bundle_contract_index: MediumOrdMap, @@ -1474,10 +1474,7 @@ mod store { use crate::persistence::{MemIndex, MemStash, MemState, StoreError, StoreProvider}; impl Stored for MemStash { - fn new_stored( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Self { + fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { Self { dirty: true, autosave, @@ -1487,7 +1484,7 @@ mod store { } fn load( - provider: impl StoreProvider + 'static, + provider: impl StoreProvider + 'static, autosave: bool, ) -> Result { let mut me = provider.load()?; @@ -1500,7 +1497,7 @@ mod store { fn autosave(&mut self) { self.autosave = true; } - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { + fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { let res = self.store_provider.is_some(); self.store_provider = Some(Box::new(provider)); self.dirty = true; @@ -1518,10 +1515,7 @@ mod store { } impl Stored for MemState { - fn new_stored( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Self { + fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { Self { dirty: true, autosave, @@ -1531,7 +1525,7 @@ mod store { } fn load( - provider: impl StoreProvider + 'static, + provider: impl StoreProvider + 'static, autosave: bool, ) -> Result { let mut me = provider.load()?; @@ -1544,7 +1538,7 @@ mod store { fn autosave(&mut self) { self.autosave = true; } - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { + fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { let res = self.store_provider.is_some(); self.store_provider = Some(Box::new(provider)); self.dirty = true; @@ -1562,10 +1556,7 @@ mod store { } impl Stored for MemIndex { - fn new_stored( - provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Self { + fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self { Self { dirty: true, autosave, @@ -1575,7 +1566,7 @@ mod store { } fn load( - provider: impl StoreProvider + 'static, + provider: impl StoreProvider + 'static, autosave: bool, ) -> Result { let mut me = provider.load()?; @@ -1588,7 +1579,7 @@ mod store { fn autosave(&mut self) { self.autosave = true; } - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { + fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool { let res = self.store_provider.is_some(); self.store_provider = Some(Box::new(provider)); self.dirty = true; diff --git a/src/persistence/mod.rs b/src/persistence/mod.rs index 9cc98f47..ce14310e 100644 --- a/src/persistence/mod.rs +++ b/src/persistence/mod.rs @@ -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; diff --git a/src/persistence/stock.rs b/src/persistence/stock.rs index f1ad280a..66b69428 100644 --- a/src/persistence/stock.rs +++ b/src/persistence/stock.rs @@ -44,7 +44,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, @@ -380,30 +380,15 @@ where H: Stored, I: Stored, { - pub fn new_stored( - stash_provider: impl StoreProvider + 'static, - state_provider: impl StoreProvider + 'static, - index_provider: impl StoreProvider + '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 + 'static, - state_provider: impl StoreProvider + 'static, - index_provider: impl StoreProvider + 'static, - autosave: bool, - ) -> Result { - 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

(provider: P, autosave: bool) -> Result + where P: StoreProvider + '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) { @@ -418,21 +403,12 @@ where self.as_index_provider().is_dirty() } - pub fn make_stored( - &mut self, - stash_provider: impl StoreProvider + 'static, - state_provider: impl StoreProvider + 'static, - index_provider: impl StoreProvider + '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

(&mut self, provider: P) -> bool + where P: StockStoreProvider + '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()?; @@ -457,6 +433,13 @@ impl Stock { #[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 + '_, StockError> { let names = self .stash diff --git a/src/persistence/store.rs b/src/persistence/store.rs index 002bc09e..8e3a154a 100644 --- a/src/persistence/store.rs +++ b/src/persistence/store.rs @@ -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)] @@ -32,23 +35,136 @@ impl From for StoreError { fn from(err: confinement::Error) -> Self { Self(Box::new(err)) } } -pub trait StoreProvider: Send + Debug { - type Object; +impl From for StoreError { + fn from(err: SerializeError) -> Self { Self(Box::new(err)) } +} + +impl From for StoreError { + fn from(err: DeserializeError) -> Self { Self(Box::new(err)) } +} + +pub trait StockStoreProvider: + StoreProvider> +{ + fn make_stored(&self, stock: &mut Stock) -> bool; +} - fn load(&self) -> Result; - fn store(&self, object: &Self::Object) -> Result<(), StoreError>; +pub trait StoreProvider: Send + Debug { + fn load(&self) -> Result; + fn store(&self, object: &T) -> Result<(), StoreError>; } pub trait Stored: Sized { - fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self; + fn new_stored(provider: impl StoreProvider + 'static, autosave: bool) -> Self; fn load( - provider: impl StoreProvider + 'static, + provider: impl StoreProvider + 'static, autosave: bool, ) -> Result; fn is_dirty(&self) -> bool; fn autosave(&mut self); - fn make_stored(&mut self, provider: impl StoreProvider + 'static) -> bool; + fn make_stored(&mut self, provider: impl StoreProvider + '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 crate::persistence::{ + MemIndex, MemStash, MemState, Stock, StockStoreProvider, StoreError, StoreProvider, Stored, + }; + + impl StoreProvider for PathBuf { + fn load(&self) -> Result { + Ok(MemStash::strict_deserialize_from_file::(&self)?) + } + + fn store(&self, object: &MemStash) -> Result<(), StoreError> { + object.strict_serialize_to_file::(&self)?; + Ok(()) + } + } + + impl StoreProvider for PathBuf { + fn load(&self) -> Result { + Ok(MemState::strict_deserialize_from_file::(&self)?) + } + + fn store(&self, object: &MemState) -> Result<(), StoreError> { + object.strict_serialize_to_file::(&self)?; + Ok(()) + } + } + + impl StoreProvider for PathBuf { + fn load(&self) -> Result { + Ok(MemIndex::strict_deserialize_from_file::(&self)?) + } + + fn store(&self, object: &MemIndex) -> Result<(), StoreError> { + object.strict_serialize_to_file::(&self)?; + Ok(()) + } + } + + impl StoreProvider for PathBuf { + fn load(&self) -> Result { + 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 for PathBuf { + fn make_stored(&self, stock: &mut Stock) -> 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 + } + } +}