@@ -384,10 +384,19 @@ void IndexBlockIter::Seek(const Slice& target) {
384384 if (data_ == nullptr ) { // Not init yet
385385 return ;
386386 }
387+ status_ = Status::OK ();
387388 uint32_t index = 0 ;
388389 bool ok = false ;
389390 if (prefix_index_) {
390- ok = PrefixSeek (target, &index);
391+ bool prefix_may_exist = true ;
392+ ok = PrefixSeek (target, &index, &prefix_may_exist);
393+ if (!prefix_may_exist) {
394+ // This is to let the caller to distinguish between non-existing prefix,
395+ // and when key is larger than the last key, which both set Valid() to
396+ // false.
397+ current_ = restarts_;
398+ status_ = Status::NotFound ();
399+ }
391400 } else if (value_delta_encoded_) {
392401 ok = BinarySeek<DecodeKeyV4>(seek_key, 0 , num_restarts_ - 1 , &index,
393402 comparator_);
@@ -453,6 +462,7 @@ void IndexBlockIter::SeekToFirst() {
453462 if (data_ == nullptr ) { // Not init yet
454463 return ;
455464 }
465+ status_ = Status::OK ();
456466 SeekToRestartPoint (0 );
457467 ParseNextIndexKey ();
458468}
@@ -471,6 +481,7 @@ void IndexBlockIter::SeekToLast() {
471481 if (data_ == nullptr ) { // Not init yet
472482 return ;
473483 }
484+ status_ = Status::OK ();
474485 SeekToRestartPoint (num_restarts_ - 1 );
475486 while (ParseNextIndexKey () && NextEntryOffset () < restarts_) {
476487 // Keep skipping
@@ -709,8 +720,12 @@ int IndexBlockIter::CompareBlockKey(uint32_t block_index, const Slice& target) {
709720// with a key >= target
710721bool IndexBlockIter::BinaryBlockIndexSeek (const Slice& target,
711722 uint32_t * block_ids, uint32_t left,
712- uint32_t right, uint32_t * index) {
723+ uint32_t right, uint32_t * index,
724+ bool * prefix_may_exist) {
713725 assert (left <= right);
726+ assert (index);
727+ assert (prefix_may_exist);
728+ *prefix_may_exist = true ;
714729 uint32_t left_bound = left;
715730
716731 while (left <= right) {
@@ -744,21 +759,53 @@ bool IndexBlockIter::BinaryBlockIndexSeek(const Slice& target,
744759 (left == left_bound || block_ids[left - 1 ] != block_ids[left] - 1 ) &&
745760 CompareBlockKey (block_ids[left] - 1 , target) > 0 ) {
746761 current_ = restarts_;
762+ *prefix_may_exist = false ;
747763 return false ;
748764 }
749765
750766 *index = block_ids[left];
751767 return true ;
752768 } else {
753769 assert (left > right);
770+
771+ // If the next block key is larger than seek key, it is possible that
772+ // no key shares the prefix with `target`, or all keys with the same
773+ // prefix as `target` are smaller than prefix. In the latter case,
774+ // we are mandated to set the position the same as the total order.
775+ // In the latter case, either:
776+ // (1) `target` falls into the range of the next block. In this case,
777+ // we can place the iterator to the next block, or
778+ // (2) `target` is larger than all block keys. In this case we can
779+ // keep the iterator invalidate without setting `prefix_may_exist`
780+ // to false.
781+ // We might sometimes end up with setting the total order position
782+ // while there is no key sharing the prefix as `target`, but it
783+ // still follows the contract.
784+ uint32_t right_index = block_ids[right];
785+ assert (right_index + 1 <= num_restarts_);
786+ if (right_index + 1 < num_restarts_) {
787+ if (CompareBlockKey (right_index + 1 , target) >= 0 ) {
788+ *index = right_index + 1 ;
789+ return true ;
790+ } else {
791+ // We have to set the flag here because we are not positioning
792+ // the iterator to the total order position.
793+ *prefix_may_exist = false ;
794+ }
795+ }
796+
754797 // Mark iterator invalid
755798 current_ = restarts_;
756799 return false ;
757800 }
758801}
759802
760- bool IndexBlockIter::PrefixSeek (const Slice& target, uint32_t * index) {
803+ bool IndexBlockIter::PrefixSeek (const Slice& target, uint32_t * index,
804+ bool * prefix_may_exist) {
805+ assert (index);
806+ assert (prefix_may_exist);
761807 assert (prefix_index_);
808+ *prefix_may_exist = true ;
762809 Slice seek_key = target;
763810 if (!key_includes_seq_) {
764811 seek_key = ExtractUserKey (target);
@@ -768,9 +815,12 @@ bool IndexBlockIter::PrefixSeek(const Slice& target, uint32_t* index) {
768815
769816 if (num_blocks == 0 ) {
770817 current_ = restarts_;
818+ *prefix_may_exist = false ;
771819 return false ;
772820 } else {
773- return BinaryBlockIndexSeek (seek_key, block_ids, 0 , num_blocks - 1 , index);
821+ assert (block_ids);
822+ return BinaryBlockIndexSeek (seek_key, block_ids, 0 , num_blocks - 1 , index,
823+ prefix_may_exist);
774824 }
775825}
776826
0 commit comments