@ -9,21 +9,6 @@
# ifndef ROCKSDB_LITE
# ifndef ROCKSDB_LITE
# include "rocksdb/utilities/backupable_db.h"
# include "file/filename.h"
# include "file/sequence_file_reader.h"
# include "file/writable_file_writer.h"
# include "logging/logging.h"
# include "port/port.h"
# include "rocksdb/rate_limiter.h"
# include "rocksdb/transaction_log.h"
# include "test_util/sync_point.h"
# include "util/channel.h"
# include "util/coding.h"
# include "util/crc32c.h"
# include "util/string_util.h"
# include "utilities/checkpoint/checkpoint_impl.h"
# include <stdlib.h>
# include <stdlib.h>
# include <algorithm>
# include <algorithm>
# include <atomic>
# include <atomic>
@ -40,6 +25,21 @@
# include <unordered_set>
# include <unordered_set>
# include <vector>
# include <vector>
# include "file/filename.h"
# include "file/sequence_file_reader.h"
# include "file/writable_file_writer.h"
# include "logging/logging.h"
# include "port/port.h"
# include "rocksdb/rate_limiter.h"
# include "rocksdb/transaction_log.h"
# include "rocksdb/utilities/backupable_db.h"
# include "test_util/sync_point.h"
# include "util/channel.h"
# include "util/coding.h"
# include "util/crc32c.h"
# include "util/string_util.h"
# include "utilities/checkpoint/checkpoint_impl.h"
namespace rocksdb {
namespace rocksdb {
void BackupStatistics : : IncrementNumberSuccessBackup ( ) {
void BackupStatistics : : IncrementNumberSuccessBackup ( ) {
@ -121,6 +121,7 @@ class BackupEngineImpl : public BackupEngine {
private :
private :
void DeleteChildren ( const std : : string & dir , uint32_t file_type_filter = 0 ) ;
void DeleteChildren ( const std : : string & dir , uint32_t file_type_filter = 0 ) ;
Status DeleteBackupInternal ( BackupID backup_id ) ;
// Extends the "result" map with pathname->size mappings for the contents of
// Extends the "result" map with pathname->size mappings for the contents of
// "dir" in "env". Pathnames are prefixed with "dir".
// "dir" in "env". Pathnames are prefixed with "dir".
@ -457,6 +458,10 @@ class BackupEngineImpl : public BackupEngine {
std : : mutex byte_report_mutex_ ;
std : : mutex byte_report_mutex_ ;
channel < CopyOrCreateWorkItem > files_to_copy_or_create_ ;
channel < CopyOrCreateWorkItem > files_to_copy_or_create_ ;
std : : vector < port : : Thread > threads_ ;
std : : vector < port : : Thread > threads_ ;
// Certain operations like PurgeOldBackups and DeleteBackup will trigger
// automatic GarbageCollect (true) unless we've already done one in this
// session and have not failed to delete backup files since then (false).
bool might_need_garbage_collect_ = true ;
// Adds a file to the backup work queue to be copied or created if it doesn't
// Adds a file to the backup work queue to be copied or created if it doesn't
// already exist.
// already exist.
@ -560,6 +565,9 @@ Status BackupEngineImpl::Initialize() {
options_ . Dump ( options_ . info_log ) ;
options_ . Dump ( options_ . info_log ) ;
if ( ! read_only_ ) {
if ( ! read_only_ ) {
// we might need to clean up from previous crash or I/O errors
might_need_garbage_collect_ = true ;
// gather the list of directories that we need to create
// gather the list of directories that we need to create
std : : vector < std : : pair < std : : string , std : : unique_ptr < Directory > * > >
std : : vector < std : : pair < std : : string , std : : unique_ptr < Directory > * > >
directories ;
directories ;
@ -929,8 +937,8 @@ Status BackupEngineImpl::CreateNewBackupWithMetadata(
ROCKS_LOG_INFO ( options_ . info_log , " Backup Statistics %s \n " ,
ROCKS_LOG_INFO ( options_ . info_log , " Backup Statistics %s \n " ,
backup_statistics_ . ToString ( ) . c_str ( ) ) ;
backup_statistics_ . ToString ( ) . c_str ( ) ) ;
// delete files that we might have already written
// delete files that we might have already written
might_need_garbage_collect_ = true ;
DeleteBackup ( new_backup_id ) ;
DeleteBackup ( new_backup_id ) ;
GarbageCollect ( ) ;
return s ;
return s ;
}
}
@ -958,6 +966,10 @@ Status BackupEngineImpl::CreateNewBackupWithMetadata(
Status BackupEngineImpl : : PurgeOldBackups ( uint32_t num_backups_to_keep ) {
Status BackupEngineImpl : : PurgeOldBackups ( uint32_t num_backups_to_keep ) {
assert ( initialized_ ) ;
assert ( initialized_ ) ;
assert ( ! read_only_ ) ;
assert ( ! read_only_ ) ;
// Best effort deletion even with errors
Status overall_status = Status : : OK ( ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Purging old backups, keeping %u " ,
ROCKS_LOG_INFO ( options_ . info_log , " Purging old backups, keeping %u " ,
num_backups_to_keep ) ;
num_backups_to_keep ) ;
std : : vector < BackupID > to_delete ;
std : : vector < BackupID > to_delete ;
@ -967,17 +979,44 @@ Status BackupEngineImpl::PurgeOldBackups(uint32_t num_backups_to_keep) {
itr + + ;
itr + + ;
}
}
for ( auto backup_id : to_delete ) {
for ( auto backup_id : to_delete ) {
auto s = DeleteBackup ( backup_id ) ;
auto s = DeleteBackupInternal ( backup_id ) ;
if ( ! s . ok ( ) ) {
if ( ! s . ok ( ) ) {
return s ;
overall_status = s ;
}
}
}
}
return Status : : OK ( ) ;
// Clean up after any incomplete backup deletion, potentially from
// earlier session.
if ( might_need_garbage_collect_ ) {
auto s = GarbageCollect ( ) ;
if ( ! s . ok ( ) & & overall_status . ok ( ) ) {
overall_status = s ;
}
}
return overall_status ;
}
}
Status BackupEngineImpl : : DeleteBackup ( BackupID backup_id ) {
Status BackupEngineImpl : : DeleteBackup ( BackupID backup_id ) {
auto s1 = DeleteBackupInternal ( backup_id ) ;
auto s2 = Status : : OK ( ) ;
// Clean up after any incomplete backup deletion, potentially from
// earlier session.
if ( might_need_garbage_collect_ ) {
s2 = GarbageCollect ( ) ;
}
if ( ! s1 . ok ( ) ) {
return s1 ;
} else {
return s2 ;
}
}
// Does not auto-GarbageCollect
Status BackupEngineImpl : : DeleteBackupInternal ( BackupID backup_id ) {
assert ( initialized_ ) ;
assert ( initialized_ ) ;
assert ( ! read_only_ ) ;
assert ( ! read_only_ ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Deleting backup %u " , backup_id ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Deleting backup %u " , backup_id ) ;
auto backup = backups_ . find ( backup_id ) ;
auto backup = backups_ . find ( backup_id ) ;
if ( backup ! = backups_ . end ( ) ) {
if ( backup ! = backups_ . end ( ) ) {
@ -998,6 +1037,10 @@ Status BackupEngineImpl::DeleteBackup(BackupID backup_id) {
corrupt_backups_ . erase ( corrupt ) ;
corrupt_backups_ . erase ( corrupt ) ;
}
}
// After removing meta file, best effort deletion even with errors.
// (Don't delete other files if we can't delete the meta file right
// now.)
if ( options_ . max_valid_backups_to_open = = port : : kMaxInt32 ) {
if ( options_ . max_valid_backups_to_open = = port : : kMaxInt32 ) {
std : : vector < std : : string > to_delete ;
std : : vector < std : : string > to_delete ;
for ( auto & itr : backuped_file_infos_ ) {
for ( auto & itr : backuped_file_infos_ ) {
@ -1006,6 +1049,10 @@ Status BackupEngineImpl::DeleteBackup(BackupID backup_id) {
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
itr . first . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
itr . first . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
to_delete . push_back ( itr . first ) ;
to_delete . push_back ( itr . first ) ;
if ( ! s . ok ( ) ) {
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
}
}
for ( auto & td : to_delete ) {
for ( auto & td : to_delete ) {
@ -1024,6 +1071,10 @@ Status BackupEngineImpl::DeleteBackup(BackupID backup_id) {
Status s = backup_env_ - > DeleteDir ( GetAbsolutePath ( private_dir ) ) ;
Status s = backup_env_ - > DeleteDir ( GetAbsolutePath ( private_dir ) ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Deleting private dir %s -- %s " ,
ROCKS_LOG_INFO ( options_ . info_log , " Deleting private dir %s -- %s " ,
private_dir . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
private_dir . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
if ( ! s . ok ( ) ) {
// Full gc or trying again later might work
might_need_garbage_collect_ = true ;
}
return Status : : OK ( ) ;
return Status : : OK ( ) ;
}
}
@ -1506,8 +1557,15 @@ Status BackupEngineImpl::InsertPathnameToSizeBytes(
Status BackupEngineImpl : : GarbageCollect ( ) {
Status BackupEngineImpl : : GarbageCollect ( ) {
assert ( ! read_only_ ) ;
assert ( ! read_only_ ) ;
// We will make a best effort to remove all garbage even in the presence
// of inconsistencies or I/O failures that inhibit finding garbage.
Status overall_status = Status : : OK ( ) ;
// If all goes well, we don't need another auto-GC this session
might_need_garbage_collect_ = false ;
ROCKS_LOG_INFO ( options_ . info_log , " Starting garbage collection " ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Starting garbage collection " ) ;
if ( options_ . max_valid_backups_to_open = = port : : kMaxInt32 ) {
if ( options_ . max_valid_backups_to_open ! = port : : kMaxInt32 ) {
ROCKS_LOG_WARN (
ROCKS_LOG_WARN (
options_ . info_log ,
options_ . info_log ,
" Garbage collection is limited since `max_valid_backups_to_open` "
" Garbage collection is limited since `max_valid_backups_to_open` "
@ -1534,7 +1592,9 @@ Status BackupEngineImpl::GarbageCollect() {
s = Status : : OK ( ) ;
s = Status : : OK ( ) ;
}
}
if ( ! s . ok ( ) ) {
if ( ! s . ok ( ) ) {
return s ;
overall_status = s ;
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
}
for ( auto & child : shared_children ) {
for ( auto & child : shared_children ) {
@ -1554,6 +1614,10 @@ Status BackupEngineImpl::GarbageCollect() {
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
rel_fname . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
rel_fname . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
backuped_file_infos_ . erase ( rel_fname ) ;
backuped_file_infos_ . erase ( rel_fname ) ;
if ( ! s . ok ( ) ) {
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
}
}
}
}
@ -1564,7 +1628,9 @@ Status BackupEngineImpl::GarbageCollect() {
auto s = backup_env_ - > GetChildren ( GetAbsolutePath ( GetPrivateDirRel ( ) ) ,
auto s = backup_env_ - > GetChildren ( GetAbsolutePath ( GetPrivateDirRel ( ) ) ,
& private_children ) ;
& private_children ) ;
if ( ! s . ok ( ) ) {
if ( ! s . ok ( ) ) {
return s ;
overall_status = s ;
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
}
for ( auto & child : private_children ) {
for ( auto & child : private_children ) {
@ -1588,14 +1654,23 @@ Status BackupEngineImpl::GarbageCollect() {
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
ROCKS_LOG_INFO ( options_ . info_log , " Deleting %s -- %s " ,
( full_private_path + subchild ) . c_str ( ) ,
( full_private_path + subchild ) . c_str ( ) ,
s . ToString ( ) . c_str ( ) ) ;
s . ToString ( ) . c_str ( ) ) ;
if ( ! s . ok ( ) ) {
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
// finally delete the private dir
// finally delete the private dir
Status s = backup_env_ - > DeleteDir ( full_private_path ) ;
Status s = backup_env_ - > DeleteDir ( full_private_path ) ;
ROCKS_LOG_INFO ( options_ . info_log , " Deleting dir %s -- %s " ,
ROCKS_LOG_INFO ( options_ . info_log , " Deleting dir %s -- %s " ,
full_private_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
full_private_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
if ( ! s . ok ( ) ) {
// Trying again later might work
might_need_garbage_collect_ = true ;
}
}
}
return Status : : OK ( ) ;
assert ( overall_status . ok ( ) | | might_need_garbage_collect_ ) ;
return overall_status ;
}
}
// ------- BackupMeta class --------
// ------- BackupMeta class --------