@ -21,34 +21,38 @@ class MergeHelperTest : public testing::Test {
MergeHelperTest ( ) = default ;
MergeHelperTest ( ) = default ;
~ MergeHelperTest ( ) = default ;
~ MergeHelperTest ( ) = default ;
void RunUInt64MergeHelper ( SequenceNumber stop_before , bool at_bottom ) {
Status RunUInt64MergeHelper ( SequenceNumber stop_before , bool at_bottom ) {
InitIterator ( ) ;
InitIterator ( ) ;
merge_op_ = MergeOperators : : CreateUInt64AddOperator ( ) ;
merge_op_ = MergeOperators : : CreateUInt64AddOperator ( ) ;
merge_helper_ . reset ( new MergeHelper ( BytewiseComparator ( ) , merge_op_ . get ( ) ,
merge_helper_ . reset ( new MergeHelper ( BytewiseComparator ( ) , merge_op_ . get ( ) ,
nullptr , 2U , tru e) ) ;
nullptr , 2U , fals e) ) ;
merge_helper_ - > MergeUntil ( iter_ . get ( ) , stop_before , at_bottom , nullptr ,
return merge_helper_ - > MergeUntil ( iter_ . get ( ) , stop_before , at_bottom ,
Env : : Default ( ) ) ;
nullptr , Env : : Default ( ) ) ;
}
}
void RunStringAppendMergeHelper ( SequenceNumber stop_before , bool at_bottom ) {
Status RunStringAppendMergeHelper ( SequenceNumber stop_before ,
bool at_bottom ) {
InitIterator ( ) ;
InitIterator ( ) ;
merge_op_ = MergeOperators : : CreateStringAppendTESTOperator ( ) ;
merge_op_ = MergeOperators : : CreateStringAppendTESTOperator ( ) ;
merge_helper_ . reset ( new MergeHelper ( BytewiseComparator ( ) , merge_op_ . get ( ) ,
merge_helper_ . reset ( new MergeHelper ( BytewiseComparator ( ) , merge_op_ . get ( ) ,
nullptr , 2U , tru e) ) ;
nullptr , 2U , fals e) ) ;
merge_helper_ - > MergeUntil ( iter_ . get ( ) , stop_before , at_bottom , nullptr ,
return merge_helper_ - > MergeUntil ( iter_ . get ( ) , stop_before , at_bottom ,
Env : : Default ( ) ) ;
nullptr , Env : : Default ( ) ) ;
}
}
std : : string Key ( const std : : string & user_key , const SequenceNumber & seq ,
std : : string Key ( const std : : string & user_key , const SequenceNumber & seq ,
const ValueType & t ) {
const ValueType & t ) {
std : : string ikey ;
return InternalKey ( user_key , seq , t ) . Encode ( ) . ToString ( ) ;
AppendInternalKey ( & ikey , ParsedInternalKey ( Slice ( user_key ) , seq , t ) ) ;
return ikey ;
}
}
void AddKeyVal ( const std : : string & user_key , const SequenceNumber & seq ,
void AddKeyVal ( const std : : string & user_key , const SequenceNumber & seq ,
const ValueType & t , const std : : string & val ) {
const ValueType & t , const std : : string & val ,
ks_ . push_back ( Key ( user_key , seq , t ) ) ;
bool corrupt = false ) {
InternalKey ikey = InternalKey ( user_key , seq , t ) ;
if ( corrupt ) {
test : : CorruptKeyType ( & ikey ) ;
}
ks_ . push_back ( ikey . Encode ( ) . ToString ( ) ) ;
vs_ . push_back ( val ) ;
vs_ . push_back ( val ) ;
}
}
@ -63,15 +67,6 @@ class MergeHelperTest : public testing::Test {
return result ;
return result ;
}
}
void CheckState ( bool success , int iter_pos ) {
ASSERT_EQ ( success , merge_helper_ - > IsSuccess ( ) ) ;
if ( iter_pos = = - 1 ) {
ASSERT_FALSE ( iter_ - > Valid ( ) ) ;
} else {
ASSERT_EQ ( ks_ [ iter_pos ] , iter_ - > key ( ) ) ;
}
}
std : : unique_ptr < test : : VectorIterator > iter_ ;
std : : unique_ptr < test : : VectorIterator > iter_ ;
std : : shared_ptr < MergeOperator > merge_op_ ;
std : : shared_ptr < MergeOperator > merge_op_ ;
std : : unique_ptr < MergeHelper > merge_helper_ ;
std : : unique_ptr < MergeHelper > merge_helper_ ;
@ -86,10 +81,12 @@ TEST_F(MergeHelperTest, MergeAtBottomSuccess) {
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 3U ) ) ;
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 3U ) ) ;
AddKeyVal ( " b " , 10 , kTypeMerge , EncodeInt ( 4U ) ) ; // <- Iterator after merge
AddKeyVal ( " b " , 10 , kTypeMerge , EncodeInt ( 4U ) ) ; // <- Iterator after merge
RunUInt64MergeHelper ( 0 , true ) ;
ASSERT_TRUE ( RunUInt64MergeHelper ( 0 , true ) . ok ( ) ) ;
CheckState ( true , 2 ) ;
ASSERT_EQ ( ks_ [ 2 ] , iter_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 20 , kTypeValue ) , merge_helper_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 20 , kTypeValue ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 4U ) , merge_helper_ - > value ( ) ) ;
ASSERT_EQ ( EncodeInt ( 4U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
}
// Merging with a value results in a successful merge.
// Merging with a value results in a successful merge.
@ -99,10 +96,12 @@ TEST_F(MergeHelperTest, MergeValue) {
AddKeyVal ( " a " , 20 , kTypeValue , EncodeInt ( 4U ) ) ; // <- Iterator after merge
AddKeyVal ( " a " , 20 , kTypeValue , EncodeInt ( 4U ) ) ; // <- Iterator after merge
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 1U ) ) ;
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 1U ) ) ;
RunUInt64MergeHelper ( 0 , false ) ;
ASSERT_TRUE ( RunUInt64MergeHelper ( 0 , false ) . ok ( ) ) ;
CheckState ( true , 3 ) ;
ASSERT_EQ ( ks_ [ 3 ] , iter_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 40 , kTypeValue ) , merge_helper_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 40 , kTypeValue ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 8U ) , merge_helper_ - > value ( ) ) ;
ASSERT_EQ ( EncodeInt ( 8U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
}
// Merging stops before a snapshot.
// Merging stops before a snapshot.
@ -113,10 +112,12 @@ TEST_F(MergeHelperTest, SnapshotBeforeValue) {
AddKeyVal ( " a " , 20 , kTypeValue , EncodeInt ( 4U ) ) ;
AddKeyVal ( " a " , 20 , kTypeValue , EncodeInt ( 4U ) ) ;
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 1U ) ) ;
AddKeyVal ( " a " , 10 , kTypeMerge , EncodeInt ( 1U ) ) ;
RunUInt64MergeHelper ( 31 , true ) ;
ASSERT_TRUE ( RunUInt64MergeHelper ( 31 , true ) . IsMergeInProgress ( ) ) ;
CheckState ( false , 2 ) ;
ASSERT_EQ ( ks_ [ 2 ] , iter_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 50 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( Key ( " a " , 50 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 4U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 4U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
}
// MergeHelper preserves the operand stack for merge operators that
// MergeHelper preserves the operand stack for merge operators that
@ -126,12 +127,26 @@ TEST_F(MergeHelperTest, NoPartialMerge) {
AddKeyVal ( " a " , 40 , kTypeMerge , " v " ) ; // <- Iterator after merge
AddKeyVal ( " a " , 40 , kTypeMerge , " v " ) ; // <- Iterator after merge
AddKeyVal ( " a " , 30 , kTypeMerge , " v " ) ;
AddKeyVal ( " a " , 30 , kTypeMerge , " v " ) ;
RunStringAppendMergeHelper ( 31 , true ) ;
ASSERT_TRUE ( RunStringAppendMergeHelper ( 31 , true ) . IsMergeInProgress ( ) ) ;
CheckState ( false , 2 ) ;
ASSERT_EQ ( ks_ [ 2 ] , iter_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 40 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( Key ( " a " , 40 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( " v " , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( " v " , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( Key ( " a " , 50 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 1 ] ) ;
ASSERT_EQ ( Key ( " a " , 50 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 1 ] ) ;
ASSERT_EQ ( " v2 " , merge_helper_ - > values ( ) [ 1 ] ) ;
ASSERT_EQ ( " v2 " , merge_helper_ - > values ( ) [ 1 ] ) ;
ASSERT_EQ ( 2U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 2U , merge_helper_ - > values ( ) . size ( ) ) ;
}
// A single operand can not be merged.
TEST_F ( MergeHelperTest , SingleOperand ) {
AddKeyVal ( " a " , 50 , kTypeMerge , EncodeInt ( 1U ) ) ;
ASSERT_TRUE ( RunUInt64MergeHelper ( 31 , true ) . IsMergeInProgress ( ) ) ;
ASSERT_FALSE ( iter_ - > Valid ( ) ) ;
ASSERT_EQ ( Key ( " a " , 50 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 1U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
}
// Merging with a deletion turns the deletion into a value
// Merging with a deletion turns the deletion into a value
@ -139,10 +154,27 @@ TEST_F(MergeHelperTest, MergeDeletion) {
AddKeyVal ( " a " , 30 , kTypeMerge , EncodeInt ( 3U ) ) ;
AddKeyVal ( " a " , 30 , kTypeMerge , EncodeInt ( 3U ) ) ;
AddKeyVal ( " a " , 20 , kTypeDeletion , " " ) ;
AddKeyVal ( " a " , 20 , kTypeDeletion , " " ) ;
RunUInt64MergeHelper ( 15 , false ) ;
ASSERT_TRUE ( RunUInt64MergeHelper ( 15 , false ) . ok ( ) ) ;
CheckState ( true , - 1 ) ;
ASSERT_FALSE ( iter_ - > Valid ( ) ) ;
ASSERT_EQ ( Key ( " a " , 30 , kTypeValue ) , merge_helper_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 30 , kTypeValue ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 3U ) , merge_helper_ - > value ( ) ) ;
ASSERT_EQ ( EncodeInt ( 3U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
// The merge helper stops upon encountering a corrupt key
TEST_F ( MergeHelperTest , CorruptKey ) {
AddKeyVal ( " a " , 30 , kTypeMerge , EncodeInt ( 3U ) ) ;
AddKeyVal ( " a " , 25 , kTypeMerge , EncodeInt ( 1U ) ) ;
// Corrupt key
AddKeyVal ( " a " , 20 , kTypeDeletion , " " , true ) ; // <- Iterator after merge
ASSERT_TRUE ( RunUInt64MergeHelper ( 15 , false ) . IsMergeInProgress ( ) ) ;
ASSERT_EQ ( ks_ [ 2 ] , iter_ - > key ( ) ) ;
ASSERT_EQ ( Key ( " a " , 30 , kTypeMerge ) , merge_helper_ - > keys ( ) [ 0 ] ) ;
ASSERT_EQ ( EncodeInt ( 4U ) , merge_helper_ - > values ( ) [ 0 ] ) ;
ASSERT_EQ ( 1U , merge_helper_ - > keys ( ) . size ( ) ) ;
ASSERT_EQ ( 1U , merge_helper_ - > values ( ) . size ( ) ) ;
}
}
} // namespace rocksdb
} // namespace rocksdb