20
20
#include < map>
21
21
#include < string>
22
22
#include < limits>
23
+ #include < atomic>
23
24
24
25
namespace rocksdb {
25
26
@@ -31,6 +32,9 @@ class BackupEngine {
31
32
Status CreateNewBackup (DB* db, bool flush_before_backup = false );
32
33
Status PurgeOldBackups (uint32_t num_backups_to_keep);
33
34
Status DeleteBackup (BackupID backup_id);
35
+ void StopBackup () {
36
+ stop_backup_.store (true , std::memory_order_release);
37
+ }
34
38
35
39
void GetBackupInfo (std::vector<BackupInfo>* backup_info);
36
40
Status RestoreDBFromBackup (BackupID backup_id, const std::string &db_dir,
@@ -106,13 +110,16 @@ class BackupEngine {
106
110
return " private" ;
107
111
}
108
112
inline std::string GetPrivateFileRel (BackupID backup_id,
109
- const std::string &file = " " ) const {
113
+ bool tmp = false ,
114
+ const std::string& file = " " ) const {
110
115
assert (file.size () == 0 || file[0 ] != ' /' );
111
- return GetPrivateDirRel () + " /" + std::to_string (backup_id) + " /" + file;
116
+ return GetPrivateDirRel () + " /" + std::to_string (backup_id) +
117
+ (tmp ? " .tmp" : " " ) + " /" + file;
112
118
}
113
- inline std::string GetSharedFileRel (const std::string& file = " " ) const {
119
+ inline std::string GetSharedFileRel (const std::string& file = " " ,
120
+ bool tmp = false ) const {
114
121
assert (file.size () == 0 || file[0 ] != ' /' );
115
- return " shared/" + file;
122
+ return " shared/" + file + (tmp ? " .tmp " : " " ) ;
116
123
}
117
124
inline std::string GetLatestBackupFile (bool tmp = false ) const {
118
125
return GetAbsolutePath (std::string (" LATEST_BACKUP" ) + (tmp ? " .tmp" : " " ));
@@ -151,6 +158,7 @@ class BackupEngine {
151
158
std::map<BackupID, BackupMeta> backups_;
152
159
std::unordered_map<std::string, int > backuped_file_refs_;
153
160
std::vector<BackupID> obsolete_backups_;
161
+ std::atomic<bool > stop_backup_;
154
162
155
163
// options data
156
164
BackupableDBOptions options_;
@@ -161,13 +169,17 @@ class BackupEngine {
161
169
};
162
170
163
171
BackupEngine::BackupEngine (Env* db_env, const BackupableDBOptions& options)
164
- : options_(options),
165
- db_env_ (db_env),
166
- backup_env_(options.backup_env != nullptr ? options.backup_env : db_env_) {
172
+ : stop_backup_(false ),
173
+ options_ (options),
174
+ db_env_(db_env),
175
+ backup_env_(options.backup_env != nullptr ? options.backup_env
176
+ : db_env_) {
167
177
168
178
// create all the dirs we need
169
179
backup_env_->CreateDirIfMissing (GetAbsolutePath ());
170
- backup_env_->CreateDirIfMissing (GetAbsolutePath (GetSharedFileRel ()));
180
+ if (!options_.share_table_files ) {
181
+ backup_env_->CreateDirIfMissing (GetAbsolutePath (GetSharedFileRel ()));
182
+ }
171
183
backup_env_->CreateDirIfMissing (GetAbsolutePath (GetPrivateDirRel ()));
172
184
backup_env_->CreateDirIfMissing (GetBackupMetaDir ());
173
185
@@ -298,8 +310,9 @@ Status BackupEngine::CreateNewBackup(DB* db, bool flush_before_backup) {
298
310
Log (options_.info_log , " Started the backup process -- creating backup %u" ,
299
311
new_backup_id);
300
312
301
- // create private dir
302
- s = backup_env_->CreateDir (GetAbsolutePath (GetPrivateFileRel (new_backup_id)));
313
+ // create temporary private dir
314
+ s = backup_env_->CreateDir (
315
+ GetAbsolutePath (GetPrivateFileRel (new_backup_id, true )));
303
316
304
317
// copy live_files
305
318
for (size_t i = 0 ; s.ok () && i < live_files.size (); ++i) {
@@ -320,7 +333,7 @@ Status BackupEngine::CreateNewBackup(DB* db, bool flush_before_backup) {
320
333
// * if it's kDescriptorFile, limit the size to manifest_file_size
321
334
s = BackupFile (new_backup_id,
322
335
&new_backup,
323
- type == kTableFile , /* shared */
336
+ options_. share_table_files && type == kTableFile ,
324
337
db->GetName (), /* src_dir */
325
338
live_files[i], /* src_fname */
326
339
(type == kDescriptorFile ) ? manifest_file_size : 0 );
@@ -342,6 +355,13 @@ Status BackupEngine::CreateNewBackup(DB* db, bool flush_before_backup) {
342
355
// we copied all the files, enable file deletions
343
356
db->EnableFileDeletions ();
344
357
358
+ if (s.ok ()) {
359
+ // move tmp private backup to real backup folder
360
+ s = backup_env_->RenameFile (
361
+ GetAbsolutePath (GetPrivateFileRel (new_backup_id, true )), // tmp
362
+ GetAbsolutePath (GetPrivateFileRel (new_backup_id, false )));
363
+ }
364
+
345
365
if (s.ok ()) {
346
366
// persist the backup metadata on the disk
347
367
s = new_backup.StoreToFile (options_.sync );
@@ -561,6 +581,9 @@ Status BackupEngine::CopyFile(const std::string& src,
561
581
Slice data;
562
582
563
583
do {
584
+ if (stop_backup_.load (std::memory_order_acquire)) {
585
+ return Status::Incomplete (" Backup stopped" );
586
+ }
564
587
size_t buffer_to_read = (copy_file_buffer_size_ < size_limit) ?
565
588
copy_file_buffer_size_ : size_limit;
566
589
s = src_file->Read (buffer_to_read, &data, buf.get ());
@@ -590,12 +613,16 @@ Status BackupEngine::BackupFile(BackupID backup_id,
590
613
591
614
assert (src_fname.size () > 0 && src_fname[0 ] == ' /' );
592
615
std::string dst_relative = src_fname.substr (1 );
616
+ std::string dst_relative_tmp;
593
617
if (shared) {
594
- dst_relative = GetSharedFileRel (dst_relative);
618
+ dst_relative_tmp = GetSharedFileRel (dst_relative, true );
619
+ dst_relative = GetSharedFileRel (dst_relative, false );
595
620
} else {
596
- dst_relative = GetPrivateFileRel (backup_id, dst_relative);
621
+ dst_relative_tmp = GetPrivateFileRel (backup_id, true , dst_relative);
622
+ dst_relative = GetPrivateFileRel (backup_id, false , dst_relative);
597
623
}
598
624
std::string dst_path = GetAbsolutePath (dst_relative);
625
+ std::string dst_path_tmp = GetAbsolutePath (dst_relative_tmp);
599
626
Status s;
600
627
uint64_t size;
601
628
@@ -607,12 +634,15 @@ Status BackupEngine::BackupFile(BackupID backup_id,
607
634
} else {
608
635
Log (options_.info_log , " Copying %s" , src_fname.c_str ());
609
636
s = CopyFile (src_dir + src_fname,
610
- dst_path ,
637
+ dst_path_tmp ,
611
638
db_env_,
612
639
backup_env_,
613
640
options_.sync ,
614
641
&size,
615
642
size_limit);
643
+ if (s.ok () && shared) {
644
+ s = backup_env_->RenameFile (dst_path_tmp, dst_path);
645
+ }
616
646
}
617
647
if (s.ok ()) {
618
648
backup->AddFile (dst_relative, size);
@@ -671,14 +701,16 @@ void BackupEngine::GarbageCollection(bool full_scan) {
671
701
&private_children);
672
702
for (auto & child : private_children) {
673
703
BackupID backup_id = 0 ;
704
+ bool tmp_dir = child.find (" .tmp" ) != std::string::npos;
674
705
sscanf (child.c_str (), " %u" , &backup_id);
675
- if (backup_id == 0 || backups_.find (backup_id) != backups_.end ()) {
706
+ if (!tmp_dir && // if it's tmp_dir, delete it
707
+ (backup_id == 0 || backups_.find (backup_id) != backups_.end ())) {
676
708
// it's either not a number or it's still alive. continue
677
709
continue ;
678
710
}
679
711
// here we have to delete the dir and all its children
680
712
std::string full_private_path =
681
- GetAbsolutePath (GetPrivateFileRel (backup_id));
713
+ GetAbsolutePath (GetPrivateFileRel (backup_id, tmp_dir ));
682
714
std::vector<std::string> subchildren;
683
715
backup_env_->GetChildren (full_private_path, &subchildren);
684
716
for (auto & subchild : subchildren) {
@@ -813,7 +845,9 @@ Status BackupEngine::BackupMeta::StoreToFile(bool sync) {
813
845
814
846
BackupableDB::BackupableDB (DB* db, const BackupableDBOptions& options)
815
847
: StackableDB(db), backup_engine_(new BackupEngine(db->GetEnv (), options)) {
816
- backup_engine_->DeleteBackupsNewerThan (GetLatestSequenceNumber ());
848
+ if (options.share_table_files ) {
849
+ backup_engine_->DeleteBackupsNewerThan (GetLatestSequenceNumber ());
850
+ }
817
851
}
818
852
819
853
BackupableDB::~BackupableDB () {
@@ -836,6 +870,10 @@ Status BackupableDB::DeleteBackup(BackupID backup_id) {
836
870
return backup_engine_->DeleteBackup (backup_id);
837
871
}
838
872
873
+ void BackupableDB::StopBackup () {
874
+ backup_engine_->StopBackup ();
875
+ }
876
+
839
877
// --- RestoreBackupableDB methods ------
840
878
841
879
RestoreBackupableDB::RestoreBackupableDB (Env* db_env,
0 commit comments