Mercurial > lbo > hg > leveldb-rs
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>;