Sync CURRENT file during checkpoint (#4322)

Summary: For the CURRENT file forged during checkpoint, we were forgetting to `fsync` or `fdatasync` it after its creation. This PR fixes it.

Differential Revision: D9525939

Pulled By: ajkr

fbshipit-source-id: a505483644026ee3f501cfc0dcbe74832165b2e3
main
Andrew Kryczka 6 years ago committed by Facebook Github Bot
parent 38ad3c9f8a
commit 42733637e1
  1. 1
      HISTORY.md
  2. 4
      db/repair_test.cc
  3. 8
      util/file_util.cc
  4. 2
      util/file_util.h
  5. 3
      utilities/checkpoint/checkpoint_impl.cc
  6. 29
      utilities/checkpoint/checkpoint_test.cc

@ -6,6 +6,7 @@
### New Features ### New Features
### Bug Fixes ### Bug Fixes
* Avoid creating empty SSTs and subsequently deleting them in certain cases during compaction. * Avoid creating empty SSTs and subsequently deleting them in certain cases during compaction.
* Sync CURRENT file contents during checkpoint.
## 5.16.0 (8/21/2018) ## 5.16.0 (8/21/2018)
### Public API Change ### Public API Change

@ -74,7 +74,7 @@ TEST_F(RepairTest, CorruptManifest) {
Close(); Close();
ASSERT_OK(env_->FileExists(manifest_path)); ASSERT_OK(env_->FileExists(manifest_path));
CreateFile(env_, manifest_path, "blah"); CreateFile(env_, manifest_path, "blah", false /* use_fsync */);
ASSERT_OK(RepairDB(dbname_, CurrentOptions())); ASSERT_OK(RepairDB(dbname_, CurrentOptions()));
Reopen(CurrentOptions()); Reopen(CurrentOptions());
@ -153,7 +153,7 @@ TEST_F(RepairTest, CorruptSst) {
Flush(); Flush();
auto sst_path = GetFirstSstPath(); auto sst_path = GetFirstSstPath();
ASSERT_FALSE(sst_path.empty()); ASSERT_FALSE(sst_path.empty());
CreateFile(env_, sst_path, "blah"); CreateFile(env_, sst_path, "blah", false /* use_fsync */);
Close(); Close();
ASSERT_OK(RepairDB(dbname_, CurrentOptions())); ASSERT_OK(RepairDB(dbname_, CurrentOptions()));

@ -68,7 +68,7 @@ Status CopyFile(Env* env, const std::string& source,
// Utility function to create a file with the provided contents // Utility function to create a file with the provided contents
Status CreateFile(Env* env, const std::string& destination, Status CreateFile(Env* env, const std::string& destination,
const std::string& contents) { const std::string& contents, bool use_fsync) {
const EnvOptions soptions; const EnvOptions soptions;
Status s; Status s;
unique_ptr<WritableFileWriter> dest_writer; unique_ptr<WritableFileWriter> dest_writer;
@ -80,7 +80,11 @@ Status CreateFile(Env* env, const std::string& destination,
} }
dest_writer.reset( dest_writer.reset(
new WritableFileWriter(std::move(destfile), destination, soptions)); new WritableFileWriter(std::move(destfile), destination, soptions));
return dest_writer->Append(Slice(contents)); s = dest_writer->Append(Slice(contents));
if (!s.ok()) {
return s;
}
return dest_writer->Sync(use_fsync);
} }
Status DeleteSSTFile(const ImmutableDBOptions* db_options, Status DeleteSSTFile(const ImmutableDBOptions* db_options,

@ -19,7 +19,7 @@ extern Status CopyFile(Env* env, const std::string& source,
bool use_fsync); bool use_fsync);
extern Status CreateFile(Env* env, const std::string& destination, extern Status CreateFile(Env* env, const std::string& destination,
const std::string& contents); const std::string& contents, bool use_fsync);
extern Status DeleteSSTFile(const ImmutableDBOptions* db_options, extern Status DeleteSSTFile(const ImmutableDBOptions* db_options,
const std::string& fname, const std::string& fname,

@ -120,7 +120,8 @@ Status CheckpointImpl::CreateCheckpoint(const std::string& checkpoint_dir,
} /* copy_file_cb */, } /* copy_file_cb */,
[&](const std::string& fname, const std::string& contents, FileType) { [&](const std::string& fname, const std::string& contents, FileType) {
ROCKS_LOG_INFO(db_options.info_log, "Creating %s", fname.c_str()); ROCKS_LOG_INFO(db_options.info_log, "Creating %s", fname.c_str());
return CreateFile(db_->GetEnv(), full_private_path + fname, contents); return CreateFile(db_->GetEnv(), full_private_path + fname, contents,
db_options.use_fsync);
} /* create_file_cb */, } /* create_file_cb */,
&sequence_number, log_size_for_flush); &sequence_number, log_size_for_flush);
// we copied all the files, enable file deletions // we copied all the files, enable file deletions

@ -17,12 +17,13 @@
#include <thread> #include <thread>
#include <utility> #include <utility>
#include "db/db_impl.h" #include "db/db_impl.h"
#include "port/stack_trace.h"
#include "port/port.h" #include "port/port.h"
#include "port/stack_trace.h"
#include "rocksdb/db.h" #include "rocksdb/db.h"
#include "rocksdb/env.h" #include "rocksdb/env.h"
#include "rocksdb/utilities/checkpoint.h" #include "rocksdb/utilities/checkpoint.h"
#include "rocksdb/utilities/transaction_db.h" #include "rocksdb/utilities/transaction_db.h"
#include "util/fault_injection_test_env.h"
#include "util/sync_point.h" #include "util/sync_point.h"
#include "util/testharness.h" #include "util/testharness.h"
@ -585,6 +586,32 @@ TEST_F(CheckpointTest, CheckpointWithParallelWrites) {
thread.join(); thread.join();
} }
TEST_F(CheckpointTest, CheckpointWithUnsyncedDataDropped) {
Options options = CurrentOptions();
std::unique_ptr<FaultInjectionTestEnv> env(new FaultInjectionTestEnv(env_));
options.env = env.get();
Reopen(options);
ASSERT_OK(Put("key1", "val1"));
Checkpoint* checkpoint;
ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
delete checkpoint;
env->DropUnsyncedFileData();
// make sure it's openable even though whatever data that wasn't synced got
// dropped.
options.env = env_;
DB* snapshot_db;
ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
ReadOptions read_opts;
std::string get_result;
ASSERT_OK(snapshot_db->Get(read_opts, "key1", &get_result));
ASSERT_EQ("val1", get_result);
delete snapshot_db;
delete db_;
db_ = nullptr;
}
} // namespace rocksdb } // namespace rocksdb
int main(int argc, char** argv) { int main(int argc, char** argv) {

Loading…
Cancel
Save