changeset 301:eea316cf8f50

db_impl: Move lockfile management into dedicated methods.
author Lewin Bormann <lbo@spheniscida.de>
date Wed, 27 Sep 2017 05:29:43 +0000
parents 8ed86e8a9a5e
children a82f7228192c
files src/db_impl.rs
diffstat 1 files changed, 37 insertions(+), 6 deletions(-) [+]
line wrap: on
line diff
--- a/src/db_impl.rs	Wed Sep 27 05:25:52 2017 +0000
+++ b/src/db_impl.rs	Wed Sep 27 05:29:43 2017 +0000
@@ -5,7 +5,7 @@
 
 use cmp::{Cmp, InternalKeyCmp};
 use env::{Env, FileLock};
-use error::{err, StatusCode, Result};
+use error::{err, Status, StatusCode, Result};
 use filter::{BoxedFilterPolicy, InternalFilterPolicy};
 use infolog::Logger;
 use log::{LogReader, LogWriter};
@@ -114,6 +114,31 @@
         Ok(db)
     }
 
+    /// acquire_lock acquires the lock file.
+    fn acquire_lock(&mut self) -> Result<()> {
+        let lock_r = self.opt.env.lock(Path::new(&lock_file_name(&self.name)));
+        if let Ok(lockfile) = lock_r {
+            self.lock = Some(lockfile);
+            return Ok(());
+        }
+
+        let e = lock_r.unwrap_err();
+        if e.code == StatusCode::LockError {
+            return err(StatusCode::LockError,
+                       "database lock is held by another instance");
+        }
+        e
+    }
+
+    /// release_lock releases the lock file, if it's currently held.
+    fn release_lock(&mut self) -> Result<()> {
+        if let Some(l) = self.lock.take() {
+            self.opt.env.unlock(l)
+        } else {
+            Ok(())
+        }
+    }
+
     /// initialize_db initializes a new database.
     fn initialize_db(&mut self) -> Result<()> {
         let mut ve = VersionEdit::new();
@@ -136,8 +161,7 @@
     /// log_and_apply() should be called after recovery has finished.
     fn recover(&mut self, ve: &mut VersionEdit) -> Result<bool> {
         self.opt.env.mkdir(Path::new(&self.name)).is_ok();
-        let lockfile = self.opt.env.lock(Path::new(&lock_file_name(&self.name)))?;
-        self.lock = Some(lockfile);
+        self.acquire_lock()?;
 
         if let Err(e) = read_current_file(&self.opt.env, &self.name) {
             if e.code == StatusCode::NotFound && self.opt.create_if_missing {
@@ -666,9 +690,7 @@
 
 impl Drop for DB {
     fn drop(&mut self) {
-        if let Some(l) = self.lock.take() {
-            self.opt.env.unlock(l);
-        }
+        self.release_lock();
     }
 }
 
@@ -931,6 +953,15 @@
     }
 
     #[test]
+    fn test_db_impl_locking() {
+        let opt = options::for_test();
+        let db = DB::open("db", opt.clone()).unwrap();
+        let want_err = Status::new(StatusCode::LockError,
+                                   "database lock is held by another instance");
+        assert_eq!(want_err, DB::open("db", opt.clone()).err().unwrap());
+    }
+
+    #[test]
     fn test_db_impl_build_table() {
         let mut opt = options::for_test();
         opt.block_size = 128;