Mercurial > lbo > hg > leveldb-rs
changeset 478:591a2285c83c
Use flock(2) instead of fcntl(2) for locking databases.
In an attempt to fix fcntl errors on Mac OS X (bitbucket issue #4).
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Thu, 11 Jul 2019 19:42:15 +0200 |
parents | 30c7871a4a9e |
children | c18f25f601e8 |
files | src/disk_env.rs |
diffstat | 1 files changed, 10 insertions(+), 27 deletions(-) [+] |
line wrap: on
line diff
--- a/src/disk_env.rs Thu Jul 11 17:22:40 2019 +0200 +++ b/src/disk_env.rs Thu Jul 11 19:42:15 2019 +0200 @@ -6,7 +6,6 @@ use std::fs; use std::io::{self, Read, Write}; use std::iter::FromIterator; -use std::mem; use std::os::unix::io::IntoRawFd; use std::path::{Path, PathBuf}; use std::sync::{Arc, Mutex}; @@ -128,26 +127,18 @@ .open(p) .map_err(|e| map_err_with_name("lock", p, e))?; - let flock_arg = libc::flock { - l_type: F_WRLCK, - l_whence: libc::SEEK_SET as libc::c_short, - l_start: 0, - l_len: 0, - l_pid: 0, - }; let fd = f.into_raw_fd(); let result = unsafe { - libc::fcntl( - fd, - libc::F_SETLK, - mem::transmute::<&libc::flock, *const libc::flock>(&&flock_arg), - ) + libc::flock(fd as libc::c_int, libc::LOCK_EX | libc::LOCK_NB) }; if result < 0 { + if errno::errno() == errno::Errno(libc::EWOULDBLOCK) { + return Err(Status::new(StatusCode::LockError, "lock on database is already held by different process")) + } return Err(Status::new( StatusCode::Errno(errno::errno()), - &format!("fcntl error on fd {} (file {})", fd, p.display()), + &format!("unknown lock error on fd {} (file {})", fd, p.display()), )); } @@ -160,7 +151,6 @@ } fn unlock(&self, l: FileLock) -> Result<()> { let mut locks = self.locks.lock().unwrap(); - if !locks.contains_key(&l.id) { return err( StatusCode::LockError, @@ -168,19 +158,12 @@ ); } else { let fd = locks.remove(&l.id).unwrap(); - let flock_arg = libc::flock { - l_type: F_UNLCK, - l_whence: libc::SEEK_SET as libc::c_short, - l_start: 0, - l_len: 0, - l_pid: 0, - }; let result = unsafe { - libc::fcntl( - fd, - libc::F_SETLK, - mem::transmute::<&libc::flock, *const libc::flock>(&&flock_arg), - ) + let ok = libc::fcntl(fd, libc::F_GETFD); + if ok < 0 { // Likely EBADF when already closed. In that case, the lock is released and all is fine. + return Ok(()) + } + libc::flock(fd, libc::LOCK_UN) }; if result < 0 { return err(StatusCode::LockError, &format!("unlock failed: {}", l.id));