Mercurial > lbo > hg > leveldb-rs
changeset 35:41695091f5b1
Implement prev() for all iterators
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Sun, 12 Jun 2016 18:55:42 +0200 |
parents | c5f2e0b7b38d |
children | 39054a947d1f |
files | src/block.rs src/memtable.rs src/skipmap.rs src/types.rs |
diffstat | 4 files changed, 172 insertions(+), 5 deletions(-) [+] |
line wrap: on
line diff
--- a/src/block.rs Sun Jun 12 17:10:19 2016 +0200 +++ b/src/block.rs Sun Jun 12 18:55:42 2016 +0200 @@ -67,6 +67,7 @@ offset: 0, key: Vec::new(), val_offset: 0, + current_entry_offset: 0, } } } @@ -74,7 +75,11 @@ pub struct BlockIter<'a, C: 'a + Comparator> { block: &'a Block<C>, + // start of next entry offset: usize, + // start of current entry + current_entry_offset: usize, + // tracks the last restart we encountered current_restart_ix: usize, // We assemble the key from two parts usually, so we keep the current full key here. @@ -119,9 +124,9 @@ type Item = (Vec<u8>, &'a [u8]); fn next(&mut self) -> Option<Self::Item> { - let current_offset = self.offset; + self.current_entry_offset = self.offset; - if current_offset >= self.block.restarts_off { + if self.current_entry_offset >= self.block.restarts_off { return None; } let (shared, non_shared, valsize) = self.parse_entry(); @@ -132,7 +137,8 @@ let num_restarts = self.block.number_restarts(); while self.current_restart_ix + 1 < num_restarts && - self.block.get_restart_point(self.current_restart_ix + 1) < current_offset { + self.block.get_restart_point(self.current_restart_ix + 1) < + self.current_entry_offset { self.current_restart_ix += 1; } Some((self.key.clone(), &self.block.data[self.val_offset..self.val_offset + valsize])) @@ -140,6 +146,36 @@ } impl<'a, C: 'a + Comparator> LdbIterator<'a> for BlockIter<'a, C> { + fn prev(&mut self) -> Option<Self::Item> { + // as in the original implementation -- seek to last restart point, then look for key + let current_offset = self.current_entry_offset; + + // At the beginning, can't go further back + if current_offset == 0 { + self.reset(); + return None; + } + + while self.block.get_restart_point(self.current_restart_ix) >= current_offset { + self.current_restart_ix -= 1; + } + + self.offset = self.block.get_restart_point(self.current_restart_ix); + assert!(self.offset < current_offset); + + let mut result; + + loop { + result = self.next(); + println!("next! {:?}", (self.current_entry_offset, self.offset)); + + if self.offset >= current_offset { + break; + } + } + result + + } fn seek(&mut self, to: &[u8]) { self.reset(); @@ -321,7 +357,6 @@ } let block_contents = builder.finish(); - let block = Block::new(block_contents); let block_iter = block.iter(); let mut i = 0; @@ -334,6 +369,35 @@ } #[test] + fn test_iterate_reverse() { + let mut o = Options::default(); + o.block_restart_interval = 3; + let data = get_data(); + let mut builder = BlockBuilder::new(o); + + for &(k, v) in data.iter() { + builder.add(k, v); + } + + let block_contents = builder.finish(); + let block = Block::new(block_contents); + let mut block_iter = block.iter(); + + assert!(!block_iter.valid()); + assert_eq!(block_iter.next(), + Some(("key1".as_bytes().to_vec(), "value1".as_bytes()))); + assert!(block_iter.valid()); + block_iter.next(); + assert!(block_iter.valid()); + block_iter.prev(); + assert!(block_iter.valid()); + assert_eq!(block_iter.current(), + ("key1".as_bytes().to_vec(), "value1".as_bytes())); + block_iter.prev(); + assert!(!block_iter.valid()); + } + + #[test] fn test_seek() { let mut o = Options::default(); o.block_restart_interval = 3;
--- a/src/memtable.rs Sun Jun 12 17:10:19 2016 +0200 +++ b/src/memtable.rs Sun Jun 12 18:55:42 2016 +0200 @@ -202,6 +202,23 @@ } impl<'a, C: 'a + Comparator> LdbIterator<'a> for MemtableIterator<'a, C> { + fn prev(&mut self) -> Option<Self::Item> { + loop { + if let Some((foundkey, _)) = self.skipmapiter.prev() { + let (keylen, keyoff, tag, vallen, valoff) = + MemTable::<C>::parse_memtable_key(foundkey); + + if tag & 0xff == ValueType::TypeValue as u64 { + return Some((&foundkey[keyoff..keyoff + keylen], + &foundkey[valoff..valoff + vallen])); + } else { + continue; + } + } else { + return None; + } + } + } fn valid(&self) -> bool { self.skipmapiter.valid() } @@ -296,6 +313,27 @@ } #[test] + fn test_memtable_iterator_reverse() { + let mt = get_memtable(); + let mut iter = mt.iter(); + + iter.next(); + assert!(iter.valid()); + assert_eq!(iter.current().0, vec![97, 98, 99].as_slice()); + + iter.next(); + assert!(iter.valid()); + assert_eq!(iter.current().0, vec![97, 98, 100].as_slice()); + + iter.prev(); + assert!(iter.valid()); + assert_eq!(iter.current().0, vec![97, 98, 99].as_slice()); + + iter.prev(); + assert!(!iter.valid()); + } + + #[test] fn test_parse_memtable_key() { let key = vec![3, 1, 2, 3, 1, 123, 0, 0, 0, 0, 0, 0, 3, 4, 5, 6]; let (keylen, keyoff, tag, vallen, valoff) =
--- a/src/skipmap.rs Sun Jun 12 17:10:19 2016 +0200 +++ b/src/skipmap.rs Sun Jun 12 18:55:42 2016 +0200 @@ -112,6 +112,38 @@ return unsafe { &(*current) }; } + /// Finds the node immediately before the node with key + fn get_next_smaller<'a>(&'a self, key: &[u8]) -> &'a Node { + // Start at the highest skip link of the head node, and work down from there + let mut current: *const Node = unsafe { transmute_copy(&self.head.as_ref()) }; + let mut level = self.head.skips.len() - 1; + + loop { + unsafe { + if let Some(next) = (*current).skips[level] { + let ord = C::cmp((*next).key.as_slice(), key); + + match ord { + Ordering::Less => { + current = next; + continue; + } + _ => { + if level == 0 { + return &(*current); + } + } + } + } + } + if level == 0 { + break; + } + level -= 1; + } + return unsafe { &(*current) }; + } + pub fn insert(&mut self, key: Vec<u8>, val: Vec<u8>) { assert!(!key.is_empty()); @@ -242,6 +274,17 @@ assert!(self.valid()); unsafe { (&(*self.current).key, &(*self.current).value) } } + fn prev(&mut self) -> Option<Self::Item> { + // Going after the original implementation here; we just seek to the node before current(). + let prev = self.map.get_next_smaller(self.current().0); + self.current = unsafe { transmute_copy(&prev) }; + + if !prev.key.is_empty() { + Some(unsafe { (&(*self.current).key, &(*self.current).value) }) + } else { + None + } + } } #[cfg(test)] @@ -290,7 +333,7 @@ } #[test] - fn test_seek() { + fn test_find() { let skm = make_skipmap(); assert_eq!(skm.get_greater_or_equal(&"abf".as_bytes().to_vec()).key, "abf".as_bytes().to_vec()); @@ -298,6 +341,14 @@ "abz".as_bytes().to_vec()); assert_eq!(skm.get_greater_or_equal(&"aaa".as_bytes().to_vec()).key, "aba".as_bytes().to_vec()); + assert_eq!(skm.get_greater_or_equal(&"ab".as_bytes()).key.as_slice(), + "aba".as_bytes()); + assert_eq!(skm.get_greater_or_equal(&"abc".as_bytes()).key.as_slice(), + "abc".as_bytes()); + assert_eq!(skm.get_next_smaller(&"abd".as_bytes()).key.as_slice(), + "abc".as_bytes()); + assert_eq!(skm.get_next_smaller(&"ab{".as_bytes()).key.as_slice(), + "abz".as_bytes()); } #[test] @@ -347,6 +398,19 @@ } } assert_eq!(iter.next(), None); + } + #[test] + fn test_iterator_prev() { + let skm = make_skipmap(); + let mut iter = skm.iter(); + + iter.next(); + assert!(iter.valid()); + iter.prev(); + assert!(!iter.valid()); + iter.seek(&"abc".as_bytes()); + iter.prev(); + assert_eq!(iter.current(), ("abb".as_bytes(), "def".as_bytes())); } }