]> git.proxmox.com Git - ceph.git/blob - 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
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
10 // Syncpoint prevents us building and running tests in release
11 #ifndef ROCKSDB_LITE
12
13 #ifndef OS_WIN
14 #include <unistd.h>
15 #endif
16 #include <iostream>
17 #include <thread>
18 #include <utility>
19 #include "db/db_impl.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/utilities/checkpoint.h"
25 #include "rocksdb/utilities/transaction_db.h"
26 #include "util/fault_injection_test_env.h"
27 #include "util/sync_point.h"
28 #include "util/testharness.h"
29
30 namespace rocksdb {
31 class CheckpointTest : public testing::Test {
32 protected:
33 // Sequence of option configurations to try
34 enum OptionConfig {
35 kDefault = 0,
36 };
37 int option_config_;
38
39 public:
40 std::string dbname_;
41 std::string alternative_wal_dir_;
42 Env* env_;
43 DB* db_;
44 Options last_options_;
45 std::vector<ColumnFamilyHandle*> handles_;
46 std::string snapshot_name_;
47
48 CheckpointTest() : env_(Env::Default()) {
49 env_->SetBackgroundThreads(1, Env::LOW);
50 env_->SetBackgroundThreads(1, Env::HIGH);
51 dbname_ = test::PerThreadDBPath(env_, "checkpoint_test");
52 alternative_wal_dir_ = dbname_ + "/wal";
53 auto options = CurrentOptions();
54 auto delete_options = options;
55 delete_options.wal_dir = alternative_wal_dir_;
56 EXPECT_OK(DestroyDB(dbname_, delete_options));
57 // Destroy it for not alternative WAL dir is used.
58 EXPECT_OK(DestroyDB(dbname_, options));
59 db_ = nullptr;
60 snapshot_name_ = test::PerThreadDBPath(env_, "snapshot");
61 std::string snapshot_tmp_name = snapshot_name_ + ".tmp";
62 EXPECT_OK(DestroyDB(snapshot_name_, options));
63 env_->DeleteDir(snapshot_name_);
64 EXPECT_OK(DestroyDB(snapshot_tmp_name, options));
65 env_->DeleteDir(snapshot_tmp_name);
66 Reopen(options);
67 }
68
69 ~CheckpointTest() {
70 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
71 rocksdb::SyncPoint::GetInstance()->LoadDependency({});
72 rocksdb::SyncPoint::GetInstance()->ClearAllCallBacks();
73 Close();
74 Options options;
75 options.db_paths.emplace_back(dbname_, 0);
76 options.db_paths.emplace_back(dbname_ + "_2", 0);
77 options.db_paths.emplace_back(dbname_ + "_3", 0);
78 options.db_paths.emplace_back(dbname_ + "_4", 0);
79 EXPECT_OK(DestroyDB(dbname_, options));
80 EXPECT_OK(DestroyDB(snapshot_name_, options));
81 }
82
83 // Return the current option configuration.
84 Options CurrentOptions() {
85 Options options;
86 options.env = env_;
87 options.create_if_missing = true;
88 return options;
89 }
90
91 void CreateColumnFamilies(const std::vector<std::string>& cfs,
92 const Options& options) {
93 ColumnFamilyOptions cf_opts(options);
94 size_t cfi = handles_.size();
95 handles_.resize(cfi + cfs.size());
96 for (auto cf : cfs) {
97 ASSERT_OK(db_->CreateColumnFamily(cf_opts, cf, &handles_[cfi++]));
98 }
99 }
100
101 void CreateAndReopenWithCF(const std::vector<std::string>& cfs,
102 const Options& options) {
103 CreateColumnFamilies(cfs, options);
104 std::vector<std::string> cfs_plus_default = cfs;
105 cfs_plus_default.insert(cfs_plus_default.begin(), kDefaultColumnFamilyName);
106 ReopenWithColumnFamilies(cfs_plus_default, options);
107 }
108
109 void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
110 const std::vector<Options>& options) {
111 ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
112 }
113
114 void ReopenWithColumnFamilies(const std::vector<std::string>& cfs,
115 const Options& options) {
116 ASSERT_OK(TryReopenWithColumnFamilies(cfs, options));
117 }
118
119 Status TryReopenWithColumnFamilies(
120 const std::vector<std::string>& cfs,
121 const std::vector<Options>& options) {
122 Close();
123 EXPECT_EQ(cfs.size(), options.size());
124 std::vector<ColumnFamilyDescriptor> column_families;
125 for (size_t i = 0; i < cfs.size(); ++i) {
126 column_families.push_back(ColumnFamilyDescriptor(cfs[i], options[i]));
127 }
128 DBOptions db_opts = DBOptions(options[0]);
129 return DB::Open(db_opts, dbname_, column_families, &handles_, &db_);
130 }
131
132 Status TryReopenWithColumnFamilies(const std::vector<std::string>& cfs,
133 const Options& options) {
134 Close();
135 std::vector<Options> v_opts(cfs.size(), options);
136 return TryReopenWithColumnFamilies(cfs, v_opts);
137 }
138
139 void Reopen(const Options& options) {
140 ASSERT_OK(TryReopen(options));
141 }
142
143 void Close() {
144 for (auto h : handles_) {
145 delete h;
146 }
147 handles_.clear();
148 delete db_;
149 db_ = nullptr;
150 }
151
152 void DestroyAndReopen(const Options& options) {
153 // Destroy using last options
154 Destroy(last_options_);
155 ASSERT_OK(TryReopen(options));
156 }
157
158 void Destroy(const Options& options) {
159 Close();
160 ASSERT_OK(DestroyDB(dbname_, options));
161 }
162
163 Status ReadOnlyReopen(const Options& options) {
164 return DB::OpenForReadOnly(options, dbname_, &db_);
165 }
166
167 Status TryReopen(const Options& options) {
168 Close();
169 last_options_ = options;
170 return DB::Open(options, dbname_, &db_);
171 }
172
173 Status Flush(int cf = 0) {
174 if (cf == 0) {
175 return db_->Flush(FlushOptions());
176 } else {
177 return db_->Flush(FlushOptions(), handles_[cf]);
178 }
179 }
180
181 Status Put(const Slice& k, const Slice& v, WriteOptions wo = WriteOptions()) {
182 return db_->Put(wo, k, v);
183 }
184
185 Status Put(int cf, const Slice& k, const Slice& v,
186 WriteOptions wo = WriteOptions()) {
187 return db_->Put(wo, handles_[cf], k, v);
188 }
189
190 Status Delete(const std::string& k) {
191 return db_->Delete(WriteOptions(), k);
192 }
193
194 Status Delete(int cf, const std::string& k) {
195 return db_->Delete(WriteOptions(), handles_[cf], k);
196 }
197
198 std::string Get(const std::string& k, const Snapshot* snapshot = nullptr) {
199 ReadOptions options;
200 options.verify_checksums = true;
201 options.snapshot = snapshot;
202 std::string result;
203 Status s = db_->Get(options, k, &result);
204 if (s.IsNotFound()) {
205 result = "NOT_FOUND";
206 } else if (!s.ok()) {
207 result = s.ToString();
208 }
209 return result;
210 }
211
212 std::string Get(int cf, const std::string& k,
213 const Snapshot* snapshot = nullptr) {
214 ReadOptions options;
215 options.verify_checksums = true;
216 options.snapshot = snapshot;
217 std::string result;
218 Status s = db_->Get(options, handles_[cf], k, &result);
219 if (s.IsNotFound()) {
220 result = "NOT_FOUND";
221 } else if (!s.ok()) {
222 result = s.ToString();
223 }
224 return result;
225 }
226 };
227
228 TEST_F(CheckpointTest, GetSnapshotLink) {
229 for (uint64_t log_size_for_flush : {0, 1000000}) {
230 Options options;
231 DB* snapshotDB;
232 ReadOptions roptions;
233 std::string result;
234 Checkpoint* checkpoint;
235
236 options = CurrentOptions();
237 delete db_;
238 db_ = nullptr;
239 ASSERT_OK(DestroyDB(dbname_, options));
240
241 // Create a database
242 Status s;
243 options.create_if_missing = true;
244 ASSERT_OK(DB::Open(options, dbname_, &db_));
245 std::string key = std::string("foo");
246 ASSERT_OK(Put(key, "v1"));
247 // Take a snapshot
248 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
249 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, log_size_for_flush));
250 ASSERT_OK(Put(key, "v2"));
251 ASSERT_EQ("v2", Get(key));
252 ASSERT_OK(Flush());
253 ASSERT_EQ("v2", Get(key));
254 // Open snapshot and verify contents while DB is running
255 options.create_if_missing = false;
256 ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
257 ASSERT_OK(snapshotDB->Get(roptions, key, &result));
258 ASSERT_EQ("v1", result);
259 delete snapshotDB;
260 snapshotDB = nullptr;
261 delete db_;
262 db_ = nullptr;
263
264 // Destroy original DB
265 ASSERT_OK(DestroyDB(dbname_, options));
266
267 // Open snapshot and verify contents
268 options.create_if_missing = false;
269 dbname_ = snapshot_name_;
270 ASSERT_OK(DB::Open(options, dbname_, &db_));
271 ASSERT_EQ("v1", Get(key));
272 delete db_;
273 db_ = nullptr;
274 ASSERT_OK(DestroyDB(dbname_, options));
275 delete checkpoint;
276
277 // Restore DB name
278 dbname_ = test::PerThreadDBPath(env_, "db_test");
279 }
280 }
281
282 TEST_F(CheckpointTest, CheckpointCF) {
283 Options options = CurrentOptions();
284 CreateAndReopenWithCF({"one", "two", "three", "four", "five"}, options);
285 rocksdb::SyncPoint::GetInstance()->LoadDependency(
286 {{"CheckpointTest::CheckpointCF:2", "DBImpl::GetLiveFiles:2"},
287 {"DBImpl::GetLiveFiles:1", "CheckpointTest::CheckpointCF:1"}});
288
289 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
290
291 ASSERT_OK(Put(0, "Default", "Default"));
292 ASSERT_OK(Put(1, "one", "one"));
293 ASSERT_OK(Put(2, "two", "two"));
294 ASSERT_OK(Put(3, "three", "three"));
295 ASSERT_OK(Put(4, "four", "four"));
296 ASSERT_OK(Put(5, "five", "five"));
297
298 DB* snapshotDB;
299 ReadOptions roptions;
300 std::string result;
301 std::vector<ColumnFamilyHandle*> cphandles;
302
303 Status s;
304 // Take a snapshot
305 rocksdb::port::Thread t([&]() {
306 Checkpoint* checkpoint;
307 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
308 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
309 delete checkpoint;
310 });
311 TEST_SYNC_POINT("CheckpointTest::CheckpointCF:1");
312 ASSERT_OK(Put(0, "Default", "Default1"));
313 ASSERT_OK(Put(1, "one", "eleven"));
314 ASSERT_OK(Put(2, "two", "twelve"));
315 ASSERT_OK(Put(3, "three", "thirteen"));
316 ASSERT_OK(Put(4, "four", "fourteen"));
317 ASSERT_OK(Put(5, "five", "fifteen"));
318 TEST_SYNC_POINT("CheckpointTest::CheckpointCF:2");
319 t.join();
320 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
321 ASSERT_OK(Put(1, "one", "twentyone"));
322 ASSERT_OK(Put(2, "two", "twentytwo"));
323 ASSERT_OK(Put(3, "three", "twentythree"));
324 ASSERT_OK(Put(4, "four", "twentyfour"));
325 ASSERT_OK(Put(5, "five", "twentyfive"));
326 ASSERT_OK(Flush());
327
328 // Open snapshot and verify contents while DB is running
329 options.create_if_missing = false;
330 std::vector<std::string> cfs;
331 cfs= {kDefaultColumnFamilyName, "one", "two", "three", "four", "five"};
332 std::vector<ColumnFamilyDescriptor> column_families;
333 for (size_t i = 0; i < cfs.size(); ++i) {
334 column_families.push_back(ColumnFamilyDescriptor(cfs[i], options));
335 }
336 ASSERT_OK(DB::Open(options, snapshot_name_,
337 column_families, &cphandles, &snapshotDB));
338 ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
339 ASSERT_EQ("Default1", result);
340 ASSERT_OK(snapshotDB->Get(roptions, cphandles[1], "one", &result));
341 ASSERT_EQ("eleven", result);
342 ASSERT_OK(snapshotDB->Get(roptions, cphandles[2], "two", &result));
343 for (auto h : cphandles) {
344 delete h;
345 }
346 cphandles.clear();
347 delete snapshotDB;
348 snapshotDB = nullptr;
349 }
350
351 TEST_F(CheckpointTest, CheckpointCFNoFlush) {
352 Options options = CurrentOptions();
353 CreateAndReopenWithCF({"one", "two", "three", "four", "five"}, options);
354
355 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
356
357 ASSERT_OK(Put(0, "Default", "Default"));
358 ASSERT_OK(Put(1, "one", "one"));
359 Flush();
360 ASSERT_OK(Put(2, "two", "two"));
361
362 DB* snapshotDB;
363 ReadOptions roptions;
364 std::string result;
365 std::vector<ColumnFamilyHandle*> cphandles;
366
367 Status s;
368 // Take a snapshot
369 rocksdb::SyncPoint::GetInstance()->SetCallBack(
370 "DBImpl::BackgroundCallFlush:start", [&](void* /*arg*/) {
371 // Flush should never trigger.
372 FAIL();
373 });
374 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
375 Checkpoint* checkpoint;
376 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
377 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_, 1000000));
378 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
379
380 delete checkpoint;
381 ASSERT_OK(Put(1, "one", "two"));
382 ASSERT_OK(Flush(1));
383 ASSERT_OK(Put(2, "two", "twentytwo"));
384 Close();
385 EXPECT_OK(DestroyDB(dbname_, options));
386
387 // Open snapshot and verify contents while DB is running
388 options.create_if_missing = false;
389 std::vector<std::string> cfs;
390 cfs = {kDefaultColumnFamilyName, "one", "two", "three", "four", "five"};
391 std::vector<ColumnFamilyDescriptor> column_families;
392 for (size_t i = 0; i < cfs.size(); ++i) {
393 column_families.push_back(ColumnFamilyDescriptor(cfs[i], options));
394 }
395 ASSERT_OK(DB::Open(options, snapshot_name_, column_families, &cphandles,
396 &snapshotDB));
397 ASSERT_OK(snapshotDB->Get(roptions, cphandles[0], "Default", &result));
398 ASSERT_EQ("Default", result);
399 ASSERT_OK(snapshotDB->Get(roptions, cphandles[1], "one", &result));
400 ASSERT_EQ("one", result);
401 ASSERT_OK(snapshotDB->Get(roptions, cphandles[2], "two", &result));
402 ASSERT_EQ("two", result);
403 for (auto h : cphandles) {
404 delete h;
405 }
406 cphandles.clear();
407 delete snapshotDB;
408 snapshotDB = nullptr;
409 }
410
411 TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing) {
412 Options options = CurrentOptions();
413 options.max_manifest_file_size = 0; // always rollover manifest for file add
414 Reopen(options);
415
416 rocksdb::SyncPoint::GetInstance()->LoadDependency(
417 {// Get past the flush in the checkpoint thread before adding any keys to
418 // the db so the checkpoint thread won't hit the WriteManifest
419 // syncpoints.
420 {"DBImpl::GetLiveFiles:1",
421 "CheckpointTest::CurrentFileModifiedWhileCheckpointing:PrePut"},
422 // Roll the manifest during checkpointing right after live files are
423 // snapshotted.
424 {"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
425 "VersionSet::LogAndApply:WriteManifest"},
426 {"VersionSet::LogAndApply:WriteManifestDone",
427 "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"}});
428 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
429
430 rocksdb::port::Thread t([&]() {
431 Checkpoint* checkpoint;
432 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
433 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
434 delete checkpoint;
435 });
436 TEST_SYNC_POINT(
437 "CheckpointTest::CurrentFileModifiedWhileCheckpointing:PrePut");
438 ASSERT_OK(Put("Default", "Default1"));
439 ASSERT_OK(Flush());
440 t.join();
441
442 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
443
444 DB* snapshotDB;
445 // Successful Open() implies that CURRENT pointed to the manifest in the
446 // checkpoint.
447 ASSERT_OK(DB::Open(options, snapshot_name_, &snapshotDB));
448 delete snapshotDB;
449 snapshotDB = nullptr;
450 }
451
452 TEST_F(CheckpointTest, CurrentFileModifiedWhileCheckpointing2PC) {
453 Close();
454 const std::string dbname = test::PerThreadDBPath("transaction_testdb");
455 ASSERT_OK(DestroyDB(dbname, CurrentOptions()));
456 env_->DeleteDir(dbname);
457
458 Options options = CurrentOptions();
459 options.allow_2pc = true;
460 // allow_2pc is implicitly set with tx prepare
461 // options.allow_2pc = true;
462 TransactionDBOptions txn_db_options;
463 TransactionDB* txdb;
464 Status s = TransactionDB::Open(options, txn_db_options, dbname, &txdb);
465 assert(s.ok());
466 ColumnFamilyHandle* cfa;
467 ColumnFamilyHandle* cfb;
468 ColumnFamilyOptions cf_options;
469 ASSERT_OK(txdb->CreateColumnFamily(cf_options, "CFA", &cfa));
470
471 WriteOptions write_options;
472 // Insert something into CFB so lots of log files will be kept
473 // before creating the checkpoint.
474 ASSERT_OK(txdb->CreateColumnFamily(cf_options, "CFB", &cfb));
475 ASSERT_OK(txdb->Put(write_options, cfb, "", ""));
476
477 ReadOptions read_options;
478 std::string value;
479 TransactionOptions txn_options;
480 Transaction* txn = txdb->BeginTransaction(write_options, txn_options);
481 s = txn->SetName("xid");
482 ASSERT_OK(s);
483 ASSERT_EQ(txdb->GetTransactionByName("xid"), txn);
484
485 s = txn->Put(Slice("foo"), Slice("bar"));
486 s = txn->Put(cfa, Slice("foocfa"), Slice("barcfa"));
487 ASSERT_OK(s);
488 // Writing prepare into middle of first WAL, then flush WALs many times
489 for (int i = 1; i <= 100000; i++) {
490 Transaction* tx = txdb->BeginTransaction(write_options, txn_options);
491 ASSERT_OK(tx->SetName("x"));
492 ASSERT_OK(tx->Put(Slice(std::to_string(i)), Slice("val")));
493 ASSERT_OK(tx->Put(cfa, Slice("aaa"), Slice("111")));
494 ASSERT_OK(tx->Prepare());
495 ASSERT_OK(tx->Commit());
496 if (i % 10000 == 0) {
497 txdb->Flush(FlushOptions());
498 }
499 if (i == 88888) {
500 ASSERT_OK(txn->Prepare());
501 }
502 delete tx;
503 }
504 rocksdb::SyncPoint::GetInstance()->LoadDependency(
505 {{"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
506 "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PreCommit"},
507 {"CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PostCommit",
508 "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"}});
509 rocksdb::SyncPoint::GetInstance()->EnableProcessing();
510 rocksdb::port::Thread t([&]() {
511 Checkpoint* checkpoint;
512 ASSERT_OK(Checkpoint::Create(txdb, &checkpoint));
513 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
514 delete checkpoint;
515 });
516 TEST_SYNC_POINT(
517 "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PreCommit");
518 ASSERT_OK(txn->Commit());
519 delete txn;
520 TEST_SYNC_POINT(
521 "CheckpointTest::CurrentFileModifiedWhileCheckpointing2PC:PostCommit");
522 t.join();
523
524 rocksdb::SyncPoint::GetInstance()->DisableProcessing();
525
526 // No more than two logs files should exist.
527 std::vector<std::string> files;
528 env_->GetChildren(snapshot_name_, &files);
529 int num_log_files = 0;
530 for (auto& file : files) {
531 uint64_t num;
532 FileType type;
533 WalFileType log_type;
534 if (ParseFileName(file, &num, &type, &log_type) && type == kLogFile) {
535 num_log_files++;
536 }
537 }
538 // One flush after preapare + one outstanding file before checkpoint + one log
539 // file generated after checkpoint.
540 ASSERT_LE(num_log_files, 3);
541
542 TransactionDB* snapshotDB;
543 std::vector<ColumnFamilyDescriptor> column_families;
544 column_families.push_back(
545 ColumnFamilyDescriptor(kDefaultColumnFamilyName, ColumnFamilyOptions()));
546 column_families.push_back(
547 ColumnFamilyDescriptor("CFA", ColumnFamilyOptions()));
548 column_families.push_back(
549 ColumnFamilyDescriptor("CFB", ColumnFamilyOptions()));
550 std::vector<rocksdb::ColumnFamilyHandle*> cf_handles;
551 ASSERT_OK(TransactionDB::Open(options, txn_db_options, snapshot_name_,
552 column_families, &cf_handles, &snapshotDB));
553 ASSERT_OK(snapshotDB->Get(read_options, "foo", &value));
554 ASSERT_EQ(value, "bar");
555 ASSERT_OK(snapshotDB->Get(read_options, cf_handles[1], "foocfa", &value));
556 ASSERT_EQ(value, "barcfa");
557
558 delete cfa;
559 delete cfb;
560 delete cf_handles[0];
561 delete cf_handles[1];
562 delete cf_handles[2];
563 delete snapshotDB;
564 snapshotDB = nullptr;
565 delete txdb;
566 }
567
568 TEST_F(CheckpointTest, CheckpointInvalidDirectoryName) {
569 for (std::string checkpoint_dir : {"", "/", "////"}) {
570 Checkpoint* checkpoint;
571 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
572 ASSERT_TRUE(checkpoint->CreateCheckpoint("").IsInvalidArgument());
573 delete checkpoint;
574 }
575 }
576
577 TEST_F(CheckpointTest, CheckpointWithParallelWrites) {
578 // When run with TSAN, this exposes the data race fixed in
579 // https://github.com/facebook/rocksdb/pull/3603
580 ASSERT_OK(Put("key1", "val1"));
581 port::Thread thread([this]() { ASSERT_OK(Put("key2", "val2")); });
582 Checkpoint* checkpoint;
583 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
584 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
585 delete checkpoint;
586 thread.join();
587 }
588
589 TEST_F(CheckpointTest, CheckpointWithUnsyncedDataDropped) {
590 Options options = CurrentOptions();
591 std::unique_ptr<FaultInjectionTestEnv> env(new FaultInjectionTestEnv(env_));
592 options.env = env.get();
593 Reopen(options);
594 ASSERT_OK(Put("key1", "val1"));
595 Checkpoint* checkpoint;
596 ASSERT_OK(Checkpoint::Create(db_, &checkpoint));
597 ASSERT_OK(checkpoint->CreateCheckpoint(snapshot_name_));
598 delete checkpoint;
599 env->DropUnsyncedFileData();
600
601 // make sure it's openable even though whatever data that wasn't synced got
602 // dropped.
603 options.env = env_;
604 DB* snapshot_db;
605 ASSERT_OK(DB::Open(options, snapshot_name_, &snapshot_db));
606 ReadOptions read_opts;
607 std::string get_result;
608 ASSERT_OK(snapshot_db->Get(read_opts, "key1", &get_result));
609 ASSERT_EQ("val1", get_result);
610 delete snapshot_db;
611 delete db_;
612 db_ = nullptr;
613 }
614
615 } // namespace rocksdb
616
617 int main(int argc, char** argv) {
618 rocksdb::port::InstallStackTraceHandler();
619 ::testing::InitGoogleTest(&argc, argv);
620 return RUN_ALL_TESTS();
621 }
622
623 #else
624 #include <stdio.h>
625
626 int main(int /*argc*/, char** /*argv*/) {
627 fprintf(stderr, "SKIPPED as Checkpoint is not supported in ROCKSDB_LITE\n");
628 return 0;
629 }
630
631 #endif // !ROCKSDB_LITE