First take on index support
This commit is contained in:
parent
4537cc34dd
commit
46656418d9
1 changed files with 92 additions and 17 deletions
109
src/storage.rs
109
src/storage.rs
|
@ -1,22 +1,95 @@
|
|||
use std::cmp::Ordering;
|
||||
use std::path::Path;
|
||||
use std::collections::HashMap;
|
||||
use std::collections::HashSet;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialOrd, PartialEq)]
|
||||
pub struct Version(pub u64);
|
||||
|
||||
struct Index;
|
||||
impl Version {
|
||||
fn next(self) -> Self {
|
||||
Version(self.0 + 1)
|
||||
}
|
||||
}
|
||||
|
||||
impl Index {
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
struct Hash([u8; 32]);
|
||||
|
||||
#[derive(Clone)]
|
||||
struct IndexHashEntry {
|
||||
source_paths: HashSet<String>,
|
||||
storage_path: String,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
struct IndexPathEntry {
|
||||
hash: Hash,
|
||||
version: Version,
|
||||
storage_path: String,
|
||||
}
|
||||
|
||||
struct Index<'a> {
|
||||
file_hashes: HashMap<Hash, IndexHashEntry>,
|
||||
file_paths: HashMap<&'a str, IndexPathEntry>,
|
||||
}
|
||||
|
||||
impl<'a> Index<'a> {
|
||||
fn new() -> Self {
|
||||
Self {}
|
||||
Self {
|
||||
file_hashes: HashMap::new(),
|
||||
file_paths: HashMap::new()
|
||||
}
|
||||
}
|
||||
|
||||
fn store(&mut self, path: &str, hash: &[u8]) -> (Version, String) {
|
||||
(Version(0), "".to_string())
|
||||
fn store(&mut self, source_path: &'a str, hash: Hash) -> (Version, String) {
|
||||
let path_entry = {
|
||||
self.file_paths.get(source_path).map_or_else(
|
||||
|| IndexPathEntry {
|
||||
hash,
|
||||
version: Version(0),
|
||||
storage_path: format!("{:X?}", hash.0),
|
||||
},
|
||||
|old_entry| {
|
||||
if old_entry.hash == hash {
|
||||
old_entry.clone() // FIXME optimise
|
||||
} else {
|
||||
IndexPathEntry {
|
||||
hash,
|
||||
version: old_entry.version.next(),
|
||||
storage_path: old_entry.storage_path.clone(),
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
self.file_paths.insert(source_path, path_entry.clone());
|
||||
|
||||
let hash_entry = {
|
||||
self.file_hashes.get(&hash).map_or_else(
|
||||
|| {
|
||||
let mut source_paths = HashSet::new();
|
||||
source_paths.insert(source_path.to_string());
|
||||
IndexHashEntry {
|
||||
source_paths,
|
||||
storage_path: format!("{:X?}", hash.0),
|
||||
}
|
||||
},
|
||||
|old_entry| {
|
||||
let mut source_paths = old_entry.source_paths.clone();
|
||||
source_paths.insert(source_path.to_string());
|
||||
IndexHashEntry {
|
||||
source_paths,
|
||||
storage_path: old_entry.storage_path.clone()
|
||||
}
|
||||
},
|
||||
)
|
||||
};
|
||||
|
||||
self.file_hashes.insert(hash, hash_entry);
|
||||
(path_entry.version, path_entry.storage_path.to_string())
|
||||
}
|
||||
|
||||
fn version(&self, hash: &[u8]) -> Version {
|
||||
Version(0)
|
||||
fn latest_version_for_path(&self, path: &str) -> Option<Version> {
|
||||
self.file_paths.get(path).map_or(None, |entry| Some(entry.version))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -25,14 +98,16 @@ mod should {
|
|||
|
||||
use super::*;
|
||||
|
||||
const SOME_HASH: Hash = Hash([1; 32]);
|
||||
const SOME_OTHER_HASH: Hash = Hash([2; 32]);
|
||||
|
||||
#[test]
|
||||
fn support_file_versions() {
|
||||
let mut index = Index::new();
|
||||
let (v1, _) = index.store("/some/path", "some hash".as_bytes());
|
||||
let (v2, _) = index.store("/some/path", "some other hash".as_bytes());
|
||||
let (v1, _) = index.store("/some/path", SOME_HASH);
|
||||
let (v2, _) = index.store("/some/path", SOME_OTHER_HASH);
|
||||
|
||||
assert_eq!(v1, index.version("some hash".as_bytes()));
|
||||
assert_eq!(v2, index.version("some other hash".as_bytes()));
|
||||
assert_eq!(v2, index.latest_version_for_path("/some/path").unwrap());
|
||||
|
||||
assert!(v2 > v1);
|
||||
}
|
||||
|
@ -40,11 +115,11 @@ mod should {
|
|||
#[test]
|
||||
fn support_deduplication() {
|
||||
let mut index = Index::new();
|
||||
let (_, storage_path1) = index.store("/some/path", "same hash".as_bytes());
|
||||
let (_, storage_path2) = index.store("/some/path", "same hash".as_bytes());
|
||||
let (_, storage_path3) = index.store("/some/other/path", "same hash".as_bytes());
|
||||
let (_, storage_path1) = index.store("/some/path", SOME_HASH);
|
||||
let (_, storage_path2) = index.store("/some/path", SOME_HASH);
|
||||
let (_, storage_path3) = index.store("/some/other/path", SOME_HASH);
|
||||
|
||||
assert_eq!(storage_path1, storage_path2);
|
||||
assert_ne!(storage_path1, storage_path3);
|
||||
assert_eq!(storage_path1, storage_path3);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue