@ -2346,6 +2346,7 @@ void BlockBasedTableIterator<TBlockIter, TValue>::Seek(const Slice& target) {
block_iter_ . Seek ( target ) ;
FindKeyForward ( ) ;
CheckOutOfBound ( ) ;
assert (
! block_iter_ . Valid ( ) | |
( key_includes_seq_ & & icomp_ . Compare ( target , block_iter_ . key ( ) ) < = 0 ) | |
@ -2409,6 +2410,7 @@ void BlockBasedTableIterator<TBlockIter, TValue>::SeekToFirst() {
InitDataBlock ( ) ;
block_iter_ . SeekToFirst ( ) ;
FindKeyForward ( ) ;
CheckOutOfBound ( ) ;
}
template < class TBlockIter , typename TValue >
@ -2491,18 +2493,24 @@ void BlockBasedTableIterator<TBlockIter, TValue>::InitDataBlock() {
template < class TBlockIter , typename TValue >
void BlockBasedTableIterator < TBlockIter , TValue > : : FindKeyForward ( ) {
assert ( ! is_out_of_bound_ ) ;
// TODO the while loop inherits from two-level-iterator. We don't know
// whether a block can be empty so it can be replaced by an "if".
while ( ! block_iter_ . Valid ( ) ) {
if ( ! block_iter_ . status ( ) . ok ( ) ) {
return ;
}
if ( read_options_ . iterate_upper_bound ! = nullptr & &
block_iter_points_to_real_block_ ) {
is_out_of_bound_ =
( user_comparator_ . Compare ( * read_options_ . iterate_upper_bound ,
ExtractUserKey ( index_iter_ - > key ( ) ) ) < = 0 ) ;
}
ResetDataIter ( ) ;
// We used to check the current index key for upperbound.
// It will only save a data reading for a small percentage of use cases,
// so for code simplicity, we removed it. We can add it back if there is a
// significnat performance regression.
if ( is_out_of_bound_ ) {
// The next block is out of bound. No need to read it.
TEST_SYNC_POINT_CALLBACK ( " BlockBasedTableIterator:out_of_bound " , nullptr ) ;
return ;
}
index_iter_ - > Next ( ) ;
if ( index_iter_ - > Valid ( ) ) {
@ -2512,25 +2520,10 @@ void BlockBasedTableIterator<TBlockIter, TValue>::FindKeyForward() {
return ;
}
}
// Check upper bound on the current key
bool reached_upper_bound =
( read_options_ . iterate_upper_bound ! = nullptr & &
block_iter_points_to_real_block_ & & block_iter_ . Valid ( ) & &
user_comparator_ . Compare ( ExtractUserKey ( block_iter_ . key ( ) ) ,
* read_options_ . iterate_upper_bound ) > = 0 ) ;
TEST_SYNC_POINT_CALLBACK (
" BlockBasedTable::BlockEntryIteratorState::KeyReachedUpperBound " ,
& reached_upper_bound ) ;
if ( reached_upper_bound ) {
is_out_of_bound_ = true ;
return ;
}
}
template < class TBlockIter , typename TValue >
void BlockBasedTableIterator < TBlockIter , TValue > : : FindKeyBackward ( ) {
assert ( ! is_out_of_bound_ ) ;
while ( ! block_iter_ . Valid ( ) ) {
if ( ! block_iter_ . status ( ) . ok ( ) ) {
return ;
@ -2551,6 +2544,16 @@ void BlockBasedTableIterator<TBlockIter, TValue>::FindKeyBackward() {
// code simplicity.
}
template < class TBlockIter , typename TValue >
void BlockBasedTableIterator < TBlockIter , TValue > : : CheckOutOfBound ( ) {
if ( read_options_ . iterate_upper_bound ! = nullptr & &
block_iter_points_to_real_block_ & & block_iter_ . Valid ( ) ) {
is_out_of_bound_ =
user_comparator_ . Compare ( * read_options_ . iterate_upper_bound ,
ExtractUserKey ( block_iter_ . key ( ) ) ) < = 0 ;
}
}
InternalIterator * BlockBasedTable : : NewIterator (
const ReadOptions & read_options , const SliceTransform * prefix_extractor ,
Arena * arena , bool skip_filters , bool for_compaction ) {