From 0f40fe4bc71d53346027fa8d1a12815c25dbd19a Mon Sep 17 00:00:00 2001 From: sdong Date: Tue, 15 Apr 2014 09:06:13 -0700 Subject: [PATCH] When creating a new DB, fail it when wal_dir contains existing log files Summary: Current behavior of creating new DB is, if there is existing log files, we will go ahead and replay them on top of empty DB. This is a behavior that no user would expect. With this patch, we will fail the creation if a user creates a DB with existing log files. Test Plan: make all check Reviewers: haobo, igor, ljin Reviewed By: haobo CC: nkg-, yhchiang, dhruba, leveldb Differential Revision: https://reviews.facebook.net/D17817 --- db/db_impl.cc | 15 +++++++++++---- db/db_test.cc | 25 +++++++++++++++++++------ 2 files changed, 30 insertions(+), 10 deletions(-) diff --git a/db/db_impl.cc b/db/db_impl.cc index 918402df51..77d6ca04c3 100644 --- a/db/db_impl.cc +++ b/db/db_impl.cc @@ -1062,6 +1062,7 @@ Status DBImpl::Recover( bool error_if_log_file_exist) { mutex_.AssertHeld(); + bool is_new_db = false; assert(db_lock_ == nullptr); if (!read_only) { // We call CreateDirIfMissing() as the directory may already exist (if we @@ -1090,6 +1091,7 @@ Status DBImpl::Recover( if (options_.create_if_missing) { // TODO: add merge_operator name check s = NewDB(); + is_new_db = true; if (!s.ok()) { return s; } @@ -1140,10 +1142,15 @@ Status DBImpl::Recover( for (size_t i = 0; i < filenames.size(); i++) { uint64_t number; FileType type; - if (ParseFileName(filenames[i], &number, &type) - && type == kLogFile - && ((number >= min_log) || (number == prev_log))) { - logs.push_back(number); + if (ParseFileName(filenames[i], &number, &type) && type == kLogFile) { + if (is_new_db) { + return Status::Corruption( + "While creating a new Db, wal_dir contains " + "existing log file: ", + filenames[i]); + } else if ((number >= min_log) || (number == prev_log)) { + logs.push_back(number); + } } } diff --git a/db/db_test.cc b/db/db_test.cc index d3c5e2d555..c9578a65ac 100644 --- a/db/db_test.cc +++ b/db/db_test.cc @@ -2095,7 +2095,24 @@ TEST(DBTest, IgnoreRecoveredLog) { ASSERT_EQ(one, Get("bar")); Close(); Destroy(&options); + Reopen(&options); + Close(); + // copy the logs from backup back to wal dir + env_->CreateDirIfMissing(options.wal_dir); + for (auto& log : logs) { + if (log != ".." && log != ".") { + CopyFile(backup_logs + "/" + log, options.wal_dir + "/" + log); + } + } + // assert that we successfully recovered only from logs, even though we + // destroyed the DB + Reopen(&options); + ASSERT_EQ(two, Get("foo")); + ASSERT_EQ(one, Get("bar")); + + // Recovery will fail if DB directory doesn't exist. + Destroy(&options); // copy the logs from backup back to wal dir env_->CreateDirIfMissing(options.wal_dir); for (auto& log : logs) { @@ -2105,12 +2122,8 @@ TEST(DBTest, IgnoreRecoveredLog) { env_->DeleteFile(backup_logs + "/" + log); } } - // assert that we successfully recovered only from logs, even though we - // destroyed the DB - Reopen(&options); - ASSERT_EQ(two, Get("foo")); - ASSERT_EQ(one, Get("bar")); - Close(); + Status s = TryReopen(&options); + ASSERT_TRUE(!s.ok()); } while (ChangeOptions()); }