From addfe1ef4b611b8ac47a24f8d7aad92a20d5cb0b Mon Sep 17 00:00:00 2001 From: Islam AbdelRahman Date: Wed, 25 Oct 2017 15:08:01 -0700 Subject: [PATCH] Fix tombstone scans in SeekForPrev outside prefix Summary: When doing a Seek() or SeekForPrev() we should stop the moment we see a key with a different prefix as start if ReadOptions:: prefix_same_as_start was set to true Right now we don't stop if we encounter a tombstone outside the prefix while executing SeekForPrev() Closes https://github.com/facebook/rocksdb/pull/3067 Differential Revision: D6149638 Pulled By: IslamAbdelRahman fbshipit-source-id: 7f659862d2bf552d3c9104a360c79439ceba2f18 --- db/db_iter.cc | 13 ++++++++----- db/db_iter_test.cc | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+), 5 deletions(-) diff --git a/db/db_iter.cc b/db/db_iter.cc index 541598834..59d47bb08 100644 --- a/db/db_iter.cc +++ b/db/db_iter.cc @@ -715,6 +715,14 @@ void DBIter::PrevInternal() { ExtractUserKey(iter_->key()), !iter_->IsKeyPinned() || !pin_thru_lifetime_ /* copy */); + if (prefix_extractor_ && prefix_same_as_start_ && + prefix_extractor_->Transform(saved_key_.GetUserKey()) + .compare(prefix_start_key_) != 0) { + // Current key does not have the same prefix as start + valid_ = false; + return; + } + if (FindValueForCurrentKey()) { if (!iter_->Valid()) { return; @@ -723,11 +731,6 @@ void DBIter::PrevInternal() { if (user_comparator_->Equal(ikey.user_key, saved_key_.GetUserKey())) { FindPrevUserKey(); } - if (valid_ && prefix_extractor_ && prefix_same_as_start_ && - prefix_extractor_->Transform(saved_key_.GetUserKey()) - .compare(prefix_start_key_) != 0) { - valid_ = false; - } return; } diff --git a/db/db_iter_test.cc b/db/db_iter_test.cc index d16ab42de..ebe3b9653 100644 --- a/db/db_iter_test.cc +++ b/db/db_iter_test.cc @@ -2813,6 +2813,42 @@ TEST_F(DBIterWithMergeIterTest, InnerMergeIteratorDataRace8) { rocksdb::SyncPoint::GetInstance()->DisableProcessing(); } + + +TEST_F(DBIteratorTest, SeekPrefixTombstones) { + ReadOptions ro; + Options options; + options.prefix_extractor.reset(NewNoopTransform()); + TestIterator* internal_iter = new TestIterator(BytewiseComparator()); + internal_iter->AddDeletion("b"); + internal_iter->AddDeletion("c"); + internal_iter->AddDeletion("d"); + internal_iter->AddDeletion("e"); + internal_iter->AddDeletion("f"); + internal_iter->AddDeletion("g"); + internal_iter->Finish(); + + ro.prefix_same_as_start = true; + std::unique_ptr db_iter(NewDBIterator( + env_, ro, ImmutableCFOptions(options), BytewiseComparator(), + internal_iter, 10, options.max_sequential_skip_in_iterations, + nullptr /*read_callback*/)); + + int skipped_keys = 0; + + get_perf_context()->Reset(); + db_iter->SeekForPrev("z"); + skipped_keys = + static_cast(get_perf_context()->internal_key_skipped_count); + ASSERT_EQ(skipped_keys, 0); + + get_perf_context()->Reset(); + db_iter->Seek("a"); + skipped_keys = + static_cast(get_perf_context()->internal_key_skipped_count); + ASSERT_EQ(skipped_keys, 0); +} + } // namespace rocksdb int main(int argc, char** argv) { -- GitLab