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 #if !defined(ROCKSDB_LITE) && !defined(OS_WIN)
11 
12 #include <algorithm>
13 #include <limits>
14 #include <string>
15 #include <utility>
16 
17 #include "db/db_impl/db_impl.h"
18 #include "env/env_chroot.h"
19 #include "file/filename.h"
20 #include "port/port.h"
21 #include "port/stack_trace.h"
22 #include "rocksdb/rate_limiter.h"
23 #include "rocksdb/transaction_log.h"
24 #include "rocksdb/types.h"
25 #include "rocksdb/utilities/backupable_db.h"
26 #include "rocksdb/utilities/options_util.h"
27 #include "test_util/sync_point.h"
28 #include "test_util/testharness.h"
29 #include "test_util/testutil.h"
30 #include "util/mutexlock.h"
31 #include "util/random.h"
32 #include "util/stderr_logger.h"
33 #include "util/string_util.h"
34 
35 namespace ROCKSDB_NAMESPACE {
36 
37 namespace {
38 
39 class DummyDB : public StackableDB {
40  public:
41   /* implicit */
DummyDB(const Options & options,const std::string & dbname)42   DummyDB(const Options& options, const std::string& dbname)
43      : StackableDB(nullptr), options_(options), dbname_(dbname),
44        deletions_enabled_(true), sequence_number_(0) {}
45 
GetLatestSequenceNumber() const46   SequenceNumber GetLatestSequenceNumber() const override {
47     return ++sequence_number_;
48   }
49 
GetName() const50   const std::string& GetName() const override { return dbname_; }
51 
GetEnv() const52   Env* GetEnv() const override { return options_.env; }
53 
54   using DB::GetOptions;
GetOptions(ColumnFamilyHandle *) const55   Options GetOptions(ColumnFamilyHandle* /*column_family*/) const override {
56     return options_;
57   }
58 
GetDBOptions() const59   DBOptions GetDBOptions() const override { return DBOptions(options_); }
60 
EnableFileDeletions(bool)61   Status EnableFileDeletions(bool /*force*/) override {
62     EXPECT_TRUE(!deletions_enabled_);
63     deletions_enabled_ = true;
64     return Status::OK();
65   }
66 
DisableFileDeletions()67   Status DisableFileDeletions() override {
68     EXPECT_TRUE(deletions_enabled_);
69     deletions_enabled_ = false;
70     return Status::OK();
71   }
72 
GetLiveFiles(std::vector<std::string> & vec,uint64_t * mfs,bool=true)73   Status GetLiveFiles(std::vector<std::string>& vec, uint64_t* mfs,
74                       bool /*flush_memtable*/ = true) override {
75     EXPECT_TRUE(!deletions_enabled_);
76     vec = live_files_;
77     *mfs = 100;
78     return Status::OK();
79   }
80 
DefaultColumnFamily() const81   ColumnFamilyHandle* DefaultColumnFamily() const override { return nullptr; }
82 
83   class DummyLogFile : public LogFile {
84    public:
85     /* implicit */
DummyLogFile(const std::string & path,bool alive=true)86      DummyLogFile(const std::string& path, bool alive = true)
87          : path_(path), alive_(alive) {}
88 
PathName() const89      std::string PathName() const override { return path_; }
90 
LogNumber() const91      uint64_t LogNumber() const override {
92        // what business do you have calling this method?
93        ADD_FAILURE();
94        return 0;
95      }
96 
Type() const97      WalFileType Type() const override {
98        return alive_ ? kAliveLogFile : kArchivedLogFile;
99      }
100 
StartSequence() const101      SequenceNumber StartSequence() const override {
102        // this seqnum guarantees the dummy file will be included in the backup
103        // as long as it is alive.
104        return kMaxSequenceNumber;
105      }
106 
SizeFileBytes() const107      uint64_t SizeFileBytes() const override { return 0; }
108 
109     private:
110      std::string path_;
111      bool alive_;
112   }; // DummyLogFile
113 
GetSortedWalFiles(VectorLogPtr & files)114   Status GetSortedWalFiles(VectorLogPtr& files) override {
115     EXPECT_TRUE(!deletions_enabled_);
116     files.resize(wal_files_.size());
117     for (size_t i = 0; i < files.size(); ++i) {
118       files[i].reset(
119           new DummyLogFile(wal_files_[i].first, wal_files_[i].second));
120     }
121     return Status::OK();
122   }
123 
124   // To avoid FlushWAL called on stacked db which is nullptr
FlushWAL(bool)125   Status FlushWAL(bool /*sync*/) override { return Status::OK(); }
126 
127   std::vector<std::string> live_files_;
128   // pair<filename, alive?>
129   std::vector<std::pair<std::string, bool>> wal_files_;
130  private:
131   Options options_;
132   std::string dbname_;
133   bool deletions_enabled_;
134   mutable SequenceNumber sequence_number_;
135 }; // DummyDB
136 
137 class TestEnv : public EnvWrapper {
138  public:
TestEnv(Env * t)139   explicit TestEnv(Env* t) : EnvWrapper(t) {}
140 
141   class DummySequentialFile : public SequentialFile {
142    public:
DummySequentialFile(bool fail_reads)143     explicit DummySequentialFile(bool fail_reads)
144         : SequentialFile(), rnd_(5), fail_reads_(fail_reads) {}
Read(size_t n,Slice * result,char * scratch)145     Status Read(size_t n, Slice* result, char* scratch) override {
146       if (fail_reads_) {
147         return Status::IOError();
148       }
149       size_t read_size = (n > size_left) ? size_left : n;
150       for (size_t i = 0; i < read_size; ++i) {
151         scratch[i] = rnd_.Next() & 255;
152       }
153       *result = Slice(scratch, read_size);
154       size_left -= read_size;
155       return Status::OK();
156     }
157 
Skip(uint64_t n)158     Status Skip(uint64_t n) override {
159       size_left = (n > size_left) ? size_left - n : 0;
160       return Status::OK();
161     }
162 
163    private:
164     size_t size_left = 200;
165     Random rnd_;
166     bool fail_reads_;
167   };
168 
NewSequentialFile(const std::string & f,std::unique_ptr<SequentialFile> * r,const EnvOptions & options)169   Status NewSequentialFile(const std::string& f,
170                            std::unique_ptr<SequentialFile>* r,
171                            const EnvOptions& options) override {
172     MutexLock l(&mutex_);
173     if (dummy_sequential_file_) {
174       r->reset(
175           new TestEnv::DummySequentialFile(dummy_sequential_file_fail_reads_));
176       return Status::OK();
177     } else {
178       Status s = EnvWrapper::NewSequentialFile(f, r, options);
179       if (s.ok()) {
180         if ((*r)->use_direct_io()) {
181           ++num_direct_seq_readers_;
182         }
183         ++num_seq_readers_;
184       }
185       return s;
186     }
187   }
188 
NewWritableFile(const std::string & f,std::unique_ptr<WritableFile> * r,const EnvOptions & options)189   Status NewWritableFile(const std::string& f, std::unique_ptr<WritableFile>* r,
190                          const EnvOptions& options) override {
191     MutexLock l(&mutex_);
192     written_files_.push_back(f);
193     if (limit_written_files_ <= 0) {
194       return Status::NotSupported("Sorry, can't do this");
195     }
196     limit_written_files_--;
197     Status s = EnvWrapper::NewWritableFile(f, r, options);
198     if (s.ok()) {
199       if ((*r)->use_direct_io()) {
200         ++num_direct_writers_;
201       }
202       ++num_writers_;
203     }
204     return s;
205   }
206 
NewRandomAccessFile(const std::string & fname,std::unique_ptr<RandomAccessFile> * result,const EnvOptions & options)207   Status NewRandomAccessFile(const std::string& fname,
208                              std::unique_ptr<RandomAccessFile>* result,
209                              const EnvOptions& options) override {
210     MutexLock l(&mutex_);
211     Status s = EnvWrapper::NewRandomAccessFile(fname, result, options);
212     if (s.ok()) {
213       if ((*result)->use_direct_io()) {
214         ++num_direct_rand_readers_;
215       }
216       ++num_rand_readers_;
217     }
218     return s;
219   }
220 
DeleteFile(const std::string & fname)221   Status DeleteFile(const std::string& fname) override {
222     MutexLock l(&mutex_);
223     if (fail_delete_files_) {
224       return Status::IOError();
225     }
226     EXPECT_GT(limit_delete_files_, 0U);
227     limit_delete_files_--;
228     return EnvWrapper::DeleteFile(fname);
229   }
230 
DeleteDir(const std::string & dirname)231   Status DeleteDir(const std::string& dirname) override {
232     MutexLock l(&mutex_);
233     if (fail_delete_files_) {
234       return Status::IOError();
235     }
236     return EnvWrapper::DeleteDir(dirname);
237   }
238 
AssertWrittenFiles(std::vector<std::string> & should_have_written)239   void AssertWrittenFiles(std::vector<std::string>& should_have_written) {
240     MutexLock l(&mutex_);
241     std::sort(should_have_written.begin(), should_have_written.end());
242     std::sort(written_files_.begin(), written_files_.end());
243 
244     ASSERT_EQ(should_have_written, written_files_);
245   }
246 
ClearWrittenFiles()247   void ClearWrittenFiles() {
248     MutexLock l(&mutex_);
249     written_files_.clear();
250   }
251 
SetLimitWrittenFiles(uint64_t limit)252   void SetLimitWrittenFiles(uint64_t limit) {
253     MutexLock l(&mutex_);
254     limit_written_files_ = limit;
255   }
256 
SetLimitDeleteFiles(uint64_t limit)257   void SetLimitDeleteFiles(uint64_t limit) {
258     MutexLock l(&mutex_);
259     limit_delete_files_ = limit;
260   }
261 
SetDeleteFileFailure(bool fail)262   void SetDeleteFileFailure(bool fail) {
263     MutexLock l(&mutex_);
264     fail_delete_files_ = fail;
265   }
266 
SetDummySequentialFile(bool dummy_sequential_file)267   void SetDummySequentialFile(bool dummy_sequential_file) {
268     MutexLock l(&mutex_);
269     dummy_sequential_file_ = dummy_sequential_file;
270   }
SetDummySequentialFileFailReads(bool dummy_sequential_file_fail_reads)271   void SetDummySequentialFileFailReads(bool dummy_sequential_file_fail_reads) {
272     MutexLock l(&mutex_);
273     dummy_sequential_file_fail_reads_ = dummy_sequential_file_fail_reads;
274   }
275 
SetGetChildrenFailure(bool fail)276   void SetGetChildrenFailure(bool fail) { get_children_failure_ = fail; }
GetChildren(const std::string & dir,std::vector<std::string> * r)277   Status GetChildren(const std::string& dir,
278                      std::vector<std::string>* r) override {
279     if (get_children_failure_) {
280       return Status::IOError("SimulatedFailure");
281     }
282     return EnvWrapper::GetChildren(dir, r);
283   }
284 
285   // Some test cases do not actually create the test files (e.g., see
286   // DummyDB::live_files_) - for those cases, we mock those files' attributes
287   // so CreateNewBackup() can get their attributes.
SetFilenamesForMockedAttrs(const std::vector<std::string> & filenames)288   void SetFilenamesForMockedAttrs(const std::vector<std::string>& filenames) {
289     filenames_for_mocked_attrs_ = filenames;
290   }
GetChildrenFileAttributes(const std::string & dir,std::vector<Env::FileAttributes> * r)291   Status GetChildrenFileAttributes(
292       const std::string& dir, std::vector<Env::FileAttributes>* r) override {
293     if (filenames_for_mocked_attrs_.size() > 0) {
294       for (const auto& filename : filenames_for_mocked_attrs_) {
295         r->push_back({dir + filename, 10 /* size_bytes */});
296       }
297       return Status::OK();
298     }
299     return EnvWrapper::GetChildrenFileAttributes(dir, r);
300   }
GetFileSize(const std::string & path,uint64_t * size_bytes)301   Status GetFileSize(const std::string& path, uint64_t* size_bytes) override {
302     if (filenames_for_mocked_attrs_.size() > 0) {
303       auto fname = path.substr(path.find_last_of('/'));
304       auto filename_iter = std::find(filenames_for_mocked_attrs_.begin(),
305                                      filenames_for_mocked_attrs_.end(), fname);
306       if (filename_iter != filenames_for_mocked_attrs_.end()) {
307         *size_bytes = 10;
308         return Status::OK();
309       }
310       return Status::NotFound(fname);
311     }
312     return EnvWrapper::GetFileSize(path, size_bytes);
313   }
314 
SetCreateDirIfMissingFailure(bool fail)315   void SetCreateDirIfMissingFailure(bool fail) {
316     create_dir_if_missing_failure_ = fail;
317   }
CreateDirIfMissing(const std::string & d)318   Status CreateDirIfMissing(const std::string& d) override {
319     if (create_dir_if_missing_failure_) {
320       return Status::IOError("SimulatedFailure");
321     }
322     return EnvWrapper::CreateDirIfMissing(d);
323   }
324 
SetNewDirectoryFailure(bool fail)325   void SetNewDirectoryFailure(bool fail) { new_directory_failure_ = fail; }
NewDirectory(const std::string & name,std::unique_ptr<Directory> * result)326   Status NewDirectory(const std::string& name,
327                       std::unique_ptr<Directory>* result) override {
328     if (new_directory_failure_) {
329       return Status::IOError("SimulatedFailure");
330     }
331     return EnvWrapper::NewDirectory(name, result);
332   }
333 
ClearFileOpenCounters()334   void ClearFileOpenCounters() {
335     MutexLock l(&mutex_);
336     num_rand_readers_ = 0;
337     num_direct_rand_readers_ = 0;
338     num_seq_readers_ = 0;
339     num_direct_seq_readers_ = 0;
340     num_writers_ = 0;
341     num_direct_writers_ = 0;
342   }
343 
num_rand_readers()344   int num_rand_readers() { return num_rand_readers_; }
num_direct_rand_readers()345   int num_direct_rand_readers() { return num_direct_rand_readers_; }
num_seq_readers()346   int num_seq_readers() { return num_seq_readers_; }
num_direct_seq_readers()347   int num_direct_seq_readers() { return num_direct_seq_readers_; }
num_writers()348   int num_writers() { return num_writers_; }
num_direct_writers()349   int num_direct_writers() { return num_direct_writers_; }
350 
351  private:
352   port::Mutex mutex_;
353   bool dummy_sequential_file_ = false;
354   bool dummy_sequential_file_fail_reads_ = false;
355   std::vector<std::string> written_files_;
356   std::vector<std::string> filenames_for_mocked_attrs_;
357   uint64_t limit_written_files_ = 1000000;
358   uint64_t limit_delete_files_ = 1000000;
359   bool fail_delete_files_ = false;
360 
361   bool get_children_failure_ = false;
362   bool create_dir_if_missing_failure_ = false;
363   bool new_directory_failure_ = false;
364 
365   // Keeps track of how many files of each type were successfully opened, and
366   // out of those, how many were opened with direct I/O.
367   std::atomic<int> num_rand_readers_;
368   std::atomic<int> num_direct_rand_readers_;
369   std::atomic<int> num_seq_readers_;
370   std::atomic<int> num_direct_seq_readers_;
371   std::atomic<int> num_writers_;
372   std::atomic<int> num_direct_writers_;
373 };  // TestEnv
374 
375 class FileManager : public EnvWrapper {
376  public:
FileManager(Env * t)377   explicit FileManager(Env* t) : EnvWrapper(t), rnd_(5) {}
378 
DeleteRandomFileInDir(const std::string & dir)379   Status DeleteRandomFileInDir(const std::string& dir) {
380     std::vector<std::string> children;
381     GetChildren(dir, &children);
382     if (children.size() <= 2) { // . and ..
383       return Status::NotFound("");
384     }
385     while (true) {
386       int i = rnd_.Next() % children.size();
387       if (children[i] != "." && children[i] != "..") {
388         return DeleteFile(dir + "/" + children[i]);
389       }
390     }
391     // should never get here
392     assert(false);
393     return Status::NotFound("");
394   }
395 
AppendToRandomFileInDir(const std::string & dir,const std::string & data)396   Status AppendToRandomFileInDir(const std::string& dir,
397                                  const std::string& data) {
398     std::vector<std::string> children;
399     GetChildren(dir, &children);
400     if (children.size() <= 2) {
401       return Status::NotFound("");
402     }
403     while (true) {
404       int i = rnd_.Next() % children.size();
405       if (children[i] != "." && children[i] != "..") {
406         return WriteToFile(dir + "/" + children[i], data);
407       }
408     }
409     // should never get here
410     assert(false);
411     return Status::NotFound("");
412   }
413 
CorruptFile(const std::string & fname,uint64_t bytes_to_corrupt)414   Status CorruptFile(const std::string& fname, uint64_t bytes_to_corrupt) {
415     std::string file_contents;
416     Status s = ReadFileToString(this, fname, &file_contents);
417     if (!s.ok()) {
418       return s;
419     }
420     s = DeleteFile(fname);
421     if (!s.ok()) {
422       return s;
423     }
424 
425     for (uint64_t i = 0; i < bytes_to_corrupt; ++i) {
426       std::string tmp;
427       test::RandomString(&rnd_, 1, &tmp);
428       file_contents[rnd_.Next() % file_contents.size()] = tmp[0];
429     }
430     return WriteToFile(fname, file_contents);
431   }
432 
CorruptChecksum(const std::string & fname,bool appear_valid)433   Status CorruptChecksum(const std::string& fname, bool appear_valid) {
434     std::string metadata;
435     Status s = ReadFileToString(this, fname, &metadata);
436     if (!s.ok()) {
437       return s;
438     }
439     s = DeleteFile(fname);
440     if (!s.ok()) {
441       return s;
442     }
443 
444     auto pos = metadata.find("private");
445     if (pos == std::string::npos) {
446       return Status::Corruption("private file is expected");
447     }
448     pos = metadata.find(" crc32 ", pos + 6);
449     if (pos == std::string::npos) {
450       return Status::Corruption("checksum not found");
451     }
452 
453     if (metadata.size() < pos + 7) {
454       return Status::Corruption("bad CRC32 checksum value");
455     }
456 
457     if (appear_valid) {
458       if (metadata[pos + 8] == '\n') {
459         // single digit value, safe to insert one more digit
460         metadata.insert(pos + 8, 1, '0');
461       } else {
462         metadata.erase(pos + 8, 1);
463       }
464     } else {
465       metadata[pos + 7] = 'a';
466     }
467 
468     return WriteToFile(fname, metadata);
469   }
470 
WriteToFile(const std::string & fname,const std::string & data)471   Status WriteToFile(const std::string& fname, const std::string& data) {
472     std::unique_ptr<WritableFile> file;
473     EnvOptions env_options;
474     env_options.use_mmap_writes = false;
475     Status s = EnvWrapper::NewWritableFile(fname, &file, env_options);
476     if (!s.ok()) {
477       return s;
478     }
479     return file->Append(Slice(data));
480   }
481 
482  private:
483   Random rnd_;
484 }; // FileManager
485 
486 // utility functions
FillDB(DB * db,int from,int to)487 static size_t FillDB(DB* db, int from, int to) {
488   size_t bytes_written = 0;
489   for (int i = from; i < to; ++i) {
490     std::string key = "testkey" + ToString(i);
491     std::string value = "testvalue" + ToString(i);
492     bytes_written += key.size() + value.size();
493 
494     EXPECT_OK(db->Put(WriteOptions(), Slice(key), Slice(value)));
495   }
496   return bytes_written;
497 }
498 
AssertExists(DB * db,int from,int to)499 static void AssertExists(DB* db, int from, int to) {
500   for (int i = from; i < to; ++i) {
501     std::string key = "testkey" + ToString(i);
502     std::string value;
503     Status s = db->Get(ReadOptions(), Slice(key), &value);
504     ASSERT_EQ(value, "testvalue" + ToString(i));
505   }
506 }
507 
AssertEmpty(DB * db,int from,int to)508 static void AssertEmpty(DB* db, int from, int to) {
509   for (int i = from; i < to; ++i) {
510     std::string key = "testkey" + ToString(i);
511     std::string value = "testvalue" + ToString(i);
512 
513     Status s = db->Get(ReadOptions(), Slice(key), &value);
514     ASSERT_TRUE(s.IsNotFound());
515   }
516 }
517 
518 class BackupableDBTest : public testing::Test {
519  public:
520   enum ShareOption {
521     kNoShare,
522     kShareNoChecksum,
523     kShareWithChecksum,
524   };
525 
526   const std::vector<ShareOption> kAllShareOptions = {
527       kNoShare, kShareNoChecksum, kShareWithChecksum};
528 
BackupableDBTest()529   BackupableDBTest() {
530     // set up files
531     std::string db_chroot = test::PerThreadDBPath("backupable_db");
532     std::string backup_chroot = test::PerThreadDBPath("backupable_db_backup");
533     Env::Default()->CreateDir(db_chroot);
534     Env::Default()->CreateDir(backup_chroot);
535     dbname_ = "/tempdb";
536     backupdir_ = "/tempbk";
537 
538     // set up envs
539     db_chroot_env_.reset(NewChrootEnv(Env::Default(), db_chroot));
540     backup_chroot_env_.reset(NewChrootEnv(Env::Default(), backup_chroot));
541     test_db_env_.reset(new TestEnv(db_chroot_env_.get()));
542     test_backup_env_.reset(new TestEnv(backup_chroot_env_.get()));
543     file_manager_.reset(new FileManager(backup_chroot_env_.get()));
544 
545     // set up db options
546     options_.create_if_missing = true;
547     options_.paranoid_checks = true;
548     options_.write_buffer_size = 1 << 17; // 128KB
549     options_.env = test_db_env_.get();
550     options_.wal_dir = dbname_;
551 
552     // Create logger
553     DBOptions logger_options;
554     logger_options.env = db_chroot_env_.get();
555     CreateLoggerFromOptions(dbname_, logger_options, &logger_);
556 
557     // set up backup db options
558     backupable_options_.reset(new BackupableDBOptions(
559         backupdir_, test_backup_env_.get(), true, logger_.get(), true));
560 
561     // most tests will use multi-threaded backups
562     backupable_options_->max_background_operations = 7;
563 
564     // delete old files in db
565     DestroyDB(dbname_, options_);
566   }
567 
OpenDB()568   DB* OpenDB() {
569     DB* db;
570     EXPECT_OK(DB::Open(options_, dbname_, &db));
571     return db;
572   }
573 
OpenDBAndBackupEngine(bool destroy_old_data=false,bool dummy=false,ShareOption shared_option=kShareNoChecksum)574   void OpenDBAndBackupEngine(bool destroy_old_data = false, bool dummy = false,
575                              ShareOption shared_option = kShareNoChecksum) {
576     // reset all the defaults
577     test_backup_env_->SetLimitWrittenFiles(1000000);
578     test_db_env_->SetLimitWrittenFiles(1000000);
579     test_db_env_->SetDummySequentialFile(dummy);
580 
581     DB* db;
582     if (dummy) {
583       dummy_db_ = new DummyDB(options_, dbname_);
584       db = dummy_db_;
585     } else {
586       ASSERT_OK(DB::Open(options_, dbname_, &db));
587     }
588     db_.reset(db);
589     backupable_options_->destroy_old_data = destroy_old_data;
590     backupable_options_->share_table_files = shared_option != kNoShare;
591     backupable_options_->share_files_with_checksum =
592         shared_option == kShareWithChecksum;
593     BackupEngine* backup_engine;
594     ASSERT_OK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
595                                  &backup_engine));
596     backup_engine_.reset(backup_engine);
597   }
598 
CloseDBAndBackupEngine()599   void CloseDBAndBackupEngine() {
600     db_.reset();
601     backup_engine_.reset();
602   }
603 
OpenBackupEngine()604   void OpenBackupEngine() {
605     backupable_options_->destroy_old_data = false;
606     BackupEngine* backup_engine;
607     ASSERT_OK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
608                                  &backup_engine));
609     backup_engine_.reset(backup_engine);
610   }
611 
CloseBackupEngine()612   void CloseBackupEngine() { backup_engine_.reset(nullptr); }
613 
614   // restores backup backup_id and asserts the existence of
615   // [start_exist, end_exist> and not-existence of
616   // [end_exist, end>
617   //
618   // if backup_id == 0, it means restore from latest
619   // if end == 0, don't check AssertEmpty
AssertBackupConsistency(BackupID backup_id,uint32_t start_exist,uint32_t end_exist,uint32_t end=0,bool keep_log_files=false)620   void AssertBackupConsistency(BackupID backup_id, uint32_t start_exist,
621                                uint32_t end_exist, uint32_t end = 0,
622                                bool keep_log_files = false) {
623     RestoreOptions restore_options(keep_log_files);
624     bool opened_backup_engine = false;
625     if (backup_engine_.get() == nullptr) {
626       opened_backup_engine = true;
627       OpenBackupEngine();
628     }
629     if (backup_id > 0) {
630       ASSERT_OK(backup_engine_->RestoreDBFromBackup(backup_id, dbname_, dbname_,
631                                                     restore_options));
632     } else {
633       ASSERT_OK(backup_engine_->RestoreDBFromLatestBackup(dbname_, dbname_,
634                                                           restore_options));
635     }
636     DB* db = OpenDB();
637     AssertExists(db, start_exist, end_exist);
638     if (end != 0) {
639       AssertEmpty(db, end_exist, end);
640     }
641     delete db;
642     if (opened_backup_engine) {
643       CloseBackupEngine();
644     }
645   }
646 
DeleteLogFiles()647   void DeleteLogFiles() {
648     std::vector<std::string> delete_logs;
649     db_chroot_env_->GetChildren(dbname_, &delete_logs);
650     for (auto f : delete_logs) {
651       uint64_t number;
652       FileType type;
653       bool ok = ParseFileName(f, &number, &type);
654       if (ok && type == kLogFile) {
655         db_chroot_env_->DeleteFile(dbname_ + "/" + f);
656       }
657     }
658   }
659 
660   // files
661   std::string dbname_;
662   std::string backupdir_;
663 
664   // logger_ must be above backup_engine_ such that the engine's destructor,
665   // which uses a raw pointer to the logger, executes first.
666   std::shared_ptr<Logger> logger_;
667 
668   // envs
669   std::unique_ptr<Env> db_chroot_env_;
670   std::unique_ptr<Env> backup_chroot_env_;
671   std::unique_ptr<TestEnv> test_db_env_;
672   std::unique_ptr<TestEnv> test_backup_env_;
673   std::unique_ptr<FileManager> file_manager_;
674 
675   // all the dbs!
676   DummyDB* dummy_db_; // BackupableDB owns dummy_db_
677   std::unique_ptr<DB> db_;
678   std::unique_ptr<BackupEngine> backup_engine_;
679 
680   // options
681   Options options_;
682 
683  protected:
684   std::unique_ptr<BackupableDBOptions> backupable_options_;
685 }; // BackupableDBTest
686 
AppendPath(const std::string & path,std::vector<std::string> & v)687 void AppendPath(const std::string& path, std::vector<std::string>& v) {
688   for (auto& f : v) {
689     f = path + f;
690   }
691 }
692 
693 class BackupableDBTestWithParam : public BackupableDBTest,
694                                   public testing::WithParamInterface<bool> {
695  public:
BackupableDBTestWithParam()696   BackupableDBTestWithParam() {
697     backupable_options_->share_files_with_checksum = GetParam();
698   }
699 };
700 
701 // This test verifies that the verifyBackup method correctly identifies
702 // invalid backups
TEST_P(BackupableDBTestWithParam,VerifyBackup)703 TEST_P(BackupableDBTestWithParam, VerifyBackup) {
704   const int keys_iteration = 5000;
705   Random rnd(6);
706   Status s;
707   OpenDBAndBackupEngine(true);
708   // create five backups
709   for (int i = 0; i < 5; ++i) {
710     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
711     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
712   }
713   CloseDBAndBackupEngine();
714 
715   OpenDBAndBackupEngine();
716   // ---------- case 1. - valid backup -----------
717   ASSERT_TRUE(backup_engine_->VerifyBackup(1).ok());
718 
719   // ---------- case 2. - delete a file -----------i
720   file_manager_->DeleteRandomFileInDir(backupdir_ + "/private/1");
721   ASSERT_TRUE(backup_engine_->VerifyBackup(1).IsNotFound());
722 
723   // ---------- case 3. - corrupt a file -----------
724   std::string append_data = "Corrupting a random file";
725   file_manager_->AppendToRandomFileInDir(backupdir_ + "/private/2",
726                                          append_data);
727   ASSERT_TRUE(backup_engine_->VerifyBackup(2).IsCorruption());
728 
729   // ---------- case 4. - invalid backup -----------
730   ASSERT_TRUE(backup_engine_->VerifyBackup(6).IsNotFound());
731   CloseDBAndBackupEngine();
732 }
733 
734 // open DB, write, close DB, backup, restore, repeat
TEST_P(BackupableDBTestWithParam,OfflineIntegrationTest)735 TEST_P(BackupableDBTestWithParam, OfflineIntegrationTest) {
736   // has to be a big number, so that it triggers the memtable flush
737   const int keys_iteration = 5000;
738   const int max_key = keys_iteration * 4 + 10;
739   // first iter -- flush before backup
740   // second iter -- don't flush before backup
741   for (int iter = 0; iter < 2; ++iter) {
742     // delete old data
743     DestroyDB(dbname_, options_);
744     bool destroy_data = true;
745 
746     // every iteration --
747     // 1. insert new data in the DB
748     // 2. backup the DB
749     // 3. destroy the db
750     // 4. restore the db, check everything is still there
751     for (int i = 0; i < 5; ++i) {
752       // in last iteration, put smaller amount of data,
753       int fill_up_to = std::min(keys_iteration * (i + 1), max_key);
754       // ---- insert new data and back up ----
755       OpenDBAndBackupEngine(destroy_data);
756       destroy_data = false;
757       FillDB(db_.get(), keys_iteration * i, fill_up_to);
758       ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), iter == 0));
759       CloseDBAndBackupEngine();
760       DestroyDB(dbname_, options_);
761 
762       // ---- make sure it's empty ----
763       DB* db = OpenDB();
764       AssertEmpty(db, 0, fill_up_to);
765       delete db;
766 
767       // ---- restore the DB ----
768       OpenBackupEngine();
769       if (i >= 3) {  // test purge old backups
770         // when i == 4, purge to only 1 backup
771         // when i == 3, purge to 2 backups
772         ASSERT_OK(backup_engine_->PurgeOldBackups(5 - i));
773       }
774       // ---- make sure the data is there ---
775       AssertBackupConsistency(0, 0, fill_up_to, max_key);
776       CloseBackupEngine();
777     }
778   }
779 }
780 
781 // open DB, write, backup, write, backup, close, restore
TEST_P(BackupableDBTestWithParam,OnlineIntegrationTest)782 TEST_P(BackupableDBTestWithParam, OnlineIntegrationTest) {
783   // has to be a big number, so that it triggers the memtable flush
784   const int keys_iteration = 5000;
785   const int max_key = keys_iteration * 4 + 10;
786   Random rnd(7);
787   // delete old data
788   DestroyDB(dbname_, options_);
789 
790   OpenDBAndBackupEngine(true);
791   // write some data, backup, repeat
792   for (int i = 0; i < 5; ++i) {
793     if (i == 4) {
794       // delete backup number 2, online delete!
795       ASSERT_OK(backup_engine_->DeleteBackup(2));
796     }
797     // in last iteration, put smaller amount of data,
798     // so that backups can share sst files
799     int fill_up_to = std::min(keys_iteration * (i + 1), max_key);
800     FillDB(db_.get(), keys_iteration * i, fill_up_to);
801     // we should get consistent results with flush_before_backup
802     // set to both true and false
803     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)));
804   }
805   // close and destroy
806   CloseDBAndBackupEngine();
807   DestroyDB(dbname_, options_);
808 
809   // ---- make sure it's empty ----
810   DB* db = OpenDB();
811   AssertEmpty(db, 0, max_key);
812   delete db;
813 
814   // ---- restore every backup and verify all the data is there ----
815   OpenBackupEngine();
816   for (int i = 1; i <= 5; ++i) {
817     if (i == 2) {
818       // we deleted backup 2
819       Status s = backup_engine_->RestoreDBFromBackup(2, dbname_, dbname_);
820       ASSERT_TRUE(!s.ok());
821     } else {
822       int fill_up_to = std::min(keys_iteration * i, max_key);
823       AssertBackupConsistency(i, 0, fill_up_to, max_key);
824     }
825   }
826 
827   // delete some backups -- this should leave only backups 3 and 5 alive
828   ASSERT_OK(backup_engine_->DeleteBackup(4));
829   ASSERT_OK(backup_engine_->PurgeOldBackups(2));
830 
831   std::vector<BackupInfo> backup_info;
832   backup_engine_->GetBackupInfo(&backup_info);
833   ASSERT_EQ(2UL, backup_info.size());
834 
835   // check backup 3
836   AssertBackupConsistency(3, 0, 3 * keys_iteration, max_key);
837   // check backup 5
838   AssertBackupConsistency(5, 0, max_key);
839 
840   CloseBackupEngine();
841 }
842 
843 INSTANTIATE_TEST_CASE_P(BackupableDBTestWithParam, BackupableDBTestWithParam,
844                         ::testing::Bool());
845 
846 // this will make sure that backup does not copy the same file twice
TEST_F(BackupableDBTest,NoDoubleCopy_And_AutoGC)847 TEST_F(BackupableDBTest, NoDoubleCopy_And_AutoGC) {
848   OpenDBAndBackupEngine(true, true);
849 
850   // should write 5 DB files + one meta file
851   test_backup_env_->SetLimitWrittenFiles(7);
852   test_backup_env_->ClearWrittenFiles();
853   test_db_env_->SetLimitWrittenFiles(0);
854   dummy_db_->live_files_ = {"/00010.sst", "/00011.sst", "/CURRENT",
855                             "/MANIFEST-01"};
856   dummy_db_->wal_files_ = {{"/00011.log", true}, {"/00012.log", false}};
857   test_db_env_->SetFilenamesForMockedAttrs(dummy_db_->live_files_);
858   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
859   std::vector<std::string> should_have_written = {
860       "/shared/.00010.sst.tmp", "/shared/.00011.sst.tmp", "/private/1/CURRENT",
861       "/private/1/MANIFEST-01", "/private/1/00011.log",   "/meta/.1.tmp"};
862   AppendPath(backupdir_, should_have_written);
863   test_backup_env_->AssertWrittenFiles(should_have_written);
864 
865   char db_number = '1';
866 
867   for (std::string other_sst : {"00015.sst", "00017.sst", "00019.sst"}) {
868     // should write 4 new DB files + one meta file
869     // should not write/copy 00010.sst, since it's already there!
870     test_backup_env_->SetLimitWrittenFiles(6);
871     test_backup_env_->ClearWrittenFiles();
872 
873     dummy_db_->live_files_ = {"/00010.sst", "/" + other_sst, "/CURRENT",
874                               "/MANIFEST-01"};
875     dummy_db_->wal_files_ = {{"/00011.log", true}, {"/00012.log", false}};
876     test_db_env_->SetFilenamesForMockedAttrs(dummy_db_->live_files_);
877     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
878     // should not open 00010.sst - it's already there
879 
880     ++db_number;
881     std::string private_dir = std::string("/private/") + db_number;
882     should_have_written = {
883         "/shared/." + other_sst + ".tmp", private_dir + "/CURRENT",
884         private_dir + "/MANIFEST-01", private_dir + "/00011.log",
885         std::string("/meta/.") + db_number + ".tmp"};
886     AppendPath(backupdir_, should_have_written);
887     test_backup_env_->AssertWrittenFiles(should_have_written);
888   }
889 
890   ASSERT_OK(backup_engine_->DeleteBackup(1));
891   ASSERT_OK(test_backup_env_->FileExists(backupdir_ + "/shared/00010.sst"));
892 
893   // 00011.sst was only in backup 1, should be deleted
894   ASSERT_EQ(Status::NotFound(),
895             test_backup_env_->FileExists(backupdir_ + "/shared/00011.sst"));
896   ASSERT_OK(test_backup_env_->FileExists(backupdir_ + "/shared/00015.sst"));
897 
898   // MANIFEST file size should be only 100
899   uint64_t size = 0;
900   test_backup_env_->GetFileSize(backupdir_ + "/private/2/MANIFEST-01", &size);
901   ASSERT_EQ(100UL, size);
902   test_backup_env_->GetFileSize(backupdir_ + "/shared/00015.sst", &size);
903   ASSERT_EQ(200UL, size);
904 
905   CloseBackupEngine();
906 
907   //
908   // Now simulate incomplete delete by removing just meta
909   //
910   ASSERT_OK(test_backup_env_->DeleteFile(backupdir_ + "/meta/2"));
911 
912   OpenBackupEngine();
913 
914   // 1 appears to be removed, so
915   // 2 non-corrupt and 0 corrupt seen
916   std::vector<BackupInfo> backup_info;
917   std::vector<BackupID> corrupt_backup_ids;
918   backup_engine_->GetBackupInfo(&backup_info);
919   backup_engine_->GetCorruptedBackups(&corrupt_backup_ids);
920   ASSERT_EQ(2UL, backup_info.size());
921   ASSERT_EQ(0UL, corrupt_backup_ids.size());
922 
923   // Keep the two we see, but this should suffice to purge unreferenced
924   // shared files from incomplete delete.
925   ASSERT_OK(backup_engine_->PurgeOldBackups(2));
926 
927   // Make sure dangling sst file has been removed (somewhere along this
928   // process). GarbageCollect should not be needed.
929   ASSERT_EQ(Status::NotFound(),
930             test_backup_env_->FileExists(backupdir_ + "/shared/00015.sst"));
931   ASSERT_OK(test_backup_env_->FileExists(backupdir_ + "/shared/00017.sst"));
932   ASSERT_OK(test_backup_env_->FileExists(backupdir_ + "/shared/00019.sst"));
933 
934   // Now actually purge a good one
935   ASSERT_OK(backup_engine_->PurgeOldBackups(1));
936 
937   ASSERT_EQ(Status::NotFound(),
938             test_backup_env_->FileExists(backupdir_ + "/shared/00017.sst"));
939   ASSERT_OK(test_backup_env_->FileExists(backupdir_ + "/shared/00019.sst"));
940 
941   CloseDBAndBackupEngine();
942 }
943 
944 // test various kind of corruptions that may happen:
945 // 1. Not able to write a file for backup - that backup should fail,
946 //      everything else should work
947 // 2. Corrupted backup meta file or missing backuped file - we should
948 //      not be able to open that backup, but all other backups should be
949 //      fine
950 // 3. Corrupted checksum value - if the checksum is not a valid uint32_t,
951 //      db open should fail, otherwise, it aborts during the restore process.
TEST_F(BackupableDBTest,CorruptionsTest)952 TEST_F(BackupableDBTest, CorruptionsTest) {
953   const int keys_iteration = 5000;
954   Random rnd(6);
955   Status s;
956 
957   OpenDBAndBackupEngine(true);
958   // create five backups
959   for (int i = 0; i < 5; ++i) {
960     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
961     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)));
962   }
963 
964   // ---------- case 1. - fail a write -----------
965   // try creating backup 6, but fail a write
966   FillDB(db_.get(), keys_iteration * 5, keys_iteration * 6);
967   test_backup_env_->SetLimitWrittenFiles(2);
968   // should fail
969   s = backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2));
970   ASSERT_TRUE(!s.ok());
971   test_backup_env_->SetLimitWrittenFiles(1000000);
972   // latest backup should have all the keys
973   CloseDBAndBackupEngine();
974   AssertBackupConsistency(0, 0, keys_iteration * 5, keys_iteration * 6);
975 
976   // --------- case 2. corrupted backup meta or missing backuped file ----
977   ASSERT_OK(file_manager_->CorruptFile(backupdir_ + "/meta/5", 3));
978   // since 5 meta is now corrupted, latest backup should be 4
979   AssertBackupConsistency(0, 0, keys_iteration * 4, keys_iteration * 5);
980   OpenBackupEngine();
981   s = backup_engine_->RestoreDBFromBackup(5, dbname_, dbname_);
982   ASSERT_TRUE(!s.ok());
983   CloseBackupEngine();
984   ASSERT_OK(file_manager_->DeleteRandomFileInDir(backupdir_ + "/private/4"));
985   // 4 is corrupted, 3 is the latest backup now
986   AssertBackupConsistency(0, 0, keys_iteration * 3, keys_iteration * 5);
987   OpenBackupEngine();
988   s = backup_engine_->RestoreDBFromBackup(4, dbname_, dbname_);
989   CloseBackupEngine();
990   ASSERT_TRUE(!s.ok());
991 
992   // --------- case 3. corrupted checksum value ----
993   ASSERT_OK(file_manager_->CorruptChecksum(backupdir_ + "/meta/3", false));
994   // checksum of backup 3 is an invalid value, this can be detected at
995   // db open time, and it reverts to the previous backup automatically
996   AssertBackupConsistency(0, 0, keys_iteration * 2, keys_iteration * 5);
997   // checksum of the backup 2 appears to be valid, this can cause checksum
998   // mismatch and abort restore process
999   ASSERT_OK(file_manager_->CorruptChecksum(backupdir_ + "/meta/2", true));
1000   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/2"));
1001   OpenBackupEngine();
1002   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/2"));
1003   s = backup_engine_->RestoreDBFromBackup(2, dbname_, dbname_);
1004   ASSERT_TRUE(!s.ok());
1005 
1006   // make sure that no corrupt backups have actually been deleted!
1007   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/1"));
1008   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/2"));
1009   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/3"));
1010   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/4"));
1011   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/5"));
1012   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/1"));
1013   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/2"));
1014   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/3"));
1015   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/4"));
1016   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/5"));
1017 
1018   // delete the corrupt backups and then make sure they're actually deleted
1019   ASSERT_OK(backup_engine_->DeleteBackup(5));
1020   ASSERT_OK(backup_engine_->DeleteBackup(4));
1021   ASSERT_OK(backup_engine_->DeleteBackup(3));
1022   ASSERT_OK(backup_engine_->DeleteBackup(2));
1023   // Should not be needed anymore with auto-GC on DeleteBackup
1024   //(void)backup_engine_->GarbageCollect();
1025   ASSERT_EQ(Status::NotFound(),
1026             file_manager_->FileExists(backupdir_ + "/meta/5"));
1027   ASSERT_EQ(Status::NotFound(),
1028             file_manager_->FileExists(backupdir_ + "/private/5"));
1029   ASSERT_EQ(Status::NotFound(),
1030             file_manager_->FileExists(backupdir_ + "/meta/4"));
1031   ASSERT_EQ(Status::NotFound(),
1032             file_manager_->FileExists(backupdir_ + "/private/4"));
1033   ASSERT_EQ(Status::NotFound(),
1034             file_manager_->FileExists(backupdir_ + "/meta/3"));
1035   ASSERT_EQ(Status::NotFound(),
1036             file_manager_->FileExists(backupdir_ + "/private/3"));
1037   ASSERT_EQ(Status::NotFound(),
1038             file_manager_->FileExists(backupdir_ + "/meta/2"));
1039   ASSERT_EQ(Status::NotFound(),
1040             file_manager_->FileExists(backupdir_ + "/private/2"));
1041 
1042   CloseBackupEngine();
1043   AssertBackupConsistency(0, 0, keys_iteration * 1, keys_iteration * 5);
1044 
1045   // new backup should be 2!
1046   OpenDBAndBackupEngine();
1047   FillDB(db_.get(), keys_iteration * 1, keys_iteration * 2);
1048   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)));
1049   CloseDBAndBackupEngine();
1050   AssertBackupConsistency(2, 0, keys_iteration * 2, keys_iteration * 5);
1051 }
1052 
TEST_F(BackupableDBTest,InterruptCreationTest)1053 TEST_F(BackupableDBTest, InterruptCreationTest) {
1054   // Interrupt backup creation by failing new writes and failing cleanup of the
1055   // partial state. Then verify a subsequent backup can still succeed.
1056   const int keys_iteration = 5000;
1057   Random rnd(6);
1058 
1059   OpenDBAndBackupEngine(true /* destroy_old_data */);
1060   FillDB(db_.get(), 0, keys_iteration);
1061   test_backup_env_->SetLimitWrittenFiles(2);
1062   test_backup_env_->SetDeleteFileFailure(true);
1063   // should fail creation
1064   ASSERT_FALSE(
1065       backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)).ok());
1066   CloseDBAndBackupEngine();
1067   // should also fail cleanup so the tmp directory stays behind
1068   ASSERT_OK(backup_chroot_env_->FileExists(backupdir_ + "/private/1/"));
1069 
1070   OpenDBAndBackupEngine(false /* destroy_old_data */);
1071   test_backup_env_->SetLimitWrittenFiles(1000000);
1072   test_backup_env_->SetDeleteFileFailure(false);
1073   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)));
1074   // latest backup should have all the keys
1075   CloseDBAndBackupEngine();
1076   AssertBackupConsistency(0, 0, keys_iteration);
1077 }
1078 
OptionsPath(std::string ret,int backupID)1079 inline std::string OptionsPath(std::string ret, int backupID) {
1080   ret += "/private/";
1081   ret += std::to_string(backupID);
1082   ret += "/";
1083   return ret;
1084 }
1085 
1086 // Backup the LATEST options file to
1087 // "<backup_dir>/private/<backup_id>/OPTIONS<number>"
1088 
TEST_F(BackupableDBTest,BackupOptions)1089 TEST_F(BackupableDBTest, BackupOptions) {
1090   OpenDBAndBackupEngine(true);
1091   for (int i = 1; i < 5; i++) {
1092     std::string name;
1093     std::vector<std::string> filenames;
1094     // Must reset() before reset(OpenDB()) again.
1095     // Calling OpenDB() while *db_ is existing will cause LOCK issue
1096     db_.reset();
1097     db_.reset(OpenDB());
1098     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1099     ROCKSDB_NAMESPACE::GetLatestOptionsFileName(db_->GetName(), options_.env,
1100                                                 &name);
1101     ASSERT_OK(file_manager_->FileExists(OptionsPath(backupdir_, i) + name));
1102     backup_chroot_env_->GetChildren(OptionsPath(backupdir_, i), &filenames);
1103     for (auto fn : filenames) {
1104       if (fn.compare(0, 7, "OPTIONS") == 0) {
1105         ASSERT_EQ(name, fn);
1106       }
1107     }
1108   }
1109 
1110   CloseDBAndBackupEngine();
1111 }
1112 
TEST_F(BackupableDBTest,SetOptionsBackupRaceCondition)1113 TEST_F(BackupableDBTest, SetOptionsBackupRaceCondition) {
1114   OpenDBAndBackupEngine(true);
1115   SyncPoint::GetInstance()->LoadDependency(
1116       {{"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
1117         "BackupableDBTest::SetOptionsBackupRaceCondition:BeforeSetOptions"},
1118        {"BackupableDBTest::SetOptionsBackupRaceCondition:AfterSetOptions",
1119         "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"}});
1120   SyncPoint::GetInstance()->EnableProcessing();
1121   ROCKSDB_NAMESPACE::port::Thread setoptions_thread{[this]() {
1122     TEST_SYNC_POINT(
1123         "BackupableDBTest::SetOptionsBackupRaceCondition:BeforeSetOptions");
1124     DBImpl* dbi = static_cast<DBImpl*>(db_.get());
1125     // Change arbitrary option to trigger OPTIONS file deletion
1126     ASSERT_OK(dbi->SetOptions(dbi->DefaultColumnFamily(),
1127                               {{"paranoid_file_checks", "false"}}));
1128     ASSERT_OK(dbi->SetOptions(dbi->DefaultColumnFamily(),
1129                               {{"paranoid_file_checks", "true"}}));
1130     ASSERT_OK(dbi->SetOptions(dbi->DefaultColumnFamily(),
1131                               {{"paranoid_file_checks", "false"}}));
1132     TEST_SYNC_POINT(
1133         "BackupableDBTest::SetOptionsBackupRaceCondition:AfterSetOptions");
1134   }};
1135   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get()));
1136   setoptions_thread.join();
1137   CloseDBAndBackupEngine();
1138 }
1139 
1140 // This test verifies we don't delete the latest backup when read-only option is
1141 // set
TEST_F(BackupableDBTest,NoDeleteWithReadOnly)1142 TEST_F(BackupableDBTest, NoDeleteWithReadOnly) {
1143   const int keys_iteration = 5000;
1144   Random rnd(6);
1145   Status s;
1146 
1147   OpenDBAndBackupEngine(true);
1148   // create five backups
1149   for (int i = 0; i < 5; ++i) {
1150     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1151     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(rnd.Next() % 2)));
1152   }
1153   CloseDBAndBackupEngine();
1154   ASSERT_OK(file_manager_->WriteToFile(backupdir_ + "/LATEST_BACKUP", "4"));
1155 
1156   backupable_options_->destroy_old_data = false;
1157   BackupEngineReadOnly* read_only_backup_engine;
1158   ASSERT_OK(BackupEngineReadOnly::Open(backup_chroot_env_.get(),
1159                                        *backupable_options_,
1160                                        &read_only_backup_engine));
1161 
1162   // assert that data from backup 5 is still here (even though LATEST_BACKUP
1163   // says 4 is latest)
1164   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/meta/5"));
1165   ASSERT_OK(file_manager_->FileExists(backupdir_ + "/private/5"));
1166 
1167   // Behavior change: We now ignore LATEST_BACKUP contents. This means that
1168   // we should have 5 backups, even if LATEST_BACKUP says 4.
1169   std::vector<BackupInfo> backup_info;
1170   read_only_backup_engine->GetBackupInfo(&backup_info);
1171   ASSERT_EQ(5UL, backup_info.size());
1172   delete read_only_backup_engine;
1173 }
1174 
TEST_F(BackupableDBTest,FailOverwritingBackups)1175 TEST_F(BackupableDBTest, FailOverwritingBackups) {
1176   options_.write_buffer_size = 1024 * 1024 * 1024;  // 1GB
1177   options_.disable_auto_compactions = true;
1178 
1179   // create backups 1, 2, 3, 4, 5
1180   OpenDBAndBackupEngine(true);
1181   for (int i = 0; i < 5; ++i) {
1182     CloseDBAndBackupEngine();
1183     DeleteLogFiles();
1184     OpenDBAndBackupEngine(false);
1185     FillDB(db_.get(), 100 * i, 100 * (i + 1));
1186     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1187   }
1188   CloseDBAndBackupEngine();
1189 
1190   // restore 3
1191   OpenBackupEngine();
1192   ASSERT_OK(backup_engine_->RestoreDBFromBackup(3, dbname_, dbname_));
1193   CloseBackupEngine();
1194 
1195   OpenDBAndBackupEngine(false);
1196   FillDB(db_.get(), 0, 300);
1197   Status s = backup_engine_->CreateNewBackup(db_.get(), true);
1198   // the new backup fails because new table files
1199   // clash with old table files from backups 4 and 5
1200   // (since write_buffer_size is huge, we can be sure that
1201   // each backup will generate only one sst file and that
1202   // a file generated by a new backup is the same as
1203   // sst file generated by backup 4)
1204   ASSERT_TRUE(s.IsCorruption());
1205   ASSERT_OK(backup_engine_->DeleteBackup(4));
1206   ASSERT_OK(backup_engine_->DeleteBackup(5));
1207   // now, the backup can succeed
1208   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1209   CloseDBAndBackupEngine();
1210 }
1211 
TEST_F(BackupableDBTest,NoShareTableFiles)1212 TEST_F(BackupableDBTest, NoShareTableFiles) {
1213   const int keys_iteration = 5000;
1214   OpenDBAndBackupEngine(true, false, kNoShare);
1215   for (int i = 0; i < 5; ++i) {
1216     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1217     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(i % 2)));
1218   }
1219   CloseDBAndBackupEngine();
1220 
1221   for (int i = 0; i < 5; ++i) {
1222     AssertBackupConsistency(i + 1, 0, keys_iteration * (i + 1),
1223                             keys_iteration * 6);
1224   }
1225 }
1226 
1227 // Verify that you can backup and restore with share_files_with_checksum on
TEST_F(BackupableDBTest,ShareTableFilesWithChecksums)1228 TEST_F(BackupableDBTest, ShareTableFilesWithChecksums) {
1229   const int keys_iteration = 5000;
1230   OpenDBAndBackupEngine(true, false, kShareWithChecksum);
1231   for (int i = 0; i < 5; ++i) {
1232     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1233     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), !!(i % 2)));
1234   }
1235   CloseDBAndBackupEngine();
1236 
1237   for (int i = 0; i < 5; ++i) {
1238     AssertBackupConsistency(i + 1, 0, keys_iteration * (i + 1),
1239                             keys_iteration * 6);
1240   }
1241 }
1242 
1243 // Verify that you can backup and restore using share_files_with_checksum set to
1244 // false and then transition this option to true
TEST_F(BackupableDBTest,ShareTableFilesWithChecksumsTransition)1245 TEST_F(BackupableDBTest, ShareTableFilesWithChecksumsTransition) {
1246   const int keys_iteration = 5000;
1247   // set share_files_with_checksum to false
1248   OpenDBAndBackupEngine(true, false, kShareNoChecksum);
1249   for (int i = 0; i < 5; ++i) {
1250     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1251     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1252   }
1253   CloseDBAndBackupEngine();
1254 
1255   for (int i = 0; i < 5; ++i) {
1256     AssertBackupConsistency(i + 1, 0, keys_iteration * (i + 1),
1257                             keys_iteration * 6);
1258   }
1259 
1260   // set share_files_with_checksum to true and do some more backups
1261   OpenDBAndBackupEngine(false /* destroy_old_data */, false,
1262                         kShareWithChecksum);
1263   for (int i = 5; i < 10; ++i) {
1264     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1265     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1266   }
1267   CloseDBAndBackupEngine();
1268 
1269   // Verify first (about to delete)
1270   AssertBackupConsistency(1, 0, keys_iteration, keys_iteration * 11);
1271 
1272   // For an extra challenge, make sure that GarbageCollect / DeleteBackup
1273   // is OK even if we open without share_table_files
1274   OpenDBAndBackupEngine(false /* destroy_old_data */, false, kNoShare);
1275   backup_engine_->DeleteBackup(1);
1276   backup_engine_->GarbageCollect();
1277   CloseDBAndBackupEngine();
1278 
1279   // Verify rest (not deleted)
1280   for (int i = 1; i < 10; ++i) {
1281     AssertBackupConsistency(i + 1, 0, keys_iteration * (i + 1),
1282                             keys_iteration * 11);
1283   }
1284 }
1285 
1286 // This test simulates cleaning up after aborted or incomplete creation
1287 // of a new backup.
TEST_F(BackupableDBTest,DeleteTmpFiles)1288 TEST_F(BackupableDBTest, DeleteTmpFiles) {
1289   for (int cleanup_fn : {1, 2, 3, 4}) {
1290     for (ShareOption shared_option : kAllShareOptions) {
1291       OpenDBAndBackupEngine(false /* destroy_old_data */, false /* dummy */,
1292                             shared_option);
1293       ASSERT_OK(backup_engine_->CreateNewBackup(db_.get()));
1294       BackupID next_id = 1;
1295       BackupID oldest_id = std::numeric_limits<BackupID>::max();
1296       {
1297         std::vector<BackupInfo> backup_info;
1298         backup_engine_->GetBackupInfo(&backup_info);
1299         for (const auto& bi : backup_info) {
1300           next_id = std::max(next_id, bi.backup_id + 1);
1301           oldest_id = std::min(oldest_id, bi.backup_id);
1302         }
1303       }
1304       CloseDBAndBackupEngine();
1305 
1306       // An aborted or incomplete new backup will always be in the next
1307       // id (maybe more)
1308       std::string next_private = "private/" + std::to_string(next_id);
1309 
1310       // NOTE: both shared and shared_checksum should be cleaned up
1311       // regardless of how the backup engine is opened.
1312       std::vector<std::string> tmp_files_and_dirs;
1313       for (const auto& dir_and_file : {
1314                std::make_pair(std::string("shared"),
1315                               std::string(".00006.sst.tmp")),
1316                std::make_pair(std::string("shared_checksum"),
1317                               std::string(".00007.sst.tmp")),
1318                std::make_pair(next_private, std::string("00003.sst")),
1319            }) {
1320         std::string dir = backupdir_ + "/" + dir_and_file.first;
1321         file_manager_->CreateDir(dir);
1322         ASSERT_OK(file_manager_->FileExists(dir));
1323 
1324         std::string file = dir + "/" + dir_and_file.second;
1325         file_manager_->WriteToFile(file, "tmp");
1326         ASSERT_OK(file_manager_->FileExists(file));
1327 
1328         tmp_files_and_dirs.push_back(file);
1329       }
1330       if (cleanup_fn != /*CreateNewBackup*/ 4) {
1331         // This exists after CreateNewBackup because it's deleted then
1332         // re-created.
1333         tmp_files_and_dirs.push_back(backupdir_ + "/" + next_private);
1334       }
1335 
1336       OpenDBAndBackupEngine(false /* destroy_old_data */, false /* dummy */,
1337                             shared_option);
1338       // Need to call one of these explicitly to delete tmp files
1339       switch (cleanup_fn) {
1340         case 1:
1341           ASSERT_OK(backup_engine_->GarbageCollect());
1342           break;
1343         case 2:
1344           ASSERT_OK(backup_engine_->DeleteBackup(oldest_id));
1345           break;
1346         case 3:
1347           ASSERT_OK(backup_engine_->PurgeOldBackups(1));
1348           break;
1349         case 4:
1350           // Does a garbage collect if it sees that next private dir exists
1351           ASSERT_OK(backup_engine_->CreateNewBackup(db_.get()));
1352           break;
1353         default:
1354           assert(false);
1355       }
1356       CloseDBAndBackupEngine();
1357       for (std::string file_or_dir : tmp_files_and_dirs) {
1358         if (file_manager_->FileExists(file_or_dir) != Status::NotFound()) {
1359           FAIL() << file_or_dir << " was expected to be deleted." << cleanup_fn;
1360         }
1361       }
1362     }
1363   }
1364 }
1365 
TEST_F(BackupableDBTest,KeepLogFiles)1366 TEST_F(BackupableDBTest, KeepLogFiles) {
1367   backupable_options_->backup_log_files = false;
1368   // basically infinite
1369   options_.WAL_ttl_seconds = 24 * 60 * 60;
1370   OpenDBAndBackupEngine(true);
1371   FillDB(db_.get(), 0, 100);
1372   ASSERT_OK(db_->Flush(FlushOptions()));
1373   FillDB(db_.get(), 100, 200);
1374   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
1375   FillDB(db_.get(), 200, 300);
1376   ASSERT_OK(db_->Flush(FlushOptions()));
1377   FillDB(db_.get(), 300, 400);
1378   ASSERT_OK(db_->Flush(FlushOptions()));
1379   FillDB(db_.get(), 400, 500);
1380   ASSERT_OK(db_->Flush(FlushOptions()));
1381   CloseDBAndBackupEngine();
1382 
1383   // all data should be there if we call with keep_log_files = true
1384   AssertBackupConsistency(0, 0, 500, 600, true);
1385 }
1386 
TEST_F(BackupableDBTest,RateLimiting)1387 TEST_F(BackupableDBTest, RateLimiting) {
1388   size_t const kMicrosPerSec = 1000 * 1000LL;
1389   uint64_t const MB = 1024 * 1024;
1390 
1391   const std::vector<std::pair<uint64_t, uint64_t>> limits(
1392       {{1 * MB, 5 * MB}, {2 * MB, 3 * MB}});
1393 
1394   std::shared_ptr<RateLimiter> backupThrottler(NewGenericRateLimiter(1));
1395   std::shared_ptr<RateLimiter> restoreThrottler(NewGenericRateLimiter(1));
1396 
1397   for (bool makeThrottler : {false, true}) {
1398     if (makeThrottler) {
1399       backupable_options_->backup_rate_limiter = backupThrottler;
1400       backupable_options_->restore_rate_limiter = restoreThrottler;
1401     }
1402     // iter 0 -- single threaded
1403     // iter 1 -- multi threaded
1404     for (int iter = 0; iter < 2; ++iter) {
1405       for (const auto& limit : limits) {
1406         // destroy old data
1407         DestroyDB(dbname_, Options());
1408         if (makeThrottler) {
1409           backupThrottler->SetBytesPerSecond(limit.first);
1410           restoreThrottler->SetBytesPerSecond(limit.second);
1411         } else {
1412           backupable_options_->backup_rate_limit = limit.first;
1413           backupable_options_->restore_rate_limit = limit.second;
1414         }
1415         backupable_options_->max_background_operations = (iter == 0) ? 1 : 10;
1416         options_.compression = kNoCompression;
1417         OpenDBAndBackupEngine(true);
1418         size_t bytes_written = FillDB(db_.get(), 0, 100000);
1419 
1420         auto start_backup = db_chroot_env_->NowMicros();
1421         ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
1422         auto backup_time = db_chroot_env_->NowMicros() - start_backup;
1423         auto rate_limited_backup_time =
1424             (bytes_written * kMicrosPerSec) / limit.first;
1425         ASSERT_GT(backup_time, 0.8 * rate_limited_backup_time);
1426 
1427         CloseDBAndBackupEngine();
1428 
1429         OpenBackupEngine();
1430         auto start_restore = db_chroot_env_->NowMicros();
1431         ASSERT_OK(backup_engine_->RestoreDBFromLatestBackup(dbname_, dbname_));
1432         auto restore_time = db_chroot_env_->NowMicros() - start_restore;
1433         CloseBackupEngine();
1434         auto rate_limited_restore_time =
1435             (bytes_written * kMicrosPerSec) / limit.second;
1436         ASSERT_GT(restore_time, 0.8 * rate_limited_restore_time);
1437 
1438         AssertBackupConsistency(0, 0, 100000, 100010);
1439       }
1440     }
1441   }
1442 }
1443 
TEST_F(BackupableDBTest,ReadOnlyBackupEngine)1444 TEST_F(BackupableDBTest, ReadOnlyBackupEngine) {
1445   DestroyDB(dbname_, options_);
1446   OpenDBAndBackupEngine(true);
1447   FillDB(db_.get(), 0, 100);
1448   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1449   FillDB(db_.get(), 100, 200);
1450   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1451   CloseDBAndBackupEngine();
1452   DestroyDB(dbname_, options_);
1453 
1454   backupable_options_->destroy_old_data = false;
1455   test_backup_env_->ClearWrittenFiles();
1456   test_backup_env_->SetLimitDeleteFiles(0);
1457   BackupEngineReadOnly* read_only_backup_engine;
1458   ASSERT_OK(BackupEngineReadOnly::Open(
1459       db_chroot_env_.get(), *backupable_options_, &read_only_backup_engine));
1460   std::vector<BackupInfo> backup_info;
1461   read_only_backup_engine->GetBackupInfo(&backup_info);
1462   ASSERT_EQ(backup_info.size(), 2U);
1463 
1464   RestoreOptions restore_options(false);
1465   ASSERT_OK(read_only_backup_engine->RestoreDBFromLatestBackup(
1466       dbname_, dbname_, restore_options));
1467   delete read_only_backup_engine;
1468   std::vector<std::string> should_have_written;
1469   test_backup_env_->AssertWrittenFiles(should_have_written);
1470 
1471   DB* db = OpenDB();
1472   AssertExists(db, 0, 200);
1473   delete db;
1474 }
1475 
TEST_F(BackupableDBTest,ProgressCallbackDuringBackup)1476 TEST_F(BackupableDBTest, ProgressCallbackDuringBackup) {
1477   DestroyDB(dbname_, options_);
1478   OpenDBAndBackupEngine(true);
1479   FillDB(db_.get(), 0, 100);
1480   bool is_callback_invoked = false;
1481   ASSERT_OK(backup_engine_->CreateNewBackup(
1482       db_.get(), true,
1483       [&is_callback_invoked]() { is_callback_invoked = true; }));
1484 
1485   ASSERT_TRUE(is_callback_invoked);
1486   CloseDBAndBackupEngine();
1487   DestroyDB(dbname_, options_);
1488 }
1489 
TEST_F(BackupableDBTest,GarbageCollectionBeforeBackup)1490 TEST_F(BackupableDBTest, GarbageCollectionBeforeBackup) {
1491   DestroyDB(dbname_, options_);
1492   OpenDBAndBackupEngine(true);
1493 
1494   backup_chroot_env_->CreateDirIfMissing(backupdir_ + "/shared");
1495   std::string file_five = backupdir_ + "/shared/000007.sst";
1496   std::string file_five_contents = "I'm not really a sst file";
1497   // this depends on the fact that 00007.sst is the first file created by the DB
1498   ASSERT_OK(file_manager_->WriteToFile(file_five, file_five_contents));
1499 
1500   FillDB(db_.get(), 0, 100);
1501   // backup overwrites file 000007.sst
1502   ASSERT_TRUE(backup_engine_->CreateNewBackup(db_.get(), true).ok());
1503 
1504   std::string new_file_five_contents;
1505   ASSERT_OK(ReadFileToString(backup_chroot_env_.get(), file_five,
1506                              &new_file_five_contents));
1507   // file 000007.sst was overwritten
1508   ASSERT_TRUE(new_file_five_contents != file_five_contents);
1509 
1510   CloseDBAndBackupEngine();
1511 
1512   AssertBackupConsistency(0, 0, 100);
1513 }
1514 
1515 // Test that we properly propagate Env failures
TEST_F(BackupableDBTest,EnvFailures)1516 TEST_F(BackupableDBTest, EnvFailures) {
1517   BackupEngine* backup_engine;
1518 
1519   // get children failure
1520   {
1521     test_backup_env_->SetGetChildrenFailure(true);
1522     ASSERT_NOK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
1523                                   &backup_engine));
1524     test_backup_env_->SetGetChildrenFailure(false);
1525   }
1526 
1527   // created dir failure
1528   {
1529     test_backup_env_->SetCreateDirIfMissingFailure(true);
1530     ASSERT_NOK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
1531                                   &backup_engine));
1532     test_backup_env_->SetCreateDirIfMissingFailure(false);
1533   }
1534 
1535   // new directory failure
1536   {
1537     test_backup_env_->SetNewDirectoryFailure(true);
1538     ASSERT_NOK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
1539                                   &backup_engine));
1540     test_backup_env_->SetNewDirectoryFailure(false);
1541   }
1542 
1543   // Read from meta-file failure
1544   {
1545     DestroyDB(dbname_, options_);
1546     OpenDBAndBackupEngine(true);
1547     FillDB(db_.get(), 0, 100);
1548     ASSERT_TRUE(backup_engine_->CreateNewBackup(db_.get(), true).ok());
1549     CloseDBAndBackupEngine();
1550     test_backup_env_->SetDummySequentialFile(true);
1551     test_backup_env_->SetDummySequentialFileFailReads(true);
1552     backupable_options_->destroy_old_data = false;
1553     ASSERT_NOK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
1554                                   &backup_engine));
1555     test_backup_env_->SetDummySequentialFile(false);
1556     test_backup_env_->SetDummySequentialFileFailReads(false);
1557   }
1558 
1559   // no failure
1560   {
1561     ASSERT_OK(BackupEngine::Open(test_db_env_.get(), *backupable_options_,
1562                                  &backup_engine));
1563     delete backup_engine;
1564   }
1565 }
1566 
1567 // Verify manifest can roll while a backup is being created with the old
1568 // manifest.
TEST_F(BackupableDBTest,ChangeManifestDuringBackupCreation)1569 TEST_F(BackupableDBTest, ChangeManifestDuringBackupCreation) {
1570   DestroyDB(dbname_, options_);
1571   options_.max_manifest_file_size = 0;  // always rollover manifest for file add
1572   OpenDBAndBackupEngine(true);
1573   FillDB(db_.get(), 0, 100);
1574 
1575   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->LoadDependency({
1576       {"CheckpointImpl::CreateCheckpoint:SavedLiveFiles1",
1577        "VersionSet::LogAndApply:WriteManifest"},
1578       {"VersionSet::LogAndApply:WriteManifestDone",
1579        "CheckpointImpl::CreateCheckpoint:SavedLiveFiles2"},
1580   });
1581   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
1582 
1583   ROCKSDB_NAMESPACE::port::Thread flush_thread{
1584       [this]() { ASSERT_OK(db_->Flush(FlushOptions())); }};
1585 
1586   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), false));
1587 
1588   flush_thread.join();
1589   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
1590 
1591   // The last manifest roll would've already been cleaned up by the full scan
1592   // that happens when CreateNewBackup invokes EnableFileDeletions. We need to
1593   // trigger another roll to verify non-full scan purges stale manifests.
1594   DBImpl* db_impl = reinterpret_cast<DBImpl*>(db_.get());
1595   std::string prev_manifest_path =
1596       DescriptorFileName(dbname_, db_impl->TEST_Current_Manifest_FileNo());
1597   FillDB(db_.get(), 0, 100);
1598   ASSERT_OK(db_chroot_env_->FileExists(prev_manifest_path));
1599   ASSERT_OK(db_->Flush(FlushOptions()));
1600   ASSERT_TRUE(db_chroot_env_->FileExists(prev_manifest_path).IsNotFound());
1601 
1602   CloseDBAndBackupEngine();
1603   DestroyDB(dbname_, options_);
1604   AssertBackupConsistency(0, 0, 100);
1605 }
1606 
1607 // see https://github.com/facebook/rocksdb/issues/921
TEST_F(BackupableDBTest,Issue921Test)1608 TEST_F(BackupableDBTest, Issue921Test) {
1609   BackupEngine* backup_engine;
1610   backupable_options_->share_table_files = false;
1611   backup_chroot_env_->CreateDirIfMissing(backupable_options_->backup_dir);
1612   backupable_options_->backup_dir += "/new_dir";
1613   ASSERT_OK(BackupEngine::Open(backup_chroot_env_.get(), *backupable_options_,
1614                                &backup_engine));
1615 
1616   delete backup_engine;
1617 }
1618 
TEST_F(BackupableDBTest,BackupWithMetadata)1619 TEST_F(BackupableDBTest, BackupWithMetadata) {
1620   const int keys_iteration = 5000;
1621   OpenDBAndBackupEngine(true);
1622   // create five backups
1623   for (int i = 0; i < 5; ++i) {
1624     const std::string metadata = std::to_string(i);
1625     FillDB(db_.get(), keys_iteration * i, keys_iteration * (i + 1));
1626     ASSERT_OK(
1627         backup_engine_->CreateNewBackupWithMetadata(db_.get(), metadata, true));
1628   }
1629   CloseDBAndBackupEngine();
1630 
1631   OpenDBAndBackupEngine();
1632   std::vector<BackupInfo> backup_infos;
1633   backup_engine_->GetBackupInfo(&backup_infos);
1634   ASSERT_EQ(5, backup_infos.size());
1635   for (int i = 0; i < 5; i++) {
1636     ASSERT_EQ(std::to_string(i), backup_infos[i].app_metadata);
1637   }
1638   CloseDBAndBackupEngine();
1639   DestroyDB(dbname_, options_);
1640 }
1641 
TEST_F(BackupableDBTest,BinaryMetadata)1642 TEST_F(BackupableDBTest, BinaryMetadata) {
1643   OpenDBAndBackupEngine(true);
1644   std::string binaryMetadata = "abc\ndef";
1645   binaryMetadata.push_back('\0');
1646   binaryMetadata.append("ghi");
1647   ASSERT_OK(
1648       backup_engine_->CreateNewBackupWithMetadata(db_.get(), binaryMetadata));
1649   CloseDBAndBackupEngine();
1650 
1651   OpenDBAndBackupEngine();
1652   std::vector<BackupInfo> backup_infos;
1653   backup_engine_->GetBackupInfo(&backup_infos);
1654   ASSERT_EQ(1, backup_infos.size());
1655   ASSERT_EQ(binaryMetadata, backup_infos[0].app_metadata);
1656   CloseDBAndBackupEngine();
1657   DestroyDB(dbname_, options_);
1658 }
1659 
TEST_F(BackupableDBTest,MetadataTooLarge)1660 TEST_F(BackupableDBTest, MetadataTooLarge) {
1661   OpenDBAndBackupEngine(true);
1662   std::string largeMetadata(1024 * 1024 + 1, 0);
1663   ASSERT_NOK(
1664       backup_engine_->CreateNewBackupWithMetadata(db_.get(), largeMetadata));
1665   CloseDBAndBackupEngine();
1666   DestroyDB(dbname_, options_);
1667 }
1668 
TEST_F(BackupableDBTest,LimitBackupsOpened)1669 TEST_F(BackupableDBTest, LimitBackupsOpened) {
1670   // Verify the specified max backups are opened, including skipping over
1671   // corrupted backups.
1672   //
1673   // Setup:
1674   // - backups 1, 2, and 4 are valid
1675   // - backup 3 is corrupt
1676   // - max_valid_backups_to_open == 2
1677   //
1678   // Expectation: the engine opens backups 4 and 2 since those are latest two
1679   // non-corrupt backups.
1680   const int kNumKeys = 5000;
1681   OpenDBAndBackupEngine(true);
1682   for (int i = 1; i <= 4; ++i) {
1683     FillDB(db_.get(), kNumKeys * i, kNumKeys * (i + 1));
1684     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1685     if (i == 3) {
1686       ASSERT_OK(file_manager_->CorruptFile(backupdir_ + "/meta/3", 3));
1687     }
1688   }
1689   CloseDBAndBackupEngine();
1690 
1691   backupable_options_->max_valid_backups_to_open = 2;
1692   backupable_options_->destroy_old_data = false;
1693   BackupEngineReadOnly* read_only_backup_engine;
1694   ASSERT_OK(BackupEngineReadOnly::Open(backup_chroot_env_.get(),
1695                                        *backupable_options_,
1696                                        &read_only_backup_engine));
1697 
1698   std::vector<BackupInfo> backup_infos;
1699   read_only_backup_engine->GetBackupInfo(&backup_infos);
1700   ASSERT_EQ(2, backup_infos.size());
1701   ASSERT_EQ(2, backup_infos[0].backup_id);
1702   ASSERT_EQ(4, backup_infos[1].backup_id);
1703   delete read_only_backup_engine;
1704 }
1705 
TEST_F(BackupableDBTest,IgnoreLimitBackupsOpenedWhenNotReadOnly)1706 TEST_F(BackupableDBTest, IgnoreLimitBackupsOpenedWhenNotReadOnly) {
1707   // Verify the specified max_valid_backups_to_open is ignored if the engine
1708   // is not read-only.
1709   //
1710   // Setup:
1711   // - backups 1, 2, and 4 are valid
1712   // - backup 3 is corrupt
1713   // - max_valid_backups_to_open == 2
1714   //
1715   // Expectation: the engine opens backups 4, 2, and 1 since those are latest
1716   // non-corrupt backups, by ignoring max_valid_backups_to_open == 2.
1717   const int kNumKeys = 5000;
1718   OpenDBAndBackupEngine(true);
1719   for (int i = 1; i <= 4; ++i) {
1720     FillDB(db_.get(), kNumKeys * i, kNumKeys * (i + 1));
1721     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1722     if (i == 3) {
1723       ASSERT_OK(file_manager_->CorruptFile(backupdir_ + "/meta/3", 3));
1724     }
1725   }
1726   CloseDBAndBackupEngine();
1727 
1728   backupable_options_->max_valid_backups_to_open = 2;
1729   OpenDBAndBackupEngine();
1730   std::vector<BackupInfo> backup_infos;
1731   backup_engine_->GetBackupInfo(&backup_infos);
1732   ASSERT_EQ(3, backup_infos.size());
1733   ASSERT_EQ(1, backup_infos[0].backup_id);
1734   ASSERT_EQ(2, backup_infos[1].backup_id);
1735   ASSERT_EQ(4, backup_infos[2].backup_id);
1736   CloseDBAndBackupEngine();
1737   DestroyDB(dbname_, options_);
1738 }
1739 
TEST_F(BackupableDBTest,CreateWhenLatestBackupCorrupted)1740 TEST_F(BackupableDBTest, CreateWhenLatestBackupCorrupted) {
1741   // we should pick an ID greater than corrupted backups' IDs so creation can
1742   // succeed even when latest backup is corrupted.
1743   const int kNumKeys = 5000;
1744   OpenDBAndBackupEngine(true /* destroy_old_data */);
1745   FillDB(db_.get(), 0 /* from */, kNumKeys);
1746   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(),
1747                                             true /* flush_before_backup */));
1748   ASSERT_OK(file_manager_->CorruptFile(backupdir_ + "/meta/1",
1749                                        3 /* bytes_to_corrupt */));
1750   CloseDBAndBackupEngine();
1751 
1752   OpenDBAndBackupEngine();
1753   ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(),
1754                                             true /* flush_before_backup */));
1755   std::vector<BackupInfo> backup_infos;
1756   backup_engine_->GetBackupInfo(&backup_infos);
1757   ASSERT_EQ(1, backup_infos.size());
1758   ASSERT_EQ(2, backup_infos[0].backup_id);
1759 }
1760 
TEST_F(BackupableDBTest,WriteOnlyEngineNoSharedFileDeletion)1761 TEST_F(BackupableDBTest, WriteOnlyEngineNoSharedFileDeletion) {
1762   // Verifies a write-only BackupEngine does not delete files belonging to valid
1763   // backups when GarbageCollect, PurgeOldBackups, or DeleteBackup are called.
1764   const int kNumKeys = 5000;
1765   for (int i = 0; i < 3; ++i) {
1766     OpenDBAndBackupEngine(i == 0 /* destroy_old_data */);
1767     FillDB(db_.get(), i * kNumKeys, (i + 1) * kNumKeys);
1768     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(), true));
1769     CloseDBAndBackupEngine();
1770 
1771     backupable_options_->max_valid_backups_to_open = 0;
1772     OpenDBAndBackupEngine();
1773     switch (i) {
1774       case 0:
1775         ASSERT_OK(backup_engine_->GarbageCollect());
1776         break;
1777       case 1:
1778         ASSERT_OK(backup_engine_->PurgeOldBackups(1 /* num_backups_to_keep */));
1779         break;
1780       case 2:
1781         ASSERT_OK(backup_engine_->DeleteBackup(2 /* backup_id */));
1782         break;
1783       default:
1784         assert(false);
1785     }
1786     CloseDBAndBackupEngine();
1787 
1788     backupable_options_->max_valid_backups_to_open = port::kMaxInt32;
1789     AssertBackupConsistency(i + 1, 0, (i + 1) * kNumKeys);
1790   }
1791 }
1792 
TEST_P(BackupableDBTestWithParam,BackupUsingDirectIO)1793 TEST_P(BackupableDBTestWithParam, BackupUsingDirectIO) {
1794   // Tests direct I/O on the backup engine's reads and writes on the DB env and
1795   // backup env
1796   // We use ChrootEnv underneath so the below line checks for direct I/O support
1797   // in the chroot directory, not the true filesystem root.
1798   if (!test::IsDirectIOSupported(test_db_env_.get(), "/")) {
1799     return;
1800   }
1801   const int kNumKeysPerBackup = 100;
1802   const int kNumBackups = 3;
1803   options_.use_direct_reads = true;
1804   OpenDBAndBackupEngine(true /* destroy_old_data */);
1805   for (int i = 0; i < kNumBackups; ++i) {
1806     FillDB(db_.get(), i * kNumKeysPerBackup /* from */,
1807            (i + 1) * kNumKeysPerBackup /* to */);
1808     ASSERT_OK(db_->Flush(FlushOptions()));
1809 
1810     // Clear the file open counters and then do a bunch of backup engine ops.
1811     // For all ops, files should be opened in direct mode.
1812     test_backup_env_->ClearFileOpenCounters();
1813     test_db_env_->ClearFileOpenCounters();
1814     CloseBackupEngine();
1815     OpenBackupEngine();
1816     ASSERT_OK(backup_engine_->CreateNewBackup(db_.get(),
1817                                               false /* flush_before_backup */));
1818     ASSERT_OK(backup_engine_->VerifyBackup(i + 1));
1819     CloseBackupEngine();
1820     OpenBackupEngine();
1821     std::vector<BackupInfo> backup_infos;
1822     backup_engine_->GetBackupInfo(&backup_infos);
1823     ASSERT_EQ(static_cast<size_t>(i + 1), backup_infos.size());
1824 
1825     // Verify backup engine always opened files with direct I/O
1826     ASSERT_EQ(0, test_db_env_->num_writers());
1827     ASSERT_EQ(0, test_db_env_->num_rand_readers());
1828     ASSERT_GT(test_db_env_->num_direct_seq_readers(), 0);
1829     // Currently the DB doesn't support reading WALs or manifest with direct
1830     // I/O, so subtract two.
1831     ASSERT_EQ(test_db_env_->num_seq_readers() - 2,
1832               test_db_env_->num_direct_seq_readers());
1833     ASSERT_EQ(0, test_db_env_->num_rand_readers());
1834   }
1835   CloseDBAndBackupEngine();
1836 
1837   for (int i = 0; i < kNumBackups; ++i) {
1838     AssertBackupConsistency(i + 1 /* backup_id */,
1839                             i * kNumKeysPerBackup /* start_exist */,
1840                             (i + 1) * kNumKeysPerBackup /* end_exist */,
1841                             (i + 2) * kNumKeysPerBackup /* end */);
1842   }
1843 }
1844 
TEST_F(BackupableDBTest,BackgroundThreadCpuPriority)1845 TEST_F(BackupableDBTest, BackgroundThreadCpuPriority) {
1846   std::atomic<CpuPriority> priority(CpuPriority::kNormal);
1847   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->SetCallBack(
1848       "BackupEngineImpl::Initialize:SetCpuPriority", [&](void* new_priority) {
1849         priority.store(*reinterpret_cast<CpuPriority*>(new_priority));
1850       });
1851   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->EnableProcessing();
1852 
1853   // 1 thread is easier to test, otherwise, we may not be sure which thread
1854   // actually does the work during CreateNewBackup.
1855   backupable_options_->max_background_operations = 1;
1856   OpenDBAndBackupEngine(true);
1857 
1858   {
1859     FillDB(db_.get(), 0, 100);
1860 
1861     // by default, cpu priority is not changed.
1862     CreateBackupOptions options;
1863     ASSERT_OK(backup_engine_->CreateNewBackup(options, db_.get()));
1864 
1865     ASSERT_EQ(priority, CpuPriority::kNormal);
1866   }
1867 
1868   {
1869     FillDB(db_.get(), 101, 200);
1870 
1871     // decrease cpu priority from normal to low.
1872     CreateBackupOptions options;
1873     options.decrease_background_thread_cpu_priority = true;
1874     options.background_thread_cpu_priority = CpuPriority::kLow;
1875     ASSERT_OK(backup_engine_->CreateNewBackup(options, db_.get()));
1876 
1877     ASSERT_EQ(priority, CpuPriority::kLow);
1878   }
1879 
1880   {
1881     FillDB(db_.get(), 201, 300);
1882 
1883     // try to upgrade cpu priority back to normal,
1884     // the priority should still low.
1885     CreateBackupOptions options;
1886     options.decrease_background_thread_cpu_priority = true;
1887     options.background_thread_cpu_priority = CpuPriority::kNormal;
1888     ASSERT_OK(backup_engine_->CreateNewBackup(options, db_.get()));
1889 
1890     ASSERT_EQ(priority, CpuPriority::kLow);
1891   }
1892 
1893   {
1894     FillDB(db_.get(), 301, 400);
1895 
1896     // decrease cpu priority from low to idle.
1897     CreateBackupOptions options;
1898     options.decrease_background_thread_cpu_priority = true;
1899     options.background_thread_cpu_priority = CpuPriority::kIdle;
1900     ASSERT_OK(backup_engine_->CreateNewBackup(options, db_.get()));
1901 
1902     ASSERT_EQ(priority, CpuPriority::kIdle);
1903   }
1904 
1905   {
1906     FillDB(db_.get(), 301, 400);
1907 
1908     // reset priority to later verify that it's not updated by SetCpuPriority.
1909     priority = CpuPriority::kNormal;
1910 
1911     // setting the same cpu priority won't call SetCpuPriority.
1912     CreateBackupOptions options;
1913     options.decrease_background_thread_cpu_priority = true;
1914     options.background_thread_cpu_priority = CpuPriority::kIdle;
1915     ASSERT_OK(backup_engine_->CreateNewBackup(options, db_.get()));
1916 
1917     ASSERT_EQ(priority, CpuPriority::kNormal);
1918   }
1919 
1920   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->DisableProcessing();
1921   ROCKSDB_NAMESPACE::SyncPoint::GetInstance()->ClearAllCallBacks();
1922   CloseDBAndBackupEngine();
1923   DestroyDB(dbname_, options_);
1924 }
1925 
1926 }  // anon namespace
1927 
1928 }  // namespace ROCKSDB_NAMESPACE
1929 
main(int argc,char ** argv)1930 int main(int argc, char** argv) {
1931   ROCKSDB_NAMESPACE::port::InstallStackTraceHandler();
1932   ::testing::InitGoogleTest(&argc, argv);
1933   return RUN_ALL_TESTS();
1934 }
1935 
1936 #else
1937 #include <stdio.h>
1938 
main(int,char **)1939 int main(int /*argc*/, char** /*argv*/) {
1940   fprintf(stderr, "SKIPPED as BackupableDB is not supported in ROCKSDB_LITE\n");
1941   return 0;
1942 }
1943 
1944 #endif  // !defined(ROCKSDB_LITE) && !defined(OS_WIN)
1945