]> git.proxmox.com Git - ceph.git/blobdiff - ceph/src/rocksdb/utilities/checkpoint/checkpoint_test.cc
update sources to ceph Nautilus 14.2.1
[ceph.git] / ceph / src / rocksdb / utilities / checkpoint / checkpoint_test.cc
index 46988898bb01d9c6ec6ecc9e53b48bf2a29df9bc..62c78faa8b4dacf7d805ae91cbd1910b4833bb5f 100644 (file)
@@ -1,7 +1,7 @@
 //  Copyright (c) 2011-present, Facebook, Inc.  All rights reserved.
-//  This source code is licensed under the BSD-style license found in the
-//  LICENSE file in the root directory of this source tree. An additional grant
-//  of patent rights can be found in the PATENTS file in the same directory.
+//  This source code is licensed under both the GPLv2 (found in the
+//  COPYING file in the root directory) and Apache 2.0 License
+//  (found in the LICENSE.Apache file in the root directory).
 //
 // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
 // Use of this source code is governed by a BSD-style license that can be
 #include <thread>
 #include <utility>
 #include "db/db_impl.h"
-#include "port/stack_trace.h"
 #include "port/port.h"
+#include "port/stack_trace.h"
 #include "rocksdb/db.h"
 #include "rocksdb/env.h"
 #include "rocksdb/utilities/checkpoint.h"
 #include "rocksdb/utilities/transaction_db.h"
+#include "util/fault_injection_test_env.h"
 #include "util/sync_point.h"
 #include "util/testharness.h"
 
@@ -42,11 +43,12 @@ class CheckpointTest : public testing::Test {
   DB* db_;
   Options last_options_;
   std::vector<ColumnFamilyHandle*> handles_;
+  std::string snapshot_name_;
 
   CheckpointTest() : env_(Env::Default()) {
     env_->SetBackgroundThreads(1, Env::LOW);
     env_->SetBackgroundThreads(1, Env::HIGH);
-    dbname_ = test::TmpDir(env_) + "/db_test";
+    dbname_ = test::PerThreadDBPath(env_, "checkpoint_test");
     alternative_wal_dir_ = dbname_ + "/wal";
     auto options = CurrentOptions();
     auto delete_options = options;
@@ -55,6 +57,12 @@ class CheckpointTest : public testing::Test {
     // Destroy it for not alternative WAL dir is used.
     EXPECT_OK(DestroyDB(dbname_, options));
     db_ = nullptr;
+    snapshot_name_ = test::PerThreadDBPath(env_, "snapshot");
+    std::string snapshot_tmp_name = snapshot_name_ + ".tmp";
+    EXPECT_OK(DestroyDB(snapshot_name_, options));
+    env_->DeleteDir(snapshot_name_);
+    EXPECT_OK(DestroyDB(snapshot_tmp_name, options));
+    env_->DeleteDir(snapshot_tmp_name);
     Reopen(options);
   }
 
@@ -69,6 +77,7 @@ class CheckpointTest : public testing::Test {
     options.db_paths.emplace_back(dbname_ + "_3", 0);
     options.db_paths.emplace_back(dbname_ + "_4", 0);
     EXPECT_OK(DestroyDB(dbname_, options));
+    EXPECT_OK(DestroyDB(snapshot_name_, options));
   }
 
   // Return the current option configuration.
@@ -217,9 +226,8 @@ class CheckpointTest : public testing::Test {
 };
 
 TEST_F(CheckpointTest, GetSnapshotLink) {
-  for (uint64_t log_size_for_fush : {0, 1000000}) {
+  for (uint64_t log_size_for_flush : {0, 1000000}) {
     Options options;
-    const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
     DB* snapshotDB;
     ReadOptions roptions;
     std::string result;
@@ -229,8 +237,6 @@ TEST_F(CheckpointTest, GetSnapshotLink) {
     delete db_;
     db_ = nullptr;
     ASSERT_OK(DestroyDB(dbname_, options));
-    ASSERT_OK(DestroyDB(snapshot_name, options));
-    env_->DeleteDir(snapshot_name);
 
     // Create a database
     Status s;
@@ -240,14 +246,14 @@ TEST_F(CheckpointTest, GetSnapshotLink) {
     ASSERT_OK(Put(key, "v1"));
     // Take a snapshot
     ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
-    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name, log_size_for_fush));
+    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, log_size_for_flush));
     ASSERT_OK(Put(key, "v2"));
     ASSERT_EQ("v2", Get(key));
     ASSERT_OK(Flush());
     ASSERT_EQ("v2", Get(key));
     // Open snapshot and verify contents while DB is running
     options.create_if_missing = false;
-    ASSERT_OK(DB::Open(options, snapshot_name, &snapshotDB));
+    ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
     ASSERT_OK(snapshotDB->Get(roptions, key, &result));
     ASSERT_EQ("v1", result);
     delete snapshotDB;
@@ -260,7 +266,7 @@ TEST_F(CheckpointTest, GetSnapshotLink) {
 
     // Open snapshot and verify contents
     options.create_if_missing = false;
-    dbname_ = snapshot_name;
+    dbname_ = snapshot_name_;
     ASSERT_OK(DB::Open(options, dbname_, &db_));
     ASSERT_EQ("v1", Get(key));
     delete db_;
@@ -269,7 +275,7 @@ TEST_F(CheckpointTest, GetSnapshotLink) {
     delete checkpoint;
 
     // Restore DB name
-    dbname_ = test::TmpDir(env_) + "/db_test";
+    dbname_ = test::PerThreadDBPath(env_, "db_test");
   }
 }
 
@@ -289,21 +295,17 @@ TEST_F(CheckpointTest, CheckpointCF) {
   ASSERT_OK(Put(4, "four", "four"));
   ASSERT_OK(Put(5, "five", "five"));
 
-  const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
   DB* snapshotDB;
   ReadOptions roptions;
   std::string result;
   std::vector<ColumnFamilyHandle*> cphandles;
 
-  ASSERT_OK(DestroyDB(snapshot_name, options));
-  env_->DeleteDir(snapshot_name);
-
   Status s;
   // Take a snapshot
   rocksdb::port::Thread t([&]() {
     Checkpoint* checkpoint;
     ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
-    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name));
+    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
     delete checkpoint;
   });
   TEST_SYNC_POINT("CheckpointTest::CheckpointCF:1");
@@ -331,7 +333,7 @@ TEST_F(CheckpointTest, CheckpointCF) {
     for (size_t i = 0; i < cfs.size(); ++i) {
       column_families.push_back(ColumnFamilyDescriptor(cfs[i], options));
     }
-  ASSERT_OK(DB::Open(options, snapshot_name,
+  ASSERT_OK(DB::Open(options, snapshot_name_,
         column_families, &cphandles, &snapshotDB));
   ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
   ASSERT_EQ("Default1", result);
@@ -344,7 +346,6 @@ TEST_F(CheckpointTest, CheckpointCF) {
   cphandles.clear();
   delete snapshotDB;
   snapshotDB = nullptr;
-  ASSERT_OK(DestroyDB(snapshot_name, options));
 }
 
 TEST_F(CheckpointTest, CheckpointCFNoFlush) {
@@ -358,26 +359,22 @@ TEST_F(CheckpointTest, CheckpointCFNoFlush) {
   Flush();
   ASSERT_OK(Put(2, "two", "two"));
 
-  const std::string snapshot_name = test::TmpDir(env_) + "/snapshot";
   DB* snapshotDB;
   ReadOptions roptions;
   std::string result;
   std::vector<ColumnFamilyHandle*> cphandles;
 
-  ASSERT_OK(DestroyDB(snapshot_name, options));
-  env_->DeleteDir(snapshot_name);
-
   Status s;
   // Take a snapshot
   rocksdb::SyncPoint::GetInstance()->SetCallBack(
-      "DBImpl::BackgroundCallFlush:start", [&](void* arg) {
+      "DBImpl::BackgroundCallFlush:start", [&](void* /*arg*/) {
         // Flush should never trigger.
-        ASSERT_TRUE(false);
+        FAIL();
       });
   rocksdb::SyncPoint::GetInstance()->EnableProcessing();
   Checkpoint* checkpoint;
   ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
-  ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name, 1000000));
+  ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, 1000000));
   rocksdb::SyncPoint::GetInstance()->DisableProcessing();
 
   delete checkpoint;
@@ -395,7 +392,7 @@ TEST_F(CheckpointTest, CheckpointCFNoFlush) {
   for (size_t i = 0; i < cfs.size(); ++i) {
     column_families.push_back(ColumnFamilyDescriptor(cfs[i], options));
   }
-  ASSERT_OK(DB::Open(options, snapshot_name, column_families, &cphandles,
+  ASSERT_OK(DB::Open(options, snapshot_name_, column_families, &cphandles,
                      &snapshotDB));
   ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
   ASSERT_EQ("Default", result);
@@ -409,14 +406,9 @@ TEST_F(CheckpointTest, CheckpointCFNoFlush) {
   cphandles.clear();
   delete snapshotDB;
   snapshotDB = nullptr;
-  ASSERT_OK(DestroyDB(snapshot_name, options));
 }
 
 TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
-  const std::string kSnapshotName = test::TmpDir(env_) + "/snapshot";
-  ASSERT_OK(DestroyDB(kSnapshotName, CurrentOptions()));
-  env_->DeleteDir(kSnapshotName);
-
   Options options = CurrentOptions();
   options.max_manifest_file_size = 0;  // always rollover manifest for file add
   Reopen(options);
@@ -438,7 +430,7 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
   rocksdb::port::Thread t([&]() {
     Checkpoint* checkpoint;
     ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
-    ASSERT_OK(checkpoint->CreateCheckpoint(kSnapshotName));
+    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
     delete checkpoint;
   });
   TEST_SYNC_POINT(
@@ -452,18 +444,15 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
   DB* snapshotDB;
   // Successful Open() implies that CURRENT pointed to the manifest in the
   // checkpoint.
-  ASSERT_OK(DB::Open(options, kSnapshotName, &snapshotDB));
+  ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
   delete snapshotDB;
   snapshotDB = nullptr;
 }
 
 TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
   Close();
-  const std::string kSnapshotName = test::TmpDir(env_) + "/snapshot";
-  const std::string dbname = test::TmpDir() + "/transaction_testdb";
-  ASSERT_OK(DestroyDB(kSnapshotName, CurrentOptions()));
+  const std::string dbname = test::PerThreadDBPath("transaction_testdb");
   ASSERT_OK(DestroyDB(dbname, CurrentOptions()));
-  env_->DeleteDir(kSnapshotName);
   env_->DeleteDir(dbname);
 
   Options options = CurrentOptions();
@@ -521,7 +510,7 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
   rocksdb::port::Thread t([&]() {
     Checkpoint* checkpoint;
     ASSERT_OK(Checkpoint::Create(txdb, &checkpoint));
-    ASSERT_OK(checkpoint->CreateCheckpoint(kSnapshotName));
+    ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
     delete checkpoint;
   });
   TEST_SYNC_POINT(
@@ -536,7 +525,7 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
 
   // No more than two logs files should exist.
   std::vector<std::string> files;
-  env_->GetChildren(kSnapshotName, &files);
+  env_->GetChildren(snapshot_name_, &files);
   int num_log_files = 0;
   for (auto& file : files) {
     uint64_t num;
@@ -559,7 +548,7 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
   column_families.push_back(
       ColumnFamilyDescriptor("CFB", ColumnFamilyOptions()));
   std::vector<rocksdb::ColumnFamilyHandle*> cf_handles;
-  ASSERT_OK(TransactionDB::Open(options, txn_db_options, kSnapshotName,
+  ASSERT_OK(TransactionDB::Open(options, txn_db_options, snapshot_name_,
                                 column_families, &cf_handles, &snapshotDB));
   ASSERT_OK(snapshotDB->Get(read_options, "foo", &value));
   ASSERT_EQ(value, "bar");
@@ -576,6 +565,53 @@ TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
   delete txdb;
 }
 
+TEST_F(CheckpointTest, CheckpointInvalidDirectoryName) {
+  for (std::string checkpoint_dir : {"", "/", "////"}) {
+    Checkpoint* checkpoint;
+    ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
+    ASSERT_TRUE(checkpoint->CreateCheckpoint("").IsInvalidArgument());
+    delete checkpoint;
+  }
+}
+
+TEST_F(CheckpointTest, CheckpointWithParallelWrites) {
+  // When run with TSAN, this exposes the data race fixed in
+  // https://github.com/facebook/rocksdb/pull/3603
+  ASSERT_OK(Put("key1", "val1"));
+  port::Thread thread([this]() { ASSERT_OK(Put("key2", "val2")); });
+  Checkpoint* checkpoint;
+  ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
+  ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
+  delete checkpoint;
+  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
 
 int main(int argc, char** argv) {
@@ -587,7 +623,7 @@ int main(int argc, char** argv) {
 #else
 #include <stdio.h>
 
-int main(int argc, char** argv) {
+int main(int /*argc*/, char** /*argv*/) {
   fprintf(stderr, "SKIPPED as Checkpoint is not supported in ROCKSDB_LITE\n");
   return 0;
 }