Fixing endless loop if seeking to end of key with seq num 0

Summary:
When seeking to the last occurrence of a key with sequence number 0, db_iter
ends up in an endless loop because it seeks to type kValueTypeForSeek
which is larger than kTypeDeletion/kTypeValue. Added test case that triggers
the behavior.

Test Plan: make clean all check

Reviewers: igor, rven, anthony, yhchiang, sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D43653
This commit is contained in:
Andres Noetzli 2015-08-06 10:43:28 -07:00
parent 48e6e9aa82
commit d7314ba759
2 changed files with 28 additions and 2 deletions

View File

@ -256,12 +256,13 @@ void DBIter::FindNextUserEntryInternal(bool skipping) {
// If we have sequentially iterated via numerous keys and still not // If we have sequentially iterated via numerous keys and still not
// found the next user-key, then it is better to seek so that we can // found the next user-key, then it is better to seek so that we can
// avoid too many key comparisons. We seek to the last occurrence of // avoid too many key comparisons. We seek to the last occurrence of
// our current key by looking for sequence number 0. // our current key by looking for sequence number 0 and type deletion
// (the smallest type).
if (skipping && num_skipped > max_skip_) { if (skipping && num_skipped > max_skip_) {
num_skipped = 0; num_skipped = 0;
std::string last_key; std::string last_key;
AppendInternalKey(&last_key, ParsedInternalKey(saved_key_.GetKey(), 0, AppendInternalKey(&last_key, ParsedInternalKey(saved_key_.GetKey(), 0,
kValueTypeForSeek)); kTypeDeletion));
iter_->Seek(last_key); iter_->Seek(last_key);
RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION); RecordTick(statistics_, NUMBER_OF_RESEEKS_IN_ITERATION);
} else { } else {

View File

@ -1644,6 +1644,7 @@ TEST_F(DBIteratorTest, DBIterator7) {
ASSERT_TRUE(!db_iter->Valid()); ASSERT_TRUE(!db_iter->Valid());
} }
} }
TEST_F(DBIteratorTest, DBIterator8) { TEST_F(DBIteratorTest, DBIterator8) {
Options options; Options options;
options.merge_operator = MergeOperators::CreateFromStringId("stringappend"); options.merge_operator = MergeOperators::CreateFromStringId("stringappend");
@ -1747,6 +1748,30 @@ TEST_F(DBIteratorTest, DBIterator10) {
ASSERT_EQ(db_iter->value().ToString(), "3"); ASSERT_EQ(db_iter->value().ToString(), "3");
} }
TEST_F(DBIteratorTest, SeekToLastOccurrenceSeq0) {
Options options;
options.merge_operator = nullptr;
TestIterator* internal_iter = new TestIterator(BytewiseComparator());
internal_iter->AddPut("a", "1");
internal_iter->AddPut("b", "2");
internal_iter->Finish();
std::unique_ptr<Iterator> db_iter(NewDBIterator(
env_, ImmutableCFOptions(options), BytewiseComparator(), internal_iter,
10, 0 /* force seek */));
db_iter->SeekToFirst();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "a");
ASSERT_EQ(db_iter->value().ToString(), "1");
db_iter->Next();
ASSERT_TRUE(db_iter->Valid());
ASSERT_EQ(db_iter->key().ToString(), "b");
ASSERT_EQ(db_iter->value().ToString(), "2");
db_iter->Next();
ASSERT_FALSE(db_iter->Valid());
}
} // namespace rocksdb } // namespace rocksdb
int main(int argc, char** argv) { int main(int argc, char** argv) {