Add a unit test to detect infinite loops with reseek optimizations (#5727)

Summary:
Iterators reseek to the target key after iterating over max_sequential_skip_in_iterations invalid values. The logic is susceptible to an infinite loop bug, which has been present with WritePrepared Transactions up until 6.2 release. Although the bug is not present on master, the patch adds a unit test to prevent it from resurfacing again.
Pull Request resolved: https://github.com/facebook/rocksdb/pull/5727

Differential Revision: D16952759

Pulled By: maysamyabandeh

fbshipit-source-id: d0d973dddc8dfabd5a794931232aa4c862c74f51
This commit is contained in:
Maysam Yabandeh 2019-09-04 14:28:39 -07:00 committed by Facebook Github Bot
parent 229e6fbe0e
commit f9fb9f1421

View File

@ -5969,6 +5969,55 @@ TEST_P(TransactionTest, DuplicateKeys) {
}
}
// Test that the reseek optimization in iterators will not result in an infinite
// loop if there are too many uncommitted entries before the snapshot.
TEST_P(TransactionTest, ReseekOptimization) {
WriteOptions write_options;
write_options.sync = true;
write_options.disableWAL = false;
ColumnFamilyDescriptor cfd;
db->DefaultColumnFamily()->GetDescriptor(&cfd);
auto max_skip = cfd.options.max_sequential_skip_in_iterations;
ASSERT_OK(db->Put(write_options, Slice("foo0"), Slice("initv")));
TransactionOptions txn_options;
Transaction* txn0 = db->BeginTransaction(write_options, txn_options);
ASSERT_OK(txn0->SetName("xid"));
// Duplicate keys will result into separate sequence numbers in WritePrepared
// and WriteUnPrepared
for (size_t i = 0; i < 2 * max_skip; i++) {
ASSERT_OK(txn0->Put(Slice("foo1"), Slice("bar")));
}
ASSERT_OK(txn0->Prepare());
ASSERT_OK(db->Put(write_options, Slice("foo2"), Slice("initv")));
ReadOptions read_options;
// To avoid loops
read_options.max_skippable_internal_keys = 10 * max_skip;
Iterator* iter = db->NewIterator(read_options);
ASSERT_OK(iter->status());
size_t cnt = 0;
iter->SeekToFirst();
while (iter->Valid()) {
iter->Next();
ASSERT_OK(iter->status());
cnt++;
}
ASSERT_EQ(cnt, 2);
cnt = 0;
iter->SeekToLast();
while (iter->Valid()) {
iter->Prev();
ASSERT_OK(iter->status());
cnt++;
}
ASSERT_EQ(cnt, 2);
delete iter;
txn0->Rollback();
delete txn0;
}
} // namespace rocksdb
int main(int argc, char** argv) {