Mercurial > lbo > hg > leveldb-rs
view src/table_reader.rs @ 91:f6b6a82fb7cd
Fix MemtableIterator: Key returned from iterator should include tag
See https://github.com/google/leveldb/blob/master/db/memtable.cc#L61
author | Lewin Bormann <lbo@spheniscida.de> |
---|---|
date | Fri, 02 Sep 2016 22:47:04 +0200 |
parents | 89810ac42bd1 |
children | b09acb0e365e 16043131cbd5 |
line wrap: on
line source
use block::Block; use blockhandle::BlockHandle; use filter::FilterPolicy; use filter_block::FilterBlockReader; use options::Options; use table_builder; use types::{Comparator, LdbIterator}; use std::io::{Read, Seek, SeekFrom, Result}; struct TableFooter { pub metaindex: BlockHandle, pub index: BlockHandle, } impl TableFooter { fn parse(footer: &[u8]) -> TableFooter { assert_eq!(footer.len(), table_builder::FULL_FOOTER_LENGTH); assert_eq!(&footer[footer.len() - 8..], table_builder::MAGIC_FOOTER_ENCODED); let (mi, n1) = BlockHandle::decode(footer); let (ix, _) = BlockHandle::decode(&footer[n1..]); TableFooter { metaindex: mi, index: ix, } } } pub struct Table<R: Read + Seek, C: Comparator, FP: FilterPolicy> { file: R, file_size: usize, opt: Options, cmp: C, footer: TableFooter, indexblock: Block<C>, filters: Option<FilterBlockReader<FP>>, } impl<R: Read + Seek, C: Comparator, FP: FilterPolicy> Table<R, C, FP> { pub fn new(mut file: R, size: usize, cmp: C, fp: FP, opt: Options) -> Result<Table<R, C, FP>> { let footer = try!(Table::<R, C, FP>::read_footer(&mut file, size)); let indexblock = try!(Table::<R, C, FP>::read_block(&cmp, &mut file, &footer.index)); let metaindexblock = try!(Table::<R, C, FP>::read_block(&cmp, &mut file, &footer.metaindex)); let mut filter_block_reader = None; let mut filter_block_location = BlockHandle::new(0, 0); let mut filter_name = "filter.".as_bytes().to_vec(); filter_name.extend_from_slice(fp.name().as_bytes()); for (key, val) in metaindexblock.iter() { if key == filter_name { filter_block_location = BlockHandle::decode(val).0; break; } } if filter_block_location.size() > 0 { let filter_block = try!(Table::<R, C, FP>::read_block(&cmp, &mut file, &filter_block_location)); filter_block_reader = Some(FilterBlockReader::new(fp, filter_block.obtain())); } Ok(Table { file: file, file_size: size, cmp: cmp, opt: opt, footer: footer, filters: filter_block_reader, indexblock: indexblock, }) } /// Reads the table footer. fn read_footer(f: &mut R, size: usize) -> Result<TableFooter> { try!(f.seek(SeekFrom::Start((size - table_builder::FULL_FOOTER_LENGTH) as u64))); let mut buf = [0; table_builder::FULL_FOOTER_LENGTH]; try!(f.read_exact(&mut buf)); Ok(TableFooter::parse(&buf)) } /// Reads a block at location. fn read_block(cmp: &C, f: &mut R, location: &BlockHandle) -> Result<Block<C>> { try!(f.seek(SeekFrom::Start(location.offset() as u64))); let mut buf = Vec::new(); buf.resize(location.size(), 0); try!(f.read_exact(&mut buf[0..location.size()])); Ok(Block::new_with_cmp(buf, *cmp)) } /// Returns the offset of the block that contains `key`. pub fn approx_offset_of(&self, key: &[u8]) -> usize { let mut iter = self.indexblock.iter(); iter.seek(key); if iter.valid() { if let Some((_, val)) = iter.current() { let location = BlockHandle::decode(val).0; return location.offset(); } } return self.footer.metaindex.offset(); } } /// This iterator is a "TwoLevelIterator"; it uses an index block in order to get an offset hint /// into the data blocks. pub struct TableIterator { }