Skip to content

Commit

Permalink
Add SeekForPrev() to Iterator
Browse files Browse the repository at this point in the history
Summary:
Add new Iterator API, `SeekForPrev`: find the last key that <= target key
support prefix_extractor
support prefix_same_as_start
support upper_bound
not supported in iterators without Prev()

Also add tests in db_iter_test and db_iterator_test

Pass all tests
Cheers!

Test Plan: make all check -j64

Reviewers: andrewkr, yiwu, IslamAbdelRahman, sdong

Reviewed By: sdong

Subscribers: andrewkr, dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D64149
  • Loading branch information
lightmark committed Sep 28, 2016
1 parent eb3894c commit f517d9d
Show file tree
Hide file tree
Showing 42 changed files with 704 additions and 86 deletions.
4 changes: 4 additions & 0 deletions db/comparator_db_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,10 @@ class KVIter : public Iterator {
virtual void Seek(const Slice& k) override {
iter_ = map_->lower_bound(k.ToString());
}
virtual void SeekForPrev(const Slice& k) override {
iter_ = map_->upper_bound(k.ToString());
Prev();
}
virtual void Next() override { ++iter_; }
virtual void Prev() override {
if (iter_ == map_->begin()) {
Expand Down
58 changes: 52 additions & 6 deletions db/db_iter.cc
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,7 @@ class DBIter: public Iterator {
virtual void Next() override;
virtual void Prev() override;
virtual void Seek(const Slice& target) override;
virtual void SeekForPrev(const Slice& target) override;
virtual void SeekToFirst() override;
virtual void SeekToLast() override;

Expand Down Expand Up @@ -503,11 +504,6 @@ void DBIter::Prev() {
local_stats_.bytes_read_ += (key().size() + value().size());
}
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_ &&
prefix_extractor_->Transform(saved_key_.GetKey())
.compare(prefix_start_key_) != 0) {
valid_ = false;
}
}

void DBIter::ReverseToBackward() {
Expand Down Expand Up @@ -544,6 +540,7 @@ void DBIter::PrevInternal() {
}

ParsedInternalKey ikey;
bool match_prefix = true;

while (iter_->Valid()) {
saved_key_.SetKey(ExtractUserKey(iter_->key()),
Expand All @@ -557,6 +554,12 @@ void DBIter::PrevInternal() {
if (user_comparator_->Equal(ikey.user_key, saved_key_.GetKey())) {
FindPrevUserKey();
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_ &&
prefix_extractor_->Transform(saved_key_.GetKey())
.compare(prefix_start_key_) != 0) {
match_prefix = false;
break;
}
return;
}
if (!iter_->Valid()) {
Expand All @@ -568,7 +571,8 @@ void DBIter::PrevInternal() {
}
}
// We haven't found any key - iterator is not valid
assert(!iter_->Valid());
// Or the prefix is different than start prefix
assert(!iter_->Valid() || !match_prefix);
valid_ = false;
}

Expand Down Expand Up @@ -819,6 +823,45 @@ void DBIter::Seek(const Slice& target) {
}
}

void DBIter::SeekForPrev(const Slice& target) {
StopWatch sw(env_, statistics_, DB_SEEK);
ReleaseTempPinnedData();
saved_key_.Clear();
// now saved_key is used to store internal key.
saved_key_.SetInternalKey(target, 0 /* sequence_number */,
kValueTypeForSeekForPrev);

{
PERF_TIMER_GUARD(seek_internal_seek_time);
iter_->SeekForPrev(saved_key_.GetKey());
}

RecordTick(statistics_, NUMBER_DB_SEEK);
if (iter_->Valid()) {
if (prefix_extractor_ && prefix_same_as_start_) {
prefix_start_key_ = prefix_extractor_->Transform(target);
}
direction_ = kReverse;
ClearSavedValue();
PrevInternal();
if (!valid_) {
prefix_start_key_.clear();
}
if (statistics_ != nullptr) {
if (valid_) {
RecordTick(statistics_, NUMBER_DB_SEEK_FOUND);
RecordTick(statistics_, ITER_BYTES_READ, key().size() + value().size());
}
}
} else {
valid_ = false;
}
if (valid_ && prefix_extractor_ && prefix_same_as_start_) {
prefix_start_buf_.SetKey(prefix_start_key_);
prefix_start_key_ = prefix_start_buf_.GetKey();
}
}

void DBIter::SeekToFirst() {
// Don't use iter_::Seek() if we set a prefix extractor
// because prefix seek will be used.
Expand Down Expand Up @@ -931,6 +974,9 @@ inline void ArenaWrappedDBIter::SeekToLast() { db_iter_->SeekToLast(); }
inline void ArenaWrappedDBIter::Seek(const Slice& target) {
db_iter_->Seek(target);
}
inline void ArenaWrappedDBIter::SeekForPrev(const Slice& target) {
db_iter_->SeekForPrev(target);
}
inline void ArenaWrappedDBIter::Next() { db_iter_->Next(); }
inline void ArenaWrappedDBIter::Prev() { db_iter_->Prev(); }
inline Slice ArenaWrappedDBIter::key() const { return db_iter_->key(); }
Expand Down
1 change: 1 addition & 0 deletions db/db_iter.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ class ArenaWrappedDBIter : public Iterator {
virtual void SeekToFirst() override;
virtual void SeekToLast() override;
virtual void Seek(const Slice& target) override;
virtual void SeekForPrev(const Slice& target) override;
virtual void Next() override;
virtual void Prev() override;
virtual Slice key() const override;
Expand Down
37 changes: 36 additions & 1 deletion db/db_iter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,11 @@ class TestIterator : public InternalIterator {
}
}

virtual void SeekForPrev(const Slice& target) override {
assert(initialized_);
SeekForPrevImpl(target, &cmp);
}

virtual void Next() override {
assert(initialized_);
if (data_.empty() || (iter_ == data_.size() - 1)) {
Expand Down Expand Up @@ -1726,6 +1731,15 @@ TEST_F(DBIteratorTest, DBIterator9) {
ASSERT_EQ(db_iter->key().ToString(), "a");
ASSERT_EQ(db_iter->value().ToString(), "merge_1,merge_2");

db_iter->SeekForPrev("b");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
ASSERT_EQ(db_iter->value().ToString(), "merge_3,merge_4");
db_iter->Next();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "d");
ASSERT_EQ(db_iter->value().ToString(), "merge_5,merge_6");

db_iter->Seek("c");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "d");
Expand All @@ -1734,6 +1748,15 @@ TEST_F(DBIteratorTest, DBIterator9) {
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
ASSERT_EQ(db_iter->value().ToString(), "merge_3,merge_4");

db_iter->SeekForPrev("c");
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
ASSERT_EQ(db_iter->value().ToString(), "merge_3,merge_4");
db_iter->Next();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "d");
ASSERT_EQ(db_iter->value().ToString(), "merge_5,merge_6");
}
}

Expand Down Expand Up @@ -1764,6 +1787,18 @@ TEST_F(DBIteratorTest, DBIterator10) {
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
ASSERT_EQ(db_iter->value().ToString(), "3");

db_iter->SeekForPrev("c");
ASSERT_TRUE(db_iter->Valid());
db_iter->Next();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "d");
ASSERT_EQ(db_iter->value().ToString(), "4");

db_iter->Prev();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "c");
ASSERT_EQ(db_iter->value().ToString(), "3");
}

TEST_F(DBIteratorTest, SeekToLastOccurrenceSeq0) {
Expand Down Expand Up @@ -1914,7 +1949,7 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIterator1) {

TEST_F(DBIterWithMergeIterTest, InnerMergeIterator2) {
// Test Prev() when one child iterator is at its end.
db_iter_->Seek("g");
db_iter_->SeekForPrev("g");
ASSERT_TRUE(db_iter_->Valid());
ASSERT_EQ(db_iter_->key().ToString(), "g");
ASSERT_EQ(db_iter_->value().ToString(), "3");
Expand Down
Loading

0 comments on commit f517d9d

Please sign in to comment.