changeset 162:d41dceaba22b

Use RandomAccess as boxed trait, analogous to Read/Write
author Lewin Bormann <lbo@spheniscida.de>
date Mon, 10 Jul 2017 19:19:38 +0200
parents 923d7cbdbb1e
children 54f8c4f68b99
files src/disk_env.rs src/env.rs src/table_reader.rs
diffstat 3 files changed, 42 insertions(+), 50 deletions(-) [+]
line wrap: on
line diff
--- a/src/disk_env.rs	Mon Jul 10 19:19:05 2017 +0200
+++ b/src/disk_env.rs	Mon Jul 10 19:19:38 2017 +0200
@@ -1,4 +1,4 @@
-use env::{Env, FileLock, Logger, RandomAccessFile};
+use env::{Env, FileLock, Logger, RandomAccess};
 use error::{from_io_result, Status, StatusCode, Result};
 
 use std::collections::HashMap;
@@ -35,9 +35,11 @@
     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<Box<RandomAccess>> {
+        from_io_result(fs::OpenOptions::new().read(true).open(p)).map(|f| {
+            let b: Box<RandomAccess> = Box::new(f);
+            b
+        })
     }
     fn open_writable_file(&self, p: &Path) -> Result<Box<Write>> {
         Ok(Box::new(try!(from_io_result(fs::OpenOptions::new()
--- a/src/env.rs	Mon Jul 10 19:19:05 2017 +0200
+++ b/src/env.rs	Mon Jul 10 19:19:38 2017 +0200
@@ -3,37 +3,27 @@
 
 use error::{self, Result};
 
-use std::convert::AsRef;
-use std::fs::File;
-use std::io::{self, Cursor, Read, Write, Seek};
+use std::io::{Read, Write};
+use std::os::unix::fs::FileExt;
 use std::path::Path;
-use std::sync::{Arc, Mutex};
-
-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: Arc<Mutex<Box<RandomAccess>>>,
+pub trait RandomAccess {
+    fn read_at(&self, off: usize, len: usize) -> Result<Vec<u8>>;
 }
-
-impl RandomAccessFile {
-    pub fn new(f: Box<RandomAccess>) -> RandomAccessFile {
-        RandomAccessFile { f: Arc::new(Mutex::new(f)) }
-    }
-
-    pub fn read_at(&self, off: usize, len: usize) -> Result<Vec<u8>> {
-        let mut f = try!(error::from_lock_result(self.f.lock()));
-        try!(error::from_io_result(f.seek(io::SeekFrom::Start(off as u64))));
-
-        let mut buf = Vec::new();
-        buf.resize(len, 0);
-        error::from_io_result(f.read_exact(&mut buf)).map(|_| buf)
+impl<T: FileExt> RandomAccess for T {
+    fn read_at(&self, off: usize, len: usize) -> Result<Vec<u8>> {
+        let mut buf = vec![0 as u8; len];
+        error::from_io_result((self as &FileExt).read_at(buf.as_mut(), off as u64)).map(|_| buf)
     }
 }
+// impl<T: AsRef<[u8]>> RandomAccess for Cursor<T> {
+// fn read_at(&self, off: usize, len: usize) -> Result<Vec<u8>> {
+// self.seek(io::SeekFrom::Start(off));
+// let mut buf = vec![0 as u8; len];
+// error::from_io_result(self.read_exact(&mut buf)).map(|_| buf)
+// }
+// }
+//
 
 pub struct FileLock {
     pub id: String,
@@ -41,7 +31,7 @@
 
 pub trait Env {
     fn open_sequential_file(&self, &Path) -> Result<Box<Read>>;
-    fn open_random_access_file(&self, &Path) -> Result<RandomAccessFile>;
+    fn open_random_access_file(&self, &Path) -> Result<Box<RandomAccess>>;
     fn open_writable_file(&self, &Path) -> Result<Box<Write>>;
     fn open_appendable_file(&self, &Path) -> Result<Box<Write>>;
 
--- a/src/table_reader.rs	Mon Jul 10 19:19:05 2017 +0200
+++ b/src/table_reader.rs	Mon Jul 10 19:19:38 2017 +0200
@@ -2,7 +2,7 @@
 use blockhandle::BlockHandle;
 use cache;
 use cmp::InternalKeyCmp;
-use env::{self, RandomAccessFile};
+use env::RandomAccess;
 use error::{Status, StatusCode, Result};
 use filter;
 use filter_block::FilterBlockReader;
@@ -18,13 +18,13 @@
 use crc::crc32::{self, Hasher32};
 
 /// Reads the table footer.
-fn read_footer(f: &RandomAccessFile, size: usize) -> Result<Footer> {
+fn read_footer(f: &RandomAccess, size: usize) -> Result<Footer> {
     let buf = try!(f.read_at(size - table_builder::FULL_FOOTER_LENGTH,
                              table_builder::FULL_FOOTER_LENGTH));
     Ok(Footer::decode(&buf))
 }
 
-fn read_bytes(f: &RandomAccessFile, location: &BlockHandle) -> Result<Vec<u8>> {
+fn read_bytes(f: &RandomAccess, location: &BlockHandle) -> Result<Vec<u8>> {
     f.read_at(location.offset(), location.size())
 }
 
@@ -37,10 +37,7 @@
 
 impl TableBlock {
     /// Reads a block at location.
-    fn read_block(opt: Options,
-                  f: &RandomAccessFile,
-                  location: &BlockHandle)
-                  -> Result<TableBlock> {
+    fn read_block(opt: Options, f: &RandomAccess, location: &BlockHandle) -> Result<TableBlock> {
         // The block is denoted by offset and length in BlockHandle. A block in an encoded
         // table is followed by 1B compression type and 4B checksum.
         let buf = try!(read_bytes(f, location));
@@ -71,7 +68,7 @@
 
 #[derive(Clone)]
 pub struct Table {
-    file: RandomAccessFile,
+    file: Arc<Box<RandomAccess>>,
     file_size: usize,
     cache_id: cache::CacheID,
 
@@ -84,11 +81,12 @@
 
 impl Table {
     /// Creates a new table reader operating on unformatted keys (i.e., UserKey).
-    fn new_raw(opt: Options, file: RandomAccessFile, size: usize) -> Result<Table> {
-        let footer = try!(read_footer(&file, size));
+    fn new_raw(opt: Options, file: Arc<Box<RandomAccess>>, size: usize) -> Result<Table> {
+        let rfile = file.as_ref().as_ref();
 
-        let indexblock = try!(TableBlock::read_block(opt.clone(), &file, &footer.index));
-        let metaindexblock = try!(TableBlock::read_block(opt.clone(), &file, &footer.meta_index));
+        let footer = try!(read_footer(rfile, size));
+        let indexblock = try!(TableBlock::read_block(opt.clone(), rfile, &footer.index));
+        let metaindexblock = try!(TableBlock::read_block(opt.clone(), rfile, &footer.meta_index));
 
         if !indexblock.verify() || !metaindexblock.verify() {
             return Err(Status::new(StatusCode::InvalidData,
@@ -107,7 +105,7 @@
             let filter_block_location = BlockHandle::decode(&val).0;
 
             if filter_block_location.size() > 0 {
-                let buf = try!(read_bytes(&file, &filter_block_location));
+                let buf = try!(read_bytes(rfile, &filter_block_location));
                 filter_block_reader = Some(FilterBlockReader::new_owned(opt.filter_policy.clone(),
                                                                         buf));
             }
@@ -116,7 +114,8 @@
         let cache_id = opt.block_cache.lock().unwrap().new_cache_id();
 
         Ok(Table {
-            file: file,
+            // clone file here so that we can use a immutable reference rfile above.
+            file: file.clone(),
             file_size: size,
             cache_id: cache_id,
             opt: opt,
@@ -129,10 +128,10 @@
     /// Creates a new table reader operating on internal keys (i.e., InternalKey). This means that
     /// a different comparator (internal_key_cmp) and a different filter policy
     /// (InternalFilterPolicy) are used.
-    pub fn new(mut opt: Options, file: Box<env::RandomAccess>, size: usize) -> Result<Table> {
+    pub fn new(mut opt: Options, file: Arc<Box<RandomAccess>>, size: usize) -> Result<Table> {
         opt.cmp = Arc::new(Box::new(InternalKeyCmp(opt.cmp.clone())));
         opt.filter_policy = filter::InternalFilterPolicy::new(opt.filter_policy);
-        let t = try!(Table::new_raw(opt, RandomAccessFile::new(file), size));
+        let t = try!(Table::new_raw(opt, file, size));
         Ok(t)
     }
 
@@ -153,7 +152,8 @@
             }
         }
 
-        let b = try!(TableBlock::read_block(self.opt.clone(), &mut self.file, location));
+        let rfile = self.file.as_ref().as_ref();
+        let b = try!(TableBlock::read_block(self.opt.clone(), rfile, location));
 
         if !b.verify() {
             return Err(Status::new(StatusCode::InvalidData, "Data block failed verification"));
@@ -466,8 +466,8 @@
         (d, size)
     }
 
-    fn wrap_buffer(src: Vec<u8>) -> RandomAccessFile {
-        RandomAccessFile::new(Box::new(Cursor::new(src)))
+    fn wrap_buffer(src: Vec<u8>) -> Box<RandomAccess> {
+        Box::new(Cursor::new(src))
     }
 
     #[test]