@@ -2,6 +2,7 @@ use std::{
2
2
collections:: { HashMap , HashSet } ,
3
3
io:: Write ,
4
4
path:: { Path , PathBuf } ,
5
+ str,
5
6
} ;
6
7
7
8
use crate :: DocumentId ;
@@ -20,10 +21,10 @@ use error::ErrorKind;
20
21
/// ## Storage layout
21
22
///
22
23
/// In order to reduce the number of files in a single directory we follow git
23
- /// in splaying the files over 256 subdirectries using the first two bytes of
24
+ /// in splaying the files over 256 subdirectories using the first two bytes of
24
25
/// the SHA256 hash of the document ID. Then within each subdirectory we use
25
- /// the full SHA256 hash of the document ID as a directory within which we
26
- /// store the incremental and snapshots saves of a document. I.e.
26
+ /// the hex encoding of the document ID as a directory within which we store the
27
+ /// incremental and snapshots saves of a document. I.e.
27
28
///
28
29
/// ```sh
29
30
/// <root>/
@@ -39,8 +40,9 @@ use error::ErrorKind;
39
40
/// on other peers and for the splaying to be useful we need to guarantee a
40
41
/// uniform distribution of documents across the subdirectories.
41
42
///
42
- /// Likewise we use the hex encoding of the document ID as the filename to avoid
43
- /// any issues with non-UTF8 characters in the document ID.
43
+ /// Likewise we use the hex encoding of the document ID as the 2nd-level
44
+ /// directory name to avoid any issues with non-UTF8 characters in the document
45
+ /// ID.
44
46
///
45
47
/// ## Compaction
46
48
///
@@ -51,7 +53,7 @@ use error::ErrorKind;
51
53
/// 2. Load the data into an automerge document
52
54
/// 3. `automerge::Automerge::save` the document to a temporary file
53
55
/// 4. Rename the temporary file to a file in the data directory named
54
- /// `SHA356(automerge::Automerge::get_heads)` .snapshot`
56
+ /// `<sha256(heads)> .snapshot`
55
57
/// 5. Delete all the files we loaded in step 1.
56
58
///
57
59
/// The fact that we name the file after the heads of the document means that
@@ -122,14 +124,14 @@ impl FsStore {
122
124
let metadata = entry
123
125
. metadata ( )
124
126
. map_err ( |e| Error ( ErrorKind :: ErrReadingLevel2Path ( entry. path ( ) , e) ) ) ?;
125
- if metadata. is_dir ( ) {
127
+ if ! metadata. is_dir ( ) {
126
128
tracing:: warn!(
127
- non_file_path =%entry. path( ) . display( ) ,
128
- "unexpected directory at level2 of database"
129
+ non_dir_path =%entry. path( ) . display( ) ,
130
+ "unexpected non- directory at level2 of database"
129
131
) ;
130
132
continue ;
131
133
}
132
- let Some ( doc_paths) = DocIdPaths :: parse ( & level1 , entry. path ( ) ) else {
134
+ let Some ( doc_paths) = DocIdPaths :: parse ( entry. path ( ) ) else {
133
135
tracing:: warn!(
134
136
non_doc_path=%entry. path( ) . display( ) ,
135
137
"unexpected non-document path at level2 of database"
@@ -236,15 +238,16 @@ impl<'a> From<&'a DocumentId> for DocIdPaths {
236
238
}
237
239
238
240
impl DocIdPaths {
239
- fn parse < P1 : AsRef < Path > , P2 : AsRef < Path > > ( level1 : P1 , level2 : P2 ) -> Option < Self > {
240
- let level1 = level1. as_ref ( ) . to_str ( ) ?;
241
+ fn parse < P : AsRef < Path > > ( level2 : P ) -> Option < Self > {
242
+ let level2 = level2. as_ref ( ) ;
243
+ let level1 = level2. parent ( ) ?. file_name ( ) ?. to_str ( ) ?;
241
244
let prefix = hex:: decode ( level1) . ok ( ) ?;
242
245
let prefix = <[ u8 ; 2 ] >:: try_from ( prefix) . ok ( ) ?;
243
246
244
- let level2 = level2. as_ref ( ) . to_str ( ) ?;
247
+ let level2 = level2. file_name ( ) ? . to_str ( ) ?;
245
248
let doc_id_bytes = hex:: decode ( level2) . ok ( ) ?;
246
- let doc_id_str = String :: from_utf8 ( doc_id_bytes) . ok ( ) ?;
247
- let doc_id = DocumentId :: from ( doc_id_str. as_str ( ) ) ;
249
+ let doc_id_str = str :: from_utf8 ( & doc_id_bytes) . ok ( ) ?;
250
+ let doc_id = DocumentId :: from ( doc_id_str) ;
248
251
let result = Self :: from ( & doc_id) ;
249
252
if result. prefix != prefix {
250
253
None
0 commit comments