diff --git a/sstable/src/dictionary.rs b/sstable/src/dictionary.rs index 718c547da..3e70d5a00 100644 --- a/sstable/src/dictionary.rs +++ b/sstable/src/dictionary.rs @@ -496,10 +496,15 @@ impl Dictionary { // Open the block for the first ordinal. let mut bytes = Vec::new(); - let mut current_block_addr = self.sstable_index.get_block_with_ord(ord); + let (mut current_block_addr, block_id) = self.sstable_index.get_and_locate_with_ord(ord); let mut current_sstable_delta_reader = self.sstable_delta_reader_block(current_block_addr.clone())?; let mut current_block_ordinal = current_block_addr.first_ordinal; + let mut current_block_bound = self + .sstable_index + .get_block(block_id + 1) + .map(|block_addr| block_addr.first_ordinal) + .unwrap_or(u64::MAX); loop { // move to the ord inside the current block @@ -528,17 +533,19 @@ impl Dictionary { } }; - // TODO optimization: it is silly to do a binary search to get the block every single - // time. - // - // Check if block changed for new term_ord - let new_block_addr = self.sstable_index.get_block_with_ord(next_ord); - if new_block_addr != current_block_addr { + if next_ord >= current_block_bound { + let (new_block_addr, block_id) = + self.sstable_index.get_and_locate_with_ord(next_ord); current_block_addr = new_block_addr; current_block_ordinal = current_block_addr.first_ordinal; current_sstable_delta_reader = self.sstable_delta_reader_block(current_block_addr.clone())?; bytes.clear(); + current_block_bound = self + .sstable_index + .get_block(block_id + 1) + .map(|block_addr| block_addr.first_ordinal) + .unwrap_or(u64::MAX) } ord = next_ord; } diff --git a/sstable/src/index/mod.rs b/sstable/src/index/mod.rs index a4aff603e..f927379be 100644 --- a/sstable/src/index/mod.rs +++ b/sstable/src/index/mod.rs @@ -98,6 +98,14 @@ impl SSTableIndex { } } + pub(crate) fn get_and_locate_with_ord(&self, ord: TermOrdinal) -> (BlockAddr, u64) { + match self { + SSTableIndex::V2(v2_index) => v2_index.get_and_locate_with_ord(ord), + SSTableIndex::V3(v3_index) => v3_index.get_and_locate_with_ord(ord), + SSTableIndex::V3Empty(v3_empty) => v3_empty.get_and_locate_with_ord(ord), + } + } + pub fn get_block_for_automaton<'a>( &'a self, automaton: &'a impl Automaton, diff --git a/sstable/src/index/v2.rs b/sstable/src/index/v2.rs index f0aa83ab0..d67bf7121 100644 --- a/sstable/src/index/v2.rs +++ b/sstable/src/index/v2.rs @@ -77,6 +77,13 @@ impl SSTableIndex { self.get_block(self.locate_with_ord(ord)).unwrap() } + pub(crate) fn get_and_locate_with_ord(&self, ord: TermOrdinal) -> (BlockAddr, u64) { + let location = self.locate_with_ord(ord); + // locate_with_ord always returns an index within range + let block_addr = self.get_block(location).unwrap(); + (block_addr, location as u64) + } + pub(crate) fn get_block_for_automaton<'a>( &'a self, automaton: &'a impl Automaton, diff --git a/sstable/src/index/v3.rs b/sstable/src/index/v3.rs index b7c6673ed..b6d009a71 100644 --- a/sstable/src/index/v3.rs +++ b/sstable/src/index/v3.rs @@ -68,6 +68,11 @@ impl SSTableIndexV3 { self.block_addr_store.binary_search_ord(ord).1 } + pub(crate) fn get_and_locate_with_ord(&self, ord: TermOrdinal) -> (BlockAddr, u64) { + let (location, block_addr) = self.block_addr_store.binary_search_ord(ord); + (block_addr, location) + } + pub(crate) fn get_block_for_automaton<'a>( &'a self, automaton: &'a impl Automaton, @@ -138,8 +143,8 @@ impl SSTableIndexV3Empty { } /// Get the [`BlockAddr`] of the requested block. - pub(crate) fn get_block(&self, _block_id: u64) -> Option { - Some(self.block_addr.clone()) + pub(crate) fn get_block(&self, block_id: u64) -> Option { + (block_id == 0).then(|| self.block_addr.clone()) } /// Get the block id of the block that would contain `key`. @@ -164,6 +169,10 @@ impl SSTableIndexV3Empty { pub(crate) fn get_block_with_ord(&self, _ord: TermOrdinal) -> BlockAddr { self.block_addr.clone() } + + pub(crate) fn get_and_locate_with_ord(&self, _ord: TermOrdinal) -> (BlockAddr, u64) { + (self.block_addr.clone(), 0) + } } const STORE_BLOCK_LEN: usize = 128;