@ -20,6 +20,7 @@
# include <map>
# include <map>
# include <string>
# include <string>
# include <limits>
# include <limits>
# include <atomic>
namespace rocksdb {
namespace rocksdb {
@ -31,6 +32,9 @@ class BackupEngine {
Status CreateNewBackup ( DB * db , bool flush_before_backup = false ) ;
Status CreateNewBackup ( DB * db , bool flush_before_backup = false ) ;
Status PurgeOldBackups ( uint32_t num_backups_to_keep ) ;
Status PurgeOldBackups ( uint32_t num_backups_to_keep ) ;
Status DeleteBackup ( BackupID backup_id ) ;
Status DeleteBackup ( BackupID backup_id ) ;
void StopBackup ( ) {
stop_backup_ . store ( true , std : : memory_order_release ) ;
}
void GetBackupInfo ( std : : vector < BackupInfo > * backup_info ) ;
void GetBackupInfo ( std : : vector < BackupInfo > * backup_info ) ;
Status RestoreDBFromBackup ( BackupID backup_id , const std : : string & db_dir ,
Status RestoreDBFromBackup ( BackupID backup_id , const std : : string & db_dir ,
@ -106,13 +110,16 @@ class BackupEngine {
return " private " ;
return " private " ;
}
}
inline std : : string GetPrivateFileRel ( BackupID backup_id ,
inline std : : string GetPrivateFileRel ( BackupID backup_id ,
const std : : string & file = " " ) const {
bool tmp = false ,
const std : : string & file = " " ) const {
assert ( file . size ( ) = = 0 | | file [ 0 ] ! = ' / ' ) ;
assert ( file . size ( ) = = 0 | | file [ 0 ] ! = ' / ' ) ;
return GetPrivateDirRel ( ) + " / " + std : : to_string ( backup_id ) + " / " + file ;
return GetPrivateDirRel ( ) + " / " + std : : to_string ( backup_id ) +
( tmp ? " .tmp " : " " ) + " / " + file ;
}
}
inline std : : string GetSharedFileRel ( const std : : string & file = " " ) const {
inline std : : string GetSharedFileRel ( const std : : string & file = " " ,
bool tmp = false ) const {
assert ( file . size ( ) = = 0 | | file [ 0 ] ! = ' / ' ) ;
assert ( file . size ( ) = = 0 | | file [ 0 ] ! = ' / ' ) ;
return " shared/ " + file ;
return " shared/ " + file + ( tmp ? " .tmp " : " " ) ;
}
}
inline std : : string GetLatestBackupFile ( bool tmp = false ) const {
inline std : : string GetLatestBackupFile ( bool tmp = false ) const {
return GetAbsolutePath ( std : : string ( " LATEST_BACKUP " ) + ( tmp ? " .tmp " : " " ) ) ;
return GetAbsolutePath ( std : : string ( " LATEST_BACKUP " ) + ( tmp ? " .tmp " : " " ) ) ;
@ -151,6 +158,7 @@ class BackupEngine {
std : : map < BackupID , BackupMeta > backups_ ;
std : : map < BackupID , BackupMeta > backups_ ;
std : : unordered_map < std : : string , int > backuped_file_refs_ ;
std : : unordered_map < std : : string , int > backuped_file_refs_ ;
std : : vector < BackupID > obsolete_backups_ ;
std : : vector < BackupID > obsolete_backups_ ;
std : : atomic < bool > stop_backup_ ;
// options data
// options data
BackupableDBOptions options_ ;
BackupableDBOptions options_ ;
@ -161,13 +169,17 @@ class BackupEngine {
} ;
} ;
BackupEngine : : BackupEngine ( Env * db_env , const BackupableDBOptions & options )
BackupEngine : : BackupEngine ( Env * db_env , const BackupableDBOptions & options )
: options_ ( options ) ,
: stop_backup_ ( false ) ,
db_env_ ( db_env ) ,
options_ ( options ) ,
backup_env_ ( options . backup_env ! = nullptr ? options . backup_env : db_env_ ) {
db_env_ ( db_env ) ,
backup_env_ ( options . backup_env ! = nullptr ? options . backup_env
: db_env_ ) {
// create all the dirs we need
// create all the dirs we need
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( ) ) ;
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( ) ) ;
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( GetSharedFileRel ( ) ) ) ;
if ( ! options_ . share_table_files ) {
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( GetSharedFileRel ( ) ) ) ;
}
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( GetPrivateDirRel ( ) ) ) ;
backup_env_ - > CreateDirIfMissing ( GetAbsolutePath ( GetPrivateDirRel ( ) ) ) ;
backup_env_ - > CreateDirIfMissing ( GetBackupMetaDir ( ) ) ;
backup_env_ - > CreateDirIfMissing ( GetBackupMetaDir ( ) ) ;
@ -298,8 +310,9 @@ Status BackupEngine::CreateNewBackup(DB* db, bool flush_before_backup) {
Log ( options_ . info_log , " Started the backup process -- creating backup %u " ,
Log ( options_ . info_log , " Started the backup process -- creating backup %u " ,
new_backup_id ) ;
new_backup_id ) ;
// create private dir
// create temporary private dir
s = backup_env_ - > CreateDir ( GetAbsolutePath ( GetPrivateFileRel ( new_backup_id ) ) ) ;
s = backup_env_ - > CreateDir (
GetAbsolutePath ( GetPrivateFileRel ( new_backup_id , true ) ) ) ;
// copy live_files
// copy live_files
for ( size_t i = 0 ; s . ok ( ) & & i < live_files . size ( ) ; + + i ) {
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) {
// * if it's kDescriptorFile, limit the size to manifest_file_size
// * if it's kDescriptorFile, limit the size to manifest_file_size
s = BackupFile ( new_backup_id ,
s = BackupFile ( new_backup_id ,
& new_backup ,
& new_backup ,
type = = kTableFile , /* shared */
options_ . share_table_files & & type = = kTableFile ,
db - > GetName ( ) , /* src_dir */
db - > GetName ( ) , /* src_dir */
live_files [ i ] , /* src_fname */
live_files [ i ] , /* src_fname */
( type = = kDescriptorFile ) ? manifest_file_size : 0 ) ;
( type = = kDescriptorFile ) ? manifest_file_size : 0 ) ;
@ -342,6 +355,13 @@ Status BackupEngine::CreateNewBackup(DB* db, bool flush_before_backup) {
// we copied all the files, enable file deletions
// we copied all the files, enable file deletions
db - > EnableFileDeletions ( ) ;
db - > EnableFileDeletions ( ) ;
if ( s . ok ( ) ) {
// move tmp private backup to real backup folder
s = backup_env_ - > RenameFile (
GetAbsolutePath ( GetPrivateFileRel ( new_backup_id , true ) ) , // tmp
GetAbsolutePath ( GetPrivateFileRel ( new_backup_id , false ) ) ) ;
}
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
// persist the backup metadata on the disk
// persist the backup metadata on the disk
s = new_backup . StoreToFile ( options_ . sync ) ;
s = new_backup . StoreToFile ( options_ . sync ) ;
@ -561,6 +581,9 @@ Status BackupEngine::CopyFile(const std::string& src,
Slice data ;
Slice data ;
do {
do {
if ( stop_backup_ . load ( std : : memory_order_acquire ) ) {
return Status : : Incomplete ( " Backup stopped " ) ;
}
size_t buffer_to_read = ( copy_file_buffer_size_ < size_limit ) ?
size_t buffer_to_read = ( copy_file_buffer_size_ < size_limit ) ?
copy_file_buffer_size_ : size_limit ;
copy_file_buffer_size_ : size_limit ;
s = src_file - > Read ( buffer_to_read , & data , buf . get ( ) ) ;
s = src_file - > Read ( buffer_to_read , & data , buf . get ( ) ) ;
@ -590,12 +613,16 @@ Status BackupEngine::BackupFile(BackupID backup_id,
assert ( src_fname . size ( ) > 0 & & src_fname [ 0 ] = = ' / ' ) ;
assert ( src_fname . size ( ) > 0 & & src_fname [ 0 ] = = ' / ' ) ;
std : : string dst_relative = src_fname . substr ( 1 ) ;
std : : string dst_relative = src_fname . substr ( 1 ) ;
std : : string dst_relative_tmp ;
if ( shared ) {
if ( shared ) {
dst_relative = GetSharedFileRel ( dst_relative ) ;
dst_relative_tmp = GetSharedFileRel ( dst_relative , true ) ;
dst_relative = GetSharedFileRel ( dst_relative , false ) ;
} else {
} else {
dst_relative = GetPrivateFileRel ( backup_id , dst_relative ) ;
dst_relative_tmp = GetPrivateFileRel ( backup_id , true , dst_relative ) ;
dst_relative = GetPrivateFileRel ( backup_id , false , dst_relative ) ;
}
}
std : : string dst_path = GetAbsolutePath ( dst_relative ) ;
std : : string dst_path = GetAbsolutePath ( dst_relative ) ;
std : : string dst_path_tmp = GetAbsolutePath ( dst_relative_tmp ) ;
Status s ;
Status s ;
uint64_t size ;
uint64_t size ;
@ -607,12 +634,15 @@ Status BackupEngine::BackupFile(BackupID backup_id,
} else {
} else {
Log ( options_ . info_log , " Copying %s " , src_fname . c_str ( ) ) ;
Log ( options_ . info_log , " Copying %s " , src_fname . c_str ( ) ) ;
s = CopyFile ( src_dir + src_fname ,
s = CopyFile ( src_dir + src_fname ,
dst_path ,
dst_path_tmp ,
db_env_ ,
db_env_ ,
backup_env_ ,
backup_env_ ,
options_ . sync ,
options_ . sync ,
& size ,
& size ,
size_limit ) ;
size_limit ) ;
if ( s . ok ( ) & & shared ) {
s = backup_env_ - > RenameFile ( dst_path_tmp , dst_path ) ;
}
}
}
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
backup - > AddFile ( dst_relative , size ) ;
backup - > AddFile ( dst_relative , size ) ;
@ -671,14 +701,16 @@ void BackupEngine::GarbageCollection(bool full_scan) {
& private_children ) ;
& private_children ) ;
for ( auto & child : private_children ) {
for ( auto & child : private_children ) {
BackupID backup_id = 0 ;
BackupID backup_id = 0 ;
bool tmp_dir = child . find ( " .tmp " ) ! = std : : string : : npos ;
sscanf ( child . c_str ( ) , " %u " , & backup_id ) ;
sscanf ( child . c_str ( ) , " %u " , & backup_id ) ;
if ( backup_id = = 0 | | backups_ . find ( backup_id ) ! = backups_ . end ( ) ) {
if ( ! tmp_dir & & // if it's tmp_dir, delete it
( backup_id = = 0 | | backups_ . find ( backup_id ) ! = backups_ . end ( ) ) ) {
// it's either not a number or it's still alive. continue
// it's either not a number or it's still alive. continue
continue ;
continue ;
}
}
// here we have to delete the dir and all its children
// here we have to delete the dir and all its children
std : : string full_private_path =
std : : string full_private_path =
GetAbsolutePath ( GetPrivateFileRel ( backup_id ) ) ;
GetAbsolutePath ( GetPrivateFileRel ( backup_id , tmp_dir ) ) ;
std : : vector < std : : string > subchildren ;
std : : vector < std : : string > subchildren ;
backup_env_ - > GetChildren ( full_private_path , & subchildren ) ;
backup_env_ - > GetChildren ( full_private_path , & subchildren ) ;
for ( auto & subchild : subchildren ) {
for ( auto & subchild : subchildren ) {
@ -813,7 +845,9 @@ Status BackupEngine::BackupMeta::StoreToFile(bool sync) {
BackupableDB : : BackupableDB ( DB * db , const BackupableDBOptions & options )
BackupableDB : : BackupableDB ( DB * db , const BackupableDBOptions & options )
: StackableDB ( db ) , backup_engine_ ( new BackupEngine ( db - > GetEnv ( ) , options ) ) {
: StackableDB ( db ) , backup_engine_ ( new BackupEngine ( db - > GetEnv ( ) , options ) ) {
backup_engine_ - > DeleteBackupsNewerThan ( GetLatestSequenceNumber ( ) ) ;
if ( options . share_table_files ) {
backup_engine_ - > DeleteBackupsNewerThan ( GetLatestSequenceNumber ( ) ) ;
}
}
}
BackupableDB : : ~ BackupableDB ( ) {
BackupableDB : : ~ BackupableDB ( ) {
@ -836,6 +870,10 @@ Status BackupableDB::DeleteBackup(BackupID backup_id) {
return backup_engine_ - > DeleteBackup ( backup_id ) ;
return backup_engine_ - > DeleteBackup ( backup_id ) ;
}
}
void BackupableDB : : StopBackup ( ) {
backup_engine_ - > StopBackup ( ) ;
}
// --- RestoreBackupableDB methods ------
// --- RestoreBackupableDB methods ------
RestoreBackupableDB : : RestoreBackupableDB ( Env * db_env ,
RestoreBackupableDB : : RestoreBackupableDB ( Env * db_env ,