Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix FsStore::list and path parsing #54

Merged
merged 1 commit into from
Oct 22, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 15 additions & 16 deletions src/fs_store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ use std::{
collections::{HashMap, HashSet},
io::Write,
path::{Path, PathBuf},
str,
};

use crate::DocumentId;
Expand All @@ -20,10 +21,10 @@ use error::ErrorKind;
/// ## Storage layout
///
/// In order to reduce the number of files in a single directory we follow git
/// in splaying the files over 256 subdirectries using the first two bytes of
/// in splaying the files over 256 subdirectories using the first two bytes of
/// the SHA256 hash of the document ID. Then within each subdirectory we use
/// the full SHA256 hash of the document ID as a directory within which we
/// store the incremental and snapshots saves of a document. I.e.
/// the hex encoding of the document ID as a directory within which we store the
/// incremental and snapshots saves of a document. I.e.
///
/// ```sh
/// <root>/
Expand All @@ -39,9 +40,6 @@ use error::ErrorKind;
/// on other peers and for the splaying to be useful we need to guarantee a
/// uniform distribution of documents across the subdirectories.
///
/// Likewise we use the hex encoding of the document ID as the filename to avoid
/// any issues with non-UTF8 characters in the document ID.
///
/// ## Compaction
///
/// In order to support compaction we do the following:
Expand All @@ -51,7 +49,7 @@ use error::ErrorKind;
/// 2. Load the data into an automerge document
/// 3. `automerge::Automerge::save` the document to a temporary file
/// 4. Rename the temporary file to a file in the data directory named
/// `SHA356(automerge::Automerge::get_heads)`.snapshot`
/// `<sha256(heads)>.snapshot`
/// 5. Delete all the files we loaded in step 1.
///
/// The fact that we name the file after the heads of the document means that
Expand Down Expand Up @@ -122,14 +120,14 @@ impl FsStore {
let metadata = entry
.metadata()
.map_err(|e| Error(ErrorKind::ErrReadingLevel2Path(entry.path(), e)))?;
if metadata.is_dir() {
if !metadata.is_dir() {
tracing::warn!(
non_file_path=%entry.path().display(),
"unexpected directory at level2 of database"
non_dir_path=%entry.path().display(),
"unexpected non-directory at level2 of database"
);
continue;
}
let Some(doc_paths) = DocIdPaths::parse(&level1, entry.path()) else {
let Some(doc_paths) = DocIdPaths::parse(entry.path()) else {
tracing::warn!(
non_doc_path=%entry.path().display(),
"unexpected non-document path at level2 of database"
Expand Down Expand Up @@ -236,15 +234,16 @@ impl<'a> From<&'a DocumentId> for DocIdPaths {
}

impl DocIdPaths {
fn parse<P1: AsRef<Path>, P2: AsRef<Path>>(level1: P1, level2: P2) -> Option<Self> {
let level1 = level1.as_ref().to_str()?;
fn parse<P: AsRef<Path>>(level2: P) -> Option<Self> {
let level2 = level2.as_ref();
let level1 = level2.parent()?.file_name()?.to_str()?;
let prefix = hex::decode(level1).ok()?;
let prefix = <[u8; 2]>::try_from(prefix).ok()?;

let level2 = level2.as_ref().to_str()?;
let level2 = level2.file_name()?.to_str()?;
let doc_id_bytes = hex::decode(level2).ok()?;
let doc_id_str = String::from_utf8(doc_id_bytes).ok()?;
let doc_id = DocumentId::from(doc_id_str.as_str());
let doc_id_str = str::from_utf8(&doc_id_bytes).ok()?;
let doc_id = DocumentId::from(doc_id_str);
let result = Self::from(&doc_id);
if result.prefix != prefix {
None
Expand Down
5 changes: 5 additions & 0 deletions tests/fs_storage/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,11 @@ fn fs_store_crud() {

store.append(&doc_id, change2.bytes().as_ref()).unwrap();

// check that list is working
let result = store.list().unwrap();
let expected = &[doc_id.clone()];
assert_eq!(&result, expected);

let result = store.get(&doc_id).unwrap().unwrap();
assert_permutation_of!(result, vec![change1.bytes(), change2.bytes()]);

Expand Down