src/backup/chunk_store.rs: fix GC

Added option to get oldest_writer timestamp from ProcessLocker.
This commit is contained in:
Dietmar Maurer
2019-03-31 17:21:36 +02:00
parent d85987aeeb
commit 11861a482d
3 changed files with 59 additions and 4 deletions

View File

@ -2,11 +2,16 @@
//!
//! This implemenation uses fcntl record locks with non-blocking
//! F_SETLK command (never blocks).
//!
//! We maintain a map of shared locks with time stamps, so you can get
//! the timestamp for the oldest open lock with
//! `oldest_shared_lock()`.
use failure::*;
use std::sync::{Arc, Mutex};
use std::os::unix::io::AsRawFd;
use std::collections::HashMap;
// fixme: use F_OFD_ locks when implemented with nix::fcntl
@ -17,12 +22,15 @@ pub struct ProcessLocker {
file: std::fs::File,
exclusive: bool,
writers: usize,
next_guard_id: u64,
shared_guard_list: HashMap<u64, i64>, // guard_id => timestamp
}
/// Lock guard for shared locks
///
/// Release the lock when it goes out of scope.
pub struct ProcessLockSharedGuard {
guard_id: u64,
locker: Arc<Mutex<ProcessLocker>>,
}
@ -32,6 +40,8 @@ impl Drop for ProcessLockSharedGuard {
if data.writers == 0 { panic!("unexpected ProcessLocker state"); }
data.shared_guard_list.remove(&self.guard_id);
if data.writers == 1 && !data.exclusive {
let op = libc::flock {
@ -97,6 +107,8 @@ impl ProcessLocker {
file: file,
exclusive: false,
writers: 0,
next_guard_id: 0,
shared_guard_list: HashMap::new(),
})))
}
@ -130,7 +142,30 @@ impl ProcessLocker {
data.writers += 1;
Ok(ProcessLockSharedGuard { locker: locker.clone() })
let guard = ProcessLockSharedGuard { locker: locker.clone(), guard_id: data.next_guard_id };
data.next_guard_id += 1;
let now = unsafe { libc::time(std::ptr::null_mut()) };
data.shared_guard_list.insert(guard.guard_id, now);
Ok(guard)
}
/// Get oldest shared lock timestamp
pub fn oldest_shared_lock(locker: Arc<Mutex<Self>>) -> Option<i64> {
let mut result = None;
let data = locker.lock().unwrap();
for (_k, v) in &data.shared_guard_list {
result = match result {
None => Some(*v),
Some(x) => if x < *v { Some(x) } else { Some(*v) },
};
}
result
}
/// Try to aquire a exclusive lock