changeset 183:98bfd5147ded

Write test for TableCache making use of MemEnv.
author Lewin Bormann <lbo@spheniscida.de>
date Sat, 12 Aug 2017 17:11:09 +0200
parents d7e4693effba
children b3da8e0fe92d
files src/mem_env.rs src/options.rs src/table_cache.rs src/table_reader.rs
diffstat 4 files changed, 44 insertions(+), 35 deletions(-) [+]
line wrap: on
line diff
--- a/src/mem_env.rs	Sat Aug 12 16:26:40 2017 +0200
+++ b/src/mem_env.rs	Sat Aug 12 17:11:09 2017 +0200
@@ -238,7 +238,7 @@
 pub struct MemEnv(MemFS);
 
 impl MemEnv {
-    fn new() -> MemEnv {
+    pub fn new() -> MemEnv {
         MemEnv(MemFS::new())
     }
 }
--- a/src/options.rs	Sat Aug 12 16:26:40 2017 +0200
+++ b/src/options.rs	Sat Aug 12 17:11:09 2017 +0200
@@ -78,9 +78,14 @@
     /// DO NOT set the comparator after having written any record with a different comparator.
     /// If the comparator used differs from the one used when writing a database that is being
     /// opened, the library is free to panic.
-    pub fn set_comparator<C: Cmp>(&mut self, c: Box<Cmp>) {
+    pub fn set_comparator(&mut self, c: Box<Cmp>) {
         self.cmp = Arc::new(c);
     }
+
+    /// Set the environment to use. The default is PosixDiskEnv.
+    pub fn set_env(&mut self, e: Box<Env>) {
+        self.env = Arc::new(e);
+    }
 }
 
 /// Supplied to DB read operations.
--- a/src/table_cache.rs	Sat Aug 12 16:26:40 2017 +0200
+++ b/src/table_cache.rs	Sat Aug 12 17:11:09 2017 +0200
@@ -23,18 +23,14 @@
     buf
 }
 
-struct TableAndFile {
-    file: Arc<Box<RandomAccess>>,
-    table: Table,
-}
-
 pub struct TableCache {
     dbname: String,
-    cache: Cache<TableAndFile>,
+    cache: Cache<Table>,
     opts: Options,
 }
 
 impl TableCache {
+    /// Create a new TableCache for the database named `db`, caching up to `entries` tables.
     pub fn new(db: &str, opt: Options, entries: usize) -> TableCache {
         TableCache {
             dbname: String::from(db),
@@ -42,32 +38,25 @@
             opts: opt,
         }
     }
-    pub fn evict(&mut self, id: u64) {
-        self.cache.remove(&filenum_to_key(id));
-    }
 
     /// Return a table from cache, or open the backing file, then cache and return it.
-    pub fn get_table(&mut self, file_num: u64, file_size: usize) -> Result<Table> {
+    pub fn get_table(&mut self, file_num: u64) -> Result<Table> {
         let key = filenum_to_key(file_num);
-        match self.cache.get(&key) {
-            Some(t) => return Ok(t.table.clone()),
-            _ => {}
+        if let Some(t) = self.cache.get(&key) {
+            return Ok(t.clone());
         }
-        self.open_table(file_num, file_size)
+        self.open_table(file_num)
     }
 
     /// Open a table on the file system and read it.
-    fn open_table(&mut self, file_num: u64, file_size: usize) -> Result<Table> {
+    fn open_table(&mut self, file_num: u64) -> Result<Table> {
         let name = table_name(&self.dbname, file_num, DEFAULT_SUFFIX);
         let path = Path::new(&name);
         let file = Arc::new(self.opts.env.open_random_access_file(&path)?);
+        let file_size = self.opts.env.size_of(&path)?;
         // No SSTable file name compatibility.
-        let table = Table::new(self.opts.clone(), file.clone(), file_size)?;
-        self.cache.insert(&filenum_to_key(file_num),
-                          TableAndFile {
-                              file: file.clone(),
-                              table: table.clone(),
-                          });
+        let table = Table::new(self.opts.clone(), file, file_size)?;
+        self.cache.insert(&filenum_to_key(file_num), table.clone());
         Ok(table)
     }
 }
@@ -76,10 +65,9 @@
 mod tests {
     use super::*;
     use cache;
+    use mem_env::MemEnv;
     use table_builder::TableBuilder;
 
-    use std::io::Write;
-
     #[test]
     fn test_table_name() {
         assert_eq!("abc/000122.ldb", table_name("abc", 122, "ldb"));
@@ -97,10 +85,9 @@
         assert_eq!(make_key(1, 2, 3), filenum_to_key(0x030201));
     }
 
-    fn write_table_to(w: Box<Write>) {
-        let mut opt = Options::default();
-        opt.block_restart_interval = 3;
-        let mut b = TableBuilder::new_raw(opt, w);
+    fn write_table_to(o: Options, p: &Path) {
+        let w = o.env.open_writable_file(p).unwrap();
+        let mut b = TableBuilder::new_raw(o, w);
 
         let data = vec![("abc", "def"), ("abd", "dee"), ("bcd", "asa"), ("bsr", "a00")];
 
@@ -110,7 +97,23 @@
         b.finish();
     }
 
-    // TODO: Write tests after memenv has been implemented.
     #[test]
-    fn test_table_cache() {}
+    fn test_table_cache() {
+        // Tests that a table can be written to a MemFS file, read back by the table cache and
+        // parsed/iterated by the table reader.
+        let mut opt = Options::default();
+        opt.set_env(Box::new(MemEnv::new()));
+        let dbname = "testdb1";
+        let tablename = table_name(dbname, 123, DEFAULT_SUFFIX);
+        let tblpath = Path::new(&tablename);
+
+        write_table_to(opt.clone(), tblpath);
+        assert!(opt.env.exists(tblpath).unwrap());
+        assert!(opt.env.size_of(tblpath).unwrap() > 20);
+
+        let mut cache = TableCache::new(dbname, opt.clone(), 10);
+        assert_eq!(cache.get_table(123).unwrap().iter().count(), 4);
+        // Test cached table.
+        assert_eq!(cache.get_table(123).unwrap().iter().count(), 4);
+    }
 }
--- a/src/table_reader.rs	Sat Aug 12 16:26:40 2017 +0200
+++ b/src/table_reader.rs	Sat Aug 12 17:11:09 2017 +0200
@@ -153,8 +153,9 @@
             }
         }
 
-        let rfile = self.file.as_ref().as_ref();
-        let b = try!(TableBlock::read_block(self.opt.clone(), rfile, location));
+        let rfile = self.file.clone();
+        // Two times as_ref(): First time to get a ref from Arc<>, then one from Box<>.
+        let b = try!(TableBlock::read_block(self.opt.clone(), rfile.as_ref().as_ref(), location));
 
         if !b.verify() {
             return Err(Status::new(StatusCode::InvalidData, "Data block failed verification"));
@@ -181,8 +182,8 @@
         return self.footer.meta_index.offset();
     }
 
-    // Iterators read from the file; thus only one iterator can be borrowed (mutably) per scope
-    fn iter<'a>(&'a mut self) -> TableIterator<'a> {
+    /// Iterators read from the file; thus only one iterator can be borrowed (mutably) per scope
+    pub fn iter<'a>(&'a mut self) -> TableIterator<'a> {
         let iter = TableIterator {
             current_block: self.indexblock.iter(),
             init: false,