pub struct Store<C> { /* private fields */ }
Expand description
Persists an append-only list of changesets (C
) to a single file.
⚠ This is a development/testing database. It does not natively support backwards compatible BDK version upgrades so should not be used in production.
Implementations§
Source§impl<C> Store<C>
impl<C> Store<C>
Sourcepub fn create<P>(magic: &[u8], file_path: P) -> Result<Self, StoreError>
pub fn create<P>(magic: &[u8], file_path: P) -> Result<Self, StoreError>
Sourcepub fn load<P>(
magic: &[u8],
file_path: P,
) -> Result<(Self, Option<C>), StoreErrorWithDump<C>>
pub fn load<P>( magic: &[u8], file_path: P, ) -> Result<(Self, Option<C>), StoreErrorWithDump<C>>
Load an existing Store
.
Use create
to create a new Store
.
§Errors
If the prefixed bytes of the loaded file do not match the provided magic
, a
StoreErrorWithDump
will be returned with the StoreError::InvalidMagicBytes
error
variant in its error field and changeset field set to Option::None
If there exist changesets in the file, load
will try to aggregate them in
a single changeset to verify their integrity. If aggregation fails
StoreErrorWithDump
will be returned with the StoreError::Bincode
error variant in
its error field and the aggregated changeset so far in the changeset field.
To get a new working file store from this error use Store::create
and Store::append
to add the aggregated changeset obtained from StoreErrorWithDump
.
To analyze the causes of the problem in the original database do not recreate the Store
using the same file path. Not changing the file path will overwrite previous file without
being able to recover its original data.
§Examples
use bdk_file_store::{Store, StoreErrorWithDump};
let (mut new_store, _aggregate_changeset) =
match Store::<TestChangeSet>::load(&MAGIC_BYTES, &file_path) {
Ok((store, changeset)) => (store, changeset),
Err(StoreErrorWithDump { changeset, .. }) => {
let new_file_path = file_path.with_extension("backup");
let mut new_store =
Store::create(&MAGIC_BYTES, &new_file_path).expect("must create new file");
if let Some(aggregated_changeset) = changeset {
new_store.append(&aggregated_changeset)?;
}
// The following will overwrite the original file. You will loose the corrupted
// portion of the original file forever.
drop(new_store);
std::fs::rename(&new_file_path, &file_path)?;
Store::load(&MAGIC_BYTES, &file_path).expect("must load new file")
}
};
Sourcepub fn dump(&mut self) -> Result<Option<C>, StoreErrorWithDump<C>>
pub fn dump(&mut self) -> Result<Option<C>, StoreErrorWithDump<C>>
Dump the aggregate of all changesets in Store
.
§Errors
If there exist changesets in the file, dump
will try to aggregate them in a single
changeset. If aggregation fails StoreErrorWithDump
will be returned with the
StoreError::Bincode
error variant in its error field and the aggregated changeset so
far in the changeset field.
Sourcepub fn load_or_create<P>(
magic: &[u8],
file_path: P,
) -> Result<(Self, Option<C>), StoreErrorWithDump<C>>
pub fn load_or_create<P>( magic: &[u8], file_path: P, ) -> Result<(Self, Option<C>), StoreErrorWithDump<C>>
Sourcepub fn append(&mut self, changeset: &C) -> Result<(), Error>
pub fn append(&mut self, changeset: &C) -> Result<(), Error>
Append a new changeset to the file. Does nothing if the changeset is empty. Truncation is not needed because file pointer is always moved to the end of the last decodable data from beginning to end.
If multiple garbage writes are produced on the file, the next load will only retrieve the first chunk of valid changesets.
If garbage data is written and then valid changesets, the next load will still only retrieve the first chunk of valid changesets. The recovery of those valid changesets after the garbage data is responsibility of the user.