@ -1280,6 +1280,7 @@ Status StressTest::TestBackupRestore(
from = " BackupEngine::VerifyBackup " ;
from = " BackupEngine::VerifyBackup " ;
}
}
}
}
const bool allow_persistent = thread - > tid = = 0 ; // not too many
bool from_latest = false ;
bool from_latest = false ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
int count = static_cast < int > ( backup_info . size ( ) ) ;
int count = static_cast < int > ( backup_info . size ( ) ) ;
@ -1302,7 +1303,7 @@ Status StressTest::TestBackupRestore(
}
}
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
uint32_t to_keep = 0 ;
uint32_t to_keep = 0 ;
if ( thread - > tid = = 0 ) {
if ( allow_persistent ) {
// allow one thread to keep up to 2 backups
// allow one thread to keep up to 2 backups
to_keep = thread - > rand . Uniform ( 3 ) ;
to_keep = thread - > rand . Uniform ( 3 ) ;
}
}
@ -1338,8 +1339,7 @@ Status StressTest::TestBackupRestore(
//
//
// For simplicity, currently only verifies existence/non-existence of a
// For simplicity, currently only verifies existence/non-existence of a
// single key
// single key
for ( size_t i = 0 ;
for ( size_t i = 0 ; restored_db & & s . ok ( ) & & i < rand_column_families . size ( ) ;
from_latest & & restored_db & & s . ok ( ) & & i < rand_column_families . size ( ) ;
+ + i ) {
+ + i ) {
std : : string key_str = Key ( rand_keys [ 0 ] ) ;
std : : string key_str = Key ( rand_keys [ 0 ] ) ;
Slice key = key_str ;
Slice key = key_str ;
@ -1349,11 +1349,11 @@ Status StressTest::TestBackupRestore(
& restored_value ) ;
& restored_value ) ;
bool exists = thread - > shared - > Exists ( rand_column_families [ i ] , rand_keys [ 0 ] ) ;
bool exists = thread - > shared - > Exists ( rand_column_families [ i ] , rand_keys [ 0 ] ) ;
if ( get_status . ok ( ) ) {
if ( get_status . ok ( ) ) {
if ( ! exists ) {
if ( ! exists & & from_latest & & ShouldAcquireMutexOnKey ( ) ) {
s = Status : : Corruption ( " key exists in restore but not in original db " ) ;
s = Status : : Corruption ( " key exists in restore but not in original db " ) ;
}
}
} else if ( get_status . IsNotFound ( ) ) {
} else if ( get_status . IsNotFound ( ) ) {
if ( exists ) {
if ( exists & & from_latest & & ShouldAcquireMutexOnKey ( ) ) {
s = Status : : Corruption ( " key exists in original db but not in restore " ) ;
s = Status : : Corruption ( " key exists in original db but not in restore " ) ;
}
}
} else {
} else {
@ -1374,6 +1374,21 @@ Status StressTest::TestBackupRestore(
delete restored_db ;
delete restored_db ;
restored_db = nullptr ;
restored_db = nullptr ;
}
}
if ( s . ok ( ) ) {
// Preserve directories on failure, or allowed persistent backup
if ( ! allow_persistent ) {
s = DestroyDir ( db_stress_env , backup_dir ) ;
if ( ! s . ok ( ) ) {
from = " Destroy backup dir " ;
}
}
}
if ( s . ok ( ) ) {
s = DestroyDir ( db_stress_env , restore_dir ) ;
if ( ! s . ok ( ) ) {
from = " Destroy restore dir " ;
}
}
if ( ! s . ok ( ) ) {
if ( ! s . ok ( ) ) {
fprintf ( stderr , " Failure in %s with: %s \n " , from . c_str ( ) ,
fprintf ( stderr , " Failure in %s with: %s \n " , from . c_str ( ) ,
s . ToString ( ) . c_str ( ) ) ;
s . ToString ( ) . c_str ( ) ) ;
@ -1426,10 +1441,6 @@ Status StressTest::TestApproximateSize(
Status StressTest : : TestCheckpoint ( ThreadState * thread ,
Status StressTest : : TestCheckpoint ( ThreadState * thread ,
const std : : vector < int > & rand_column_families ,
const std : : vector < int > & rand_column_families ,
const std : : vector < int64_t > & rand_keys ) {
const std : : vector < int64_t > & rand_keys ) {
// Note the column families chosen by `rand_column_families` cannot be
// dropped while the locks for `rand_keys` are held. So we should not have
// to worry about accessing those column families throughout this function.
assert ( rand_column_families . size ( ) = = rand_keys . size ( ) ) ;
std : : string checkpoint_dir =
std : : string checkpoint_dir =
FLAGS_db + " /.checkpoint " + ToString ( thread - > tid ) ;
FLAGS_db + " /.checkpoint " + ToString ( thread - > tid ) ;
Options tmp_opts ( options_ ) ;
Options tmp_opts ( options_ ) ;
@ -1479,6 +1490,7 @@ Status StressTest::TestCheckpoint(ThreadState* thread,
// `clear_column_family_one_in != 0`. But we can't easily switch to
// `clear_column_family_one_in != 0`. But we can't easily switch to
// `ListColumnFamilies` to get names because it won't necessarily give
// `ListColumnFamilies` to get names because it won't necessarily give
// the same order as `column_family_names_`.
// the same order as `column_family_names_`.
assert ( FLAGS_clear_column_family_one_in = = 0 ) ;
if ( FLAGS_clear_column_family_one_in = = 0 ) {
if ( FLAGS_clear_column_family_one_in = = 0 ) {
for ( const auto & name : column_family_names_ ) {
for ( const auto & name : column_family_names_ ) {
cf_descs . emplace_back ( name , ColumnFamilyOptions ( options ) ) ;
cf_descs . emplace_back ( name , ColumnFamilyOptions ( options ) ) ;
@ -1488,21 +1500,24 @@ Status StressTest::TestCheckpoint(ThreadState* thread,
}
}
}
}
if ( checkpoint_db ! = nullptr ) {
if ( checkpoint_db ! = nullptr ) {
// Note the column families chosen by `rand_column_families` cannot be
// dropped while the locks for `rand_keys` are held. So we should not have
// to worry about accessing those column families throughout this function.
for ( size_t i = 0 ; s . ok ( ) & & i < rand_column_families . size ( ) ; + + i ) {
for ( size_t i = 0 ; s . ok ( ) & & i < rand_column_families . size ( ) ; + + i ) {
std : : string key_str = Key ( rand_keys [ i ] ) ;
std : : string key_str = Key ( rand_keys [ 0 ] ) ;
Slice key = key_str ;
Slice key = key_str ;
std : : string value ;
std : : string value ;
Status get_status = checkpoint_db - > Get (
Status get_status = checkpoint_db - > Get (
ReadOptions ( ) , cf_handles [ rand_column_families [ i ] ] , key , & value ) ;
ReadOptions ( ) , cf_handles [ rand_column_families [ i ] ] , key , & value ) ;
bool exists =
bool exists =
thread - > shared - > Exists ( rand_column_families [ i ] , rand_keys [ i ] ) ;
thread - > shared - > Exists ( rand_column_families [ i ] , rand_keys [ 0 ] ) ;
if ( get_status . ok ( ) ) {
if ( get_status . ok ( ) ) {
if ( ! exists ) {
if ( ! exists & & ShouldAcquireMutexOnKey ( ) ) {
s = Status : : Corruption (
s = Status : : Corruption (
" key exists in checkpoint but not in original db " ) ;
" key exists in checkpoint but not in original db " ) ;
}
}
} else if ( get_status . IsNotFound ( ) ) {
} else if ( get_status . IsNotFound ( ) ) {
if ( exists ) {
if ( exists & & ShouldAcquireMutexOnKey ( ) ) {
s = Status : : Corruption (
s = Status : : Corruption (
" key exists in original db but not in checkpoint " ) ;
" key exists in original db but not in checkpoint " ) ;
}
}