Trigger non-trivial compaction in fault_injection_test

Summary: Now the major test cases of fault_injection_test only insert keys in sorted order so compactions will be trivial move. Add a new mode to insert in non-sequential order to trigger non-trivial compactions.

Test Plan: Run the test

Reviewers: kradhakrishnan, anthony, IslamAbdelRahman, yhchiang, igor

Reviewed By: igor

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D42435
This commit is contained in:
sdong 2015-07-16 12:18:32 -07:00
parent 59eca2cc99
commit 58b4209e05

View File

@ -424,7 +424,8 @@ Status TestWritableFile::Sync() {
return Status::OK(); return Status::OK();
} }
class FaultInjectionTest : public testing::Test { class FaultInjectionTest : public testing::Test,
public testing::WithParamInterface<bool> {
protected: protected:
enum OptionConfig { enum OptionConfig {
kDefault, kDefault,
@ -441,6 +442,8 @@ class FaultInjectionTest : public testing::Test {
// When need to make sure data is persistent, call DB::CompactRange() // When need to make sure data is persistent, call DB::CompactRange()
bool sync_use_compact_; bool sync_use_compact_;
bool sequential_order_;
protected: protected:
public: public:
enum ExpectedVerifResult { kValExpectFound, kValExpectNoError }; enum ExpectedVerifResult { kValExpectFound, kValExpectNoError };
@ -467,6 +470,11 @@ class FaultInjectionTest : public testing::Test {
db_(NULL) { db_(NULL) {
} }
~FaultInjectionTest() {
rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
}
bool ChangeOptions() { bool ChangeOptions() {
option_config_++; option_config_++;
if (option_config_ >= kEnd) { if (option_config_ >= kEnd) {
@ -547,7 +555,10 @@ class FaultInjectionTest : public testing::Test {
return s; return s;
} }
void SetUp() override { ASSERT_OK(NewDB()); } void SetUp() override {
sequential_order_ = GetParam();
ASSERT_OK(NewDB());
}
void TearDown() override { void TearDown() override {
CloseDB(); CloseDB();
@ -562,34 +573,33 @@ class FaultInjectionTest : public testing::Test {
ASSERT_OK(s); ASSERT_OK(s);
} }
void Build(const WriteOptions& write_options, int start_idx, int num_vals, void Build(const WriteOptions& write_options, int start_idx, int num_vals) {
bool sequential = true) {
std::string key_space, value_space; std::string key_space, value_space;
WriteBatch batch; WriteBatch batch;
for (int i = start_idx; i < start_idx + num_vals; i++) { for (int i = start_idx; i < start_idx + num_vals; i++) {
Slice key = Key(sequential, i, &key_space); Slice key = Key(i, &key_space);
batch.Clear(); batch.Clear();
batch.Put(key, Value(i, &value_space)); batch.Put(key, Value(i, &value_space));
ASSERT_OK(db_->Write(write_options, &batch)); ASSERT_OK(db_->Write(write_options, &batch));
} }
} }
Status ReadValue(int i, std::string* val, bool sequential) const { Status ReadValue(int i, std::string* val) const {
std::string key_space, value_space; std::string key_space, value_space;
Slice key = Key(sequential, i, &key_space); Slice key = Key(i, &key_space);
Value(i, &value_space); Value(i, &value_space);
ReadOptions options; ReadOptions options;
return db_->Get(options, key, val); return db_->Get(options, key, val);
} }
Status Verify(int start_idx, int num_vals, ExpectedVerifResult expected, Status Verify(int start_idx, int num_vals,
bool sequential = true) const { ExpectedVerifResult expected) const {
std::string val; std::string val;
std::string value_space; std::string value_space;
Status s; Status s;
for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) { for (int i = start_idx; i < start_idx + num_vals && s.ok(); i++) {
Value(i, &value_space); Value(i, &value_space);
s = ReadValue(i, &val, sequential); s = ReadValue(i, &val);
if (s.ok()) { if (s.ok()) {
EXPECT_EQ(value_space, val); EXPECT_EQ(value_space, val);
} }
@ -609,9 +619,9 @@ class FaultInjectionTest : public testing::Test {
} }
// Return the ith key // Return the ith key
Slice Key(bool sequential, int i, std::string* storage) const { Slice Key(int i, std::string* storage) const {
int num = i; int num = i;
if (!sequential) { if (!sequential_order_) {
// random transfer // random transfer
const int m = 0x5bd1e995; const int m = 0x5bd1e995;
num *= m; num *= m;
@ -701,6 +711,10 @@ class FaultInjectionTest : public testing::Test {
ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::kValExpectFound)); ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::kValExpectFound));
ASSERT_OK(Verify(num_pre_sync, num_post_sync, ASSERT_OK(Verify(num_pre_sync, num_post_sync,
FaultInjectionTest::kValExpectNoError)); FaultInjectionTest::kValExpectNoError));
WaitCompactionFinish();
ASSERT_OK(Verify(0, num_pre_sync, FaultInjectionTest::kValExpectFound));
ASSERT_OK(Verify(num_pre_sync, num_post_sync,
FaultInjectionTest::kValExpectNoError));
} }
void NoWriteTestPreFault() { void NoWriteTestPreFault() {
@ -711,9 +725,14 @@ class FaultInjectionTest : public testing::Test {
ResetDBState(reset_method); ResetDBState(reset_method);
ASSERT_OK(OpenDB()); ASSERT_OK(OpenDB());
} }
void WaitCompactionFinish() {
static_cast<DBImpl*>(db_)->TEST_WaitForCompact();
ASSERT_OK(db_->Put(WriteOptions(), "", ""));
}
}; };
TEST_F(FaultInjectionTest, FaultTest) { TEST_P(FaultInjectionTest, FaultTest) {
do { do {
Random rnd(301); Random rnd(301);
@ -787,7 +806,7 @@ class SleepingBackgroundTask {
// Disable the test because it is not passing. // Disable the test because it is not passing.
// Previous log file is not fsynced if sync is forced after log rolling. // Previous log file is not fsynced if sync is forced after log rolling.
// TODO(FB internal task#6730880) Fix the bug // TODO(FB internal task#6730880) Fix the bug
TEST_F(FaultInjectionTest, DISABLED_WriteOptionSyncTest) { TEST_P(FaultInjectionTest, DISABLED_WriteOptionSyncTest) {
SleepingBackgroundTask sleeping_task_low; SleepingBackgroundTask sleeping_task_low;
env_->SetBackgroundThreads(1, Env::HIGH); env_->SetBackgroundThreads(1, Env::HIGH);
// Block the job queue to prevent flush job from running. // Block the job queue to prevent flush job from running.
@ -798,14 +817,14 @@ TEST_F(FaultInjectionTest, DISABLED_WriteOptionSyncTest) {
write_options.sync = false; write_options.sync = false;
std::string key_space, value_space; std::string key_space, value_space;
ASSERT_OK(db_->Put(write_options, Key(true, 1, &key_space), ASSERT_OK(
Value(1, &value_space))); db_->Put(write_options, Key(1, &key_space), Value(1, &value_space)));
FlushOptions flush_options; FlushOptions flush_options;
flush_options.wait = false; flush_options.wait = false;
ASSERT_OK(db_->Flush(flush_options)); ASSERT_OK(db_->Flush(flush_options));
write_options.sync = true; write_options.sync = true;
ASSERT_OK(db_->Put(write_options, Key(true, 2, &key_space), ASSERT_OK(
Value(2, &value_space))); db_->Put(write_options, Key(2, &key_space), Value(2, &value_space)));
env_->SetFilesystemActive(false); env_->SetFilesystemActive(false);
NoWriteTestReopenWithFault(kResetDropAndDeleteUnsynced); NoWriteTestReopenWithFault(kResetDropAndDeleteUnsynced);
@ -814,15 +833,15 @@ TEST_F(FaultInjectionTest, DISABLED_WriteOptionSyncTest) {
ASSERT_OK(OpenDB()); ASSERT_OK(OpenDB());
std::string val; std::string val;
Value(2, &value_space); Value(2, &value_space);
ASSERT_OK(ReadValue(2, &val, true)); ASSERT_OK(ReadValue(2, &val));
ASSERT_EQ(value_space, val); ASSERT_EQ(value_space, val);
Value(1, &value_space); Value(1, &value_space);
ASSERT_OK(ReadValue(1, &val, true)); ASSERT_OK(ReadValue(1, &val));
ASSERT_EQ(value_space, val); ASSERT_EQ(value_space, val);
} }
TEST_F(FaultInjectionTest, UninstalledCompaction) { TEST_P(FaultInjectionTest, UninstalledCompaction) {
options_.target_file_size_base = 32 * 1024; options_.target_file_size_base = 32 * 1024;
options_.write_buffer_size = 100 << 10; // 100KB options_.write_buffer_size = 100 << 10; // 100KB
options_.level0_file_num_compaction_trigger = 6; options_.level0_file_num_compaction_trigger = 6;
@ -831,16 +850,18 @@ TEST_F(FaultInjectionTest, UninstalledCompaction) {
options_.max_background_compactions = 1; options_.max_background_compactions = 1;
OpenDB(); OpenDB();
if (!sequential_order_) {
rocksdb::SyncPoint::GetInstance()->LoadDependency({ rocksdb::SyncPoint::GetInstance()->LoadDependency({
{"FaultInjectionTest::FaultTest:0", "DBImpl::BGWorkCompaction"}, {"FaultInjectionTest::FaultTest:0", "DBImpl::BGWorkCompaction"},
{"CompactionJob::Run():End", "FaultInjectionTest::FaultTest:1"}, {"CompactionJob::Run():End", "FaultInjectionTest::FaultTest:1"},
{"FaultInjectionTest::FaultTest:2", {"FaultInjectionTest::FaultTest:2",
"DBImpl::BackgroundCompaction:NonTrivial:AfterRun"}, "DBImpl::BackgroundCompaction:NonTrivial:AfterRun"},
}); });
}
rocksdb::SyncPoint::GetInstance()->EnableProcessing(); rocksdb::SyncPoint::GetInstance()->EnableProcessing();
int kNumKeys = 1000; int kNumKeys = 1000;
Build(WriteOptions(), 0, kNumKeys, false); Build(WriteOptions(), 0, kNumKeys);
FlushOptions flush_options; FlushOptions flush_options;
flush_options.wait = true; flush_options.wait = true;
db_->Flush(flush_options); db_->Flush(flush_options);
@ -861,12 +882,15 @@ TEST_F(FaultInjectionTest, UninstalledCompaction) {
[&](void* arg) { ASSERT_TRUE(opened.load()); }); [&](void* arg) { ASSERT_TRUE(opened.load()); });
rocksdb::SyncPoint::GetInstance()->EnableProcessing(); rocksdb::SyncPoint::GetInstance()->EnableProcessing();
ASSERT_OK(OpenDB()); ASSERT_OK(OpenDB());
static_cast<DBImpl*>(db_)->TEST_WaitForCompact(); ASSERT_OK(Verify(0, kNumKeys, FaultInjectionTest::kValExpectFound));
ASSERT_OK(Verify(0, kNumKeys, FaultInjectionTest::kValExpectFound, false)); WaitCompactionFinish();
ASSERT_OK(db_->Put(WriteOptions(), "", "")); ASSERT_OK(Verify(0, kNumKeys, FaultInjectionTest::kValExpectFound));
rocksdb::SyncPoint::GetInstance()->DisableProcessing(); rocksdb::SyncPoint::GetInstance()->DisableProcessing();
rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
} }
INSTANTIATE_TEST_CASE_P(FaultTest, FaultInjectionTest, ::testing::Bool());
} // namespace rocksdb } // namespace rocksdb
int main(int argc, char** argv) { int main(int argc, char** argv) {