changeset 157:de83256f4423

Refactor Env and PosixDiskEnv to be more dynamic. This comes closer to the original LevelDB implementation, is more flexible, and most importantly enables inclusion as member of Options.
author Lewin Bormann <lbo@spheniscida.de>
date Sun, 09 Jul 2017 20:33:20 +0200
parents 94d50060a94a
children c15ac746e903
files src/disk_env.rs src/env.rs
diffstat 2 files changed, 57 insertions(+), 53 deletions(-) [+]
line wrap: on
line diff
--- a/src/disk_env.rs	Sun Jul 09 17:06:20 2017 +0200
+++ b/src/disk_env.rs	Sun Jul 09 20:33:20 2017 +0200
@@ -1,13 +1,14 @@
-use env::{Env, Logger, RandomAccessFile};
+use env::{Env, FileLock, Logger, RandomAccessFile};
 use error::{from_io_result, Status, StatusCode, Result};
 
-use std::collections::HashSet;
+use std::collections::HashMap;
 use std::fs;
+use std::io::{Read, Write};
 use std::iter::FromIterator;
 use std::mem;
-use std::os::unix::io::{FromRawFd, IntoRawFd};
+use std::os::unix::io::IntoRawFd;
 use std::path::Path;
-use std::sync::Mutex;
+use std::sync::{Arc, Mutex};
 use std::thread;
 use std::time;
 
@@ -17,38 +18,40 @@
 const F_WRLCK: libc::c_short = 1;
 const F_UNLCK: libc::c_short = 2;
 
-pub struct DiskFileLock {
-    p: String,
-    f: fs::File,
-}
+type FileDescriptor = i32;
 
+#[derive(Clone)]
 pub struct PosixDiskEnv {
-    locks: Mutex<HashSet<String>>,
+    locks: Arc<Mutex<HashMap<String, FileDescriptor>>>,
 }
 
 impl PosixDiskEnv {
     pub fn new() -> PosixDiskEnv {
-        PosixDiskEnv { locks: Mutex::new(HashSet::new()) }
+        PosixDiskEnv { locks: Arc::new(Mutex::new(HashMap::new())) }
     }
 }
 
 impl Env for PosixDiskEnv {
-    type SequentialReader = fs::File;
-    type RandomReader = fs::File;
-    type Writer = fs::File;
-    type FileLock = DiskFileLock;
-
-    fn open_sequential_file(&self, p: &Path) -> Result<Self::SequentialReader> {
+    fn open_sequential_file(&self, p: &Path) -> Result<Box<Read>> {
+        Ok(Box::new(try!(from_io_result(fs::OpenOptions::new().read(true).open(p)))))
+    }
+    fn open_random_access_file(&self, p: &Path) -> Result<RandomAccessFile> {
         from_io_result(fs::OpenOptions::new().read(true).open(p))
+            .map(|f| RandomAccessFile::new(Box::new(f)))
     }
-    fn open_random_access_file(&self, p: &Path) -> Result<RandomAccessFile<Self::RandomReader>> {
-        from_io_result(fs::OpenOptions::new().read(true).open(p)).map(|f| RandomAccessFile::new(f))
+    fn open_writable_file(&self, p: &Path) -> Result<Box<Write>> {
+        Ok(Box::new(try!(from_io_result(fs::OpenOptions::new()
+            .create(true)
+            .write(true)
+            .append(false)
+            .open(p)))))
     }
-    fn open_writable_file(&self, p: &Path) -> Result<Self::Writer> {
-        from_io_result(fs::OpenOptions::new().create(true).write(true).append(false).open(p))
-    }
-    fn open_appendable_file(&self, p: &Path) -> Result<Self::Writer> {
-        from_io_result(fs::OpenOptions::new().create(true).write(true).append(true).open(p))
+    fn open_appendable_file(&self, p: &Path) -> Result<Box<Write>> {
+        Ok(Box::new(try!(from_io_result(fs::OpenOptions::new()
+            .create(true)
+            .write(true)
+            .append(true)
+            .open(p)))))
     }
 
     fn exists(&self, p: &Path) -> Result<bool> {
@@ -85,10 +88,10 @@
         from_io_result(fs::rename(old, new))
     }
 
-    fn lock(&self, p: &Path) -> Result<DiskFileLock> {
+    fn lock(&self, p: &Path) -> Result<FileLock> {
         let mut locks = self.locks.lock().unwrap();
 
-        if locks.contains(&p.to_str().unwrap().to_string()) {
+        if locks.contains_key(&p.to_str().unwrap().to_string()) {
             Err(Status::new(StatusCode::AlreadyExists, "Lock is held"))
         } else {
             let f = try!(fs::OpenOptions::new().write(true).open(p));
@@ -111,22 +114,18 @@
                 return Err(Status::new(StatusCode::AlreadyExists, "Lock is held (fcntl)"));
             }
 
-            locks.insert(p.to_str().unwrap().to_string());
-            let lock = DiskFileLock {
-                p: p.to_str().unwrap().to_string(),
-                f: unsafe { fs::File::from_raw_fd(fd) },
-            };
+            locks.insert(p.to_str().unwrap().to_string(), fd);
+            let lock = FileLock { id: p.to_str().unwrap().to_string() };
             Ok(lock)
         }
     }
-    fn unlock(&self, l: DiskFileLock) {
+    fn unlock(&self, l: FileLock) {
         let mut locks = self.locks.lock().unwrap();
 
-        if !locks.contains(&l.p) {
+        if !locks.contains_key(&l.id) {
             panic!("Unlocking a file that is not locked!");
         } else {
-            locks.remove(&l.p);
-
+            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,
@@ -135,11 +134,10 @@
                 l_pid: 0,
             };
             let result = unsafe {
-                libc::fcntl(l.f.into_raw_fd(),
+                libc::fcntl(fd,
                             libc::F_SETLK,
                             mem::transmute::<&libc::flock, *const libc::flock>(&&flock_arg))
             };
-
             if result < 0 {
                 // ignore for now
             }
--- a/src/env.rs	Sun Jul 09 17:06:20 2017 +0200
+++ b/src/env.rs	Sun Jul 09 20:33:20 2017 +0200
@@ -3,18 +3,25 @@
 
 use error::{self, Result};
 
-use std::io::{self, Read, Write, Seek};
+use std::convert::AsRef;
+use std::fs::File;
+use std::io::{self, Cursor, Read, Write, Seek};
 use std::path::Path;
 use std::sync::{Arc, Mutex};
 
-/// RandomAccessFile wraps a type implementing read and seek to enable atomic random reads
+pub trait RandomAccess: Read + Seek {}
+impl RandomAccess for File {}
+impl<T: AsRef<[u8]>> RandomAccess for Cursor<T> {}
+
+/// RandomAccessFile dynamically wraps a type implementing read and seek to enable atomic random
+/// reads.
 #[derive(Clone)]
-pub struct RandomAccessFile<F: Read + Seek> {
-    f: Arc<Mutex<F>>,
+pub struct RandomAccessFile {
+    f: Arc<Mutex<Box<RandomAccess>>>,
 }
 
-impl<F: Read + Seek> RandomAccessFile<F> {
-    pub fn new(f: F) -> RandomAccessFile<F> {
+impl RandomAccessFile {
+    pub fn new(f: Box<RandomAccess>) -> RandomAccessFile {
         RandomAccessFile { f: Arc::new(Mutex::new(f)) }
     }
 
@@ -28,16 +35,15 @@
     }
 }
 
+pub struct FileLock {
+    pub id: String,
+}
+
 pub trait Env {
-    type SequentialReader: Read;
-    type RandomReader: Read + Seek;
-    type Writer: Write;
-    type FileLock;
-
-    fn open_sequential_file(&self, &Path) -> Result<Self::SequentialReader>;
-    fn open_random_access_file(&self, &Path) -> Result<RandomAccessFile<Self::RandomReader>>;
-    fn open_writable_file(&self, &Path) -> Result<Self::Writer>;
-    fn open_appendable_file(&self, &Path) -> Result<Self::Writer>;
+    fn open_sequential_file(&self, &Path) -> Result<Box<Read>>;
+    fn open_random_access_file(&self, &Path) -> Result<RandomAccessFile>;
+    fn open_writable_file(&self, &Path) -> Result<Box<Write>>;
+    fn open_appendable_file(&self, &Path) -> Result<Box<Write>>;
 
     fn exists(&self, &Path) -> Result<bool>;
     fn children(&self, &Path) -> Result<Vec<String>>;
@@ -48,8 +54,8 @@
     fn rmdir(&self, &Path) -> Result<()>;
     fn rename(&self, &Path, &Path) -> Result<()>;
 
-    fn lock(&self, &Path) -> Result<Self::FileLock>;
-    fn unlock(&self, l: Self::FileLock);
+    fn lock(&self, &Path) -> Result<FileLock>;
+    fn unlock(&self, l: FileLock);
 
     fn new_logger(&self, &Path) -> Result<Logger>;