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