checkpoint_test.cc 37 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087
  1. // Copyright (c) 2011-present, Facebook, Inc. All rights reserved.
  2. // This source code is licensed under both the GPLv2 (found in the
  3. // COPYING file in the root directory) and Apache 2.0 License
  4. // (found in the LICENSE.Apache file in the root directory).
  5. //
  6. // Copyright (c) 2011 The LevelDB Authors. All rights reserved.
  7. // Use of this source code is governed by a BSD-style license that can be
  8. // found in the LICENSE file. See the AUTHORS file for names of contributors.
  9. // Syncpoint prevents us building and running tests in release
  10. #include "rocksdb/utilities/checkpoint.h"
  11. #ifndef OS_WIN
  12. #include <unistd.h>
  13. #endif
  14. #include <cstdlib>
  15. #include <iostream>
  16. #include <thread>
  17. #include <utility>
  18. #include "db/db_impl/db_impl.h"
  19. #include "file/file_util.h"
  20. #include "port/port.h"
  21. #include "port/stack_trace.h"
  22. #include "rocksdb/db.h"
  23. #include "rocksdb/env.h"
  24. #include "rocksdb/rocksdb_namespace.h"
  25. #include "rocksdb/sst_file_manager.h"
  26. #include "rocksdb/utilities/transaction_db.h"
  27. #include "test_util/sync_point.h"
  28. #include "test_util/testharness.h"
  29. #include "test_util/testutil.h"
  30. #include "utilities/fault_injection_env.h"
  31. #include "utilities/fault_injection_fs.h"
  32. namespace ROCKSDB_NAMESPACE {
  33. class CheckpointTest : public testing::Test {
  34. protected:
  35. // Sequence of option configurations to try
  36. enum OptionConfig {
  37. kDefault = 0,
  38. };
  39. int option_config_;
  40. public:
  41. std::string dbname_;
  42. std::string alternative_wal_dir_;
  43. Env* env_;
  44. DB* db_;
  45. Options last_options_;
  46. std::vector<ColumnFamilyHandle*> handles_;
  47. std::string snapshot_name_;
  48. std::string export_path_;
  49. ColumnFamilyHandle* cfh_reverse_comp_;
  50. ExportImportFilesMetaData* metadata_;
  51. CheckpointTest() : env_(Env::Default()) {
  52. env_->SetBackgroundThreads(1, Env::LOW);
  53. env_->SetBackgroundThreads(1, Env::HIGH);
  54. dbname_ = test::PerThreadDBPath(env_, "checkpoint_test");
  55. alternative_wal_dir_ = dbname_ + "/wal";
  56. auto options = CurrentOptions();
  57. auto delete_options = options;
  58. delete_options.wal_dir = alternative_wal_dir_;
  59. EXPECT_OK(DestroyDB(dbname_, delete_options));
  60. // Destroy it for not alternative WAL dir is used.
  61. EXPECT_OK(DestroyDB(dbname_, options));
  62. db_ = nullptr;
  63. snapshot_name_ = test::PerThreadDBPath(env_, "snapshot");
  64. std::string snapshot_tmp_name = snapshot_name_ + ".tmp";
  65. EXPECT_OK(DestroyDB(snapshot_name_, options));
  66. test::DeleteDir(env_, snapshot_name_);
  67. EXPECT_OK(DestroyDB(snapshot_tmp_name, options));
  68. test::DeleteDir(env_, snapshot_tmp_name);
  69. Reopen(options);
  70. export_path_ = test::PerThreadDBPath("/export");
  71. DestroyDir(env_, export_path_).PermitUncheckedError();
  72. cfh_reverse_comp_ = nullptr;
  73. metadata_ = nullptr;
  74. }
  75. ~CheckpointTest() override {
  76. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  77. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({});
  78. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
  79. if (cfh_reverse_comp_) {
  80. EXPECT_OK(db_->DestroyColumnFamilyHandle(cfh_reverse_comp_));
  81. cfh_reverse_comp_ = nullptr;
  82. }
  83. if (metadata_) {
  84. delete metadata_;
  85. metadata_ = nullptr;
  86. }
  87. Close();
  88. Options options;
  89. options.db_paths.emplace_back(dbname_, 0);
  90. options.db_paths.emplace_back(dbname_ + "_2", 0);
  91. options.db_paths.emplace_back(dbname_ + "_3", 0);
  92. options.db_paths.emplace_back(dbname_ + "_4", 0);
  93. EXPECT_OK(DestroyDB(dbname_, options));
  94. EXPECT_OK(DestroyDB(snapshot_name_, options));
  95. DestroyDir(env_, export_path_).PermitUncheckedError();
  96. }
  97. // Return the current option configuration.
  98. Options CurrentOptions() {
  99. Options options;
  100. options.env = env_;
  101. options.create_if_missing = true;
  102. return options;
  103. }
  104. void CreateColumnFamilies(const std::vector<std::string>& cfs,
  105. const Options& options) {
  106. ColumnFamilyOptions cf_opts(options);
  107. size_t cfi = handles_.size();
  108. handles_.resize(cfi + cfs.size());
  109. for (const auto& cf : cfs) {
  110. ASSERT_OK(db_->CreateColumnFamily(cf_opts, cf, &handles_[cfi++]));
  111. }
  112. }
  113. void CreateAndReopenWithCF(const std::vector<std::string>& cfs,
  114. const Options& options) {
  115. CreateColumnFamilies(cfs, options);
  116. std::vector<std::string> cfs_plus_default = cfs;
  117. cfs_plus_default.insert(cfs_plus_default.begin(), kDefaultColumnFamilyName);
  118. ReopenWithColumnFamilies(cfs_plus_default, options);
  119. }
  120. void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
  121. const std::vector<Options>& options) {
  122. ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
  123. }
  124. void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
  125. const Options& options) {
  126. ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
  127. }
  128. Status TryReopenWithColumnFamilies(const std::vector<std::string>& cfs,
  129. const std::vector<Options>& options) {
  130. Close();
  131. EXPECT_EQ(cfs.size(), options.size());
  132. std::vector<ColumnFamilyDescriptor> column_families;
  133. for (size_t i = 0; i < cfs.size(); ++i) {
  134. column_families.emplace_back(cfs[i], options[i]);
  135. }
  136. DBOptions db_opts = DBOptions(options[0]);
  137. return DB::Open(db_opts, dbname_, column_families, &handles_, &db_);
  138. }
  139. Status TryReopenWithColumnFamilies(const std::vector<std::string>& cfs,
  140. const Options& options) {
  141. Close();
  142. std::vector<Options> v_opts(cfs.size(), options);
  143. return TryReopenWithColumnFamilies(cfs, v_opts);
  144. }
  145. void Reopen(const Options& options) { ASSERT_OK(TryReopen(options)); }
  146. void CompactAll() {
  147. for (auto h : handles_) {
  148. ASSERT_OK(db_->CompactRange(CompactRangeOptions(), h, nullptr, nullptr));
  149. }
  150. }
  151. void Close() {
  152. for (auto h : handles_) {
  153. delete h;
  154. }
  155. handles_.clear();
  156. delete db_;
  157. db_ = nullptr;
  158. }
  159. void DestroyAndReopen(const Options& options) {
  160. // Destroy using last options
  161. Destroy(last_options_);
  162. ASSERT_OK(TryReopen(options));
  163. }
  164. void Destroy(const Options& options) {
  165. Close();
  166. ASSERT_OK(DestroyDB(dbname_, options));
  167. }
  168. Status ReadOnlyReopen(const Options& options) {
  169. return DB::OpenForReadOnly(options, dbname_, &db_);
  170. }
  171. Status ReadOnlyReopenWithColumnFamilies(const std::vector<std::string>& cfs,
  172. const Options& options) {
  173. std::vector<ColumnFamilyDescriptor> column_families;
  174. for (const auto& cf : cfs) {
  175. column_families.emplace_back(cf, options);
  176. }
  177. return DB::OpenForReadOnly(options, dbname_, column_families, &handles_,
  178. &db_);
  179. }
  180. Status TryReopen(const Options& options) {
  181. Close();
  182. last_options_ = options;
  183. return DB::Open(options, dbname_, &db_);
  184. }
  185. Status Flush(int cf = 0) {
  186. if (cf == 0) {
  187. return db_->Flush(FlushOptions());
  188. } else {
  189. return db_->Flush(FlushOptions(), handles_[cf]);
  190. }
  191. }
  192. Status Put(const Slice& k, const Slice& v, WriteOptions wo = WriteOptions()) {
  193. return db_->Put(wo, k, v);
  194. }
  195. Status Put(int cf, const Slice& k, const Slice& v,
  196. WriteOptions wo = WriteOptions()) {
  197. return db_->Put(wo, handles_[cf], k, v);
  198. }
  199. Status Delete(const std::string& k) { return db_->Delete(WriteOptions(), k); }
  200. Status Delete(int cf, const std::string& k) {
  201. return db_->Delete(WriteOptions(), handles_[cf], k);
  202. }
  203. std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
  204. ReadOptions options;
  205. options.verify_checksums = true;
  206. options.snapshot = snapshot;
  207. std::string result;
  208. Status s = db_->Get(options, k, &result);
  209. if (s.IsNotFound()) {
  210. result = "NOT_FOUND";
  211. } else if (!s.ok()) {
  212. result = s.ToString();
  213. }
  214. return result;
  215. }
  216. std::string Get(int cf, const std::string& k,
  217. const Snapshot* snapshot = nullptr) {
  218. ReadOptions options;
  219. options.verify_checksums = true;
  220. options.snapshot = snapshot;
  221. std::string result;
  222. Status s = db_->Get(options, handles_[cf], k, &result);
  223. if (s.IsNotFound()) {
  224. result = "NOT_FOUND";
  225. } else if (!s.ok()) {
  226. result = s.ToString();
  227. }
  228. return result;
  229. }
  230. int NumTableFilesAtLevel(int level) {
  231. std::string property;
  232. EXPECT_TRUE(db_->GetProperty(
  233. "rocksdb.num-files-at-level" + std::to_string(level), &property));
  234. return atoi(property.c_str());
  235. }
  236. };
  237. TEST_F(CheckpointTest, GetSnapshotLink) {
  238. for (uint64_t log_size_for_flush : {0, 1000000}) {
  239. Options options;
  240. DB* snapshotDB;
  241. ReadOptions roptions;
  242. std::string result;
  243. Checkpoint* checkpoint;
  244. options = CurrentOptions();
  245. delete db_;
  246. db_ = nullptr;
  247. ASSERT_OK(DestroyDB(dbname_, options));
  248. // Create a database
  249. options.create_if_missing = true;
  250. ASSERT_OK(DB::Open(options, dbname_, &db_));
  251. std::string key = std::string("foo");
  252. ASSERT_OK(Put(key, "v1"));
  253. // Take a snapshot
  254. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  255. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, log_size_for_flush));
  256. ASSERT_OK(Put(key, "v2"));
  257. ASSERT_EQ("v2", Get(key));
  258. ASSERT_OK(Flush());
  259. ASSERT_EQ("v2", Get(key));
  260. // Open snapshot and verify contents while DB is running
  261. options.create_if_missing = false;
  262. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
  263. ASSERT_OK(snapshotDB->Get(roptions, key, &result));
  264. ASSERT_EQ("v1", result);
  265. delete snapshotDB;
  266. snapshotDB = nullptr;
  267. delete db_;
  268. db_ = nullptr;
  269. // Destroy original DB
  270. ASSERT_OK(DestroyDB(dbname_, options));
  271. // Open snapshot and verify contents
  272. options.create_if_missing = false;
  273. dbname_ = snapshot_name_;
  274. ASSERT_OK(DB::Open(options, dbname_, &db_));
  275. ASSERT_EQ("v1", Get(key));
  276. delete db_;
  277. db_ = nullptr;
  278. ASSERT_OK(DestroyDB(dbname_, options));
  279. delete checkpoint;
  280. // Restore DB name
  281. dbname_ = test::PerThreadDBPath(env_, "db_test");
  282. }
  283. }
  284. TEST_F(CheckpointTest, CheckpointWithBlob) {
  285. // Create a database with a blob file
  286. Options options = CurrentOptions();
  287. options.create_if_missing = true;
  288. options.enable_blob_files = true;
  289. options.min_blob_size = 0;
  290. Reopen(options);
  291. constexpr char key[] = "key";
  292. constexpr char blob[] = "blob";
  293. ASSERT_OK(Put(key, blob));
  294. ASSERT_OK(Flush());
  295. // Create a checkpoint
  296. Checkpoint* checkpoint = nullptr;
  297. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  298. std::unique_ptr<Checkpoint> checkpoint_guard(checkpoint);
  299. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  300. // Make sure it contains the blob file
  301. std::vector<std::string> files;
  302. ASSERT_OK(env_->GetChildren(snapshot_name_, &files));
  303. bool blob_file_found = false;
  304. for (const auto& file : files) {
  305. uint64_t number = 0;
  306. FileType type = kWalFile;
  307. if (ParseFileName(file, &number, &type) && type == kBlobFile) {
  308. blob_file_found = true;
  309. break;
  310. }
  311. }
  312. ASSERT_TRUE(blob_file_found);
  313. // Make sure the checkpoint can be opened and the blob value read
  314. options.create_if_missing = false;
  315. DB* checkpoint_db = nullptr;
  316. ASSERT_OK(DB::Open(options, snapshot_name_, &checkpoint_db));
  317. std::unique_ptr<DB> checkpoint_db_guard(checkpoint_db);
  318. PinnableSlice value;
  319. ASSERT_OK(checkpoint_db->Get(
  320. ReadOptions(), checkpoint_db->DefaultColumnFamily(), key, &value));
  321. ASSERT_EQ(value, blob);
  322. }
  323. TEST_F(CheckpointTest, ExportColumnFamilyWithLinks) {
  324. // Create a database
  325. auto options = CurrentOptions();
  326. options.create_if_missing = true;
  327. CreateAndReopenWithCF({}, options);
  328. // Helper to verify the number of files in metadata and export dir
  329. auto verify_files_exported = [&](const ExportImportFilesMetaData& metadata,
  330. int num_files_expected) {
  331. ASSERT_EQ(metadata.files.size(), num_files_expected);
  332. std::vector<std::string> subchildren;
  333. ASSERT_OK(env_->GetChildren(export_path_, &subchildren));
  334. ASSERT_EQ(subchildren.size(), num_files_expected);
  335. };
  336. // Test DefaultColumnFamily
  337. {
  338. const auto key = std::string("foo");
  339. ASSERT_OK(Put(key, "v1"));
  340. Checkpoint* checkpoint;
  341. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  342. // Export the Tables and verify
  343. ASSERT_OK(checkpoint->ExportColumnFamily(db_->DefaultColumnFamily(),
  344. export_path_, &metadata_));
  345. verify_files_exported(*metadata_, 1);
  346. ASSERT_EQ(metadata_->db_comparator_name, options.comparator->Name());
  347. ASSERT_OK(DestroyDir(env_, export_path_));
  348. delete metadata_;
  349. metadata_ = nullptr;
  350. // Check again after compaction
  351. CompactAll();
  352. ASSERT_OK(Put(key, "v2"));
  353. ASSERT_OK(checkpoint->ExportColumnFamily(db_->DefaultColumnFamily(),
  354. export_path_, &metadata_));
  355. verify_files_exported(*metadata_, 2);
  356. ASSERT_EQ(metadata_->db_comparator_name, options.comparator->Name());
  357. ASSERT_OK(DestroyDir(env_, export_path_));
  358. delete metadata_;
  359. metadata_ = nullptr;
  360. delete checkpoint;
  361. }
  362. // Test non default column family with non default comparator
  363. {
  364. auto cf_options = CurrentOptions();
  365. cf_options.comparator = ReverseBytewiseComparator();
  366. ASSERT_OK(db_->CreateColumnFamily(cf_options, "yoyo", &cfh_reverse_comp_));
  367. const auto key = std::string("foo");
  368. ASSERT_OK(db_->Put(WriteOptions(), cfh_reverse_comp_, key, "v1"));
  369. Checkpoint* checkpoint;
  370. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  371. // Export the Tables and verify
  372. ASSERT_OK(checkpoint->ExportColumnFamily(cfh_reverse_comp_, export_path_,
  373. &metadata_));
  374. verify_files_exported(*metadata_, 1);
  375. ASSERT_EQ(metadata_->db_comparator_name,
  376. ReverseBytewiseComparator()->Name());
  377. delete checkpoint;
  378. }
  379. }
  380. TEST_F(CheckpointTest, ExportColumnFamilyNegativeTest) {
  381. // Create a database
  382. auto options = CurrentOptions();
  383. options.create_if_missing = true;
  384. CreateAndReopenWithCF({}, options);
  385. const auto key = std::string("foo");
  386. ASSERT_OK(Put(key, "v1"));
  387. Checkpoint* checkpoint;
  388. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  389. // Export onto existing directory
  390. ASSERT_OK(env_->CreateDirIfMissing(export_path_));
  391. ASSERT_EQ(checkpoint->ExportColumnFamily(db_->DefaultColumnFamily(),
  392. export_path_, &metadata_),
  393. Status::InvalidArgument("Specified export_dir exists"));
  394. ASSERT_OK(DestroyDir(env_, export_path_));
  395. // Export with invalid directory specification
  396. export_path_ = "";
  397. ASSERT_EQ(checkpoint->ExportColumnFamily(db_->DefaultColumnFamily(),
  398. export_path_, &metadata_),
  399. Status::InvalidArgument("Specified export_dir invalid"));
  400. delete checkpoint;
  401. }
  402. TEST_F(CheckpointTest, CheckpointCF) {
  403. Options options = CurrentOptions();
  404. CreateAndReopenWithCF({"one", "two", "three", "four", "five"}, options);
  405. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
  406. {{"CheckpointTest::CheckpointCF:2", "DBImpl::FlushAllColumnFamilies:2"},
  407. {"DBImpl::FlushAllColumnFamilies:1", "CheckpointTest::CheckpointCF:1"}});
  408. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  409. ASSERT_OK(Put(0, "Default", "Default"));
  410. ASSERT_OK(Put(1, "one", "one"));
  411. ASSERT_OK(Put(2, "two", "two"));
  412. ASSERT_OK(Put(3, "three", "three"));
  413. ASSERT_OK(Put(4, "four", "four"));
  414. ASSERT_OK(Put(5, "five", "five"));
  415. DB* snapshotDB;
  416. ReadOptions roptions;
  417. std::string result;
  418. std::vector<ColumnFamilyHandle*> cphandles;
  419. // Take a snapshot
  420. ROCKSDB_NAMESPACE::port::Thread t([&]() {
  421. Checkpoint* checkpoint;
  422. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  423. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  424. delete checkpoint;
  425. });
  426. TEST_SYNC_POINT("CheckpointTest::CheckpointCF:1");
  427. ASSERT_OK(Put(0, "Default", "Default1"));
  428. ASSERT_OK(Put(1, "one", "eleven"));
  429. ASSERT_OK(Put(2, "two", "twelve"));
  430. ASSERT_OK(Put(3, "three", "thirteen"));
  431. ASSERT_OK(Put(4, "four", "fourteen"));
  432. ASSERT_OK(Put(5, "five", "fifteen"));
  433. TEST_SYNC_POINT("CheckpointTest::CheckpointCF:2");
  434. t.join();
  435. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  436. ASSERT_OK(Put(1, "one", "twentyone"));
  437. ASSERT_OK(Put(2, "two", "twentytwo"));
  438. ASSERT_OK(Put(3, "three", "twentythree"));
  439. ASSERT_OK(Put(4, "four", "twentyfour"));
  440. ASSERT_OK(Put(5, "five", "twentyfive"));
  441. ASSERT_OK(Flush());
  442. // Open snapshot and verify contents while DB is running
  443. options.create_if_missing = false;
  444. std::vector<std::string> cfs;
  445. cfs = {kDefaultColumnFamilyName, "one", "two", "three", "four", "five"};
  446. std::vector<ColumnFamilyDescriptor> column_families;
  447. for (size_t i = 0; i < cfs.size(); ++i) {
  448. column_families.emplace_back(cfs[i], options);
  449. }
  450. ASSERT_OK(DB::Open(options, snapshot_name_, column_families, &cphandles,
  451. &snapshotDB));
  452. ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
  453. ASSERT_EQ("Default1", result);
  454. ASSERT_OK(snapshotDB->Get(roptions, cphandles[1], "one", &result));
  455. ASSERT_EQ("eleven", result);
  456. ASSERT_OK(snapshotDB->Get(roptions, cphandles[2], "two", &result));
  457. for (auto h : cphandles) {
  458. delete h;
  459. }
  460. cphandles.clear();
  461. delete snapshotDB;
  462. snapshotDB = nullptr;
  463. }
  464. TEST_F(CheckpointTest, CheckpointCFNoFlush) {
  465. Options options = CurrentOptions();
  466. CreateAndReopenWithCF({"one", "two", "three", "four", "five"}, options);
  467. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  468. ASSERT_OK(Put(0, "Default", "Default"));
  469. ASSERT_OK(Put(1, "one", "one"));
  470. ASSERT_OK(Flush());
  471. ASSERT_OK(Put(2, "two", "two"));
  472. DB* snapshotDB;
  473. ReadOptions roptions;
  474. std::string result;
  475. std::vector<ColumnFamilyHandle*> cphandles;
  476. // Take a snapshot
  477. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  478. "DBImpl::BackgroundCallFlush:start", [&](void* /*arg*/) {
  479. // Flush should never trigger.
  480. FAIL();
  481. });
  482. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  483. Checkpoint* checkpoint;
  484. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  485. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, 1000000));
  486. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  487. delete checkpoint;
  488. ASSERT_OK(Put(1, "one", "two"));
  489. ASSERT_OK(Flush(1));
  490. ASSERT_OK(Put(2, "two", "twentytwo"));
  491. Close();
  492. EXPECT_OK(DestroyDB(dbname_, options));
  493. // Open snapshot and verify contents while DB is running
  494. options.create_if_missing = false;
  495. std::vector<std::string> cfs;
  496. cfs = {kDefaultColumnFamilyName, "one", "two", "three", "four", "five"};
  497. std::vector<ColumnFamilyDescriptor> column_families;
  498. for (size_t i = 0; i < cfs.size(); ++i) {
  499. column_families.emplace_back(cfs[i], options);
  500. }
  501. ASSERT_OK(DB::Open(options, snapshot_name_, column_families, &cphandles,
  502. &snapshotDB));
  503. ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
  504. ASSERT_EQ("Default", result);
  505. ASSERT_OK(snapshotDB->Get(roptions, cphandles[1], "one", &result));
  506. ASSERT_EQ("one", result);
  507. ASSERT_OK(snapshotDB->Get(roptions, cphandles[2], "two", &result));
  508. ASSERT_EQ("two", result);
  509. for (auto h : cphandles) {
  510. delete h;
  511. }
  512. cphandles.clear();
  513. delete snapshotDB;
  514. snapshotDB = nullptr;
  515. }
  516. TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
  517. Options options = CurrentOptions();
  518. options.max_manifest_file_size = 0; // always rollover manifest for file add
  519. Reopen(options);
  520. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
  521. {// Get past the flush in the checkpoint thread before adding any keys to
  522. // the db so the checkpoint thread won't hit the WriteManifest
  523. // syncpoints.
  524. {"CheckpointImpl::CreateCheckpoint:FlushDone",
  525. "CheckpointTest::CurrentFileModifiedWhileCheckpointing:PrePut"},
  526. // Roll the manifest during checkpointing right after live files are
  527. // snapshotted.
  528. {"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
  529. "VersionSet::LogAndApply:WriteManifest"},
  530. {"VersionSet::LogAndApply:WriteManifestDone",
  531. "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"}});
  532. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  533. ROCKSDB_NAMESPACE::port::Thread t([&]() {
  534. Checkpoint* checkpoint;
  535. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  536. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  537. delete checkpoint;
  538. });
  539. TEST_SYNC_POINT(
  540. "CheckpointTest::CurrentFileModifiedWhileCheckpointing:PrePut");
  541. ASSERT_OK(Put("Default", "Default1"));
  542. ASSERT_OK(Flush());
  543. t.join();
  544. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  545. DB* snapshotDB;
  546. // Successful Open() implies that CURRENT pointed to the manifest in the
  547. // checkpoint.
  548. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
  549. delete snapshotDB;
  550. snapshotDB = nullptr;
  551. }
  552. TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
  553. Close();
  554. const std::string dbname = test::PerThreadDBPath("transaction_testdb");
  555. ASSERT_OK(DestroyDB(dbname, CurrentOptions()));
  556. test::DeleteDir(env_, dbname);
  557. Options options = CurrentOptions();
  558. options.allow_2pc = true;
  559. // allow_2pc is implicitly set with tx prepare
  560. // options.allow_2pc = true;
  561. TransactionDBOptions txn_db_options;
  562. TransactionDB* txdb;
  563. Status s = TransactionDB::Open(options, txn_db_options, dbname, &txdb);
  564. ASSERT_OK(s);
  565. ColumnFamilyHandle* cfa;
  566. ColumnFamilyHandle* cfb;
  567. ColumnFamilyOptions cf_options;
  568. ASSERT_OK(txdb->CreateColumnFamily(cf_options, "CFA", &cfa));
  569. WriteOptions write_options;
  570. // Insert something into CFB so lots of log files will be kept
  571. // before creating the checkpoint.
  572. ASSERT_OK(txdb->CreateColumnFamily(cf_options, "CFB", &cfb));
  573. ASSERT_OK(txdb->Put(write_options, cfb, "", ""));
  574. ReadOptions read_options;
  575. std::string value;
  576. TransactionOptions txn_options;
  577. Transaction* txn = txdb->BeginTransaction(write_options, txn_options);
  578. s = txn->SetName("xid");
  579. ASSERT_OK(s);
  580. ASSERT_EQ(txdb->GetTransactionByName("xid"), txn);
  581. s = txn->Put(Slice("foo"), Slice("bar"));
  582. ASSERT_OK(s);
  583. s = txn->Put(cfa, Slice("foocfa"), Slice("barcfa"));
  584. ASSERT_OK(s);
  585. // Writing prepare into middle of first WAL, then flush WALs many times
  586. for (int i = 1; i <= 100000; i++) {
  587. Transaction* tx = txdb->BeginTransaction(write_options, txn_options);
  588. ASSERT_OK(tx->SetName("x"));
  589. ASSERT_OK(tx->Put(Slice(std::to_string(i)), Slice("val")));
  590. ASSERT_OK(tx->Put(cfa, Slice("aaa"), Slice("111")));
  591. ASSERT_OK(tx->Prepare());
  592. ASSERT_OK(tx->Commit());
  593. if (i % 10000 == 0) {
  594. ASSERT_OK(txdb->Flush(FlushOptions()));
  595. }
  596. if (i == 88888) {
  597. ASSERT_OK(txn->Prepare());
  598. }
  599. delete tx;
  600. }
  601. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
  602. {{"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
  603. "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PreCommit"},
  604. {"CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PostCommit",
  605. "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"}});
  606. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  607. ROCKSDB_NAMESPACE::port::Thread t([&]() {
  608. Checkpoint* checkpoint;
  609. ASSERT_OK(Checkpoint::Create(txdb, &checkpoint));
  610. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  611. delete checkpoint;
  612. });
  613. TEST_SYNC_POINT(
  614. "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PreCommit");
  615. ASSERT_OK(txn->Commit());
  616. delete txn;
  617. TEST_SYNC_POINT(
  618. "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PostCommit");
  619. t.join();
  620. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  621. // No more than two logs files should exist.
  622. std::vector<std::string> files;
  623. ASSERT_OK(env_->GetChildren(snapshot_name_, &files));
  624. int num_log_files = 0;
  625. for (auto& file : files) {
  626. uint64_t num;
  627. FileType type;
  628. WalFileType log_type;
  629. if (ParseFileName(file, &num, &type, &log_type) && type == kWalFile) {
  630. num_log_files++;
  631. }
  632. }
  633. // One flush after preapare + one outstanding file before checkpoint + one log
  634. // file generated after checkpoint.
  635. ASSERT_LE(num_log_files, 3);
  636. TransactionDB* snapshotDB;
  637. std::vector<ColumnFamilyDescriptor> column_families;
  638. column_families.emplace_back(kDefaultColumnFamilyName, ColumnFamilyOptions());
  639. column_families.emplace_back("CFA", ColumnFamilyOptions());
  640. column_families.emplace_back("CFB", ColumnFamilyOptions());
  641. std::vector<ROCKSDB_NAMESPACE::ColumnFamilyHandle*> cf_handles;
  642. ASSERT_OK(TransactionDB::Open(options, txn_db_options, snapshot_name_,
  643. column_families, &cf_handles, &snapshotDB));
  644. ASSERT_OK(snapshotDB->Get(read_options, "foo", &value));
  645. ASSERT_EQ(value, "bar");
  646. ASSERT_OK(snapshotDB->Get(read_options, cf_handles[1], "foocfa", &value));
  647. ASSERT_EQ(value, "barcfa");
  648. delete cfa;
  649. delete cfb;
  650. delete cf_handles[0];
  651. delete cf_handles[1];
  652. delete cf_handles[2];
  653. delete snapshotDB;
  654. snapshotDB = nullptr;
  655. delete txdb;
  656. }
  657. TEST_F(CheckpointTest, CheckpointInvalidDirectoryName) {
  658. for (std::string checkpoint_dir : {"", "/", "////"}) {
  659. Checkpoint* checkpoint;
  660. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  661. ASSERT_TRUE(
  662. checkpoint->CreateCheckpoint(checkpoint_dir).IsInvalidArgument());
  663. delete checkpoint;
  664. }
  665. }
  666. TEST_F(CheckpointTest, CheckpointWithParallelWrites) {
  667. // When run with TSAN, this exposes the data race fixed in
  668. // https://github.com/facebook/rocksdb/pull/3603
  669. ASSERT_OK(Put("key1", "val1"));
  670. port::Thread thread([this]() { ASSERT_OK(Put("key2", "val2")); });
  671. Checkpoint* checkpoint;
  672. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  673. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  674. delete checkpoint;
  675. thread.join();
  676. }
  677. class CheckpointTestWithWalParams
  678. : public CheckpointTest,
  679. public testing::WithParamInterface<
  680. std::tuple<uint64_t, bool, bool, bool>> {
  681. public:
  682. uint64_t GetLogSizeForFlush() { return std::get<0>(GetParam()); }
  683. bool GetWalsInManifest() { return std::get<1>(GetParam()); }
  684. bool GetManualWalFlush() { return std::get<2>(GetParam()); }
  685. bool GetBackgroundCloseInactiveWals() { return std::get<3>(GetParam()); }
  686. };
  687. INSTANTIATE_TEST_CASE_P(NormalWalParams, CheckpointTestWithWalParams,
  688. ::testing::Combine(::testing::Values(0U, 100000000U),
  689. ::testing::Bool(), ::testing::Bool(),
  690. ::testing::Values(false)));
  691. INSTANTIATE_TEST_CASE_P(DeprecatedWalParams, CheckpointTestWithWalParams,
  692. ::testing::Values(std::make_tuple(100000000U, true,
  693. false, true)));
  694. TEST_P(CheckpointTestWithWalParams, CheckpointWithUnsyncedDataDropped) {
  695. Options options = CurrentOptions();
  696. options.max_write_buffer_number = 4;
  697. options.track_and_verify_wals_in_manifest = GetWalsInManifest();
  698. options.manual_wal_flush = GetManualWalFlush();
  699. options.background_close_inactive_wals = GetBackgroundCloseInactiveWals();
  700. auto fault_fs = std::make_shared<FaultInjectionTestFS>(FileSystem::Default());
  701. std::unique_ptr<Env> fault_fs_env(NewCompositeEnv(fault_fs));
  702. if (options.background_close_inactive_wals) {
  703. // Disable this hygiene check when the fix is disabled
  704. fault_fs->SetAllowLinkOpenFile();
  705. }
  706. options.env = fault_fs_env.get();
  707. Reopen(options);
  708. ASSERT_OK(Put("key1", "val1"));
  709. if (GetLogSizeForFlush() > 0) {
  710. // When not flushing memtable for checkpoint, this is the simplest way
  711. // to get
  712. // * one inactive WAL, synced
  713. // * one inactive WAL, not synced, and
  714. // * one active WAL, not synced
  715. // with a single thread, so that we have at least one that can be hard
  716. // linked, etc.
  717. ASSERT_OK(static_cast_with_check<DBImpl>(db_)->PauseBackgroundWork());
  718. ASSERT_OK(static_cast_with_check<DBImpl>(db_)->TEST_SwitchMemtable());
  719. ASSERT_OK(db_->SyncWAL());
  720. }
  721. ASSERT_OK(Put("key2", "val2"));
  722. if (GetLogSizeForFlush() > 0) {
  723. ASSERT_OK(static_cast_with_check<DBImpl>(db_)->TEST_SwitchMemtable());
  724. }
  725. ASSERT_OK(Put("key3", "val3"));
  726. Checkpoint* checkpoint;
  727. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  728. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, GetLogSizeForFlush()));
  729. delete checkpoint;
  730. ASSERT_OK(fault_fs->DropUnsyncedFileData());
  731. // make sure it's openable even though whatever data that wasn't synced got
  732. // dropped.
  733. options.env = env_;
  734. DB* snapshot_db;
  735. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
  736. ReadOptions read_opts;
  737. std::string get_result;
  738. ASSERT_OK(snapshot_db->Get(read_opts, "key1", &get_result));
  739. ASSERT_EQ("val1", get_result);
  740. ASSERT_OK(snapshot_db->Get(read_opts, "key2", &get_result));
  741. ASSERT_EQ("val2", get_result);
  742. ASSERT_OK(snapshot_db->Get(read_opts, "key3", &get_result));
  743. ASSERT_EQ("val3", get_result);
  744. delete snapshot_db;
  745. delete db_;
  746. db_ = nullptr;
  747. }
  748. TEST_F(CheckpointTest, CheckpointReadOnlyDB) {
  749. ASSERT_OK(Put("foo", "foo_value"));
  750. ASSERT_OK(Flush());
  751. Close();
  752. Options options = CurrentOptions();
  753. ASSERT_OK(ReadOnlyReopen(options));
  754. Checkpoint* checkpoint = nullptr;
  755. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  756. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  757. delete checkpoint;
  758. checkpoint = nullptr;
  759. Close();
  760. DB* snapshot_db = nullptr;
  761. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
  762. ReadOptions read_opts;
  763. std::string get_result;
  764. ASSERT_OK(snapshot_db->Get(read_opts, "foo", &get_result));
  765. ASSERT_EQ("foo_value", get_result);
  766. delete snapshot_db;
  767. }
  768. TEST_F(CheckpointTest, CheckpointWithLockWAL) {
  769. Options options = CurrentOptions();
  770. ASSERT_OK(Put("foo", "foo_value"));
  771. ASSERT_OK(db_->LockWAL());
  772. Checkpoint* checkpoint = nullptr;
  773. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  774. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  775. delete checkpoint;
  776. checkpoint = nullptr;
  777. ASSERT_OK(db_->UnlockWAL());
  778. Close();
  779. DB* snapshot_db = nullptr;
  780. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
  781. ReadOptions read_opts;
  782. std::string get_result;
  783. ASSERT_OK(snapshot_db->Get(read_opts, "foo", &get_result));
  784. ASSERT_EQ("foo_value", get_result);
  785. delete snapshot_db;
  786. }
  787. TEST_F(CheckpointTest, CheckpointReadOnlyDBWithMultipleColumnFamilies) {
  788. Options options = CurrentOptions();
  789. CreateAndReopenWithCF({"pikachu", "eevee"}, options);
  790. for (int i = 0; i != 3; ++i) {
  791. ASSERT_OK(Put(i, "foo", "foo_value"));
  792. ASSERT_OK(Flush(i));
  793. }
  794. Close();
  795. Status s = ReadOnlyReopenWithColumnFamilies(
  796. {kDefaultColumnFamilyName, "pikachu", "eevee"}, options);
  797. ASSERT_OK(s);
  798. Checkpoint* checkpoint = nullptr;
  799. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  800. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  801. delete checkpoint;
  802. checkpoint = nullptr;
  803. Close();
  804. std::vector<ColumnFamilyDescriptor> column_families{
  805. {kDefaultColumnFamilyName, options},
  806. {"pikachu", options},
  807. {"eevee", options}};
  808. DB* snapshot_db = nullptr;
  809. std::vector<ColumnFamilyHandle*> snapshot_handles;
  810. s = DB::Open(options, snapshot_name_, column_families, &snapshot_handles,
  811. &snapshot_db);
  812. ASSERT_OK(s);
  813. ReadOptions read_opts;
  814. for (int i = 0; i != 3; ++i) {
  815. std::string get_result;
  816. s = snapshot_db->Get(read_opts, snapshot_handles[i], "foo", &get_result);
  817. ASSERT_OK(s);
  818. ASSERT_EQ("foo_value", get_result);
  819. }
  820. for (auto snapshot_h : snapshot_handles) {
  821. delete snapshot_h;
  822. }
  823. snapshot_handles.clear();
  824. delete snapshot_db;
  825. }
  826. TEST_F(CheckpointTest, CheckpointWithDbPath) {
  827. Options options = CurrentOptions();
  828. options.db_paths.emplace_back(dbname_ + "_2", 0);
  829. Reopen(options);
  830. ASSERT_OK(Put("key1", "val1"));
  831. ASSERT_OK(Flush());
  832. Checkpoint* checkpoint;
  833. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  834. // Currently not supported
  835. ASSERT_TRUE(checkpoint->CreateCheckpoint(snapshot_name_).IsNotSupported());
  836. delete checkpoint;
  837. }
  838. TEST_F(CheckpointTest, CheckpointWithArchievedLog) {
  839. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency(
  840. {{"WalManager::ArchiveWALFile",
  841. "CheckpointTest:CheckpointWithArchievedLog"}});
  842. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  843. Options options = CurrentOptions();
  844. options.WAL_ttl_seconds = 3600;
  845. options.disable_auto_compactions = true;
  846. DestroyAndReopen(options);
  847. ASSERT_OK(Put("key1", std::string(1024 * 1024, 'a')));
  848. // flush and archive the first log
  849. ASSERT_OK(Flush());
  850. ASSERT_OK(Put("key2", std::string(1024, 'a')));
  851. Checkpoint* checkpoint;
  852. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  853. TEST_SYNC_POINT("CheckpointTest:CheckpointWithArchievedLog");
  854. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, 1024 * 1024));
  855. // unflushed log size < 1024 * 1024 < total file size including archived log,
  856. // so flush shouldn't occur, there is only one file at level 0
  857. ASSERT_EQ(NumTableFilesAtLevel(0), 1);
  858. delete checkpoint;
  859. checkpoint = nullptr;
  860. DB* snapshot_db;
  861. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
  862. ReadOptions read_opts;
  863. std::string get_result;
  864. ASSERT_OK(snapshot_db->Get(read_opts, "key1", &get_result));
  865. ASSERT_EQ(std::string(1024 * 1024, 'a'), get_result);
  866. get_result.clear();
  867. ASSERT_OK(snapshot_db->Get(read_opts, "key2", &get_result));
  868. ASSERT_EQ(std::string(1024, 'a'), get_result);
  869. delete snapshot_db;
  870. }
  871. class CheckpointDestroyTest : public CheckpointTest,
  872. public testing::WithParamInterface<bool> {};
  873. TEST_P(CheckpointDestroyTest, DisableEnableSlowDeletion) {
  874. bool slow_deletion = GetParam();
  875. Options options = CurrentOptions();
  876. options.num_levels = 2;
  877. options.disable_auto_compactions = true;
  878. Status s;
  879. options.sst_file_manager.reset(NewSstFileManager(
  880. options.env, options.info_log, "", slow_deletion ? 1024 * 1024 : 0,
  881. false /* delete_existing_trash */, &s, 1));
  882. ASSERT_OK(s);
  883. DestroyAndReopen(options);
  884. ASSERT_OK(Put("foo", "a"));
  885. ASSERT_OK(Flush());
  886. ASSERT_OK(Put("bar", "b"));
  887. ASSERT_OK(Flush());
  888. ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  889. for (int i = 0; i < 10; i++) {
  890. ASSERT_OK(Put("bar", "val" + std::to_string(i)));
  891. ASSERT_OK(Flush());
  892. }
  893. ASSERT_EQ(NumTableFilesAtLevel(0), 10);
  894. ASSERT_EQ(NumTableFilesAtLevel(1), 2);
  895. Checkpoint* checkpoint;
  896. ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
  897. ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
  898. delete checkpoint;
  899. checkpoint = nullptr;
  900. ASSERT_OK(db_->CompactRange(CompactRangeOptions(), nullptr, nullptr));
  901. ASSERT_EQ(NumTableFilesAtLevel(0), 0);
  902. ASSERT_EQ(NumTableFilesAtLevel(1), 2);
  903. DB* snapshot_db;
  904. ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
  905. ReadOptions read_opts;
  906. std::string get_result;
  907. ASSERT_OK(snapshot_db->Get(read_opts, "foo", &get_result));
  908. ASSERT_EQ("a", get_result);
  909. ASSERT_OK(snapshot_db->Get(read_opts, "bar", &get_result));
  910. ASSERT_EQ("val9", get_result);
  911. delete snapshot_db;
  912. // Make sure original obsolete files for hard linked files are all deleted.
  913. DBImpl* db_impl = static_cast_with_check<DBImpl>(db_);
  914. db_impl->TEST_DeleteObsoleteFiles();
  915. auto sfm = static_cast_with_check<SstFileManagerImpl>(
  916. options.sst_file_manager.get());
  917. ASSERT_NE(nullptr, sfm);
  918. sfm->WaitForEmptyTrash();
  919. // SST file 2-12 for "bar" will be compacted into one file on L1 during the
  920. // compaction after checkpoint is created. SST file 1 on L1: foo, seq:
  921. // 1 (hard links is 1 after checkpoint destroy)
  922. std::atomic<int> bg_delete_sst{0};
  923. std::atomic<int> fg_delete_sst{0};
  924. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  925. "DeleteScheduler::DeleteFile::cb", [&](void* arg) {
  926. ASSERT_NE(nullptr, arg);
  927. auto file_name = *static_cast<std::string*>(arg);
  928. if (file_name.size() >= 4 &&
  929. file_name.compare(file_name.size() - 4, 4, ".sst") == 0) {
  930. fg_delete_sst.fetch_add(1);
  931. }
  932. });
  933. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
  934. "DeleteScheduler::DeleteTrashFile::cb", [&](void* arg) {
  935. ASSERT_NE(nullptr, arg);
  936. auto file_name = *static_cast<std::string*>(arg);
  937. if (file_name.size() >= 10 &&
  938. file_name.compare(file_name.size() - 10, 10, ".sst.trash") == 0) {
  939. bg_delete_sst.fetch_add(1);
  940. }
  941. });
  942. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
  943. ASSERT_OK(DestroyDB(snapshot_name_, options));
  944. if (slow_deletion) {
  945. ASSERT_EQ(fg_delete_sst, 1);
  946. ASSERT_EQ(bg_delete_sst, 11);
  947. } else {
  948. ASSERT_EQ(fg_delete_sst, 12);
  949. }
  950. ASSERT_EQ("a", Get("foo"));
  951. ASSERT_EQ("val9", Get("bar"));
  952. ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
  953. }
  954. INSTANTIATE_TEST_CASE_P(CheckpointDestroyTest, CheckpointDestroyTest,
  955. ::testing::Values(true, false));
  956. } // namespace ROCKSDB_NAMESPACE
  957. int main(int argc, char** argv) {
  958. ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
  959. ::testing::InitGoogleTest(&argc, argv);
  960. return RUN_ALL_TESTS();
  961. }