From ca7153117b863da7083259434cea17b4b09a1b3b Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Sun, 16 Apr 2017 21:06:59 +0200 Subject: [PATCH] Enforce ordering for bundles with duplicate chunks (closes #13) --- src/bundledb/mod.rs | 2 +- src/index.rs | 14 +++++++------- src/repository/mod.rs | 10 ++++++++-- src/util/hash.rs | 2 +- 4 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/bundledb/mod.rs b/src/bundledb/mod.rs index 9e99475..6e2c0a3 100644 --- a/src/bundledb/mod.rs +++ b/src/bundledb/mod.rs @@ -21,7 +21,7 @@ pub static HEADER_STRING: [u8; 7] = *b"zvault\x01"; pub static HEADER_VERSION: u8 = 1; -#[derive(Hash, PartialEq, Eq, Clone, Default)] +#[derive(Hash, PartialEq, Eq, Clone, Default, Ord, PartialOrd)] pub struct BundleId(pub Hash); impl Serialize for BundleId { diff --git a/src/index.rs b/src/index.rs index dbe1fd5..400af0a 100644 --- a/src/index.rs +++ b/src/index.rs @@ -341,13 +341,13 @@ impl Index { } /// Adds the key, data pair into the table. - /// If the key existed in the table before, it is overwritten and false is returned. - /// Otherwise it will be added to the table and true is returned. - pub fn set(&mut self, key: &Hash, data: &Location) -> Result { + /// If the key existed the old data is returned. + pub fn set(&mut self, key: &Hash, data: &Location) -> Result, IndexError> { match self.locate(key) { LocateResult::Found(pos) => { - self.data[pos].data = *data; - Ok(false) + let mut old = *data; + mem::swap(&mut old, &mut self.data[pos].data); + Ok(Some(old)) }, LocateResult::Hole(pos) => { { @@ -356,7 +356,7 @@ impl Index { entry.data = *data; } try!(self.increase_count()); - Ok(true) + Ok(None) }, LocateResult::Steal(pos) => { let mut stolen_key; @@ -382,7 +382,7 @@ impl Index { } } try!(self.increase_count()); - Ok(true) + Ok(None) } } } diff --git a/src/repository/mod.rs b/src/repository/mod.rs index 5c6c289..90612b0 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -268,7 +268,7 @@ impl Repository { BundleMode::Meta => self.next_meta_bundle }; let chunks = try!(self.bundles.get_chunk_list(&bundle.id)); - self.bundle_map.set(bundle_id, bundle.id); + self.bundle_map.set(bundle_id, bundle.id.clone()); if self.next_meta_bundle == bundle_id { self.next_meta_bundle = self.next_free_bundle_id() } @@ -276,7 +276,13 @@ impl Repository { self.next_data_bundle = self.next_free_bundle_id() } for (i, (hash, _len)) in chunks.into_inner().into_iter().enumerate() { - try!(self.index.set(&hash, &Location{bundle: bundle_id as u32, chunk: i as u32})); + if let Some(old) = try!(self.index.set(&hash, &Location{bundle: bundle_id as u32, chunk: i as u32})) { + // Duplicate chunk, forced ordering: higher bundle id wins + let old_bundle_id = try!(self.get_bundle_id(old.bundle)); + if old_bundle_id > bundle.id { + try!(self.index.set(&hash, &old)); + } + } } Ok(()) } diff --git a/src/util/hash.rs b/src/util/hash.rs index 494e527..f93bd1c 100644 --- a/src/util/hash.rs +++ b/src/util/hash.rs @@ -13,7 +13,7 @@ use std::io::{self, Read, Write}; #[repr(packed)] -#[derive(Clone, Copy, PartialEq, Hash, Eq, Default)] +#[derive(Clone, Copy, PartialEq, Hash, Eq, Default, Ord, PartialOrd)] pub struct Hash { pub high: u64, pub low: u64