Use prefix_same_as_start to avoid iteration in FindNextUserEntryInternal. (#1102)

This avoids excessive iteration in tombstone fields.
This commit is contained in:
Peter Mattis 2016-04-28 19:48:03 -04:00 committed by Islam AbdelRahman
parent 992a8f83b7
commit c6c770a1ac
2 changed files with 38 additions and 19 deletions

View File

@ -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();
@ -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_;
@ -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());
@ -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);
@ -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) {
@ -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;
}
}
@ -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);
@ -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();
}
}
@ -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);
@ -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();
}
}
@ -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();
}
}

View File

@ -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());
}
}
}