Skip to content

Commit

Permalink
Use prefix_same_as_start to avoid iteration in FindNextUserEntryInter…
Browse files Browse the repository at this point in the history
…nal. (facebook#1102)

This avoids excessive iteration in tombstone fields.
  • Loading branch information
petermattis authored and IslamAbdelRahman committed Apr 28, 2016
1 parent 992a8f8 commit c6c770a
Show file tree
Hide file tree
Showing 2 changed files with 38 additions and 19 deletions.
53 changes: 34 additions & 19 deletions db/db_iter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -201,8 +201,8 @@ class DBIter: public Iterator {
bool FindValueForCurrentKeyUsingSeek();
void FindPrevUserKey();
void FindNextUserKey();
inline void FindNextUserEntry(bool skipping);
void FindNextUserEntryInternal(bool skipping);
inline void FindNextUserEntry(bool skipping, bool prefix_check);
void FindNextUserEntryInternal(bool skipping, bool prefix_check);
bool ParseKey(ParsedInternalKey* key);
void MergeValuesNewToOld();

Expand Down Expand Up @@ -234,8 +234,9 @@ class DBIter: public Iterator {
uint64_t max_skip_;
uint64_t version_number_;
const Slice* iterate_upper_bound_;
IterKey prefix_start_;
bool prefix_same_as_start_;
IterKey prefix_start_buf_;
Slice prefix_start_key_;
const bool prefix_same_as_start_;
// Means that we will pin all data blocks we read as long the Iterator
// is not deleted, will be true if ReadOptions::pin_data is true
const bool pin_thru_lifetime_;
Expand Down Expand Up @@ -289,12 +290,7 @@ void DBIter::Next() {
valid_ = false;
return;
}
FindNextUserEntry(true /* skipping the current user key */);
if (valid_ && prefix_extractor_ && prefix_same_as_start_ &&
prefix_extractor_->Transform(saved_key_.GetKey())
.compare(prefix_start_.GetKey()) != 0) {
valid_ = false;
}
FindNextUserEntry(true /* skipping the current user key */, prefix_same_as_start_);
if (statistics_ != nullptr && valid_) {
local_stats_.next_found_count_++;
local_stats_.bytes_read_ += (key().size() + value().size());
Expand All @@ -309,13 +305,18 @@ void DBIter::Next() {
//
// NOTE: In between, saved_key_ can point to a user key that has
// a delete marker
inline void DBIter::FindNextUserEntry(bool skipping) {
//
// The prefix_check parameter controls whether we check the iterated
// keys against the prefix of the seeked key. Set to false when
// performing a seek without a key (e.g. SeekToFirst). Set to
// prefix_same_as_start_ for other iterations.
inline void DBIter::FindNextUserEntry(bool skipping, bool prefix_check) {
PERF_TIMER_GUARD(find_next_user_entry_time);
FindNextUserEntryInternal(skipping);
FindNextUserEntryInternal(skipping, prefix_check);
}

// Actual implementation of DBIter::FindNextUserEntry()
void DBIter::FindNextUserEntryInternal(bool skipping) {
void DBIter::FindNextUserEntryInternal(bool skipping, bool prefix_check) {
// Loop until we hit an acceptable entry to yield
assert(iter_->Valid());
assert(direction_ == kForward);
Expand All @@ -330,6 +331,11 @@ void DBIter::FindNextUserEntryInternal(bool skipping) {
break;
}

if (prefix_extractor_ && prefix_check &&
prefix_extractor_->Transform(ikey.user_key).compare(prefix_start_key_) != 0) {
break;
}

if (ikey.sequence <= sequence_) {
if (skipping &&
user_comparator_->Compare(ikey.user_key, saved_key_.GetKey()) <= 0) {
Expand Down Expand Up @@ -476,7 +482,7 @@ void DBIter::Prev() {
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_ &&
prefix_extractor_->Transform(saved_key_.GetKey())
.compare(prefix_start_.GetKey()) != 0) {
.compare(prefix_start_key_) != 0) {
valid_ = false;
}
}
Expand Down Expand Up @@ -772,9 +778,15 @@ void DBIter::Seek(const Slice& target) {

RecordTick(statistics_, NUMBER_DB_SEEK);
if (iter_->Valid()) {
if (prefix_extractor_ && prefix_same_as_start_) {
prefix_start_key_ = prefix_extractor_->Transform(target);
}
direction_ = kForward;
ClearSavedValue();
FindNextUserEntry(false /* not skipping */);
FindNextUserEntry(false /* not skipping */, prefix_same_as_start_);
if (!valid_) {
prefix_start_key_.clear();
}
if (statistics_ != nullptr) {
if (valid_) {
RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
Expand All @@ -785,7 +797,8 @@ void DBIter::Seek(const Slice& target) {
valid_ = false;
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
prefix_start_.SetKey(prefix_extractor_->Transform(target));
prefix_start_buf_.SetKey(prefix_start_key_);
prefix_start_key_ = prefix_start_buf_.GetKey();
}
}

Expand All @@ -805,7 +818,7 @@ void DBIter::SeekToFirst() {

RecordTick(statistics_, NUMBER_DB_SEEK);
if (iter_->Valid()) {
FindNextUserEntry(false /* not skipping */);
FindNextUserEntry(false /* not skipping */, false /* no prefix check */);
if (statistics_ != nullptr) {
if (valid_) {
RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
Expand All @@ -816,7 +829,8 @@ void DBIter::SeekToFirst() {
valid_ = false;
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
prefix_start_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
prefix_start_buf_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
prefix_start_key_ = prefix_start_buf_.GetKey();
}
}

Expand Down Expand Up @@ -864,7 +878,8 @@ void DBIter::SeekToLast() {
}
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
prefix_start_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
prefix_start_buf_.SetKey(prefix_extractor_->Transform(saved_key_.GetKey()));
prefix_start_key_ = prefix_start_buf_.GetKey();
}
}

Expand Down
4 changes: 4 additions & 0 deletions db/prefix_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -446,6 +446,10 @@ TEST_F(PrefixTest, PrefixValid) {
iter->Next();
ASSERT_FALSE(iter->Valid());
ASSERT_EQ(kNotFoundResult, Get(db.get(), read_options, 12346, 8));

// Verify seeking past the prefix won't return a result.
SeekIterator(iter.get(), 12345, 10);
ASSERT_TRUE(!iter->Valid());
}
}
}
Expand Down

0 comments on commit c6c770a

Please sign in to comment.