@ -29,79 +29,132 @@ namespace ROCKSDB_NAMESPACE {
Status ImportColumnFamilyJob : : Prepare ( uint64_t next_file_number ,
Status ImportColumnFamilyJob : : Prepare ( uint64_t next_file_number ,
SuperVersion * sv ) {
SuperVersion * sv ) {
Status status ;
Status status ;
std : : vector < ColumnFamilyIngestFileInfo > cf_ingest_infos ;
for ( const auto & metadata_per_cf : metadatas_ ) {
// Read the information of files we are importing
ColumnFamilyIngestFileInfo cf_file_info ;
InternalKey smallest , largest ;
int num_files = 0 ;
std : : vector < IngestedFileInfo > files_to_import_per_cf ;
for ( size_t i = 0 ; i < metadata_per_cf . size ( ) ; i + + ) {
auto file_metadata = * metadata_per_cf [ i ] ;
const auto file_path = file_metadata . db_path + " / " + file_metadata . name ;
IngestedFileInfo file_to_import ;
status = GetIngestedFileInfo ( file_path , next_file_number + + , sv ,
file_metadata , & file_to_import ) ;
if ( ! status . ok ( ) ) {
return status ;
}
// Read the information of files we are importing
if ( file_to_import . num_entries = = 0 ) {
for ( const auto & file_metadata : metadata_ ) {
status = Status : : InvalidArgument ( " File contain no entries " ) ;
const auto file_path = file_metadata . db_path + " / " + file_metadata . name ;
return status ;
IngestedFileInfo file_to_import ;
}
status = GetIngestedFileInfo ( file_path , next_file_number + + , sv ,
file_metadata , & file_to_import ) ;
if ( ! status . ok ( ) ) {
return status ;
}
files_to_import_ . push_back ( file_to_import ) ;
}
auto num_files = files_to_import_ . size ( ) ;
if ( ! file_to_import . smallest_internal_key . Valid ( ) | |
if ( num_files = = 0 ) {
! file_to_import . largest_internal_key . Valid ( ) ) {
status = Status : : InvalidArgument ( " The list of files is empty " ) ;
status = Status : : Corruption ( " File has corrupted keys " ) ;
return status ;
return status ;
}
}
files_to_import_per_cf . push_back ( file_to_import ) ;
num_files + + ;
// Calculate the smallest and largest keys of all files in this CF
if ( i = = 0 ) {
smallest = file_to_import . smallest_internal_key ;
largest = file_to_import . largest_internal_key ;
} else {
if ( cfd_ - > internal_comparator ( ) . Compare (
smallest , file_to_import . smallest_internal_key ) < 0 ) {
smallest = file_to_import . smallest_internal_key ;
}
if ( cfd_ - > internal_comparator ( ) . Compare (
largest , file_to_import . largest_internal_key ) > 0 ) {
largest = file_to_import . largest_internal_key ;
}
}
}
for ( const auto & f : files_to_import_ ) {
if ( num_files = = 0 ) {
if ( f . num_entries = = 0 ) {
status = Status : : InvalidArgument ( " The list of files is empty " ) ;
status = Status : : InvalidArgument ( " File contain no entries " ) ;
return status ;
return status ;
}
}
files_to_import_ . push_back ( files_to_import_per_cf ) ;
cf_file_info . smallest_internal_key = smallest ;
cf_file_info . largest_internal_key = largest ;
cf_ingest_infos . push_back ( cf_file_info ) ;
}
if ( ! f . smallest_internal_key . Valid ( ) | | ! f . largest_internal_key . Valid ( ) ) {
std : : sort ( cf_ingest_infos . begin ( ) , cf_ingest_infos . end ( ) ,
status = Status : : Corruption ( " File has corrupted keys " ) ;
[ this ] ( const ColumnFamilyIngestFileInfo & info1 ,
const ColumnFamilyIngestFileInfo & info2 ) {
return cfd_ - > user_comparator ( ) - > Compare (
info1 . smallest_internal_key . user_key ( ) ,
info2 . smallest_internal_key . user_key ( ) ) < 0 ;
} ) ;
for ( size_t i = 0 ; i + 1 < cf_ingest_infos . size ( ) ; i + + ) {
if ( cfd_ - > user_comparator ( ) - > Compare (
cf_ingest_infos [ i ] . largest_internal_key . user_key ( ) ,
cf_ingest_infos [ i + 1 ] . smallest_internal_key . user_key ( ) ) > = 0 ) {
status = Status : : InvalidArgument ( " CFs have overlapping ranges " ) ;
return status ;
return status ;
}
}
}
}
// Copy/Move external files into DB
// Copy/Move external files into DB
auto hardlink_files = import_options_ . move_files ;
auto hardlink_files = import_options_ . move_files ;
for ( auto & f : files_to_import_ ) {
const auto path_outside_db = f . external_file_path ;
for ( auto & files_to_import_per_cf : files_to_import_ ) {
const auto path_inside_db = TableFileName (
for ( auto & f : files_to_import_per_cf ) {
cfd_ - > ioptions ( ) - > cf_paths , f . fd . GetNumber ( ) , f . fd . GetPathId ( ) ) ;
const auto path_outside_db = f . external_file_path ;
const auto path_inside_db = TableFileName (
if ( hardlink_files ) {
cfd_ - > ioptions ( ) - > cf_paths , f . fd . GetNumber ( ) , f . fd . GetPathId ( ) ) ;
status =
fs_ - > LinkFile ( path_outside_db , path_inside_db , IOOptions ( ) , nullptr ) ;
if ( hardlink_files ) {
if ( status . IsNotSupported ( ) ) {
status = fs_ - > LinkFile ( path_outside_db , path_inside_db , IOOptions ( ) ,
// Original file is on a different FS, use copy instead of hard linking
nullptr ) ;
hardlink_files = false ;
if ( status . IsNotSupported ( ) ) {
ROCKS_LOG_INFO ( db_options_ . info_log ,
// Original file is on a different FS, use copy instead of hard
" Try to link file %s but it's not supported : %s " ,
// linking
f . internal_file_path . c_str ( ) , status . ToString ( ) . c_str ( ) ) ;
hardlink_files = false ;
ROCKS_LOG_INFO ( db_options_ . info_log ,
" Try to link file %s but it's not supported : %s " ,
f . internal_file_path . c_str ( ) ,
status . ToString ( ) . c_str ( ) ) ;
}
}
}
}
if ( ! hardlink_files ) {
if ( ! hardlink_files ) {
status =
status =
CopyFile ( fs_ . get ( ) , path_outside_db , path_inside_db , 0 ,
CopyFile ( fs_ . get ( ) , path_outside_db , path_inside_db , 0 ,
db_options_ . use_fsync , io_tracer_ , Temperature : : kUnknown ) ;
db_options_ . use_fsync , io_tracer_ , Temperature : : kUnknown ) ;
}
if ( ! status . ok ( ) ) {
break ;
}
f . copy_file = ! hardlink_files ;
f . internal_file_path = path_inside_db ;
}
}
if ( ! status . ok ( ) ) {
if ( ! status . ok ( ) ) {
break ;
break ;
}
}
f . copy_file = ! hardlink_files ;
f . internal_file_path = path_inside_db ;
}
}
if ( ! status . ok ( ) ) {
if ( ! status . ok ( ) ) {
// We failed, remove all files that we copied into the db
// We failed, remove all files that we copied into the db
for ( const auto & f : files_to_import_ ) {
for ( auto & files_to_import_per_cf : files_to_import_ ) {
if ( f . internal_file_path . empty ( ) ) {
for ( auto & f : files_to_import_per_cf ) {
break ;
if ( f . internal_file_path . empty ( ) ) {
}
break ;
const auto s =
}
fs_ - > DeleteFile ( f . internal_file_path , IOOptions ( ) , nullptr ) ;
const auto s =
if ( ! s . ok ( ) ) {
fs_ - > DeleteFile ( f . internal_file_path , IOOptions ( ) , nullptr ) ;
ROCKS_LOG_WARN ( db_options_ . info_log ,
if ( ! s . ok ( ) ) {
" AddFile() clean up for file %s failed : %s " ,
ROCKS_LOG_WARN ( db_options_ . info_log ,
f . internal_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
" AddFile() clean up for file %s failed : %s " ,
f . internal_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
}
}
}
}
}
}
}
@ -134,30 +187,35 @@ Status ImportColumnFamilyJob::Run() {
nullptr /* src_vstorage */ , cfd_ - > ioptions ( ) - > force_consistency_checks ,
nullptr /* src_vstorage */ , cfd_ - > ioptions ( ) - > force_consistency_checks ,
EpochNumberRequirement : : kMightMissing ) ;
EpochNumberRequirement : : kMightMissing ) ;
Status s ;
Status s ;
for ( size_t i = 0 ; s . ok ( ) & & i < files_to_import_ . size ( ) ; + + i ) {
for ( size_t i = 0 ; s . ok ( ) & & i < files_to_import_ . size ( ) ; + + i ) {
const auto & f = files_to_import_ [ i ] ;
for ( size_t j = 0 ; s . ok ( ) & & j < files_to_import_ [ i ] . size ( ) ; + + j ) {
const auto & file_metadata = metadata_ [ i ] ;
const auto & f = files_to_import_ [ i ] [ j ] ;
const auto & file_metadata = * metadatas_ [ i ] [ j ] ;
uint64_t tail_size = 0 ;
bool contain_no_data_blocks = f . table_properties . num_entries > 0 & &
uint64_t tail_size = 0 ;
( f . table_properties . num_entries = =
bool contain_no_data_blocks = f . table_properties . num_entries > 0 & &
f . table_properties . num_range_deletions ) ;
( f . table_properties . num_entries = =
if ( f . table_properties . tail_start_offset > 0 | | contain_no_data_blocks ) {
f . table_properties . num_range_deletions ) ;
uint64_t file_size = f . fd . GetFileSize ( ) ;
if ( f . table_properties . tail_start_offset > 0 | | contain_no_data_blocks ) {
assert ( f . table_properties . tail_start_offset < = file_size ) ;
uint64_t file_size = f . fd . GetFileSize ( ) ;
tail_size = file_size - f . table_properties . tail_start_offset ;
assert ( f . table_properties . tail_start_offset < = file_size ) ;
}
tail_size = file_size - f . table_properties . tail_start_offset ;
}
VersionEdit dummy_version_edit ;
VersionEdit dummy_version_edit ;
dummy_version_edit . AddFile (
dummy_version_edit . AddFile (
file_metadata . level , f . fd . GetNumber ( ) , f . fd . GetPathId ( ) ,
file_metadata . level , f . fd . GetNumber ( ) , f . fd . GetPathId ( ) ,
f . fd . GetFileSize ( ) , f . smallest_internal_key , f . largest_internal_key ,
f . fd . GetFileSize ( ) , f . smallest_internal_key , f . largest_internal_key ,
file_metadata . smallest_seqno , file_metadata . largest_seqno , false ,
file_metadata . smallest_seqno , file_metadata . largest_seqno , false ,
file_metadata . temperature , kInvalidBlobFileNumber , oldest_ancester_time ,
file_metadata . temperature , kInvalidBlobFileNumber ,
current_time , file_metadata . epoch_number , kUnknownFileChecksum ,
oldest_ancester_time , current_time , file_metadata . epoch_number ,
kUnknownFileChecksumFuncName , f . unique_id , 0 , tail_size ) ;
kUnknownFileChecksum , kUnknownFileChecksumFuncName , f . unique_id , 0 ,
s = dummy_version_builder . Apply ( & dummy_version_edit ) ;
tail_size ) ;
s = dummy_version_builder . Apply ( & dummy_version_edit ) ;
}
}
}
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
s = dummy_version_builder . SaveTo ( & dummy_vstorage ) ;
s = dummy_version_builder . SaveTo ( & dummy_vstorage ) ;
}
}
@ -198,26 +256,30 @@ Status ImportColumnFamilyJob::Run() {
void ImportColumnFamilyJob : : Cleanup ( const Status & status ) {
void ImportColumnFamilyJob : : Cleanup ( const Status & status ) {
if ( ! status . ok ( ) ) {
if ( ! status . ok ( ) ) {
// We failed to add files to the database remove all the files we copied.
// We failed to add files to the database remove all the files we copied.
for ( const auto & f : files_to_import_ ) {
for ( auto & files_to_import_per_cf : files_to_import_ ) {
const auto s =
for ( auto & f : files_to_import_per_cf ) {
fs_ - > DeleteFile ( f . internal_file_path , IOOptions ( ) , nullptr ) ;
const auto s =
if ( ! s . ok ( ) ) {
fs_ - > DeleteFile ( f . internal_file_path , IOOptions ( ) , nullptr ) ;
ROCKS_LOG_WARN ( db_options_ . info_log ,
if ( ! s . ok ( ) ) {
" AddFile() clean up for file %s failed : %s " ,
ROCKS_LOG_WARN ( db_options_ . info_log ,
f . internal_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
" AddFile() clean up for file %s failed : %s " ,
f . internal_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
}
}
}
}
}
} else if ( status . ok ( ) & & import_options_ . move_files ) {
} else if ( status . ok ( ) & & import_options_ . move_files ) {
// The files were moved and added successfully, remove original file links
// The files were moved and added successfully, remove original file links
for ( IngestedFileInfo & f : files_to_import_ ) {
for ( auto & files_to_import_per_cf : files_to_import_ ) {
const auto s =
for ( auto & f : files_to_import_per_cf ) {
fs_ - > DeleteFile ( f . external_file_path , IOOptions ( ) , nullptr ) ;
const auto s =
if ( ! s . ok ( ) ) {
fs_ - > DeleteFile ( f . external_file_path , IOOptions ( ) , nullptr ) ;
ROCKS_LOG_WARN (
if ( ! s . ok ( ) ) {
db_options_ . info_log ,
ROCKS_LOG_WARN (
" %s was added to DB successfully but failed to remove original "
db_options_ . info_log ,
" file link : %s " ,
" %s was added to DB successfully but failed to remove original "
f . external_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
" file link : %s " ,
f . external_file_path . c_str ( ) , s . ToString ( ) . c_str ( ) ) ;
}
}
}
}
}
}
}
@ -361,4 +423,4 @@ Status ImportColumnFamilyJob::GetIngestedFileInfo(
return status ;
return status ;
}
}
} // namespace ROCKSDB_NAMESPACE
} // namespace ROCKSDB_NAMESPACE