@ -352,6 +352,11 @@ class TableConstructor: public Constructor {
}
uint64_t ApproximateOffsetOf ( const Slice & key ) const {
if ( convert_to_internal_key_ ) {
InternalKey ikey ( key , kMaxSequenceNumber , kTypeValue ) ;
const Slice skey = ikey . Encode ( ) ;
return table_reader_ - > ApproximateOffsetOf ( skey ) ;
}
return table_reader_ - > ApproximateOffsetOf ( key ) ;
}
@ -373,6 +378,8 @@ class TableConstructor: public Constructor {
void ResetTableReader ( ) { table_reader_ . reset ( ) ; }
bool ConvertToInternalKey ( ) { return convert_to_internal_key_ ; }
private :
void Reset ( ) {
uniq_id_ = 0 ;
@ -685,7 +692,10 @@ class HarnessTest : public testing::Test {
table_options_ . format_version = args . format_version ;
options_ . table_factory . reset (
new BlockBasedTableFactory ( table_options_ ) ) ;
constructor_ = new TableConstructor ( options_ . comparator ) ;
constructor_ = new TableConstructor (
options_ . comparator , true /* convert_to_internal_key_ */ ) ;
internal_comparator_ . reset (
new InternalKeyComparator ( options_ . comparator ) ) ;
break ;
// Plain table is not supported in ROCKSDB_LITE
# ifndef ROCKSDB_LITE
@ -694,7 +704,8 @@ class HarnessTest : public testing::Test {
only_support_prefix_seek_ = true ;
options_ . prefix_extractor . reset ( new FixedOrLessPrefixTransform ( 2 ) ) ;
options_ . table_factory . reset ( NewPlainTableFactory ( ) ) ;
constructor_ = new TableConstructor ( options_ . comparator , true ) ;
constructor_ = new TableConstructor (
options_ . comparator , true /* convert_to_internal_key_ */ ) ;
internal_comparator_ . reset (
new InternalKeyComparator ( options_ . comparator ) ) ;
break ;
@ -703,7 +714,8 @@ class HarnessTest : public testing::Test {
only_support_prefix_seek_ = true ;
options_ . prefix_extractor . reset ( NewNoopTransform ( ) ) ;
options_ . table_factory . reset ( NewPlainTableFactory ( ) ) ;
constructor_ = new TableConstructor ( options_ . comparator , true ) ;
constructor_ = new TableConstructor (
options_ . comparator , true /* convert_to_internal_key_ */ ) ;
internal_comparator_ . reset (
new InternalKeyComparator ( options_ . comparator ) ) ;
break ;
@ -721,7 +733,8 @@ class HarnessTest : public testing::Test {
options_ . table_factory . reset (
NewPlainTableFactory ( plain_table_options ) ) ;
}
constructor_ = new TableConstructor ( options_ . comparator , true ) ;
constructor_ = new TableConstructor (
options_ . comparator , true /* convert_to_internal_key_ */ ) ;
internal_comparator_ . reset (
new InternalKeyComparator ( options_ . comparator ) ) ;
break ;
@ -1019,7 +1032,7 @@ TEST_F(TablePropertyTest, PrefixScanTest) {
// This test include all the basic checks except those for index size and block
// size, which will be conducted in separated unit tests.
TEST_F ( BlockBasedTableTest , BasicBlockBasedTableProperties ) {
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " a1 " , " val1 " ) ;
c . Add ( " b2 " , " val2 " ) ;
@ -1030,6 +1043,7 @@ TEST_F(BlockBasedTableTest, BasicBlockBasedTableProperties) {
c . Add ( " g7 " , " val7 " ) ;
c . Add ( " h8 " , " val8 " ) ;
c . Add ( " j9 " , " val9 " ) ;
uint64_t diff_internal_user_bytes = 9 * 8 ; // 8 is seq size, 9 k-v totally
std : : vector < std : : string > keys ;
stl_wrappers : : KVMap kvmap ;
@ -1049,7 +1063,7 @@ TEST_F(BlockBasedTableTest, BasicBlockBasedTableProperties) {
auto raw_key_size = kvmap . size ( ) * 2ul ;
auto raw_value_size = kvmap . size ( ) * 4ul ;
ASSERT_EQ ( raw_key_size , props . raw_key_size ) ;
ASSERT_EQ ( raw_key_size + diff_internal_user_bytes , props . raw_key_size ) ;
ASSERT_EQ ( raw_value_size , props . raw_value_size ) ;
ASSERT_EQ ( 1ul , props . num_data_blocks ) ;
ASSERT_EQ ( " " , props . filter_policy_name ) ; // no filter policy is used
@ -1060,7 +1074,8 @@ TEST_F(BlockBasedTableTest, BasicBlockBasedTableProperties) {
block_builder . Add ( item . first , item . second ) ;
}
Slice content = block_builder . Finish ( ) ;
ASSERT_EQ ( content . size ( ) + kBlockTrailerSize , props . data_size ) ;
ASSERT_EQ ( content . size ( ) + kBlockTrailerSize + diff_internal_user_bytes ,
props . data_size ) ;
c . ResetTableReader ( ) ;
}
@ -1120,8 +1135,50 @@ TEST_F(BlockBasedTableTest, BlockBasedTableProperties2) {
}
}
TEST_F ( BlockBasedTableTest , RangeDelBlock ) {
TableConstructor c ( BytewiseComparator ( ) ) ;
std : : vector < std : : string > keys = { " 1pika " , " 2chu " } ;
std : : vector < std : : string > vals = { " p " , " c " } ;
for ( int i = 0 ; i < 2 ; i + + ) {
RangeTombstone t ( keys [ i ] , vals [ i ] , i ) ;
std : : pair < InternalKey , Slice > p = t . Serialize ( ) ;
c . Add ( p . first . Encode ( ) . ToString ( ) , p . second ) ;
}
std : : vector < std : : string > sorted_keys ;
stl_wrappers : : KVMap kvmap ;
Options options ;
options . compression = kNoCompression ;
BlockBasedTableOptions table_options ;
table_options . block_restart_interval = 1 ;
options . table_factory . reset ( NewBlockBasedTableFactory ( table_options ) ) ;
const ImmutableCFOptions ioptions ( options ) ;
std : : unique_ptr < InternalKeyComparator > internal_cmp (
new InternalKeyComparator ( options . comparator ) ) ;
c . Finish ( options , ioptions , table_options , * internal_cmp , & sorted_keys ,
& kvmap ) ;
std : : unique_ptr < InternalIterator > iter (
c . GetTableReader ( ) - > NewRangeTombstoneIterator ( ReadOptions ( ) ) ) ;
ASSERT_EQ ( false , iter - > Valid ( ) ) ;
iter - > SeekToFirst ( ) ;
ASSERT_EQ ( true , iter - > Valid ( ) ) ;
for ( int i = 0 ; i < 2 ; i + + ) {
ASSERT_TRUE ( iter - > Valid ( ) ) ;
RangeTombstone t ( iter - > key ( ) , iter - > value ( ) ) ;
ASSERT_EQ ( t . start_key_ , keys [ i ] ) ;
ASSERT_EQ ( t . end_key_ , vals [ i ] ) ;
ASSERT_EQ ( t . seq_ , i ) ;
iter - > Next ( ) ;
}
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
c . ResetTableReader ( ) ;
}
TEST_F ( BlockBasedTableTest , FilterPolicyNameProperties ) {
TableConstructor c ( BytewiseComparator ( ) , true ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " a1 " , " val1 " ) ;
std : : vector < std : : string > keys ;
stl_wrappers : : KVMap kvmap ;
@ -1143,19 +1200,29 @@ TEST_F(BlockBasedTableTest, FilterPolicyNameProperties) {
//
void AssertKeysInCache ( BlockBasedTable * table_reader ,
const std : : vector < std : : string > & keys_in_cache ,
const std : : vector < std : : string > & keys_not_in_cache ) {
const std : : vector < std : : string > & keys_not_in_cache ,
bool convert = false ) {
if ( convert ) {
for ( auto key : keys_in_cache ) {
InternalKey ikey ( key , kMaxSequenceNumber , kTypeValue ) ;
ASSERT_TRUE ( table_reader - > TEST_KeyInCache ( ReadOptions ( ) , ikey . Encode ( ) ) ) ;
}
for ( auto key : keys_not_in_cache ) {
InternalKey ikey ( key , kMaxSequenceNumber , kTypeValue ) ;
ASSERT_TRUE ( ! table_reader - > TEST_KeyInCache ( ReadOptions ( ) , ikey . Encode ( ) ) ) ;
}
} else {
for ( auto key : keys_in_cache ) {
ASSERT_TRUE ( table_reader - > TEST_KeyInCache ( ReadOptions ( ) , key ) ) ;
}
for ( auto key : keys_not_in_cache ) {
ASSERT_TRUE ( ! table_reader - > TEST_KeyInCache ( ReadOptions ( ) , key ) ) ;
}
}
}
void PrefetchRange ( TableConstructor * c , Options * opt ,
BlockBasedTableOptions * table_options ,
const std : : vector < std : : string > & keys , const char * key_begin ,
BlockBasedTableOptions * table_options , const char * key_begin ,
const char * key_end ,
const std : : vector < std : : string > & keys_in_cache ,
const std : : vector < std : : string > & keys_not_in_cache ,
@ -1168,15 +1235,32 @@ void PrefetchRange(TableConstructor* c, Options* opt,
// prefetch
auto * table_reader = dynamic_cast < BlockBasedTable * > ( c - > GetTableReader ( ) ) ;
// empty string replacement is a trick so we don't crash the test
Slice begin ( key_begin ? key_begin : " " ) ;
Slice end ( key_end ? key_end : " " ) ;
Status s = table_reader - > Prefetch ( key_begin ? & begin : nullptr ,
key_end ? & end : nullptr ) ;
Status s ;
unique_ptr < Slice > begin , end ;
unique_ptr < InternalKey > i_begin , i_end ;
if ( key_begin ! = nullptr ) {
if ( c - > ConvertToInternalKey ( ) ) {
i_begin . reset ( new InternalKey ( key_begin , kMaxSequenceNumber , kTypeValue ) ) ;
begin . reset ( new Slice ( i_begin - > Encode ( ) ) ) ;
} else {
begin . reset ( new Slice ( key_begin ) ) ;
}
}
if ( key_end ! = nullptr ) {
if ( c - > ConvertToInternalKey ( ) ) {
i_end . reset ( new InternalKey ( key_end , kMaxSequenceNumber , kTypeValue ) ) ;
end . reset ( new Slice ( i_end - > Encode ( ) ) ) ;
} else {
end . reset ( new Slice ( key_end ) ) ;
}
}
s = table_reader - > Prefetch ( begin . get ( ) , end . get ( ) ) ;
ASSERT_TRUE ( s . code ( ) = = expected_status . code ( ) ) ;
// assert our expectation in cache warmup
AssertKeysInCache ( table_reader , keys_in_cache , keys_not_in_cache ) ;
AssertKeysInCache ( table_reader , keys_in_cache , keys_not_in_cache ,
c - > ConvertToInternalKey ( ) ) ;
c - > ResetTableReader ( ) ;
}
@ -1193,7 +1277,7 @@ TEST_F(BlockBasedTableTest, PrefetchTest) {
table_options . block_cache = NewLRUCache ( 16 * 1024 * 1024 , 4 ) ;
opt . table_factory . reset ( NewBlockBasedTableFactory ( table_options ) ) ;
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " k01 " , " hello " ) ;
c . Add ( " k02 " , " hello2 " ) ;
c . Add ( " k03 " , std : : string ( 10000 , ' x ' ) ) ;
@ -1218,48 +1302,31 @@ TEST_F(BlockBasedTableTest, PrefetchTest) {
// Simple
PrefetchRange ( & c , & opt , & table_options , keys ,
PrefetchRange ( & c , & opt , & table_options ,
/*key_range=*/ " k01 " , " k05 " ,
/*keys_in_cache=*/ { " k01 " , " k02 " , " k03 " , " k04 " , " k05 " } ,
/*keys_not_in_cache=*/ { " k06 " , " k07 " } ) ;
PrefetchRange ( & c , & opt , & table_options , keys ,
" k01 " , " k01 " ,
{ " k01 " , " k02 " , " k03 " } ,
PrefetchRange ( & c , & opt , & table_options , " k01 " , " k01 " , { " k01 " , " k02 " , " k03 " } ,
{ " k04 " , " k05 " , " k06 " , " k07 " } ) ;
// odd
PrefetchRange ( & c , & opt , & table_options , keys ,
" a " , " z " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } ,
{ } ) ;
PrefetchRange ( & c , & opt , & table_options , keys ,
" k00 " , " k00 " ,
{ " k01 " , " k02 " , " k03 " } ,
PrefetchRange ( & c , & opt , & table_options , " a " , " z " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } , { } ) ;
PrefetchRange ( & c , & opt , & table_options , " k00 " , " k00 " , { " k01 " , " k02 " , " k03 " } ,
{ " k04 " , " k05 " , " k06 " , " k07 " } ) ;
// Edge cases
PrefetchRange ( & c , & opt , & table_options , keys ,
" k00 " , " k06 " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } ,
{ } ) ;
PrefetchRange ( & c , & opt , & table_options , keys ,
" k00 " , " zzz " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } ,
{ } ) ;
PrefetchRange ( & c , & opt , & table_options , " k00 " , " k06 " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } , { } ) ;
PrefetchRange ( & c , & opt , & table_options , " k00 " , " zzz " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } , { } ) ;
// null keys
PrefetchRange ( & c , & opt , & table_options , keys ,
nullptr , nullptr ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } ,
{ } ) ;
PrefetchRange ( & c , & opt , & table_options , keys ,
" k04 " , nullptr ,
{ " k04 " , " k05 " , " k06 " , " k07 " } ,
{ " k01 " , " k02 " , " k03 " } ) ;
PrefetchRange ( & c , & opt , & table_options , keys ,
nullptr , " k05 " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " } ,
{ " k06 " , " k07 " } ) ;
PrefetchRange ( & c , & opt , & table_options , nullptr , nullptr ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " , " k06 " , " k07 " } , { } ) ;
PrefetchRange ( & c , & opt , & table_options , " k04 " , nullptr ,
{ " k04 " , " k05 " , " k06 " , " k07 " } , { " k01 " , " k02 " , " k03 " } ) ;
PrefetchRange ( & c , & opt , & table_options , nullptr , " k05 " ,
{ " k01 " , " k02 " , " k03 " , " k04 " , " k05 " } , { " k06 " , " k07 " } ) ;
// invalid
PrefetchRange ( & c , & opt , & table_options , keys ,
" k06 " , " k00 " , { } , { } ,
PrefetchRange ( & c , & opt , & table_options , " k06 " , " k00 " , { } , { } ,
Status : : InvalidArgument ( Slice ( " k06 " ) , Slice ( " k07 " ) ) ) ;
c . ResetTableReader ( ) ;
}
@ -1299,7 +1366,8 @@ TEST_F(BlockBasedTableTest, TotalOrderSeekOnHashIndex) {
break ;
}
TableConstructor c ( BytewiseComparator ( ) , true ) ;
TableConstructor c ( BytewiseComparator ( ) ,
true /* convert_to_internal_key_ */ ) ;
c . Add ( " aaaa1 " , std : : string ( ' a ' , 56 ) ) ;
c . Add ( " bbaa1 " , std : : string ( ' a ' , 56 ) ) ;
c . Add ( " cccc1 " , std : : string ( ' a ' , 56 ) ) ;
@ -1527,7 +1595,8 @@ TEST_F(BlockBasedTableTest, IndexSizeStat) {
// Each time we load one more key to the table. the table index block
// size is expected to be larger than last time's.
for ( size_t i = 1 ; i < keys . size ( ) ; + + i ) {
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) ,
true /* convert_to_internal_key_ */ ) ;
for ( size_t j = 0 ; j < i ; + + j ) {
c . Add ( keys [ j ] , " val " ) ;
}
@ -1552,7 +1621,7 @@ TEST_F(BlockBasedTableTest, IndexSizeStat) {
TEST_F ( BlockBasedTableTest , NumBlockStat ) {
Random rnd ( test : : RandomSeed ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
Options options ;
options . compression = kNoCompression ;
BlockBasedTableOptions table_options ;
@ -1652,7 +1721,7 @@ TEST_F(BlockBasedTableTest, BlockCacheDisabledTest) {
std : : vector < std : : string > keys ;
stl_wrappers : : KVMap kvmap ;
TableConstructor c ( BytewiseComparator ( ) , true ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " key " , " value " ) ;
const ImmutableCFOptions ioptions ( options ) ;
c . Finish ( options , ioptions , table_options ,
@ -1698,7 +1767,7 @@ TEST_F(BlockBasedTableTest, FilterBlockInBlockCache) {
std : : vector < std : : string > keys ;
stl_wrappers : : KVMap kvmap ;
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " key " , " value " ) ;
const ImmutableCFOptions ioptions ( options ) ;
c . Finish ( options , ioptions , table_options ,
@ -1979,7 +2048,7 @@ TEST_F(BlockBasedTableTest, BlockCacheLeak) {
table_options . block_cache = NewLRUCache ( 16 * 1024 * 1024 , 4 ) ;
opt . table_factory . reset ( NewBlockBasedTableFactory ( table_options ) ) ;
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " k01 " , " hello " ) ;
c . Add ( " k02 " , " hello2 " ) ;
c . Add ( " k03 " , std : : string ( 10000 , ' x ' ) ) ;
@ -2079,7 +2148,7 @@ TEST_F(PlainTableTest, BasicPlainTableProperties) {
# endif // !ROCKSDB_LITE
TEST_F ( GeneralTableTest , ApproximateOffsetOfPlain ) {
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
c . Add ( " k01 " , " hello " ) ;
c . Add ( " k02 " , " hello2 " ) ;
c . Add ( " k03 " , std : : string ( 10000 , ' x ' ) ) ;
@ -2104,7 +2173,9 @@ TEST_F(GeneralTableTest, ApproximateOffsetOfPlain) {
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k02 " ) , 0 , 0 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k03 " ) , 0 , 0 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k04 " ) , 10000 , 11000 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k04a " ) , 210000 , 211000 ) ) ;
// k04 and k05 will be in two consecutive blocks, the index is
// an arbitrary slice between k04 and k05, either before or after k04a
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k04a " ) , 10000 , 211000 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k05 " ) , 210000 , 211000 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k06 " ) , 510000 , 511000 ) ) ;
ASSERT_TRUE ( Between ( c . ApproximateOffsetOf ( " k07 " ) , 510000 , 511000 ) ) ;
@ -2114,7 +2185,7 @@ TEST_F(GeneralTableTest, ApproximateOffsetOfPlain) {
static void DoCompressionTest ( CompressionType comp ) {
Random rnd ( 301 ) ;
TableConstructor c ( BytewiseComparator ( ) ) ;
TableConstructor c ( BytewiseComparator ( ) , true /* convert_to_internal_key_ */ ) ;
std : : string tmp ;
c . Add ( " k01 " , " hello " ) ;
c . Add ( " k02 " , test : : CompressibleString ( & rnd , 0.25 , 10000 , & tmp ) ) ;