@ -235,7 +235,6 @@ class BlobDBTest : public testing::Test {
const std : : string dbname_ ;
const std : : string dbname_ ;
std : : unique_ptr < MockTimeEnv > mock_env_ ;
std : : unique_ptr < MockTimeEnv > mock_env_ ;
std : : shared_ptr < TTLExtractor > ttl_extractor_ ;
BlobDB * blob_db_ ;
BlobDB * blob_db_ ;
} ; // class BlobDBTest
} ; // class BlobDBTest
@ -312,191 +311,6 @@ TEST_F(BlobDBTest, PutUntil) {
VerifyDB ( data ) ;
VerifyDB ( data ) ;
}
}
TEST_F ( BlobDBTest , TTLExtrator_NoTTL ) {
// The default ttl extractor return no ttl for every key.
ttl_extractor_ . reset ( new TTLExtractor ( ) ) ;
Random rnd ( 301 ) ;
Options options ;
options . env = mock_env_ . get ( ) ;
BlobDBOptions bdb_options ;
bdb_options . ttl_range_secs = 1000 ;
bdb_options . min_blob_size = 0 ;
bdb_options . blob_file_size = 256 * 1000 * 1000 ;
bdb_options . ttl_extractor = ttl_extractor_ ;
bdb_options . disable_background_tasks = true ;
Open ( bdb_options , options ) ;
std : : map < std : : string , std : : string > data ;
mock_env_ - > set_current_time ( 0 ) ;
for ( size_t i = 0 ; i < 100 ; i + + ) {
PutRandom ( " key " + ToString ( i ) , & rnd , & data ) ;
}
// very far in the future..
mock_env_ - > set_current_time ( std : : numeric_limits < uint64_t > : : max ( ) / 1000000 -
10 ) ;
auto * bdb_impl = static_cast < BlobDBImpl * > ( blob_db_ ) ;
auto blob_files = bdb_impl - > TEST_GetBlobFiles ( ) ;
ASSERT_EQ ( 1 , blob_files . size ( ) ) ;
ASSERT_FALSE ( blob_files [ 0 ] - > HasTTL ( ) ) ;
ASSERT_OK ( bdb_impl - > TEST_CloseBlobFile ( blob_files [ 0 ] ) ) ;
GCStats gc_stats ;
ASSERT_OK ( bdb_impl - > TEST_GCFileAndUpdateLSM ( blob_files [ 0 ] , & gc_stats ) ) ;
ASSERT_EQ ( 0 , gc_stats . num_keys_expired ) ;
ASSERT_EQ ( 100 , gc_stats . num_keys_relocated ) ;
VerifyDB ( data ) ;
}
TEST_F ( BlobDBTest , TTLExtractor_ExtractTTL ) {
Random rnd ( 301 ) ;
class TestTTLExtractor : public TTLExtractor {
public :
explicit TestTTLExtractor ( Random * r ) : rnd ( r ) { }
virtual bool ExtractTTL ( const Slice & key , const Slice & value , uint64_t * ttl ,
std : : string * /*new_value*/ ,
bool * /*value_changed*/ ) override {
* ttl = rnd - > Next ( ) % 100 ;
if ( * ttl > 50 ) {
data [ key . ToString ( ) ] = value . ToString ( ) ;
}
return true ;
}
Random * rnd ;
std : : map < std : : string , std : : string > data ;
} ;
ttl_extractor_ . reset ( new TestTTLExtractor ( & rnd ) ) ;
Options options ;
options . env = mock_env_ . get ( ) ;
BlobDBOptions bdb_options ;
bdb_options . ttl_range_secs = 1000 ;
bdb_options . min_blob_size = 0 ;
bdb_options . blob_file_size = 256 * 1000 * 1000 ;
bdb_options . ttl_extractor = ttl_extractor_ ;
bdb_options . disable_background_tasks = true ;
Open ( bdb_options , options ) ;
mock_env_ - > set_current_time ( 50 ) ;
for ( size_t i = 0 ; i < 100 ; i + + ) {
PutRandom ( " key " + ToString ( i ) , & rnd ) ;
}
mock_env_ - > set_current_time ( 100 ) ;
auto * bdb_impl = static_cast < BlobDBImpl * > ( blob_db_ ) ;
auto blob_files = bdb_impl - > TEST_GetBlobFiles ( ) ;
ASSERT_EQ ( 1 , blob_files . size ( ) ) ;
ASSERT_TRUE ( blob_files [ 0 ] - > HasTTL ( ) ) ;
ASSERT_OK ( bdb_impl - > TEST_CloseBlobFile ( blob_files [ 0 ] ) ) ;
GCStats gc_stats ;
ASSERT_OK ( bdb_impl - > TEST_GCFileAndUpdateLSM ( blob_files [ 0 ] , & gc_stats ) ) ;
auto & data = static_cast < TestTTLExtractor * > ( ttl_extractor_ . get ( ) ) - > data ;
ASSERT_EQ ( 100 - data . size ( ) , gc_stats . num_keys_expired ) ;
ASSERT_EQ ( data . size ( ) , gc_stats . num_keys_relocated ) ;
VerifyDB ( data ) ;
}
TEST_F ( BlobDBTest , TTLExtractor_ExtractExpiration ) {
Random rnd ( 301 ) ;
class TestTTLExtractor : public TTLExtractor {
public :
explicit TestTTLExtractor ( Random * r ) : rnd ( r ) { }
virtual bool ExtractExpiration ( const Slice & key , const Slice & value ,
uint64_t /*now*/ , uint64_t * expiration ,
std : : string * /*new_value*/ ,
bool * /*value_changed*/ ) override {
* expiration = rnd - > Next ( ) % 100 + 50 ;
if ( * expiration > 100 ) {
data [ key . ToString ( ) ] = value . ToString ( ) ;
}
return true ;
}
Random * rnd ;
std : : map < std : : string , std : : string > data ;
} ;
ttl_extractor_ . reset ( new TestTTLExtractor ( & rnd ) ) ;
Options options ;
options . env = mock_env_ . get ( ) ;
BlobDBOptions bdb_options ;
bdb_options . ttl_range_secs = 1000 ;
bdb_options . min_blob_size = 0 ;
bdb_options . blob_file_size = 256 * 1000 * 1000 ;
bdb_options . ttl_extractor = ttl_extractor_ ;
bdb_options . disable_background_tasks = true ;
Open ( bdb_options , options ) ;
mock_env_ - > set_current_time ( 50 ) ;
for ( size_t i = 0 ; i < 100 ; i + + ) {
PutRandom ( " key " + ToString ( i ) , & rnd ) ;
}
mock_env_ - > set_current_time ( 100 ) ;
auto * bdb_impl = static_cast < BlobDBImpl * > ( blob_db_ ) ;
auto blob_files = bdb_impl - > TEST_GetBlobFiles ( ) ;
ASSERT_EQ ( 1 , blob_files . size ( ) ) ;
ASSERT_TRUE ( blob_files [ 0 ] - > HasTTL ( ) ) ;
ASSERT_OK ( bdb_impl - > TEST_CloseBlobFile ( blob_files [ 0 ] ) ) ;
GCStats gc_stats ;
ASSERT_OK ( bdb_impl - > TEST_GCFileAndUpdateLSM ( blob_files [ 0 ] , & gc_stats ) ) ;
auto & data = static_cast < TestTTLExtractor * > ( ttl_extractor_ . get ( ) ) - > data ;
ASSERT_EQ ( 100 - data . size ( ) , gc_stats . num_keys_expired ) ;
ASSERT_EQ ( data . size ( ) , gc_stats . num_keys_relocated ) ;
VerifyDB ( data ) ;
}
TEST_F ( BlobDBTest , TTLExtractor_ChangeValue ) {
class TestTTLExtractor : public TTLExtractor {
public :
const Slice kTTLSuffix = Slice ( " ttl: " ) ;
bool ExtractTTL ( const Slice & /*key*/ , const Slice & value , uint64_t * ttl ,
std : : string * new_value , bool * value_changed ) override {
if ( value . size ( ) < 12 ) {
return false ;
}
const char * p = value . data ( ) + value . size ( ) - 12 ;
if ( kTTLSuffix ! = Slice ( p , 4 ) ) {
return false ;
}
* ttl = DecodeFixed64 ( p + 4 ) ;
* new_value = Slice ( value . data ( ) , value . size ( ) - 12 ) . ToString ( ) ;
* value_changed = true ;
return true ;
}
} ;
Random rnd ( 301 ) ;
Options options ;
options . env = mock_env_ . get ( ) ;
BlobDBOptions bdb_options ;
bdb_options . ttl_range_secs = 1000 ;
bdb_options . min_blob_size = 0 ;
bdb_options . blob_file_size = 256 * 1000 * 1000 ;
bdb_options . ttl_extractor = std : : make_shared < TestTTLExtractor > ( ) ;
bdb_options . disable_background_tasks = true ;
Open ( bdb_options , options ) ;
std : : map < std : : string , std : : string > data ;
mock_env_ - > set_current_time ( 50 ) ;
for ( size_t i = 0 ; i < 100 ; i + + ) {
int len = rnd . Next ( ) % kMaxBlobSize + 1 ;
std : : string key = " key " + ToString ( i ) ;
std : : string value = test : : RandomHumanReadableString ( & rnd , len ) ;
uint64_t ttl = rnd . Next ( ) % 100 ;
std : : string value_ttl = value + " ttl: " ;
PutFixed64 ( & value_ttl , ttl ) ;
ASSERT_OK ( blob_db_ - > Put ( WriteOptions ( ) , Slice ( key ) , Slice ( value_ttl ) ) ) ;
if ( ttl > 50 ) {
data [ key ] = value ;
}
}
mock_env_ - > set_current_time ( 100 ) ;
auto * bdb_impl = static_cast < BlobDBImpl * > ( blob_db_ ) ;
auto blob_files = bdb_impl - > TEST_GetBlobFiles ( ) ;
ASSERT_EQ ( 1 , blob_files . size ( ) ) ;
ASSERT_TRUE ( blob_files [ 0 ] - > HasTTL ( ) ) ;
ASSERT_OK ( bdb_impl - > TEST_CloseBlobFile ( blob_files [ 0 ] ) ) ;
GCStats gc_stats ;
ASSERT_OK ( bdb_impl - > TEST_GCFileAndUpdateLSM ( blob_files [ 0 ] , & gc_stats ) ) ;
ASSERT_EQ ( 100 - data . size ( ) , gc_stats . num_keys_expired ) ;
ASSERT_EQ ( data . size ( ) , gc_stats . num_keys_relocated ) ;
VerifyDB ( data ) ;
}
TEST_F ( BlobDBTest , StackableDBGet ) {
TEST_F ( BlobDBTest , StackableDBGet ) {
Random rnd ( 301 ) ;
Random rnd ( 301 ) ;
BlobDBOptions bdb_options ;
BlobDBOptions bdb_options ;