fault_injection_test: add a test case to drop random number of unsynced data

Summary: Currently fault_injection_test has a test case to drop all the unsynced data. Add one more case to take a randomized bytes from it.

Test Plan: Run the test

Reviewers: rven, yhchiang, igor

Reviewed By: igor

Subscribers: leveldb, dhruba

Differential Revision: https://reviews.facebook.net/D32229
This commit is contained in:
sdong 2015-01-26 15:22:18 -08:00
parent d888c95748
commit c1de6c42a0

View File

@ -114,6 +114,8 @@ struct FileState {
bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; } bool IsFullySynced() const { return pos_ <= 0 || pos_ == pos_at_last_sync_; }
Status DropUnsyncedData() const; Status DropUnsyncedData() const;
Status DropRandomUnsyncedData(Random* rand) const;
}; };
} // anonymous namespace } // anonymous namespace
@ -226,7 +228,9 @@ class FaultInjectionTestEnv : public EnvWrapper {
db_file_state_[state.filename_] = state; db_file_state_[state.filename_] = state;
} }
Status DropUnsyncedFileData() { // For every file that is not fully synced, make a call to `func` with
// FileState of the file as the parameter.
Status DropFileData(std::function<Status(FileState)> func) {
Status s; Status s;
MutexLock l(&mutex_); MutexLock l(&mutex_);
for (std::map<std::string, FileState>::const_iterator it = for (std::map<std::string, FileState>::const_iterator it =
@ -234,12 +238,23 @@ class FaultInjectionTestEnv : public EnvWrapper {
s.ok() && it != db_file_state_.end(); ++it) { s.ok() && it != db_file_state_.end(); ++it) {
const FileState& state = it->second; const FileState& state = it->second;
if (!state.IsFullySynced()) { if (!state.IsFullySynced()) {
s = state.DropUnsyncedData(); s = func(state);
} }
} }
return s; return s;
} }
Status DropUnsyncedFileData() {
return DropFileData(
[&](const FileState& state) { return state.DropUnsyncedData(); });
}
Status DropRandomUnsyncedFileData(Random* rnd) {
return DropFileData([&](const FileState& state) {
return state.DropRandomUnsyncedData(rnd);
});
}
Status DeleteFilesCreatedAfterLastDirSync() { Status DeleteFilesCreatedAfterLastDirSync() {
// Because DeleteFile access this container make a copy to avoid deadlock // Because DeleteFile access this container make a copy to avoid deadlock
std::map<std::string, std::set<std::string>> map_copy; std::map<std::string, std::set<std::string>> map_copy;
@ -296,6 +311,15 @@ Status FileState::DropUnsyncedData() const {
return Truncate(filename_, sync_pos); return Truncate(filename_, sync_pos);
} }
Status FileState::DropRandomUnsyncedData(Random* rand) const {
ssize_t sync_pos = pos_at_last_sync_ == -1 ? 0 : pos_at_last_sync_;
assert(pos_ >= sync_pos);
int range = static_cast<int>(pos_ - sync_pos);
uint64_t truncated_size =
static_cast<uint64_t>(sync_pos) + rand->Uniform(range);
return Truncate(filename_, truncated_size);
}
Status TestDirectory::Fsync() { Status TestDirectory::Fsync() {
env_->SyncDir(dirname_); env_->SyncDir(dirname_);
return dir_->Fsync(); return dir_->Fsync();
@ -373,6 +397,7 @@ class FaultInjectionTest {
enum ExpectedVerifResult { kValExpectFound, kValExpectNoError }; enum ExpectedVerifResult { kValExpectFound, kValExpectNoError };
enum ResetMethod { enum ResetMethod {
kResetDropUnsyncedData, kResetDropUnsyncedData,
kResetDropRandomUnsyncedData,
kResetDeleteUnsyncedFiles, kResetDeleteUnsyncedFiles,
kResetDropAndDeleteUnsynced kResetDropAndDeleteUnsynced
}; };
@ -563,11 +588,15 @@ class FaultInjectionTest {
db_->Flush(flush_options); db_->Flush(flush_options);
} }
void ResetDBState(ResetMethod reset_method) { // rnd cannot be null for kResetDropRandomUnsyncedData
void ResetDBState(ResetMethod reset_method, Random* rnd = nullptr) {
switch (reset_method) { switch (reset_method) {
case kResetDropUnsyncedData: case kResetDropUnsyncedData:
ASSERT_OK(env_->DropUnsyncedFileData()); ASSERT_OK(env_->DropUnsyncedFileData());
break; break;
case kResetDropRandomUnsyncedData:
ASSERT_OK(env_->DropRandomUnsyncedFileData(rnd));
break;
case kResetDeleteUnsyncedFiles: case kResetDeleteUnsyncedFiles:
ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync()); ASSERT_OK(env_->DeleteFilesCreatedAfterLastDirSync());
break; break;
@ -595,11 +624,11 @@ class FaultInjectionTest {
} }
void PartialCompactTestReopenWithFault(ResetMethod reset_method, void PartialCompactTestReopenWithFault(ResetMethod reset_method,
int num_pre_sync, int num_pre_sync, int num_post_sync,
int num_post_sync) { Random* rnd = nullptr) {
env_->SetFilesystemActive(false); env_->SetFilesystemActive(false);
CloseDB(); CloseDB();
ResetDBState(reset_method); ResetDBState(reset_method, rnd);
ASSERT_OK(OpenDB()); ASSERT_OK(OpenDB());
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,
@ -631,6 +660,12 @@ TEST(FaultInjectionTest, FaultTest) {
NoWriteTestPreFault(); NoWriteTestPreFault();
NoWriteTestReopenWithFault(kResetDropUnsyncedData); NoWriteTestReopenWithFault(kResetDropUnsyncedData);
PartialCompactTestPreFault(num_pre_sync, num_post_sync);
PartialCompactTestReopenWithFault(kResetDropRandomUnsyncedData,
num_pre_sync, num_post_sync, &rnd);
NoWriteTestPreFault();
NoWriteTestReopenWithFault(kResetDropUnsyncedData);
// Setting a separate data path won't pass the test as we don't sync // Setting a separate data path won't pass the test as we don't sync
// it after creating new files, // it after creating new files,
PartialCompactTestPreFault(num_pre_sync, num_post_sync); PartialCompactTestPreFault(num_pre_sync, num_post_sync);