@ -22,7 +22,9 @@
# include "rocksdb/filter_policy.h"
# include "rocksdb/filter_policy.h"
# include "rocksdb/slice_transform.h"
# include "rocksdb/slice_transform.h"
# include "rocksdb/table.h"
# include "rocksdb/table.h"
# include "table/meta_blocks.h"
# include "table/plain_table_factory.h"
# include "table/plain_table_factory.h"
# include "table/plain_table_reader.h"
# include "util/hash.h"
# include "util/hash.h"
# include "util/logging.h"
# include "util/logging.h"
# include "util/mutexlock.h"
# include "util/mutexlock.h"
@ -46,6 +48,7 @@ class PlainTableDBTest {
public :
public :
PlainTableDBTest ( ) : env_ ( Env : : Default ( ) ) {
PlainTableDBTest ( ) : env_ ( Env : : Default ( ) ) {
ro_ . prefix_seek = true ;
dbname_ = test : : TmpDir ( ) + " /plain_table_db_test " ;
dbname_ = test : : TmpDir ( ) + " /plain_table_db_test " ;
ASSERT_OK ( DestroyDB ( dbname_ , Options ( ) ) ) ;
ASSERT_OK ( DestroyDB ( dbname_ , Options ( ) ) ) ;
db_ = nullptr ;
db_ = nullptr ;
@ -57,10 +60,12 @@ class PlainTableDBTest {
ASSERT_OK ( DestroyDB ( dbname_ , Options ( ) ) ) ;
ASSERT_OK ( DestroyDB ( dbname_ , Options ( ) ) ) ;
}
}
ReadOptions ro_ ;
// Return the current option configuration.
// Return the current option configuration.
Options CurrentOptions ( ) {
Options CurrentOptions ( ) {
Options options ;
Options options ;
options . table_factory . reset ( new PlainTableFactory ( 16 , 2 , 0.8 ) ) ;
options . table_factory . reset ( New PlainTableFactory( 16 , 2 , 0.8 , 3 ) ) ;
options . prefix_extractor = prefix_transform . get ( ) ;
options . prefix_extractor = prefix_transform . get ( ) ;
options . allow_mmap_reads = true ;
options . allow_mmap_reads = true ;
return options ;
return options ;
@ -119,7 +124,7 @@ class PlainTableDBTest {
}
}
std : : string Get ( const std : : string & k , const Snapshot * snapshot = nullptr ) {
std : : string Get ( const std : : string & k , const Snapshot * snapshot = nullptr ) {
ReadOptions options ;
ReadOptions options = ro_ ;
options . snapshot = snapshot ;
options . snapshot = snapshot ;
std : : string result ;
std : : string result ;
Status s = db_ - > Get ( options , k , & result ) ;
Status s = db_ - > Get ( options , k , & result ) ;
@ -176,16 +181,94 @@ TEST(PlainTableDBTest, Empty) {
ASSERT_EQ ( " NOT_FOUND " , Get ( " 0000000000000foo " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 0000000000000foo " ) ) ;
}
}
TEST ( PlainTableDBTest , ReadWrite ) {
class TestPlainTableReader : public PlainTableReader {
ASSERT_OK ( Put ( " 1000000000000foo " , " v1 " ) ) ;
public :
ASSERT_EQ ( " v1 " , Get ( " 1000000000000foo " ) ) ;
TestPlainTableReader ( const EnvOptions & storage_options ,
ASSERT_OK ( Put ( " 0000000000000bar " , " v2 " ) ) ;
const InternalKeyComparator & icomparator ,
ASSERT_OK ( Put ( " 1000000000000foo " , " v3 " ) ) ;
uint64_t file_size , int bloom_bits_per_key ,
ASSERT_EQ ( " v3 " , Get ( " 1000000000000foo " ) ) ;
double hash_table_ratio , size_t index_sparseness ,
ASSERT_EQ ( " v2 " , Get ( " 0000000000000bar " ) ) ;
const TableProperties * table_properties ,
unique_ptr < RandomAccessFile > & & file ,
const Options & options , bool * expect_bloom_not_match )
: PlainTableReader ( storage_options , icomparator , file_size ,
bloom_bits_per_key , hash_table_ratio , index_sparseness ,
table_properties ) ,
expect_bloom_not_match_ ( expect_bloom_not_match ) {
file_ = std : : move ( file ) ;
options_ = options ;
Status s = PopulateIndex ( ) ;
ASSERT_TRUE ( s . ok ( ) ) ;
}
virtual ~ TestPlainTableReader ( ) { }
private :
virtual bool MatchBloom ( uint32_t hash ) const override {
bool ret = PlainTableReader : : MatchBloom ( hash ) ;
ASSERT_TRUE ( ! * expect_bloom_not_match_ | | ! ret ) ;
return ret ;
}
}
bool * expect_bloom_not_match_ ;
} ;
extern const uint64_t kPlainTableMagicNumber ;
class TestPlainTableFactory : public PlainTableFactory {
public :
explicit TestPlainTableFactory ( bool * expect_bloom_not_match ,
uint32_t user_key_len =
kPlainTableVariableLength ,
int bloom_bits_per_key = 0 ,
double hash_table_ratio = 0.75 ,
size_t index_sparseness = 16 )
: PlainTableFactory ( user_key_len , user_key_len , hash_table_ratio ,
hash_table_ratio ) ,
user_key_len_ ( user_key_len ) ,
bloom_bits_per_key_ ( bloom_bits_per_key ) ,
hash_table_ratio_ ( hash_table_ratio ) ,
index_sparseness_ ( index_sparseness ) ,
expect_bloom_not_match_ ( expect_bloom_not_match ) { }
Status NewTableReader ( const Options & options , const EnvOptions & soptions ,
const InternalKeyComparator & internal_comparator ,
unique_ptr < RandomAccessFile > & & file , uint64_t file_size ,
unique_ptr < TableReader > * table ) const override {
TableProperties * props = nullptr ;
auto s = ReadTableProperties ( file . get ( ) , file_size , kPlainTableMagicNumber ,
options . env , options . info_log . get ( ) , & props ) ;
ASSERT_TRUE ( s . ok ( ) ) ;
std : : unique_ptr < PlainTableReader > new_reader ( new TestPlainTableReader (
soptions , internal_comparator , file_size , bloom_bits_per_key_ ,
hash_table_ratio_ , index_sparseness_ , props , std : : move ( file ) , options ,
expect_bloom_not_match_ ) ) ;
* table = std : : move ( new_reader ) ;
return s ;
}
private :
uint32_t user_key_len_ ;
int bloom_bits_per_key_ ;
double hash_table_ratio_ ;
size_t index_sparseness_ ;
bool * expect_bloom_not_match_ ;
} ;
TEST ( PlainTableDBTest , Flush ) {
TEST ( PlainTableDBTest , Flush ) {
for ( int bloom_bits = 0 ; bloom_bits < = 8 ; bloom_bits + = 8 ) {
for ( int total_order = 0 ; total_order < = 1 ; total_order + + ) {
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
if ( total_order ) {
options . table_factory . reset (
NewTotalOrderPlainTableFactory ( 16 , bloom_bits , 2 ) ) ;
} else {
options . table_factory . reset ( NewPlainTableFactory ( 16 , bloom_bits ) ) ;
}
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " v2 " ) ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " v2 " ) ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v3 " ) ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v3 " ) ) ;
@ -193,8 +276,82 @@ TEST(PlainTableDBTest, Flush) {
ASSERT_EQ ( " v3 " , Get ( " 1000000000000foo " ) ) ;
ASSERT_EQ ( " v3 " , Get ( " 1000000000000foo " ) ) ;
ASSERT_EQ ( " v2 " , Get ( " 0000000000000bar " ) ) ;
ASSERT_EQ ( " v2 " , Get ( " 0000000000000bar " ) ) ;
}
}
}
}
TEST ( PlainTableDBTest , Flush2 ) {
for ( int bloom_bits = 0 ; bloom_bits < = 10 ; bloom_bits + = 10 ) {
for ( int total_order = 0 ; total_order < = 1 ; total_order + + ) {
bool expect_bloom_not_match = false ;
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
if ( total_order ) {
options . prefix_extractor = nullptr ;
options . table_factory . reset ( new TestPlainTableFactory (
& expect_bloom_not_match , 16 , bloom_bits , 0 , 2 ) ) ;
} else {
options . table_factory . reset (
new TestPlainTableFactory ( & expect_bloom_not_match , 16 , bloom_bits ) ) ;
}
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " b " ) ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v1 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_OK ( Put ( " 1000000000000foo " , " v2 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v2 " , Get ( " 1000000000000foo " ) ) ;
ASSERT_OK ( Put ( " 0000000000000eee " , " v3 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v3 " , Get ( " 0000000000000eee " ) ) ;
ASSERT_OK ( Delete ( " 0000000000000bar " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 0000000000000bar " ) ) ;
ASSERT_OK ( Put ( " 0000000000000eee " , " v5 " ) ) ;
ASSERT_OK ( Put ( " 9000000000000eee " , " v5 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v5 " , Get ( " 0000000000000eee " ) ) ;
// Test Bloom Filter
if ( bloom_bits > 0 ) {
// Neither key nor value should exist.
expect_bloom_not_match = true ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 5_not00000000bar " ) ) ;
// Key doesn't exist any more but prefix exists.
if ( total_order ) {
ASSERT_EQ ( " NOT_FOUND " , Get ( " 1000000000000not " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 0000000000000not " ) ) ;
}
expect_bloom_not_match = false ;
}
}
}
}
TEST ( PlainTableDBTest , Iterator ) {
TEST ( PlainTableDBTest , Iterator ) {
for ( int bloom_bits = 0 ; bloom_bits < = 8 ; bloom_bits + = 8 ) {
for ( int total_order = 0 ; total_order < = 1 ; total_order + + ) {
bool expect_bloom_not_match = false ;
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
if ( total_order ) {
options . prefix_extractor = nullptr ;
options . table_factory . reset ( new TestPlainTableFactory (
& expect_bloom_not_match , 16 , bloom_bits , 0 , 2 ) ) ;
} else {
options . table_factory . reset (
new TestPlainTableFactory ( & expect_bloom_not_match , 16 , bloom_bits ) ) ;
}
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 1000000000foo002 " , " v_2 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo002 " , " v_2 " ) ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " random " ) ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " random " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo001 " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo001 " , " v1 " ) ) ;
@ -207,9 +364,8 @@ TEST(PlainTableDBTest, Iterator) {
dbfull ( ) - > TEST_FlushMemTable ( ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v1 " , Get ( " 1000000000foo001 " ) ) ;
ASSERT_EQ ( " v1 " , Get ( " 1000000000foo001 " ) ) ;
ASSERT_EQ ( " v__3 " , Get ( " 1000000000foo003 " ) ) ;
ASSERT_EQ ( " v__3 " , Get ( " 1000000000foo003 " ) ) ;
ReadOptions ro ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro_ ) ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro ) ;
iter - > Seek ( " 1000000000foo000 " ) ;
iter - > Seek ( " 1000000000foo001 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo001 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " 1000000000foo001 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v1 " , iter - > value ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v1 " , iter - > value ( ) . ToString ( ) ) ;
@ -254,34 +410,328 @@ TEST(PlainTableDBTest, Iterator) {
ASSERT_EQ ( " 1000000000foo008 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " 1000000000foo008 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__8 " , iter - > value ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__8 " , iter - > value ( ) . ToString ( ) ) ;
if ( total_order = = 0 ) {
iter - > Seek ( " 1000000000foo009 " ) ;
iter - > Seek ( " 1000000000foo009 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 3000000000000bar " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " 3000000000000bar " , iter - > key ( ) . ToString ( ) ) ;
}
// Test Bloom Filter
if ( bloom_bits > 0 ) {
// Neither key nor value should exist.
expect_bloom_not_match = true ;
iter - > Seek ( " 2not000000000bar " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
// Key doesn't exist any more but prefix exists.
if ( total_order ) {
iter - > Seek ( " 2not000000000bar " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
}
expect_bloom_not_match = false ;
}
delete iter ;
delete iter ;
}
}
}
}
TEST ( PlainTableDBTest , Flush2 ) {
// A test comparator which compare two strings in this way:
ASSERT_OK ( Put ( " 0000000000000bar " , " b " ) ) ;
// (1) first compare prefix of 8 bytes in alphabet order,
ASSERT_OK ( Put ( " 1000000000000foo " , " v1 " ) ) ;
// (2) if two strings share the same prefix, sort the other part of the string
dbfull ( ) - > TEST_FlushMemTable ( ) ;
// in the reverse alphabet order.
class SimpleSuffixReverseComparator : public Comparator {
public :
SimpleSuffixReverseComparator ( ) { }
ASSERT_OK ( Put ( " 1000000000000foo " , " v2 " ) ) ;
virtual const char * Name ( ) const { return " SimpleSuffixReverseComparator " ; }
virtual int Compare ( const Slice & a , const Slice & b ) const {
Slice prefix_a = Slice ( a . data ( ) , 8 ) ;
Slice prefix_b = Slice ( b . data ( ) , 8 ) ;
int prefix_comp = prefix_a . compare ( prefix_b ) ;
if ( prefix_comp ! = 0 ) {
return prefix_comp ;
} else {
Slice suffix_a = Slice ( a . data ( ) + 8 , a . size ( ) - 8 ) ;
Slice suffix_b = Slice ( b . data ( ) + 8 , b . size ( ) - 8 ) ;
return - ( suffix_a . compare ( suffix_b ) ) ;
}
}
virtual void FindShortestSeparator ( std : : string * start ,
const Slice & limit ) const { }
virtual void FindShortSuccessor ( std : : string * key ) const { }
} ;
TEST ( PlainTableDBTest , IteratorReverseSuffixComparator ) {
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
SimpleSuffixReverseComparator comp ;
options . comparator = & comp ;
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 1000000000foo002 " , " v_2 " ) ) ;
ASSERT_OK ( Put ( " 0000000000000bar " , " random " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo001 " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 3000000000000bar " , " bar_v " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo003 " , " v__3 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo004 " , " v__4 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo005 " , " v__5 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo007 " , " v__7 " ) ) ;
ASSERT_OK ( Put ( " 1000000000foo008 " , " v__8 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v2 " , Get ( " 1000000000000foo " ) ) ;
ASSERT_EQ ( " v1 " , Get ( " 1000000000foo001 " ) ) ;
ASSERT_EQ ( " v__3 " , Get ( " 1000000000foo003 " ) ) ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro_ ) ;
iter - > Seek ( " 1000000000foo009 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo008 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__8 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo007 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__7 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo005 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__5 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo004 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__4 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Seek ( " 3000000000000bar " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 3000000000000bar " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " bar_v " , iter - > value ( ) . ToString ( ) ) ;
iter - > Seek ( " 1000000000foo005 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo005 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__5 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Seek ( " 1000000000foo006 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo005 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__5 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Seek ( " 1000000000foo008 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 1000000000foo008 " , iter - > key ( ) . ToString ( ) ) ;
ASSERT_EQ ( " v__8 " , iter - > value ( ) . ToString ( ) ) ;
iter - > Seek ( " 1000000000foo000 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 3000000000000bar " , iter - > key ( ) . ToString ( ) ) ;
delete iter ;
}
TEST ( PlainTableDBTest , HashBucketConflict ) {
for ( unsigned char i = 1 ; i < = 3 ; i + + ) {
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
options . table_factory . reset ( NewTotalOrderPlainTableFactory ( 16 , 0 , 2 ^ i ) ) ;
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 5000000000000fo0 " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo1 " , " v2 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo2 " , " v " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo0 " , " v3 " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo1 " , " v4 " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo2 " , " v " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo3 " , " v " ) ) ;
ASSERT_OK ( Put ( " 0000000000000eee " , " v3 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v3 " , Get ( " 0000000000000eee " ) ) ;
ASSERT_OK ( Delete ( " 0000000000000bar " ) ) ;
ASSERT_EQ ( " v1 " , Get ( " 5000000000000fo0 " ) ) ;
ASSERT_EQ ( " v2 " , Get ( " 5000000000000fo1 " ) ) ;
ASSERT_EQ ( " v3 " , Get ( " 2000000000000fo0 " ) ) ;
ASSERT_EQ ( " v4 " , Get ( " 2000000000000fo1 " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 5000000000000bar " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 2000000000000bar " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 5000000000000fo8 " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 2000000000000fo8 " ) ) ;
ReadOptions ro ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro ) ;
iter - > Seek ( " 5000000000000fo0 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 5000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000fo0 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000bar " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 5000000000000bar " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000fo8 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) | |
options . comparator - > Compare ( iter - > key ( ) , " 20000001 " ) > 0 ) ;
iter - > Seek ( " 5000000000000fo8 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 1000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 3000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 8000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
delete iter ;
}
}
TEST ( PlainTableDBTest , HashBucketConflictReverseSuffixComparator ) {
for ( unsigned char i = 1 ; i < = 3 ; i + + ) {
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
SimpleSuffixReverseComparator comp ;
options . comparator = & comp ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
options . table_factory . reset ( NewTotalOrderPlainTableFactory ( 16 , 0 , 2 ^ i ) ) ;
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 5000000000000fo0 " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo1 " , " v2 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo2 " , " v " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo0 " , " v3 " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo1 " , " v4 " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo2 " , " v " ) ) ;
ASSERT_OK ( Put ( " 2000000000000fo3 " , " v " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 0000000000000bar " ) ) ;
ASSERT_OK ( Put ( " 0000000000000eee " , " v5 " ) ) ;
ASSERT_EQ ( " v1 " , Get ( " 5000000000000fo0 " ) ) ;
ASSERT_EQ ( " v2 " , Get ( " 5000000000000fo1 " ) ) ;
ASSERT_EQ ( " v3 " , Get ( " 2000000000000fo0 " ) ) ;
ASSERT_EQ ( " v4 " , Get ( " 2000000000000fo1 " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 5000000000000bar " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 2000000000000bar " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 5000000000000fo8 " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 2000000000000fo8 " ) ) ;
ReadOptions ro ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro ) ;
iter - > Seek ( " 5000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 5000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Next ( ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000fo1 " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo1 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 2000000000000var " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 2000000000000fo3 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 5000000000000var " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo2 " , iter - > key ( ) . ToString ( ) ) ;
std : : string seek_key = " 2000000000000bar " ;
iter - > Seek ( seek_key ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) | |
options . prefix_extractor - > Transform ( iter - > key ( ) ) ! =
options . prefix_extractor - > Transform ( seek_key ) ) ;
iter - > Seek ( " 1000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 3000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 8000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
delete iter ;
}
}
TEST ( PlainTableDBTest , NonExistingKeyToNonEmptyBucket ) {
Options options = CurrentOptions ( ) ;
options . create_if_missing = true ;
// Set only one bucket to force bucket conflict.
// Test index interval for the same prefix to be 1, 2 and 4
options . table_factory . reset ( NewTotalOrderPlainTableFactory ( 16 , 0 , 5 ) ) ;
DestroyAndReopen ( & options ) ;
ASSERT_OK ( Put ( " 5000000000000fo0 " , " v1 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo1 " , " v2 " ) ) ;
ASSERT_OK ( Put ( " 5000000000000fo2 " , " v3 " ) ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
dbfull ( ) - > TEST_FlushMemTable ( ) ;
ASSERT_EQ ( " v5 " , Get ( " 0000000000000eee " ) ) ;
ASSERT_EQ ( " v1 " , Get ( " 5000000000000fo0 " ) ) ;
ASSERT_EQ ( " v2 " , Get ( " 5000000000000fo1 " ) ) ;
ASSERT_EQ ( " v3 " , Get ( " 5000000000000fo2 " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 8000000000000bar " ) ) ;
ASSERT_EQ ( " NOT_FOUND " , Get ( " 1000000000000bar " ) ) ;
Iterator * iter = dbfull ( ) - > NewIterator ( ro_ ) ;
iter - > Seek ( " 5000000000000bar " ) ;
ASSERT_TRUE ( iter - > Valid ( ) ) ;
ASSERT_EQ ( " 5000000000000fo0 " , iter - > key ( ) . ToString ( ) ) ;
iter - > Seek ( " 5000000000000fo8 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 1000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
iter - > Seek ( " 8000000000000fo2 " ) ;
ASSERT_TRUE ( ! iter - > Valid ( ) ) ;
delete iter ;
}
}
static std : : string Key ( int i ) {
static std : : string Key ( int i ) {