Dirty flag on error

pull/10/head
Dennis Schwerdel 2017-04-10 20:15:13 +02:00 committed by Dennis Schwerdel
parent 7efc3de78f
commit 26d73e79a4
9 changed files with 47 additions and 2 deletions

View File

@ -3,7 +3,7 @@
## Functionality
* XAttrs in fuse
* XAttrs in tar
* `check --repair`
* Repair
## Stability / Reliability
* Lock the local repository to avoid index corruption

View File

@ -438,6 +438,7 @@ pub fn run() -> Result<(), ErrorCode> {
} else {
checked!(repo.check_backups(), "check repository", ErrorCode::CheckRun)
}
repo.set_clean();
info!("Integrity verified")
},
Arguments::List{repo_path, backup_name, inode} => {

View File

@ -225,6 +225,10 @@ impl Repository {
#[allow(dead_code)]
pub fn create_backup_recursively<P: AsRef<Path>>(&mut self, path: P, reference: Option<&Backup>, options: &BackupOptions) -> Result<Backup, RepositoryError> {
let _lock = try!(self.lock(false));
if self.dirty {
return Err(RepositoryError::Dirty)
}
self.dirty = true;
let reference_inode = reference.and_then(|b| self.get_inode(&b.root).ok());
let mut backup = Backup::default();
backup.config = self.config.clone();
@ -251,6 +255,7 @@ impl Repository {
backup.bundle_count = info_after.bundle_count - info_before.bundle_count;
backup.chunk_count = info_after.chunk_count - info_before.chunk_count;
backup.avg_chunk_size = backup.deduplicated_data_size as f32 / backup.chunk_count as f32;
self.dirty = false;
if failed_paths.is_empty() {
Ok(backup)
} else {

View File

@ -78,6 +78,10 @@ quick_error!{
description("Integrity error")
display("Repository error: integrity error\n\tcaused by: {}", err)
}
Dirty {
description("Dirty repository")
display("The repository is dirty, please run a check")
}
Backup(err: BackupError) {
from()
cause(err)

View File

@ -61,6 +61,10 @@ impl Repository {
}
pub fn analyze_usage(&mut self) -> Result<HashMap<u32, BundleAnalysis>, RepositoryError> {
if self.dirty {
return Err(RepositoryError::Dirty)
}
self.dirty = true;
let mut usage = HashMap::new();
for (id, bundle) in self.bundle_map.bundles() {
let bundle = try!(self.bundles.get_bundle_info(&bundle).ok_or_else(|| IntegrityError::MissingBundle(bundle)));
@ -101,6 +105,7 @@ impl Repository {
}
}
}
self.dirty = false;
Ok(usage)
}

View File

@ -102,4 +102,8 @@ impl RepositoryLayout {
pub fn remote_bundle_cache_path(&self) -> PathBuf {
self.0.join("bundles/remote.cache")
}
pub fn dirtyfile_path(&self) -> PathBuf {
self.0.join("dirty")
}
}

View File

@ -48,7 +48,8 @@ pub struct Repository {
data_bundle: Option<BundleWriter>,
meta_bundle: Option<BundleWriter>,
chunker: Chunker,
locks: LockFolder
locks: LockFolder,
dirty: bool
}
@ -92,8 +93,10 @@ impl Repository {
(BundleMap::create(), true)
}
};
let dirty = layout.dirtyfile_path().exists();
let mut repo = Repository {
layout: layout,
dirty: true,
chunker: config.chunker.create(),
config: config,
index: index,
@ -128,6 +131,7 @@ impl Repository {
if rebuild_index {
try!(repo.rebuild_index());
}
repo.dirty = dirty;
Ok(repo)
}
@ -190,6 +194,10 @@ impl Repository {
}
pub fn flush(&mut self) -> Result<(), RepositoryError> {
let dirtyfile = self.layout.dirtyfile_path();
if self.dirty && !dirtyfile.exists() {
try!(File::create(&dirtyfile));
}
if self.data_bundle.is_some() {
let mut finished = None;
mem::swap(&mut self.data_bundle, &mut finished);
@ -211,6 +219,9 @@ impl Repository {
try!(self.bundles.finish_uploads());
try!(self.save_bundle_map());
try!(self.bundles.save_cache());
if !self.dirty && dirtyfile.exists() {
try!(fs::remove_file(&dirtyfile));
}
Ok(())
}
@ -281,6 +292,10 @@ impl Repository {
fn lock(&self, exclusive: bool) -> Result<LockHandle, RepositoryError> {
Ok(try!(self.locks.lock(exclusive)))
}
pub fn set_clean(&mut self) {
self.dirty = false;
}
}

View File

@ -155,6 +155,10 @@ impl Repository {
pub fn import_tarfile<P: AsRef<Path>>(&mut self, tarfile: P) -> Result<Backup, RepositoryError> {
let _lock = try!(self.lock(false));
if self.dirty {
return Err(RepositoryError::Dirty)
}
self.dirty = true;
let mut backup = Backup::default();
backup.config = self.config.clone();
backup.host = get_hostname().unwrap_or_else(|_| "".to_string());
@ -177,6 +181,7 @@ impl Repository {
backup.bundle_count = info_after.bundle_count - info_before.bundle_count;
backup.chunk_count = info_after.chunk_count - info_before.chunk_count;
backup.avg_chunk_size = backup.deduplicated_data_size as f32 / backup.chunk_count as f32;
self.dirty = false;
if failed_paths.is_empty() {
Ok(backup)
} else {

View File

@ -17,6 +17,10 @@ impl Repository {
try!(self.flush());
info!("Locking repository");
let _lock = try!(self.lock(true));
if self.dirty {
return Err(RepositoryError::Dirty)
}
self.dirty = true;
info!("Analyzing chunk usage");
let usage = try!(self.analyze_usage());
let mut data_total = 0;
@ -36,6 +40,7 @@ impl Repository {
}
info!("Reclaiming {} by rewriting {} bundles", to_file_size(reclaim_space as u64), rewrite_bundles.len());
if !force {
self.dirty = false;
return Ok(())
}
for id in &rewrite_bundles {
@ -65,6 +70,7 @@ impl Repository {
try!(self.delete_bundle(id));
}
try!(self.save_bundle_map());
self.dirty = false;
Ok(())
}
}