@ -39,14 +39,17 @@ void appendToReplayLog(std::string* replay_log, ValueType type, Slice value) {
} // namespace
GetContext : : GetContext (
const Comparator * ucmp , const MergeOperator * merge_operator , Logger * logger ,
Statistics * statistics , GetState init_state , const Slice & user_key ,
PinnableSlice * pinnable_val , std : : string * timestamp , bool * value_found ,
GetContext : : GetContext ( const Comparator * ucmp ,
const MergeOperator * merge_operator , Logger * logger ,
Statistics * statistics , GetState init_state ,
const Slice & user_key , PinnableSlice * pinnable_val ,
std : : string * timestamp , bool * value_found ,
MergeContext * merge_context , bool do_merge ,
SequenceNumber * _max_covering_tombstone_seq , SystemClock * clock ,
SequenceNumber * seq , PinnedIteratorsManager * _pinned_iters_mgr ,
ReadCallback * callback , bool * is_blob_index , uint64_t tracing_get_id )
SequenceNumber * _max_covering_tombstone_seq ,
SystemClock * clock , SequenceNumber * seq ,
PinnedIteratorsManager * _pinned_iters_mgr ,
ReadCallback * callback , bool * is_blob_index ,
uint64_t tracing_get_id , BlobFetcher * blob_fetcher )
: ucmp_ ( ucmp ) ,
merge_operator_ ( merge_operator ) ,
logger_ ( logger ) ,
@ -65,7 +68,8 @@ GetContext::GetContext(
callback_ ( callback ) ,
do_merge_ ( do_merge ) ,
is_blob_index_ ( is_blob_index ) ,
tracing_get_id_ ( tracing_get_id ) {
tracing_get_id_ ( tracing_get_id ) ,
blob_fetcher_ ( blob_fetcher ) {
if ( seq_ ) {
* seq_ = kMaxSequenceNumber ;
}
@ -79,11 +83,11 @@ GetContext::GetContext(
bool do_merge , SequenceNumber * _max_covering_tombstone_seq ,
SystemClock * clock , SequenceNumber * seq ,
PinnedIteratorsManager * _pinned_iters_mgr , ReadCallback * callback ,
bool * is_blob_index , uint64_t tracing_get_id )
bool * is_blob_index , uint64_t tracing_get_id , BlobFetcher * blob_fetcher )
: GetContext ( ucmp , merge_operator , logger , statistics , init_state , user_key ,
pinnable_val , nullptr , value_found , merge_context , do_merge ,
_max_covering_tombstone_seq , clock , seq , _pinned_iters_mgr ,
callback , is_blob_index , tracing_get_id ) { }
callback , is_blob_index , tracing_get_id , blob_fetcher ) { }
// Called from TableCache::Get and Table::Get when file/block in which
// key may exist are not there in TableCache/BlockCache respectively. In this
@ -250,6 +254,9 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
state_ = kUnexpectedBlobIndex ;
return false ;
}
if ( is_blob_index_ ! = nullptr ) {
* is_blob_index_ = ( type = = kTypeBlobIndex ) ;
}
if ( kNotFound = = state_ ) {
state_ = kFound ;
if ( do_merge_ ) {
@ -260,7 +267,6 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
} else {
TEST_SYNC_POINT_CALLBACK ( " GetContext::SaveValue::PinSelf " ,
this ) ;
// Otherwise copy the value
pinnable_val_ - > PinSelf ( value ) ;
}
@ -269,22 +275,38 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
// It means this function is called as part of DB GetMergeOperands
// API and the current value should be part of
// merge_context_->operand_list
if ( is_blob_index_ ! = nullptr & & * is_blob_index_ ) {
PinnableSlice pin_val ;
if ( GetBlobValue ( value , & pin_val ) = = false ) {
return false ;
}
Slice blob_value ( pin_val ) ;
push_operand ( blob_value , nullptr ) ;
} else {
push_operand ( value , value_pinner ) ;
}
}
} else if ( kMerge = = state_ ) {
assert ( merge_operator_ ! = nullptr ) ;
if ( is_blob_index_ ! = nullptr & & * is_blob_index_ ) {
PinnableSlice pin_val ;
if ( GetBlobValue ( value , & pin_val ) = = false ) {
return false ;
}
Slice blob_value ( pin_val ) ;
state_ = kFound ;
if ( do_merge_ ) {
if ( LIKELY ( pinnable_val_ ! = nullptr ) ) {
Status merge_status = MergeHelper : : TimedFullMerge (
merge_operator_ , user_key_ , & value ,
merge_context_ - > GetOperands ( ) , pinnable_val_ - > GetSelf ( ) ,
logger_ , statistics_ , clock_ ) ;
pinnable_val_ - > PinSelf ( ) ;
if ( ! merge_status . ok ( ) ) {
state_ = kCorrupt ;
}
Merge ( & blob_value ) ;
} else {
// It means this function is called as part of DB GetMergeOperands
// API and the current value should be part of
// merge_context_->operand_list
push_operand ( blob_value , nullptr ) ;
}
} else {
state_ = kFound ;
if ( do_merge_ ) {
Merge ( & value ) ;
} else {
// It means this function is called as part of DB GetMergeOperands
// API and the current value should be part of
@ -292,6 +314,7 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
push_operand ( value , value_pinner ) ;
}
}
}
if ( state_ = = kFound ) {
size_t ts_sz = ucmp_ - > timestamp_size ( ) ;
if ( ts_sz > 0 & & timestamp_ ! = nullptr ) {
@ -299,9 +322,6 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
timestamp_ - > assign ( ts . data ( ) , ts . size ( ) ) ;
}
}
if ( is_blob_index_ ! = nullptr ) {
* is_blob_index_ = ( type = = kTypeBlobIndex ) ;
}
return false ;
case kTypeDeletion :
@ -315,21 +335,10 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
state_ = kDeleted ;
} else if ( kMerge = = state_ ) {
state_ = kFound ;
if ( LIKELY ( pinnable_val_ ! = nullptr ) ) {
if ( do_merge_ ) {
Status merge_status = MergeHelper : : TimedFullMerge (
merge_operator_ , user_key_ , nullptr ,
merge_context_ - > GetOperands ( ) , pinnable_val_ - > GetSelf ( ) ,
logger_ , statistics_ , clock_ ) ;
pinnable_val_ - > PinSelf ( ) ;
if ( ! merge_status . ok ( ) ) {
state_ = kCorrupt ;
}
}
Merge ( nullptr ) ;
// If do_merge_ = false then the current value shouldn't be part of
// merge_context_->operand_list
}
}
return false ;
case kTypeMerge :
@ -341,33 +350,49 @@ bool GetContext::SaveValue(const ParsedInternalKey& parsed_key,
merge_operator_ - > ShouldMerge (
merge_context_ - > GetOperandsDirectionBackward ( ) ) ) {
state_ = kFound ;
Merge ( nullptr ) ;
return false ;
}
return true ;
default :
assert ( false ) ;
break ;
}
}
// state_ could be Corrupt, merge or notfound
return false ;
}
void GetContext : : Merge ( const Slice * value ) {
if ( LIKELY ( pinnable_val_ ! = nullptr ) ) {
// do_merge_ = true this is the case where this function is called
// as part of DB Get API hence merge operators should be merged.
if ( do_merge_ ) {
Status merge_status = MergeHelper : : TimedFullMerge (
merge_operator_ , user_key_ , nullptr ,
merge_context_ - > GetOperands ( ) , pinnable_val_ - > GetSelf ( ) ,
logger_ , statistics_ , clock_ ) ;
merge_operator_ , user_key_ , value , merge_context_ - > GetOperands ( ) ,
pinnable_val_ - > GetSelf ( ) , logger_ , statistics_ , clock_ ) ;
pinnable_val_ - > PinSelf ( ) ;
if ( ! merge_status . ok ( ) ) {
state_ = kCorrupt ;
}
}
}
return false ;
}
return true ;
default :
assert ( false ) ;
break ;
}
bool GetContext : : GetBlobValue ( const Slice & blob_index ,
PinnableSlice * blob_value ) {
Status status = blob_fetcher_ - > FetchBlob ( user_key_ , blob_index , blob_value ) ;
if ( ! status . ok ( ) ) {
if ( status . IsIncomplete ( ) ) {
MarkKeyMayExist ( ) ;
return false ;
}
// state_ could be Corrupt, merge or notfound
state_ = kCorrupt ;
return false ;
}
* is_blob_index_ = false ;
return true ;
}
void GetContext : : push_operand ( const Slice & value , Cleanable * value_pinner ) {
if ( pinned_iters_mgr ( ) & & pinned_iters_mgr ( ) - > PinningEnabled ( ) & &