Skip to content

Commit 478990c

Browse files
committed
Make CompactionInputErrorParanoid less flakey
Summary: I'm getting lots of e-mails with CompactionInputErrorParanoid failing. Most recent example early morning today was: http://ci-builds.fb.com/job/rocksdb_valgrind/562/consoleFull I'm putting a stop to these e-mails. I investigated why the test is flakey and it turns out it's because of non-determinsim of compaction scheduling. If there is a compaction after the last flush, CorruptFile will corrupt the compacted file instead of file at level 0 (as it assumes). That makes `Check(9, 9)` fail big time. I also saw some errors with table file getting outputed to >= 1 levels instead of 0. Also fixed that. Test Plan: Ran corruption_test 100 times without a failure. Previously it usually failed at 10th occurrence. Reviewers: dhruba, haobo, ljin Reviewed By: ljin CC: leveldb Differential Revision: https://reviews.facebook.net/D18285
1 parent fc3127e commit 478990c

File tree

1 file changed

+43
-21
lines changed

1 file changed

+43
-21
lines changed

db/corruption_test.cc

+43-21
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class CorruptionTest {
4040
CorruptionTest() {
4141
tiny_cache_ = NewLRUCache(100);
4242
options_.env = &env_;
43-
dbname_ = test::TmpDir() + "/db_test";
43+
dbname_ = test::TmpDir() + "/corruption_test";
4444
DestroyDB(dbname_, options_);
4545

4646
db_ = nullptr;
@@ -127,24 +127,7 @@ class CorruptionTest {
127127
ASSERT_GE(max_expected, correct);
128128
}
129129

130-
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
131-
// Pick file to corrupt
132-
std::vector<std::string> filenames;
133-
ASSERT_OK(env_.GetChildren(dbname_, &filenames));
134-
uint64_t number;
135-
FileType type;
136-
std::string fname;
137-
int picked_number = -1;
138-
for (unsigned int i = 0; i < filenames.size(); i++) {
139-
if (ParseFileName(filenames[i], &number, &type) &&
140-
type == filetype &&
141-
int(number) > picked_number) { // Pick latest file
142-
fname = dbname_ + "/" + filenames[i];
143-
picked_number = number;
144-
}
145-
}
146-
ASSERT_TRUE(!fname.empty()) << filetype;
147-
130+
void CorruptFile(const std::string fname, int offset, int bytes_to_corrupt) {
148131
struct stat sbuf;
149132
if (stat(fname.c_str(), &sbuf) != 0) {
150133
const char* msg = strerror(errno);
@@ -177,6 +160,42 @@ class CorruptionTest {
177160
ASSERT_TRUE(s.ok()) << s.ToString();
178161
}
179162

163+
void Corrupt(FileType filetype, int offset, int bytes_to_corrupt) {
164+
// Pick file to corrupt
165+
std::vector<std::string> filenames;
166+
ASSERT_OK(env_.GetChildren(dbname_, &filenames));
167+
uint64_t number;
168+
FileType type;
169+
std::string fname;
170+
int picked_number = -1;
171+
for (unsigned int i = 0; i < filenames.size(); i++) {
172+
if (ParseFileName(filenames[i], &number, &type) &&
173+
type == filetype &&
174+
static_cast<int>(number) > picked_number) { // Pick latest file
175+
fname = dbname_ + "/" + filenames[i];
176+
picked_number = number;
177+
}
178+
}
179+
ASSERT_TRUE(!fname.empty()) << filetype;
180+
181+
CorruptFile(fname, offset, bytes_to_corrupt);
182+
}
183+
184+
// corrupts exactly one file at level `level`. if no file found at level,
185+
// asserts
186+
void CorruptTableFileAtLevel(int level, int offset, int bytes_to_corrupt) {
187+
std::vector<LiveFileMetaData> metadata;
188+
db_->GetLiveFilesMetaData(&metadata);
189+
for (const auto& m : metadata) {
190+
if (m.level == level) {
191+
CorruptFile(dbname_ + "/" + m.name, offset, bytes_to_corrupt);
192+
return;
193+
}
194+
}
195+
ASSERT_TRUE(false) << "no file found at level";
196+
}
197+
198+
180199
int Property(const std::string& name) {
181200
std::string property;
182201
int result;
@@ -331,19 +350,22 @@ TEST(CorruptionTest, CompactionInputErrorParanoid) {
331350
Reopen(&options);
332351
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
333352

334-
// Fill levels >= 1 so memtable compaction outputs to level 1
353+
// Fill levels >= 1 so memtable flush outputs to level 0
335354
for (int level = 1; level < dbi->NumberLevels(); level++) {
336355
dbi->Put(WriteOptions(), "", "begin");
337356
dbi->Put(WriteOptions(), "~", "end");
338357
dbi->TEST_FlushMemTable();
339358
}
340359

360+
options.max_mem_compaction_level = 0;
361+
Reopen(&options);
362+
341363
Build(10);
342364
dbi->TEST_FlushMemTable();
343365
dbi->TEST_WaitForCompact();
344366
ASSERT_EQ(1, Property("rocksdb.num-files-at-level0"));
345367

346-
Corrupt(kTableFile, 100, 1);
368+
CorruptTableFileAtLevel(0, 100, 1);
347369
Check(9, 9);
348370

349371
// Write must eventually fail because of corrupted table

0 commit comments

Comments
 (0)