diff --git a/crates/chain/src/persist.rs b/crates/chain/src/persist.rs index 2ecc23c13c..634e369e9a 100644 --- a/crates/chain/src/persist.rs +++ b/crates/chain/src/persist.rs @@ -80,6 +80,15 @@ pub trait PersistBackend { /// Return the aggregate changeset `C` from persistence. fn load_from_persistence(&mut self) -> Result; + + /// Returns whether the persistence backend contains no data. + fn is_empty(&mut self) -> Result + where + C: Append, + { + self.load_from_persistence() + .map(|changeset| changeset.is_empty()) + } } impl PersistBackend for () { @@ -94,4 +103,8 @@ impl PersistBackend for () { fn load_from_persistence(&mut self) -> Result { Ok(C::default()) } + + fn is_empty(&mut self) -> Result { + Ok(true) + } } diff --git a/crates/file_store/src/store.rs b/crates/file_store/src/store.rs index a4aa2963ce..fa73480e52 100644 --- a/crates/file_store/src/store.rs +++ b/crates/file_store/src/store.rs @@ -37,6 +37,14 @@ where let (changeset, result) = self.aggregate_changesets(); result.map(|_| changeset) } + + fn is_empty(&mut self) -> Result { + let init_pos = self.db_file.stream_position()?; + let stream_len = self.db_file.seek(io::SeekFrom::End(0))?; + let magic_len = self.magic.len() as u64; + self.db_file.seek(io::SeekFrom::Start(init_pos))?; + Ok(stream_len == magic_len) + } } impl<'a, C> Store<'a, C> @@ -182,6 +190,19 @@ mod test { #[derive(Debug)] struct TestTracker; + #[test] + fn is_empty() { + let mut file = NamedTempFile::new().unwrap(); + file.write_all(&TEST_MAGIC_BYTES).expect("should write"); + + let mut db = Store::::new(&TEST_MAGIC_BYTES, file.reopen().unwrap()) + .expect("must open"); + assert!(db.is_empty().expect("must read")); + db.write_changes(&vec!["hello".to_string(), "world".to_string()]) + .expect("must write"); + assert!(!db.is_empty().expect("must read")); + } + #[test] fn new_fails_if_file_is_too_short() { let mut file = NamedTempFile::new().unwrap();