Add test for iteration+mutation of WBWI

Summary: We should support use-cases that mutate WBWI while they're iterating it. This diff adds a unit test to check this behavior.

Test Plan: this is a test

Reviewers: sdong

Reviewed By: sdong

Subscribers: dhruba, leveldb

Differential Revision: https://reviews.facebook.net/D39501
This commit is contained in:
Igor Canadi 2015-06-09 13:10:31 -07:00
parent d9b3338ebe
commit 62c3a95796

View File

@ -1182,6 +1182,188 @@ TEST_F(WriteBatchWithIndexTest, TestGetFromBatchAndDBMerge) {
DestroyDB(dbname, options);
}
void AssertKey(std::string key, WBWIIterator* iter) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key, iter->Entry().key.ToString());
}
void AssertValue(std::string value, WBWIIterator* iter) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(value, iter->Entry().value.ToString());
}
// Tests that we can write to the WBWI while we iterate (from a single thread).
// iteration should see the newest writes
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingCorrectnessTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
}
std::unique_ptr<WBWIIterator> iter(batch.NewIterator());
iter->Seek("k");
AssertKey("k", iter.get());
iter->Next();
AssertKey("l", iter.get());
batch.Put("ab", "cc");
iter->Next();
AssertKey("m", iter.get());
batch.Put("mm", "kk");
iter->Next();
AssertKey("mm", iter.get());
AssertValue("kk", iter.get());
batch.Delete("mm");
iter->Next();
AssertKey("n", iter.get());
iter->Prev();
AssertKey("mm", iter.get());
ASSERT_EQ(kDeleteRecord, iter->Entry().type);
iter->Seek("ab");
AssertKey("ab", iter.get());
batch.Delete("x");
iter->Seek("x");
AssertKey("x", iter.get());
ASSERT_EQ(kDeleteRecord, iter->Entry().type);
iter->Prev();
AssertKey("w", iter.get());
}
void AssertIterKey(std::string key, Iterator* iter) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(key, iter->key().ToString());
}
void AssertIterValue(std::string value, Iterator* iter) {
ASSERT_TRUE(iter->Valid());
ASSERT_EQ(value, iter->value().ToString());
}
// same thing as above, but testing IteratorWithBase
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseCorrectnessTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
}
KVMap map;
map["aa"] = "aa";
map["cc"] = "cc";
map["ee"] = "ee";
map["em"] = "me";
std::unique_ptr<Iterator> iter(
batch.NewIteratorWithBase(new KVIter(&map)));
iter->Seek("k");
AssertIterKey("k", iter.get());
iter->Next();
AssertIterKey("l", iter.get());
batch.Put("ab", "cc");
iter->Next();
AssertIterKey("m", iter.get());
batch.Put("mm", "kk");
iter->Next();
AssertIterKey("mm", iter.get());
AssertIterValue("kk", iter.get());
batch.Delete("mm");
// still mm even though it's deleted
AssertIterKey("mm", iter.get());
AssertIterValue("kk", iter.get());
iter->Next();
AssertIterKey("n", iter.get());
iter->Prev();
// "mm" is deleted, so we're back at "m"
AssertIterKey("m", iter.get());
iter->Seek("ab");
AssertIterKey("ab", iter.get());
iter->Prev();
AssertIterKey("aa", iter.get());
iter->Prev();
AssertIterKey("a", iter.get());
batch.Delete("aa");
iter->Next();
AssertIterKey("ab", iter.get());
iter->Prev();
AssertIterKey("a", iter.get());
batch.Delete("x");
iter->Seek("x");
AssertIterKey("y", iter.get());
iter->Next();
AssertIterKey("z", iter.get());
iter->Prev();
iter->Prev();
AssertIterKey("w", iter.get());
batch.Delete("e");
iter->Seek("e");
AssertIterKey("ee", iter.get());
AssertIterValue("ee", iter.get());
batch.Put("ee", "xx");
// still the same value
AssertIterValue("ee", iter.get());
iter->Next();
AssertIterKey("em", iter.get());
iter->Prev();
// new value
AssertIterValue("xx", iter.get());
}
// stress testing mutations with IteratorWithBase
TEST_F(WriteBatchWithIndexTest, MutateWhileIteratingBaseStressTest) {
WriteBatchWithIndex batch(BytewiseComparator(), 0, true);
for (char c = 'a'; c <= 'z'; ++c) {
batch.Put(std::string(1, c), std::string(1, c));
}
KVMap map;
for (char c = 'a'; c <= 'z'; ++c) {
map[std::string(2, c)] = std::string(2, c);
}
std::unique_ptr<Iterator> iter(
batch.NewIteratorWithBase(new KVIter(&map)));
Random rnd(301);
for (int i = 0; i < 1000000; ++i) {
int random = rnd.Uniform(8);
char c = static_cast<char>(rnd.Uniform(26) + 'a');
switch (random) {
case 0:
batch.Put(std::string(1, c), "xxx");
break;
case 1:
batch.Put(std::string(2, c), "xxx");
break;
case 2:
batch.Delete(std::string(1, c));
break;
case 3:
batch.Delete(std::string(2, c));
break;
case 4:
iter->Seek(std::string(1, c));
break;
case 5:
iter->Seek(std::string(2, c));
break;
case 6:
if (iter->Valid()) {
iter->Next();
}
break;
case 7:
if (iter->Valid()) {
iter->Prev();
}
break;
default:
assert(false);
}
}
}
} // namespace
int main(int argc, char** argv) {