Skip to content

Commit ac328a8

Browse files
committed
Merge branch 'master' into columnfamilies
Conflicts: db/db_impl.cc db/db_test.cc
2 parents e20fa3f + c21ce14 commit ac328a8

12 files changed

+319
-104
lines changed

HISTORY.md

+2
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
* Chagned Options.prefix_extractor from raw pointer to shared_ptr (take ownership)
2020
Changed HashSkipListRepFactory and HashLinkListRepFactory constructor to not take SliceTransform object (use Options.prefix_extractor implicitly)
2121
* Added Env::GetThreadPoolQueueLen(), which returns the waiting queue length of thread pools
22+
* Added a command "checkconsistency" in ldb tool, which checks
23+
if file system state matches DB state (file existence and file sizes)
2224

2325
### New Features
2426
* If we find one truncated record at the end of the MANIFEST or WAL files,

db/corruption_test.cc

+33
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,39 @@ TEST(CorruptionTest, UnrelatedKeys) {
376376
ASSERT_EQ(Value(1000, &tmp2).ToString(), v);
377377
}
378378

379+
TEST(CorruptionTest, FileSystemStateCorrupted) {
380+
for (int iter = 0; iter < 2; ++iter) {
381+
Options options;
382+
options.paranoid_checks = true;
383+
options.create_if_missing = true;
384+
Reopen(&options);
385+
Build(10);
386+
ASSERT_OK(db_->Flush(FlushOptions()));
387+
DBImpl* dbi = reinterpret_cast<DBImpl*>(db_);
388+
std::vector<LiveFileMetaData> metadata;
389+
dbi->GetLiveFilesMetaData(&metadata);
390+
ASSERT_GT(metadata.size(), 0);
391+
std::string filename = dbname_ + metadata[0].name;
392+
393+
delete db_;
394+
db_ = nullptr;
395+
396+
if (iter == 0) { // corrupt file size
397+
unique_ptr<WritableFile> file;
398+
env_.NewWritableFile(filename, &file, EnvOptions());
399+
file->Append(Slice("corrupted sst"));
400+
file.reset();
401+
} else { // delete the file
402+
env_.DeleteFile(filename);
403+
}
404+
405+
Status x = TryReopen(&options);
406+
ASSERT_TRUE(x.IsCorruption());
407+
DestroyDB(dbname_, options_);
408+
Reopen(&options);
409+
}
410+
}
411+
379412
} // namespace rocksdb
380413

381414
int main(int argc, char** argv) {

db/db_impl.cc

+43-6
Original file line numberDiff line numberDiff line change
@@ -826,6 +826,9 @@ Status DBImpl::Recover(
826826
}
827827

828828
Status s = versions_->Recover(column_families);
829+
if (options_.paranoid_checks && s.ok()) {
830+
s = CheckConsistency();
831+
}
829832
if (s.ok()) {
830833
SequenceNumber max_sequence(0);
831834
default_cf_handle_ = new ColumnFamilyHandleImpl(
@@ -1211,14 +1214,14 @@ Status DBImpl::FlushMemTableToOutputFile(ColumnFamilyData* cfd,
12111214

12121215
if (!s.ok()) {
12131216
cfd->imm()->RollbackMemtableFlush(mems, file_number, &pending_outputs_);
1214-
return s;
1217+
} else {
1218+
// Replace immutable memtable with the generated Table
1219+
s = cfd->imm()->InstallMemtableFlushResults(
1220+
cfd, mems, versions_.get(), &mutex_, options_.info_log.get(),
1221+
file_number, pending_outputs_, &deletion_state.memtables_to_free,
1222+
db_directory_.get());
12151223
}
12161224

1217-
// Replace immutable memtable with the generated Table
1218-
s = cfd->imm()->InstallMemtableFlushResults(
1219-
cfd, mems, versions_.get(), &mutex_, options_.info_log.get(), file_number,
1220-
pending_outputs_, &deletion_state.memtables_to_free, db_directory_.get());
1221-
12221225
if (s.ok()) {
12231226
InstallSuperVersion(cfd, deletion_state);
12241227
if (madeProgress) {
@@ -1236,6 +1239,13 @@ Status DBImpl::FlushMemTableToOutputFile(ColumnFamilyData* cfd,
12361239
}
12371240
}
12381241
}
1242+
1243+
if (!s.ok() && !s.IsShutdownInProgress() && options_.paranoid_checks &&
1244+
bg_error_.ok()) {
1245+
// if a bad error happened (not ShutdownInProgress) and paranoid_checks is
1246+
// true, mark DB read-only
1247+
bg_error_ = s;
1248+
}
12391249
return s;
12401250
}
12411251

@@ -3955,6 +3965,33 @@ void DBImpl::GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata) {
39553965
versions_->GetLiveFilesMetaData(metadata);
39563966
}
39573967

3968+
Status DBImpl::CheckConsistency() {
3969+
mutex_.AssertHeld();
3970+
std::vector<LiveFileMetaData> metadata;
3971+
versions_->GetLiveFilesMetaData(&metadata);
3972+
3973+
std::string corruption_messages;
3974+
for (const auto& md : metadata) {
3975+
std::string file_path = dbname_ + md.name;
3976+
uint64_t fsize = 0;
3977+
Status s = env_->GetFileSize(file_path, &fsize);
3978+
if (!s.ok()) {
3979+
corruption_messages +=
3980+
"Can't access " + md.name + ": " + s.ToString() + "\n";
3981+
} else if (fsize != md.size) {
3982+
corruption_messages += "Sst file size mismatch: " + md.name +
3983+
". Size recorded in manifest " +
3984+
std::to_string(md.size) + ", actual size " +
3985+
std::to_string(fsize) + "\n";
3986+
}
3987+
}
3988+
if (corruption_messages.size() == 0) {
3989+
return Status::OK();
3990+
} else {
3991+
return Status::Corruption(corruption_messages);
3992+
}
3993+
}
3994+
39583995
void DBImpl::TEST_GetFilesMetaData(
39593996
ColumnFamilyHandle* column_family,
39603997
std::vector<std::vector<FileMetaData>>* metadata) {

db/db_impl.h

+4
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,10 @@ class DBImpl : public DB {
130130

131131
virtual void GetLiveFilesMetaData(std::vector<LiveFileMetaData>* metadata);
132132

133+
// checks if all live files exist on file system and that their file sizes
134+
// match to our in-memory records
135+
virtual Status CheckConsistency();
136+
133137
virtual Status GetDbIdentity(std::string& identity);
134138

135139
Status RunManualCompaction(ColumnFamilyData* cfd, int input_level,

db/db_impl_readonly.cc

+1-1
Original file line numberDiff line numberDiff line change
@@ -114,4 +114,4 @@ Status DB::OpenForReadOnly(const Options& options, const std::string& dbname,
114114
return s;
115115
}
116116

117-
}
117+
} // namespace rocksdb

0 commit comments

Comments
 (0)