image_index.rs: implement atomic write/rename

This commit is contained in:
Dietmar Maurer 2018-12-16 13:39:21 +01:00
parent 798881a68a
commit 4fbb72a8b4
2 changed files with 49 additions and 4 deletions

View File

@ -21,6 +21,8 @@ pub struct ImageIndexHeader {
pub struct ImageIndexWriter<'a> { pub struct ImageIndexWriter<'a> {
store: &'a mut ChunkStore, store: &'a mut ChunkStore,
filename: PathBuf,
tmp_filename: PathBuf,
chunk_size: usize, chunk_size: usize,
size: usize, size: usize,
index: *mut u8, index: *mut u8,
@ -28,18 +30,29 @@ pub struct ImageIndexWriter<'a> {
ctime: u64, ctime: u64,
} }
impl <'a> Drop for ImageIndexWriter<'a> {
fn drop(&mut self) {
let _ = std::fs::remove_file(&self.tmp_filename); // ignore errors
if let Err(err) = self.unmap() {
eprintln!("Unable to unmap file {:?}", self.tmp_filename);
}
}
}
impl <'a> ImageIndexWriter<'a> { impl <'a> ImageIndexWriter<'a> {
pub fn create(store: &'a mut ChunkStore, path: &Path, size: usize) -> Result<Self, Error> { pub fn create(store: &'a mut ChunkStore, path: &Path, size: usize) -> Result<Self, Error> {
let full_path = store.relative_path(path); let full_path = store.relative_path(path);
println!("FULLPATH: {:?} {}", full_path, size); let mut tmp_path = full_path.clone();
tmp_path.set_extension("tmp_iidx");
let mut file = std::fs::OpenOptions::new() let mut file = std::fs::OpenOptions::new()
.create(true).truncate(true) .create(true).truncate(true)
.read(true) .read(true)
.write(true) .write(true)
.open(&full_path)?; .open(&tmp_path)?;
let chunk_size = 64*1024; let chunk_size = 64*1024;
@ -67,8 +80,6 @@ impl <'a> ImageIndexWriter<'a> {
let index_size = ((size + chunk_size - 1)/chunk_size)*32; let index_size = ((size + chunk_size - 1)/chunk_size)*32;
nix::unistd::ftruncate(file.as_raw_fd(), (header_size + index_size) as i64)?; nix::unistd::ftruncate(file.as_raw_fd(), (header_size + index_size) as i64)?;
println!("SIZES: {} {}", index_size, header_size);
let data = unsafe { nix::sys::mman::mmap( let data = unsafe { nix::sys::mman::mmap(
std::ptr::null_mut(), std::ptr::null_mut(),
index_size, index_size,
@ -80,6 +91,8 @@ impl <'a> ImageIndexWriter<'a> {
Ok(Self { Ok(Self {
store, store,
filename: full_path,
tmp_filename: tmp_path,
chunk_size, chunk_size,
size, size,
index: data, index: data,
@ -88,9 +101,39 @@ impl <'a> ImageIndexWriter<'a> {
}) })
} }
fn unmap(&mut self) -> Result<(), Error> {
if self.index == std::ptr::null_mut() { return Ok(()); }
let index_size = ((self.size + self.chunk_size - 1)/self.chunk_size)*32;
if let Err(err) = unsafe { nix::sys::mman::munmap(self.index as *mut std::ffi::c_void, index_size) } {
bail!("unmap file {:?} failed", self.tmp_filename);
}
self.index = std::ptr::null_mut();
Ok(())
}
pub fn close(&mut self) -> Result<(), Error> {
if self.index == std::ptr::null_mut() { bail!("cannot close already closed index file."); }
self.unmap()?;
if let Err(err) = std::fs::rename(&self.tmp_filename, &self.filename) {
bail!("Atomic rename file {:?} failed - {}", self.filename, err);
}
Ok(())
}
// Note: We want to add data out of order, so do not assume and order here. // Note: We want to add data out of order, so do not assume and order here.
pub fn add_chunk(&mut self, pos: usize, chunk: &[u8]) -> Result<(), Error> { pub fn add_chunk(&mut self, pos: usize, chunk: &[u8]) -> Result<(), Error> {
if self.index == std::ptr::null_mut() { bail!("cannot write to closed index file."); }
let end = pos + chunk.len(); let end = pos + chunk.len();
if end > self.size { if end > self.size {

View File

@ -45,6 +45,8 @@ fn backup_file(param: Value, _info: &ApiMethod) -> Result<Value, Error> {
Ok(true) Ok(true)
})?; })?;
index.close()?; // commit changes
Ok(Value::Null) Ok(Value::Null)
} }