Skip to content

Commit 64904b3

Browse files
committed
Merge branch 'master' into columnfamilies
Conflicts: utilities/backupable/backupable_db.cc
2 parents e0c1211 + 5601bc4 commit 64904b3

File tree

5 files changed

+150
-52
lines changed

5 files changed

+150
-52
lines changed

db/memtable.cc

+8-6
Original file line numberDiff line numberDiff line change
@@ -78,21 +78,23 @@ bool MemTable::ShouldFlushNow() const {
7878
auto allocated_memory =
7979
table_->ApproximateMemoryUsage() + arena_.MemoryAllocatedBytes();
8080

81-
if (allocated_memory + kArenaBlockSize * kAllowOverAllocationRatio <
82-
kWriteBufferSize) {
81+
// if we can still allocate one more block without exceeding the
82+
// over-allocation ratio, then we should not flush.
83+
if (allocated_memory + kArenaBlockSize <
84+
kWriteBufferSize + kArenaBlockSize * kAllowOverAllocationRatio) {
8385
return false;
8486
}
8587

8688
// if user keeps adding entries that exceeds kWriteBufferSize, we need to
87-
// flush
88-
// earlier even though we still have much available memory left.
89-
if (allocated_memory > kWriteBufferSize * (1 + kAllowOverAllocationRatio)) {
89+
// flush earlier even though we still have much available memory left.
90+
if (allocated_memory >
91+
kWriteBufferSize + kArenaBlockSize * kAllowOverAllocationRatio) {
9092
return true;
9193
}
9294

9395
// In this code path, Arena has already allocated its "last block", which
9496
// means the total allocatedmemory size is either:
95-
// (1) "moderately" over allocated the memory (no more than `0.4 * arena
97+
// (1) "moderately" over allocated the memory (no more than `0.6 * arena
9698
// block size`. Or,
9799
// (2) the allocated memory is less than write buffer size, but we'll stop
98100
// here since if we allocate a new arena block, we'll over allocate too much

include/utilities/backupable_db.h

+34-9
Original file line numberDiff line numberDiff line change
@@ -55,19 +55,39 @@ struct BackupableDBOptions {
5555
// Default: false
5656
bool destroy_old_data;
5757

58+
// If false, we won't backup log files. This option can be useful for backing
59+
// up in-memory databases where log file are persisted, but table files are in
60+
// memory.
61+
// Default: true
62+
bool backup_log_files;
63+
5864
void Dump(Logger* logger) const;
5965

6066
explicit BackupableDBOptions(const std::string& _backup_dir,
6167
Env* _backup_env = nullptr,
6268
bool _share_table_files = true,
6369
Logger* _info_log = nullptr, bool _sync = true,
64-
bool _destroy_old_data = false)
70+
bool _destroy_old_data = false,
71+
bool _backup_log_files = true)
6572
: backup_dir(_backup_dir),
6673
backup_env(_backup_env),
6774
share_table_files(_share_table_files),
6875
info_log(_info_log),
6976
sync(_sync),
70-
destroy_old_data(_destroy_old_data) {}
77+
destroy_old_data(_destroy_old_data),
78+
backup_log_files(_backup_log_files) {}
79+
};
80+
81+
struct RestoreOptions {
82+
// If true, restore won't overwrite the existing log files in wal_dir. It will
83+
// also move all log files from archive directory to wal_dir. Use this option
84+
// in combination with BackupableDBOptions::backup_log_files = false for
85+
// persisting in-memory databases.
86+
// Default: false
87+
bool keep_log_files;
88+
89+
explicit RestoreOptions(bool _keep_log_files = false)
90+
: keep_log_files(_keep_log_files) {}
7191
};
7292

7393
typedef uint32_t BackupID;
@@ -96,11 +116,12 @@ class BackupEngine {
96116
virtual void StopBackup() = 0;
97117

98118
virtual void GetBackupInfo(std::vector<BackupInfo>* backup_info) = 0;
99-
virtual Status RestoreDBFromBackup(BackupID backup_id,
100-
const std::string& db_dir,
101-
const std::string& wal_dir) = 0;
102-
virtual Status RestoreDBFromLatestBackup(const std::string& db_dir,
103-
const std::string& wal_dir) = 0;
119+
virtual Status RestoreDBFromBackup(
120+
BackupID backup_id, const std::string& db_dir, const std::string& wal_dir,
121+
const RestoreOptions& restore_options = RestoreOptions()) = 0;
122+
virtual Status RestoreDBFromLatestBackup(
123+
const std::string& db_dir, const std::string& wal_dir,
124+
const RestoreOptions& restore_options = RestoreOptions()) = 0;
104125
};
105126

106127
// Stack your DB with BackupableDB to be able to backup the DB
@@ -156,11 +177,15 @@ class RestoreBackupableDB {
156177
// If you want to create new backup, you will first have to delete backups 4
157178
// and 5.
158179
Status RestoreDBFromBackup(BackupID backup_id, const std::string& db_dir,
159-
const std::string& wal_dir);
180+
const std::string& wal_dir,
181+
const RestoreOptions& restore_options =
182+
RestoreOptions());
160183

161184
// restore from the latest backup
162185
Status RestoreDBFromLatestBackup(const std::string& db_dir,
163-
const std::string& wal_dir);
186+
const std::string& wal_dir,
187+
const RestoreOptions& restore_options =
188+
RestoreOptions());
164189
// deletes old backups, keeping latest num_backups_to_keep alive
165190
Status PurgeOldBackups(uint32_t num_backups_to_keep);
166191
// deletes a specific backup

tools/db_stress.cc

+5-3
Original file line numberDiff line numberDiff line change
@@ -979,13 +979,14 @@ class StressTest {
979979
}
980980

981981
int count = 0;
982-
while (iters[0]->Valid()) {
982+
while (iters[0]->Valid() && iters[0]->key().starts_with(prefix_slices[0])) {
983983
count++;
984984
std::string values[10];
985985
// get list of all values for this iteration
986986
for (int i = 0; i < 10; i++) {
987987
// no iterator should finish before the first one
988-
assert(iters[i]->Valid());
988+
assert(iters[i]->Valid() &&
989+
iters[i]->key().starts_with(prefix_slices[i]));
989990
values[i] = iters[i]->value().ToString();
990991

991992
char expected_first = (prefixes[i])[0];
@@ -1013,7 +1014,8 @@ class StressTest {
10131014
// cleanup iterators and snapshot
10141015
for (int i = 0; i < 10; i++) {
10151016
// if the first iterator finished, they should have all finished
1016-
assert(!iters[i]->Valid());
1017+
assert(!iters[i]->Valid() ||
1018+
!iters[i]->key().starts_with(prefix_slices[i]));
10171019
assert(iters[i]->status().ok());
10181020
delete iters[i];
10191021
}

utilities/backupable/backupable_db.cc

+75-31
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ void BackupableDBOptions::Dump(Logger* logger) const {
3535
Log(logger, " Options.sync: %d", static_cast<int>(sync));
3636
Log(logger, " Options.destroy_old_data: %d",
3737
static_cast<int>(destroy_old_data));
38+
Log(logger, " Options.backup_log_files: %d",
39+
static_cast<int>(backup_log_files));
3840
}
3941

4042
// -------- BackupEngineImpl class ---------
@@ -50,14 +52,21 @@ class BackupEngineImpl : public BackupEngine {
5052
}
5153

5254
void GetBackupInfo(std::vector<BackupInfo>* backup_info);
53-
Status RestoreDBFromBackup(BackupID backup_id, const std::string &db_dir,
54-
const std::string &wal_dir);
55-
Status RestoreDBFromLatestBackup(const std::string &db_dir,
56-
const std::string &wal_dir) {
57-
return RestoreDBFromBackup(latest_backup_id_, db_dir, wal_dir);
55+
Status RestoreDBFromBackup(BackupID backup_id, const std::string& db_dir,
56+
const std::string& wal_dir,
57+
const RestoreOptions& restore_options =
58+
RestoreOptions());
59+
Status RestoreDBFromLatestBackup(const std::string& db_dir,
60+
const std::string& wal_dir,
61+
const RestoreOptions& restore_options =
62+
RestoreOptions()) {
63+
return RestoreDBFromBackup(latest_backup_id_, db_dir, wal_dir,
64+
restore_options);
5865
}
5966

6067
private:
68+
void DeleteChildren(const std::string& dir, uint32_t file_type_filter = 0);
69+
6170
struct FileInfo {
6271
FileInfo(const std::string& fname, uint64_t sz, uint32_t checksum)
6372
: refs(0), filename(fname), size(sz), checksum_value(checksum) {}
@@ -314,7 +323,8 @@ Status BackupEngineImpl::CreateNewBackup(DB* db, bool flush_before_backup) {
314323
// this will return live_files prefixed with "/"
315324
s = db->GetLiveFiles(live_files, &manifest_file_size, flush_before_backup);
316325
}
317-
if (s.ok()) {
326+
// if we didn't flush before backup, we need to also get WAL files
327+
if (s.ok() && !flush_before_backup && options_.backup_log_files) {
318328
// returns file names prefixed with "/"
319329
s = db->GetSortedWalFiles(live_wal_files);
320330
}
@@ -468,9 +478,9 @@ void BackupEngineImpl::GetBackupInfo(std::vector<BackupInfo>* backup_info) {
468478
}
469479
}
470480

471-
Status BackupEngineImpl::RestoreDBFromBackup(BackupID backup_id,
472-
const std::string& db_dir,
473-
const std::string& wal_dir) {
481+
Status BackupEngineImpl::RestoreDBFromBackup(
482+
BackupID backup_id, const std::string& db_dir, const std::string& wal_dir,
483+
const RestoreOptions& restore_options) {
474484
auto backup_itr = backups_.find(backup_id);
475485
if (backup_itr == backups_.end()) {
476486
return Status::NotFound("Backup not found");
@@ -481,25 +491,40 @@ Status BackupEngineImpl::RestoreDBFromBackup(BackupID backup_id,
481491
}
482492

483493
Log(options_.info_log, "Restoring backup id %u\n", backup_id);
494+
Log(options_.info_log, "keep_log_files: %d\n",
495+
static_cast<int>(restore_options.keep_log_files));
484496

485497
// just in case. Ignore errors
486498
db_env_->CreateDirIfMissing(db_dir);
487499
db_env_->CreateDirIfMissing(wal_dir);
488500

489-
// delete log files that might have been already in wal_dir.
490-
// This is important since they might get replayed to the restored DB,
491-
// which will then differ from the backuped DB
492-
std::vector<std::string> delete_children;
493-
db_env_->GetChildren(wal_dir, &delete_children); // ignore errors
494-
for (auto f : delete_children) {
495-
db_env_->DeleteFile(wal_dir + "/" + f); // ignore errors
496-
}
497-
// Also delete all the db_dir children. This is not so important
498-
// because obsolete files will be deleted by DBImpl::PurgeObsoleteFiles()
499-
delete_children.clear();
500-
db_env_->GetChildren(db_dir, &delete_children); // ignore errors
501-
for (auto f : delete_children) {
502-
db_env_->DeleteFile(db_dir + "/" + f); // ignore errors
501+
if (restore_options.keep_log_files) {
502+
// delete files in db_dir, but keep all the log files
503+
DeleteChildren(db_dir, 1 << kLogFile);
504+
// move all the files from archive dir to wal_dir
505+
std::string archive_dir = ArchivalDirectory(wal_dir);
506+
std::vector<std::string> archive_files;
507+
db_env_->GetChildren(archive_dir, &archive_files); // ignore errors
508+
for (const auto& f : archive_files) {
509+
uint64_t number;
510+
FileType type;
511+
bool ok = ParseFileName(f, &number, &type);
512+
if (ok && type == kLogFile) {
513+
Log(options_.info_log, "Moving log file from archive/ to wal_dir: %s",
514+
f.c_str());
515+
Status s =
516+
db_env_->RenameFile(archive_dir + "/" + f, wal_dir + "/" + f);
517+
if (!s.ok()) {
518+
// if we can't move log file from archive_dir to wal_dir,
519+
// we should fail, since it might mean data loss
520+
return s;
521+
}
522+
}
523+
}
524+
} else {
525+
DeleteChildren(wal_dir);
526+
DeleteChildren(ArchivalDirectory(wal_dir));
527+
DeleteChildren(db_dir);
503528
}
504529

505530
Status s;
@@ -760,6 +785,23 @@ Status BackupEngineImpl::CalculateChecksum(const std::string& src, Env* src_env,
760785
return s;
761786
}
762787

788+
void BackupEngineImpl::DeleteChildren(const std::string& dir,
789+
uint32_t file_type_filter) {
790+
std::vector<std::string> children;
791+
db_env_->GetChildren(dir, &children); // ignore errors
792+
793+
for (const auto& f : children) {
794+
uint64_t number;
795+
FileType type;
796+
bool ok = ParseFileName(f, &number, &type);
797+
if (ok && (file_type_filter & (1 << type))) {
798+
// don't delete this file
799+
continue;
800+
}
801+
db_env_->DeleteFile(dir + "/" + f); // ignore errors
802+
}
803+
}
804+
763805
void BackupEngineImpl::GarbageCollection(bool full_scan) {
764806
Log(options_.info_log, "Starting garbage collection");
765807
std::vector<std::string> to_delete;
@@ -1042,16 +1084,18 @@ RestoreBackupableDB::GetBackupInfo(std::vector<BackupInfo>* backup_info) {
10421084
backup_engine_->GetBackupInfo(backup_info);
10431085
}
10441086

1045-
Status RestoreBackupableDB::RestoreDBFromBackup(BackupID backup_id,
1046-
const std::string& db_dir,
1047-
const std::string& wal_dir) {
1048-
return backup_engine_->RestoreDBFromBackup(backup_id, db_dir, wal_dir);
1087+
Status RestoreBackupableDB::RestoreDBFromBackup(
1088+
BackupID backup_id, const std::string& db_dir, const std::string& wal_dir,
1089+
const RestoreOptions& restore_options) {
1090+
return backup_engine_->RestoreDBFromBackup(backup_id, db_dir, wal_dir,
1091+
restore_options);
10491092
}
10501093

1051-
Status
1052-
RestoreBackupableDB::RestoreDBFromLatestBackup(const std::string& db_dir,
1053-
const std::string& wal_dir) {
1054-
return backup_engine_->RestoreDBFromLatestBackup(db_dir, wal_dir);
1094+
Status RestoreBackupableDB::RestoreDBFromLatestBackup(
1095+
const std::string& db_dir, const std::string& wal_dir,
1096+
const RestoreOptions& restore_options) {
1097+
return backup_engine_->RestoreDBFromLatestBackup(db_dir, wal_dir,
1098+
restore_options);
10551099
}
10561100

10571101
Status RestoreBackupableDB::PurgeOldBackups(uint32_t num_backups_to_keep) {

utilities/backupable/backupable_db_test.cc

+28-3
Original file line numberDiff line numberDiff line change
@@ -402,16 +402,20 @@ class BackupableDBTest {
402402
// if backup_id == 0, it means restore from latest
403403
// if end == 0, don't check AssertEmpty
404404
void AssertBackupConsistency(BackupID backup_id, uint32_t start_exist,
405-
uint32_t end_exist, uint32_t end = 0) {
405+
uint32_t end_exist, uint32_t end = 0,
406+
bool keep_log_files = false) {
407+
RestoreOptions restore_options(keep_log_files);
406408
bool opened_restore = false;
407409
if (restore_db_.get() == nullptr) {
408410
opened_restore = true;
409411
OpenRestoreDB();
410412
}
411413
if (backup_id > 0) {
412-
ASSERT_OK(restore_db_->RestoreDBFromBackup(backup_id, dbname_, dbname_));
414+
ASSERT_OK(restore_db_->RestoreDBFromBackup(backup_id, dbname_, dbname_,
415+
restore_options));
413416
} else {
414-
ASSERT_OK(restore_db_->RestoreDBFromLatestBackup(dbname_, dbname_));
417+
ASSERT_OK(restore_db_->RestoreDBFromLatestBackup(dbname_, dbname_,
418+
restore_options));
415419
}
416420
DB* db = OpenDB();
417421
AssertExists(db, start_exist, end_exist);
@@ -795,6 +799,27 @@ TEST(BackupableDBTest, DeleteTmpFiles) {
795799
ASSERT_EQ(false, file_manager_->FileExists(private_tmp_dir));
796800
}
797801

802+
TEST(BackupableDBTest, KeepLogFiles) {
803+
// basically infinite
804+
backupable_options_->backup_log_files = false;
805+
options_.WAL_ttl_seconds = 24 * 60 * 60;
806+
OpenBackupableDB(true);
807+
FillDB(db_.get(), 0, 100);
808+
ASSERT_OK(db_->Flush(FlushOptions()));
809+
FillDB(db_.get(), 100, 200);
810+
ASSERT_OK(db_->CreateNewBackup(false));
811+
FillDB(db_.get(), 200, 300);
812+
ASSERT_OK(db_->Flush(FlushOptions()));
813+
FillDB(db_.get(), 300, 400);
814+
ASSERT_OK(db_->Flush(FlushOptions()));
815+
FillDB(db_.get(), 400, 500);
816+
ASSERT_OK(db_->Flush(FlushOptions()));
817+
CloseBackupableDB();
818+
819+
// all data should be there if we call with keep_log_files = true
820+
AssertBackupConsistency(0, 0, 500, 600, true);
821+
}
822+
798823
} // anon namespace
799824

800825
} // namespace rocksdb

0 commit comments

Comments
 (0)