Make DB::Open fail if sst files are missing.

Also, cleanup for Clang's -Wimplicit-fallthrough warning.
This commit is contained in:
David Grogan 2013-02-06 18:03:32 -08:00
parent d84c825a70
commit 514c943a8e
3 changed files with 52 additions and 6 deletions

View File

@ -310,16 +310,24 @@ Status DBImpl::Recover(VersionEdit* edit) {
if (!s.ok()) { if (!s.ok()) {
return s; return s;
} }
std::set<uint64_t> expected;
versions_->AddLiveFiles(&expected);
uint64_t number; uint64_t number;
FileType type; FileType type;
std::vector<uint64_t> logs; std::vector<uint64_t> logs;
for (size_t i = 0; i < filenames.size(); i++) { for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type) if (ParseFileName(filenames[i], &number, &type)) {
&& type == kLogFile expected.erase(number);
&& ((number >= min_log) || (number == prev_log))) { if (type == kLogFile && ((number >= min_log) || (number == prev_log)))
logs.push_back(number); logs.push_back(number);
} }
} }
if (!expected.empty()) {
char buf[50];
snprintf(buf, sizeof(buf), "%d missing files; e.g.",
static_cast<int>(expected.size()));
return Status::Corruption(buf, TableFileName(dbname_, *(expected.begin())));
}
// Recover in the order in which the logs were generated // Recover in the order in which the logs were generated
std::sort(logs.begin(), logs.end()); std::sort(logs.begin(), logs.end());

View File

@ -461,6 +461,20 @@ class DBTest {
} }
return result; return result;
} }
bool DeleteAnSSTFile() {
std::vector<std::string> filenames;
ASSERT_OK(env_->GetChildren(dbname_, &filenames));
uint64_t number;
FileType type;
for (size_t i = 0; i < filenames.size(); i++) {
if (ParseFileName(filenames[i], &number, &type) && type == kTableFile) {
ASSERT_OK(env_->DeleteFile(TableFileName(dbname_, number)));
return true;
}
}
return false;
}
}; };
TEST(DBTest, Empty) { TEST(DBTest, Empty) {
@ -1567,6 +1581,23 @@ TEST(DBTest, ManifestWriteError) {
} }
} }
TEST(DBTest, MissingSSTFile) {
ASSERT_OK(Put("foo", "bar"));
ASSERT_EQ("bar", Get("foo"));
// Dump the memtable to disk.
dbfull()->TEST_CompactMemTable();
ASSERT_EQ("bar", Get("foo"));
ASSERT_TRUE(DeleteAnSSTFile());
Options options = CurrentOptions();
options.paranoid_checks = true;
Status s = TryReopen(&options);
ASSERT_TRUE(!s.ok());
ASSERT_TRUE(s.ToString().find("issing") != std::string::npos)
<< s.ToString();
}
TEST(DBTest, FilesDeletedAfterCompaction) { TEST(DBTest, FilesDeletedAfterCompaction) {
ASSERT_OK(Put("foo", "v2")); ASSERT_OK(Put("foo", "v2"));
Compact("a", "z"); Compact("a", "z");

View File

@ -6,6 +6,13 @@
#include "util/coding.h" #include "util/coding.h"
#include "util/hash.h" #include "util/hash.h"
// The FALLTHROUGH_INTENDED macro can be used to annotate implicit fall-through
// between switch labels. The real definition should be provided externally.
// This one is a fallback version for unsupported compilers.
#ifndef FALLTHROUGH_INTENDED
#define FALLTHROUGH_INTENDED do { } while (0)
#endif
namespace leveldb { namespace leveldb {
uint32_t Hash(const char* data, size_t n, uint32_t seed) { uint32_t Hash(const char* data, size_t n, uint32_t seed) {
@ -28,10 +35,10 @@ uint32_t Hash(const char* data, size_t n, uint32_t seed) {
switch (limit - data) { switch (limit - data) {
case 3: case 3:
h += data[2] << 16; h += data[2] << 16;
// fall through FALLTHROUGH_INTENDED;
case 2: case 2:
h += data[1] << 8; h += data[1] << 8;
// fall through FALLTHROUGH_INTENDED;
case 1: case 1:
h += data[0]; h += data[0];
h *= m; h *= m;