Mercurial > lbo > hg > leveldb-rs
changeset 218:24935679995f
version: Test and fix up Version iterator.
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 08 Sep 2017 21:13:45 +0200 |
parents | fe32a8b830c9 |
children | 7ee8c2fc7756 |
files | src/version.rs |
diffstat | 1 files changed, 78 insertions(+), 2 deletions(-) [+] |
line wrap: on
line diff
--- a/src/version.rs Fri Sep 08 13:49:15 2017 +0000 +++ b/src/version.rs Fri Sep 08 21:13:45 2017 +0200 @@ -238,6 +238,8 @@ } + /// new_concat_iter returns an iterator that iterates over the files in a level. Note that this + /// only really makes sense for levels > 0. fn new_concat_iter(&self, level: usize) -> VersionIter { VersionIter { files: self.files[level].clone(), @@ -247,6 +249,23 @@ current_ix: 0, } } + + /// new_iters returns a set of iterators that can be merged to yield all entries in this + /// version. + fn new_iters(&self) -> Result<Vec<Box<LdbIterator>>> { + let mut iters: Vec<Box<LdbIterator>> = vec![]; + for f in &self.files[0] { + iters.push(Box::new(self.table_cache.borrow_mut().get_table(f.borrow().num)?.iter())); + } + + for l in 1..NUM_LEVELS { + if !self.files[l].is_empty() { + iters.push(Box::new(self.new_concat_iter(l))); + } + } + + Ok(iters) + } } /// VersionIter iterates over all files belonging to a certain level. @@ -263,13 +282,21 @@ impl LdbIterator for VersionIter { fn advance(&mut self) -> bool { + assert!(!self.files.is_empty()); + if let Some(ref mut t) = self.current { if t.advance() { return true; } else if self.current_ix >= self.files.len() - 1 { + // Already on last table; can't advance further. return false; } + + // Load next table if current table is exhausted and we have more tables to go through. + self.current_ix += 1; } + + // Initialize iterator or load next table. if let Ok(tbl) = self.cache .borrow_mut() .get_table(self.files[self.current_ix].borrow().num) { @@ -277,7 +304,6 @@ } else { return false; } - self.current_ix += 1; self.advance() } fn current(&self, key: &mut Vec<u8>, val: &mut Vec<u8>) -> bool { @@ -306,7 +332,7 @@ self.current_ix = 0; } fn valid(&self) -> bool { - self.current.is_some() + self.current.as_ref().map(|t| t.valid()).unwrap_or(false) } fn prev(&mut self) -> bool { if let Some(ref mut t) = self.current { @@ -321,6 +347,7 @@ // The saved largest key must be in the table. assert!(iter.valid()); self.current_ix -= 1; + *t = iter; return true; } } @@ -401,9 +428,11 @@ use env::Env; use error::Result; use mem_env::MemEnv; + use merging_iter::MergingIter; use options::Options; use table_builder::TableBuilder; use table_cache::{table_name, TableCache}; + use test_util::{test_iterator_properties, LdbIteratorIter}; use types::share; fn new_file(num: u64, @@ -488,6 +517,14 @@ ("gab".as_bytes(), "val2".as_bytes()), ("gba".as_bytes(), "val3".as_bytes())]; let t7 = write_table(&env, f7, 19, 7); + // Level 3 (2 * 2 entries, for iterator behavior). + let f8: &[(&[u8], &[u8])] = &[("haa".as_bytes(), "val1".as_bytes()), + ("hba".as_bytes(), "val2".as_bytes())]; + let t8 = write_table(&env, f8, 22, 8); + let f9: &[(&[u8], &[u8])] = &[("iaa".as_bytes(), "val1".as_bytes()), + ("iba".as_bytes(), "val2".as_bytes())]; + let t9 = write_table(&env, f9, 25, 9); + opts.set_env(Box::new(env)); let cache = TableCache::new("db", opts, 100); @@ -495,10 +532,49 @@ v.files[0] = vec![t1, t2]; v.files[1] = vec![t3, t4, t5]; v.files[2] = vec![t6, t7]; + v.files[3] = vec![t8, t9]; v } #[test] + fn test_version_concat_iter() { + let v = make_version(); + + let expected_entries = vec![0, 9, 6, 4]; + for l in 1..4 { + let mut iter = v.new_concat_iter(l); + let iter = LdbIteratorIter::wrap(&mut iter); + assert_eq!(iter.count(), expected_entries[l]); + } + } + + #[test] + fn test_version_concat_iter_properties() { + let v = make_version(); + let iter = v.new_concat_iter(3); + test_iterator_properties(iter); + } + + #[test] + fn test_version_all_iters() { + let v = make_version(); + let iters = v.new_iters().unwrap(); + let mut opt = Options::default(); + opt.set_comparator(Box::new(InternalKeyCmp(Rc::new(Box::new(DefaultCmp))))); + + let mut miter = MergingIter::new(opt, iters); + assert_eq!(LdbIteratorIter::wrap(&mut miter).count(), 25); + + // Check that all elements are in order. + let init = LookupKey::new("000".as_bytes(), MAX_SEQUENCE_NUMBER); + let cmp = InternalKeyCmp(Rc::new(Box::new(DefaultCmp))); + LdbIteratorIter::wrap(&mut miter).fold(init.internal_key().to_vec(), |b, (k, _)| { + assert!(cmp.cmp(&b, &k) == Ordering::Less); + k + }); + } + + #[test] fn test_version_get_simple() { let v = make_version(); let cases: &[(&[u8], u64, Result<Option<Vec<u8>>>)] =