@ -36,12 +36,13 @@ const size_t kNumIterReserve = 4;
class MergingIterator : public InternalIterator {
class MergingIterator : public InternalIterator {
public :
public :
MergingIterator ( const Comparator * comparator , InternalIterator * * children ,
MergingIterator ( const Comparator * comparator , InternalIterator * * children ,
int n , bool is_arena_mode )
int n , bool is_arena_mode , bool prefix_seek_mode )
: is_arena_mode_ ( is_arena_mode ) ,
: is_arena_mode_ ( is_arena_mode ) ,
comparator_ ( comparator ) ,
comparator_ ( comparator ) ,
current_ ( nullptr ) ,
current_ ( nullptr ) ,
direction_ ( kForward ) ,
direction_ ( kForward ) ,
minHeap_ ( comparator_ ) ,
minHeap_ ( comparator_ ) ,
prefix_seek_mode_ ( prefix_seek_mode ) ,
pinned_iters_mgr_ ( nullptr ) {
pinned_iters_mgr_ ( nullptr ) {
children_ . resize ( n ) ;
children_ . resize ( n ) ;
for ( int i = 0 ; i < n ; i + + ) {
for ( int i = 0 ; i < n ; i + + ) {
@ -204,9 +205,23 @@ class MergingIterator : public InternalIterator {
InitMaxHeap ( ) ;
InitMaxHeap ( ) ;
for ( auto & child : children_ ) {
for ( auto & child : children_ ) {
if ( & child ! = current_ ) {
if ( & child ! = current_ ) {
child . SeekForPrev ( key ( ) ) ;
if ( ! prefix_seek_mode_ ) {
if ( child . Valid ( ) & & comparator_ - > Equal ( key ( ) , child . key ( ) ) ) {
child . Seek ( key ( ) ) ;
child . Prev ( ) ;
if ( child . Valid ( ) ) {
// Child is at first entry >= key(). Step back one to be < key()
TEST_SYNC_POINT_CALLBACK ( " MergeIterator::Prev:BeforePrev " ,
& child ) ;
child . Prev ( ) ;
} else {
// Child has no entries >= key(). Position at last entry.
TEST_SYNC_POINT ( " MergeIterator::Prev:BeforeSeekToLast " ) ;
child . SeekToLast ( ) ;
}
} else {
child . SeekForPrev ( key ( ) ) ;
if ( child . Valid ( ) & & comparator_ - > Equal ( key ( ) , child . key ( ) ) ) {
child . Prev ( ) ;
}
}
}
}
}
if ( child . Valid ( ) ) {
if ( child . Valid ( ) ) {
@ -214,6 +229,13 @@ class MergingIterator : public InternalIterator {
}
}
}
}
direction_ = kReverse ;
direction_ = kReverse ;
if ( ! prefix_seek_mode_ ) {
// Note that we don't do assert(current_ == CurrentReverse()) here
// because it is possible to have some keys larger than the seek-key
// inserted between Seek() and SeekToLast(), which makes current_ not
// equal to CurrentReverse().
current_ = CurrentReverse ( ) ;
}
// The loop advanced all non-current children to be < key() so current_
// The loop advanced all non-current children to be < key() so current_
// should still be strictly the smallest key.
// should still be strictly the smallest key.
assert ( current_ = = CurrentReverse ( ) ) ;
assert ( current_ = = CurrentReverse ( ) ) ;
@ -299,6 +321,8 @@ class MergingIterator : public InternalIterator {
} ;
} ;
Direction direction_ ;
Direction direction_ ;
MergerMinIterHeap minHeap_ ;
MergerMinIterHeap minHeap_ ;
bool prefix_seek_mode_ ;
// Max heap is used for reverse iteration, which is way less common than
// Max heap is used for reverse iteration, which is way less common than
// forward. Lazily initialize it to save memory.
// forward. Lazily initialize it to save memory.
std : : unique_ptr < MergerMaxIterHeap > maxHeap_ ;
std : : unique_ptr < MergerMaxIterHeap > maxHeap_ ;
@ -331,7 +355,7 @@ void MergingIterator::InitMaxHeap() {
InternalIterator * NewMergingIterator ( const Comparator * cmp ,
InternalIterator * NewMergingIterator ( const Comparator * cmp ,
InternalIterator * * list , int n ,
InternalIterator * * list , int n ,
Arena * arena ) {
Arena * arena , bool prefix_seek_mode ) {
assert ( n > = 0 ) ;
assert ( n > = 0 ) ;
if ( n = = 0 ) {
if ( n = = 0 ) {
return NewEmptyInternalIterator ( arena ) ;
return NewEmptyInternalIterator ( arena ) ;
@ -339,19 +363,20 @@ InternalIterator* NewMergingIterator(const Comparator* cmp,
return list [ 0 ] ;
return list [ 0 ] ;
} else {
} else {
if ( arena = = nullptr ) {
if ( arena = = nullptr ) {
return new MergingIterator ( cmp , list , n , false ) ;
return new MergingIterator ( cmp , list , n , false , prefix_seek_mode ) ;
} else {
} else {
auto mem = arena - > AllocateAligned ( sizeof ( MergingIterator ) ) ;
auto mem = arena - > AllocateAligned ( sizeof ( MergingIterator ) ) ;
return new ( mem ) MergingIterator ( cmp , list , n , true ) ;
return new ( mem ) MergingIterator ( cmp , list , n , true , prefix_seek_mode ) ;
}
}
}
}
}
}
MergeIteratorBuilder : : MergeIteratorBuilder ( const Comparator * comparator ,
MergeIteratorBuilder : : MergeIteratorBuilder ( const Comparator * comparator ,
Arena * a )
Arena * a , bool prefix_seek_mode )
: first_iter ( nullptr ) , use_merging_iter ( false ) , arena ( a ) {
: first_iter ( nullptr ) , use_merging_iter ( false ) , arena ( a ) {
auto mem = arena - > AllocateAligned ( sizeof ( MergingIterator ) ) ;
auto mem = arena - > AllocateAligned ( sizeof ( MergingIterator ) ) ;
merge_iter = new ( mem ) MergingIterator ( comparator , nullptr , 0 , true ) ;
merge_iter =
new ( mem ) MergingIterator ( comparator , nullptr , 0 , true , prefix_seek_mode ) ;
}
}
void MergeIteratorBuilder : : AddIterator ( InternalIterator * iter ) {
void MergeIteratorBuilder : : AddIterator ( InternalIterator * iter ) {