@ -5,6 +5,8 @@
# include "db/wal_edit.h"
# include "db/db_test_util.h"
# include "file/file_util.h"
# include "port/port.h"
# include "port/stack_trace.h"
# include "test_util/testharness.h"
@ -131,6 +133,111 @@ TEST(WalSet, DeleteNonClosedWal) {
std : : string : : npos ) ;
}
class WalSetTest : public DBTestBase {
public :
WalSetTest ( ) : DBTestBase ( " WalSetTest " , /* env_do_fsync */ true ) { }
void SetUp ( ) override {
test_dir_ = test : : PerThreadDBPath ( " wal_set_test " ) ;
ASSERT_OK ( env_ - > CreateDir ( test_dir_ ) ) ;
}
void TearDown ( ) override {
EXPECT_OK ( DestroyDir ( env_ , test_dir_ ) ) ;
logs_on_disk_ . clear ( ) ;
wals_ . Reset ( ) ;
}
void CreateWalOnDisk ( WalNumber number , const std : : string & fname ,
uint64_t size_bytes ) {
std : : unique_ptr < WritableFile > f ;
std : : string fpath = Path ( fname ) ;
ASSERT_OK ( env_ - > NewWritableFile ( fpath , & f , EnvOptions ( ) ) ) ;
std : : string content ( size_bytes , ' 0 ' ) ;
ASSERT_OK ( f - > Append ( content ) ) ;
ASSERT_OK ( f - > Close ( ) ) ;
logs_on_disk_ [ number ] = fpath ;
}
void AddWalToWalSet ( WalNumber number , uint64_t size_bytes ) {
// Create WAL.
ASSERT_OK ( wals_ . AddWal ( WalAddition ( number ) ) ) ;
// Close WAL.
WalMetadata wal ( size_bytes ) ;
wal . SetClosed ( ) ;
ASSERT_OK ( wals_ . AddWal ( WalAddition ( number , wal ) ) ) ;
}
Status CheckWals ( ) const { return wals_ . CheckWals ( env_ , logs_on_disk_ ) ; }
private :
std : : string test_dir_ ;
std : : unordered_map < WalNumber , std : : string > logs_on_disk_ ;
WalSet wals_ ;
std : : string Path ( const std : : string & fname ) { return test_dir_ + " / " + fname ; }
} ;
TEST_F ( WalSetTest , CheckEmptyWals ) { ASSERT_OK ( CheckWals ( ) ) ; }
TEST_F ( WalSetTest , CheckWals ) {
for ( int number = 1 ; number < 10 ; number + + ) {
uint64_t size = rand ( ) % 100 ;
std : : stringstream ss ;
ss < < " log " < < number ;
std : : string fname = ss . str ( ) ;
CreateWalOnDisk ( number , fname , size ) ;
// log 0 - 5 are obsolete.
if ( number > 5 ) {
AddWalToWalSet ( number , size ) ;
}
}
ASSERT_OK ( CheckWals ( ) ) ;
}
TEST_F ( WalSetTest , CheckMissingWals ) {
for ( int number = 1 ; number < 10 ; number + + ) {
uint64_t size = rand ( ) % 100 ;
AddWalToWalSet ( number , size ) ;
// logs with even number are missing from disk.
if ( number % 2 ) {
std : : stringstream ss ;
ss < < " log " < < number ;
std : : string fname = ss . str ( ) ;
CreateWalOnDisk ( number , fname , size ) ;
}
}
Status s = CheckWals ( ) ;
ASSERT_TRUE ( s . IsCorruption ( ) ) < < s . ToString ( ) ;
// The first log with even number is missing.
std : : stringstream expected_err ;
expected_err < < " Missing WAL with log number: " < < 2 ;
ASSERT_TRUE ( s . ToString ( ) . find ( expected_err . str ( ) ) ! = std : : string : : npos )
< < s . ToString ( ) ;
}
TEST_F ( WalSetTest , CheckWalsWithShrinkedSize ) {
for ( int number = 1 ; number < 10 ; number + + ) {
uint64_t size = rand ( ) % 100 + 1 ;
AddWalToWalSet ( number , size ) ;
// logs with even number have shrinked size.
std : : stringstream ss ;
ss < < " log " < < number ;
std : : string fname = ss . str ( ) ;
CreateWalOnDisk ( number , fname , ( number % 2 ) ? size : size - 1 ) ;
}
Status s = CheckWals ( ) ;
ASSERT_TRUE ( s . IsCorruption ( ) ) < < s . ToString ( ) ;
// The first log with even number has wrong size.
std : : stringstream expected_err ;
expected_err < < " Size mismatch: WAL (log number: " < < 2 < < " ) " ;
ASSERT_TRUE ( s . ToString ( ) . find ( expected_err . str ( ) ) ! = std : : string : : npos )
< < s . ToString ( ) ;
}
} // namespace ROCKSDB_NAMESPACE
int main ( int argc , char * * argv ) {