Use a flock(2)-based Mutex in Filesystem::lock().
- If this proves to be too expensive, we may need to look for a shared-memory based synchronization mechanism. However, no existing one seemed suitable. - Fixes #81.
This commit is contained in:
parent
37edb8e774
commit
0ac9fe32e7
|
@ -20,6 +20,7 @@ hex = "0.3"
|
|||
base64 = "0.10"
|
||||
pathdiff = "0.1"
|
||||
idna = "0.1"
|
||||
fs2 = "0.4"
|
||||
|
||||
[lib]
|
||||
name = "hagrid_database"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
use parking_lot::Mutex;
|
||||
use std::convert::{TryInto, TryFrom};
|
||||
use std::fs::{create_dir_all, read_link, remove_file, rename, File};
|
||||
use std::io::{Read, Write};
|
||||
|
@ -14,11 +13,11 @@ use pathdiff::diff_paths;
|
|||
|
||||
use {Database, Delete, Verify, Query};
|
||||
use types::{Email, Fingerprint, KeyID};
|
||||
use sync::MutexGuard;
|
||||
use sync::{MutexGuard, FlockMutex};
|
||||
use Result;
|
||||
|
||||
pub struct Filesystem {
|
||||
update_lock: Mutex<()>,
|
||||
update_lock: FlockMutex,
|
||||
|
||||
base: PathBuf,
|
||||
base_by_keyid: PathBuf,
|
||||
|
@ -83,7 +82,7 @@ impl Filesystem {
|
|||
|
||||
info!("Opened base dir '{}'", base.display());
|
||||
Ok(Filesystem {
|
||||
update_lock: Mutex::new(()),
|
||||
update_lock: FlockMutex::new(&base)?,
|
||||
base: base,
|
||||
base_by_keyid: base_by_keyid,
|
||||
base_by_fingerprint: base_by_fingerprint,
|
||||
|
|
|
@ -12,6 +12,7 @@ use std::str::FromStr;
|
|||
extern crate failure;
|
||||
use failure::Error;
|
||||
use failure::Fallible as Result;
|
||||
extern crate fs2;
|
||||
extern crate idna;
|
||||
#[macro_use] extern crate log;
|
||||
extern crate parking_lot;
|
||||
|
|
|
@ -1,7 +1,13 @@
|
|||
use std::fs::File;
|
||||
use std::io;
|
||||
use std::path::Path;
|
||||
|
||||
use fs2::FileExt;
|
||||
use parking_lot;
|
||||
|
||||
pub enum MutexGuard<'a, T> {
|
||||
ParkingLot(parking_lot::MutexGuard<'a, T>),
|
||||
Flock(FlockMutexGuard<'a>),
|
||||
}
|
||||
|
||||
impl<'a, T> From<parking_lot::MutexGuard<'a, T>> for MutexGuard<'a, T> {
|
||||
|
@ -9,3 +15,71 @@ impl<'a, T> From<parking_lot::MutexGuard<'a, T>> for MutexGuard<'a, T> {
|
|||
MutexGuard::ParkingLot(g)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<FlockMutexGuard<'a>> for MutexGuard<'a, ()> {
|
||||
fn from(g: FlockMutexGuard<'a>) -> Self {
|
||||
MutexGuard::Flock(g)
|
||||
}
|
||||
}
|
||||
|
||||
/// A minimalistic flock-based mutex.
|
||||
///
|
||||
/// This just barely implements enough what we need from a mutex.
|
||||
pub struct FlockMutex {
|
||||
f: File,
|
||||
}
|
||||
|
||||
impl FlockMutex {
|
||||
pub fn new<P: AsRef<Path>>(p: P) -> io::Result<Self> {
|
||||
Ok(Self {
|
||||
f: File::open(p)?
|
||||
})
|
||||
}
|
||||
|
||||
pub fn lock(&self) -> FlockMutexGuard {
|
||||
while let Err(e) = self.f.lock_exclusive() {
|
||||
// According to flock(2), possible errors returned are:
|
||||
//
|
||||
// EBADF fd is not an open file descriptor.
|
||||
//
|
||||
// EINTR While waiting to acquire a lock, the call
|
||||
// was interrupted by delivery of a signal
|
||||
// caught by a handler; see signal(7).
|
||||
//
|
||||
// EINVAL operation is invalid.
|
||||
//
|
||||
// ENOLCK The kernel ran out of memory for allocating
|
||||
// lock records.
|
||||
//
|
||||
// EWOULDBLOCK
|
||||
// The file is locked and the LOCK_NB flag was
|
||||
// selected.
|
||||
//
|
||||
// We entrust Rust's type system with keeping the file
|
||||
// handle valid, therefore flock should not fail with
|
||||
// EBADF. We use only valid operations, we don't use
|
||||
// LOCK_NB, and we don't handle resource exhaustion.
|
||||
//
|
||||
// Therefore, only EINTR needs to be handled, which we do
|
||||
// by retrying.
|
||||
assert_eq!(e.kind(), io::ErrorKind::Interrupted);
|
||||
}
|
||||
|
||||
FlockMutexGuard {
|
||||
m: &self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FlockMutexGuard<'a> {
|
||||
m: &'a FlockMutex,
|
||||
}
|
||||
|
||||
impl<'a> Drop for FlockMutexGuard<'a> {
|
||||
fn drop(&mut self) {
|
||||
while let Err(e) = self.m.f.unlock() {
|
||||
// See above.
|
||||
assert_eq!(e.kind(), io::ErrorKind::Interrupted);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue