From 0b3ab573350d2be70b1ddf26b332a5213751fdd0 Mon Sep 17 00:00:00 2001 From: Dennis Schwerdel Date: Sat, 8 Apr 2017 15:28:01 +0200 Subject: [PATCH] Recover from missing index and bundle map by rebuilding those --- TODO.md | 1 - src/cli/args.rs | 12 ------------ src/cli/mod.rs | 9 ++------- src/repository/mod.rs | 44 ++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 43 insertions(+), 23 deletions(-) diff --git a/TODO.md b/TODO.md index da8ac6e..80eb9d2 100644 --- a/TODO.md +++ b/TODO.md @@ -8,7 +8,6 @@ ## Stability / Reliability * Lock the local repository to avoid index corruption -* Recover from missing index, bundle cache and bundle map by rebuilding those ## Usability * Verbosity control diff --git a/src/cli/args.rs b/src/cli/args.rs index dd35a1e..58ff0b8 100644 --- a/src/cli/args.rs +++ b/src/cli/args.rs @@ -125,9 +125,6 @@ pub enum Arguments { compression: Option, encrypt: bool, hash: HashMethod - }, - RebuildIndex { - repo_path: String } } @@ -400,9 +397,6 @@ pub fn parse() -> Result { .validator(|val| validate_repo_path(val, true, Some(false), Some(false)))) .arg(Arg::from_usage("[FILE] 'File containing the keypair'") .required_unless("generate").validator(validate_existing_path))) - .subcommand(SubCommand::with_name("rebuild-index").about("Rebuild the index") - .arg(Arg::from_usage(" 'Path of the repository'") - .validator(|val| validate_repo_path(val, true, Some(false), Some(false))))) .subcommand(SubCommand::with_name("algotest").about("Test a specific algorithm combination") .arg(Arg::from_usage("[bundle_size] --bundle-size [SIZE] 'Set the target bundle size in MiB'") .default_value(DEFAULT_BUNDLE_SIZE_STR).validator(validate_num)) @@ -553,12 +547,6 @@ pub fn parse() -> Result { repo_path: repository.to_string() }) }, - ("rebuild-index", Some(args)) => { - let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), true, Some(false), Some(false)).unwrap(); - Ok(Arguments::RebuildIndex { - repo_path: repository.to_string() - }) - }, ("import", Some(args)) => { let (repository, _backup, _inode) = parse_repo_path(args.value_of("REPO").unwrap(), false, Some(false), Some(false)).unwrap(); Ok(Arguments::Import { diff --git a/src/cli/mod.rs b/src/cli/mod.rs index e01ee8b..cb6bb6c 100644 --- a/src/cli/mod.rs +++ b/src/cli/mod.rs @@ -24,7 +24,7 @@ pub enum ErrorCode { SaveConfig, LoadExcludes, InvalidExcludes, BackupRun, RestoreRun, RemoveRun, PruneRun, VacuumRun, CheckRun, AnalyzeRun, DiffRun, - VersionsRun, ImportRun, FuseMount, RebuildIndexRun + VersionsRun, ImportRun, FuseMount } impl ErrorCode { pub fn code(&self) -> i32 { @@ -58,8 +58,7 @@ impl ErrorCode { ErrorCode::DiffRun => 21, ErrorCode::VersionsRun => 22, ErrorCode::ImportRun => 23, - ErrorCode::FuseMount => 24, - ErrorCode::RebuildIndexRun => 25 + ErrorCode::FuseMount => 24 } } } @@ -482,10 +481,6 @@ pub fn run() -> Result<(), ErrorCode> { let mut repo = try!(open_repository(&repo_path)); print_analysis(&checked!(repo.analyze_usage(), "analyze repository", ErrorCode::AnalyzeRun)); }, - Arguments::RebuildIndex{repo_path} => { - let mut repo = try!(open_repository(&repo_path)); - checked!(repo.rebuild_index(), "rebuild index", ErrorCode::RebuildIndexRun); - }, Arguments::BundleList{repo_path} => { let repo = try!(open_repository(&repo_path)); for bundle in repo.list_bundles() { diff --git a/src/repository/mod.rs b/src/repository/mod.rs index f708390..0514840 100644 --- a/src/repository/mod.rs +++ b/src/repository/mod.rs @@ -78,8 +78,20 @@ impl Repository { let locks = LockFolder::new(layout.remote_locks_path()); let crypto = Arc::new(Mutex::new(try!(Crypto::open(layout.keys_path())))); let (bundles, new, gone) = try!(BundleDb::open(layout.clone(), crypto.clone())); - let index = try!(Index::open(layout.index_path())); - let bundle_map = try!(BundleMap::load(layout.bundle_map_path())); + let (index, mut rebuild_index) = match Index::open(layout.index_path()) { + Ok(index) => (index, false), + Err(err) => { + error!("Failed to load local index:\n\tcaused by: {}", err); + (try!(Index::create(layout.index_path())), true) + } + }; + let (bundle_map, rebuild_bundle_map) = match BundleMap::load(layout.bundle_map_path()) { + Ok(bundle_map) => (bundle_map, false), + Err(err) => { + error!("Failed to load local bundle map:\n\tcaused by: {}", err); + (BundleMap::create(), true) + } + }; let mut repo = Repository { layout: layout, chunker: config.chunker.create(), @@ -103,6 +115,13 @@ impl Repository { try!(repo.save_bundle_map()); repo.next_meta_bundle = repo.next_free_bundle_id(); repo.next_data_bundle = repo.next_free_bundle_id(); + if rebuild_bundle_map { + try!(repo.rebuild_bundle_map()); + rebuild_index = true; + } + if rebuild_index { + try!(repo.rebuild_index()); + } Ok(repo) } @@ -208,7 +227,26 @@ impl Repository { Ok(()) } - pub fn rebuild_index(&mut self) -> Result<(), RepositoryError> { + fn rebuild_bundle_map(&mut self) -> Result<(), RepositoryError> { + info!("Rebuilding bundle map from bundles"); + for bundle in self.bundles.list_bundles() { + let bundle_id = match bundle.mode { + BundleMode::Data => self.next_data_bundle, + BundleMode::Meta => self.next_meta_bundle + }; + 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() + } + if self.next_data_bundle == bundle_id { + self.next_data_bundle = self.next_free_bundle_id() + } + } + self.save_bundle_map() + } + + fn rebuild_index(&mut self) -> Result<(), RepositoryError> { + info!("Rebuilding index from bundles"); self.index.clear(); for (num, id) in self.bundle_map.bundles() { let chunks = try!(self.bundles.get_chunk_list(&id));