@ -64,7 +64,9 @@ ImmutableMemTableOptions::ImmutableMemTableOptions(
statistics ( ioptions . stats ) ,
statistics ( ioptions . stats ) ,
merge_operator ( ioptions . merge_operator . get ( ) ) ,
merge_operator ( ioptions . merge_operator . get ( ) ) ,
info_log ( ioptions . logger ) ,
info_log ( ioptions . logger ) ,
allow_data_in_errors ( ioptions . allow_data_in_errors ) { }
allow_data_in_errors ( ioptions . allow_data_in_errors ) ,
protection_bytes_per_key (
mutable_cf_options . memtable_protection_bytes_per_key ) { }
MemTable : : MemTable ( const InternalKeyComparator & cmp ,
MemTable : : MemTable ( const InternalKeyComparator & cmp ,
const ImmutableOptions & ioptions ,
const ImmutableOptions & ioptions ,
@ -237,6 +239,73 @@ void MemTable::UpdateOldestKeyTime() {
}
}
}
}
Status MemTable : : VerifyEntryChecksum ( const char * entry ,
size_t protection_bytes_per_key ,
bool allow_data_in_errors ) {
if ( protection_bytes_per_key = = 0 ) {
return Status : : OK ( ) ;
}
uint32_t key_length ;
const char * key_ptr = GetVarint32Ptr ( entry , entry + 5 , & key_length ) ;
if ( key_ptr = = nullptr ) {
return Status : : Corruption ( " Unable to parse internal key length " ) ;
}
if ( key_length < 8 ) {
return Status : : Corruption ( " Memtable entry internal key length too short. " ) ;
}
Slice user_key = Slice ( key_ptr , key_length - 8 ) ;
const uint64_t tag = DecodeFixed64 ( key_ptr + key_length - 8 ) ;
ValueType type ;
SequenceNumber seq ;
UnPackSequenceAndType ( tag , & seq , & type ) ;
uint32_t value_length = 0 ;
const char * value_ptr = GetVarint32Ptr (
key_ptr + key_length , key_ptr + key_length + 5 , & value_length ) ;
if ( value_ptr = = nullptr ) {
return Status : : Corruption ( " Unable to parse internal key value " ) ;
}
Slice value = Slice ( value_ptr , value_length ) ;
const char * checksum_ptr = value_ptr + value_length ;
uint64_t expected = ProtectionInfo64 ( )
. ProtectKVO ( user_key , value , type )
. ProtectS ( seq )
. GetVal ( ) ;
bool match = true ;
switch ( protection_bytes_per_key ) {
case 1 :
match = static_cast < uint8_t > ( checksum_ptr [ 0 ] ) = =
static_cast < uint8_t > ( expected ) ;
break ;
case 2 :
match = DecodeFixed16 ( checksum_ptr ) = = static_cast < uint16_t > ( expected ) ;
break ;
case 4 :
match = DecodeFixed32 ( checksum_ptr ) = = static_cast < uint32_t > ( expected ) ;
break ;
case 8 :
match = DecodeFixed64 ( checksum_ptr ) = = expected ;
break ;
default :
assert ( false ) ;
}
if ( ! match ) {
std : : string msg (
" Corrupted memtable entry, per key-value checksum verification "
" failed. " ) ;
if ( allow_data_in_errors ) {
msg . append ( " Unrecognized value type: " +
std : : to_string ( static_cast < int > ( type ) ) + " . " ) ;
msg . append ( " User key: " + user_key . ToString ( /*hex=*/ true ) + " . " ) ;
msg . append ( " seq: " + std : : to_string ( seq ) + " . " ) ;
}
return Status : : Corruption ( msg . c_str ( ) ) ;
}
return Status : : OK ( ) ;
}
int MemTable : : KeyComparator : : operator ( ) ( const char * prefix_len_key1 ,
int MemTable : : KeyComparator : : operator ( ) ( const char * prefix_len_key1 ,
const char * prefix_len_key2 ) const {
const char * prefix_len_key2 ) const {
// Internal keys are encoded as length-prefixed strings.
// Internal keys are encoded as length-prefixed strings.
@ -291,7 +360,10 @@ class MemTableIterator : public InternalIterator {
valid_ ( false ) ,
valid_ ( false ) ,
arena_mode_ ( arena ! = nullptr ) ,
arena_mode_ ( arena ! = nullptr ) ,
value_pinned_ (
value_pinned_ (
! mem . GetImmutableMemTableOptions ( ) - > inplace_update_support ) {
! mem . GetImmutableMemTableOptions ( ) - > inplace_update_support ) ,
protection_bytes_per_key_ ( mem . moptions_ . protection_bytes_per_key ) ,
status_ ( Status : : OK ( ) ) ,
logger_ ( mem . moptions_ . info_log ) {
if ( use_range_del_table ) {
if ( use_range_del_table ) {
iter_ = mem . range_del_table_ - > GetIterator ( arena ) ;
iter_ = mem . range_del_table_ - > GetIterator ( arena ) ;
} else if ( prefix_extractor_ ! = nullptr & & ! read_options . total_order_seek & &
} else if ( prefix_extractor_ ! = nullptr & & ! read_options . total_order_seek & &
@ -302,6 +374,7 @@ class MemTableIterator : public InternalIterator {
} else {
} else {
iter_ = mem . table_ - > GetIterator ( arena ) ;
iter_ = mem . table_ - > GetIterator ( arena ) ;
}
}
status_ . PermitUncheckedError ( ) ;
}
}
// No copying allowed
// No copying allowed
MemTableIterator ( const MemTableIterator & ) = delete ;
MemTableIterator ( const MemTableIterator & ) = delete ;
@ -327,7 +400,7 @@ class MemTableIterator : public InternalIterator {
PinnedIteratorsManager * pinned_iters_mgr_ = nullptr ;
PinnedIteratorsManager * pinned_iters_mgr_ = nullptr ;
# endif
# endif
bool Valid ( ) const override { return valid_ ; }
bool Valid ( ) const override { return valid_ & & status_ . ok ( ) ; }
void Seek ( const Slice & k ) override {
void Seek ( const Slice & k ) override {
PERF_TIMER_GUARD ( seek_on_memtable_time ) ;
PERF_TIMER_GUARD ( seek_on_memtable_time ) ;
PERF_COUNTER_ADD ( seek_on_memtable_count , 1 ) ;
PERF_COUNTER_ADD ( seek_on_memtable_count , 1 ) ;
@ -348,6 +421,7 @@ class MemTableIterator : public InternalIterator {
}
}
iter_ - > Seek ( k , nullptr ) ;
iter_ - > Seek ( k , nullptr ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
VerifyEntryChecksum ( ) ;
}
}
void SeekForPrev ( const Slice & k ) override {
void SeekForPrev ( const Slice & k ) override {
PERF_TIMER_GUARD ( seek_on_memtable_time ) ;
PERF_TIMER_GUARD ( seek_on_memtable_time ) ;
@ -368,7 +442,8 @@ class MemTableIterator : public InternalIterator {
}
}
iter_ - > Seek ( k , nullptr ) ;
iter_ - > Seek ( k , nullptr ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
if ( ! Valid ( ) ) {
VerifyEntryChecksum ( ) ;
if ( ! Valid ( ) & & status ( ) . ok ( ) ) {
SeekToLast ( ) ;
SeekToLast ( ) ;
}
}
while ( Valid ( ) & & comparator_ . comparator . Compare ( k , key ( ) ) < 0 ) {
while ( Valid ( ) & & comparator_ . comparator . Compare ( k , key ( ) ) < 0 ) {
@ -378,10 +453,12 @@ class MemTableIterator : public InternalIterator {
void SeekToFirst ( ) override {
void SeekToFirst ( ) override {
iter_ - > SeekToFirst ( ) ;
iter_ - > SeekToFirst ( ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
VerifyEntryChecksum ( ) ;
}
}
void SeekToLast ( ) override {
void SeekToLast ( ) override {
iter_ - > SeekToLast ( ) ;
iter_ - > SeekToLast ( ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
VerifyEntryChecksum ( ) ;
}
}
void Next ( ) override {
void Next ( ) override {
PERF_COUNTER_ADD ( next_on_memtable_count , 1 ) ;
PERF_COUNTER_ADD ( next_on_memtable_count , 1 ) ;
@ -389,10 +466,11 @@ class MemTableIterator : public InternalIterator {
iter_ - > Next ( ) ;
iter_ - > Next ( ) ;
TEST_SYNC_POINT_CALLBACK ( " MemTableIterator::Next:0 " , iter_ ) ;
TEST_SYNC_POINT_CALLBACK ( " MemTableIterator::Next:0 " , iter_ ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
VerifyEntryChecksum ( ) ;
}
}
bool NextAndGetResult ( IterateResult * result ) override {
bool NextAndGetResult ( IterateResult * result ) override {
Next ( ) ;
Next ( ) ;
bool is_valid = valid_ ;
bool is_valid = Valid ( ) ;
if ( is_valid ) {
if ( is_valid ) {
result - > key = key ( ) ;
result - > key = key ( ) ;
result - > bound_check_result = IterBoundCheck : : kUnknown ;
result - > bound_check_result = IterBoundCheck : : kUnknown ;
@ -405,6 +483,7 @@ class MemTableIterator : public InternalIterator {
assert ( Valid ( ) ) ;
assert ( Valid ( ) ) ;
iter_ - > Prev ( ) ;
iter_ - > Prev ( ) ;
valid_ = iter_ - > Valid ( ) ;
valid_ = iter_ - > Valid ( ) ;
VerifyEntryChecksum ( ) ;
}
}
Slice key ( ) const override {
Slice key ( ) const override {
assert ( Valid ( ) ) ;
assert ( Valid ( ) ) ;
@ -416,7 +495,7 @@ class MemTableIterator : public InternalIterator {
return GetLengthPrefixedSlice ( key_slice . data ( ) + key_slice . size ( ) ) ;
return GetLengthPrefixedSlice ( key_slice . data ( ) + key_slice . size ( ) ) ;
}
}
Status status ( ) const override { return Status : : OK ( ) ; }
Status status ( ) const override { return status_ ; }
bool IsKeyPinned ( ) const override {
bool IsKeyPinned ( ) const override {
// memtable data is always pinned
// memtable data is always pinned
@ -436,6 +515,19 @@ class MemTableIterator : public InternalIterator {
bool valid_ ;
bool valid_ ;
bool arena_mode_ ;
bool arena_mode_ ;
bool value_pinned_ ;
bool value_pinned_ ;
size_t protection_bytes_per_key_ ;
Status status_ ;
Logger * logger_ ;
void VerifyEntryChecksum ( ) {
if ( protection_bytes_per_key_ > 0 & & Valid ( ) ) {
status_ = MemTable : : VerifyEntryChecksum ( iter_ - > key ( ) ,
protection_bytes_per_key_ ) ;
if ( ! status_ . ok ( ) ) {
ROCKS_LOG_ERROR ( logger_ , " In MemtableIterator: %s " , status_ . getState ( ) ) ;
}
}
}
} ;
} ;
InternalIterator * MemTable : : NewIterator ( const ReadOptions & read_options ,
InternalIterator * MemTable : : NewIterator ( const ReadOptions & read_options ,
@ -560,6 +652,39 @@ Status MemTable::VerifyEncodedEntry(Slice encoded,
. GetStatus ( ) ;
. GetStatus ( ) ;
}
}
void MemTable : : UpdateEntryChecksum ( const ProtectionInfoKVOS64 * kv_prot_info ,
const Slice & key , const Slice & value ,
ValueType type , SequenceNumber s ,
char * checksum_ptr ) {
if ( moptions_ . protection_bytes_per_key = = 0 ) {
return ;
}
uint64_t checksum = 0 ;
if ( kv_prot_info = = nullptr ) {
checksum =
ProtectionInfo64 ( ) . ProtectKVO ( key , value , type ) . ProtectS ( s ) . GetVal ( ) ;
} else {
checksum = kv_prot_info - > GetVal ( ) ;
}
switch ( moptions_ . protection_bytes_per_key ) {
case 1 :
checksum_ptr [ 0 ] = static_cast < uint8_t > ( checksum ) ;
break ;
case 2 :
EncodeFixed16 ( checksum_ptr , static_cast < uint16_t > ( checksum ) ) ;
break ;
case 4 :
EncodeFixed32 ( checksum_ptr , static_cast < uint32_t > ( checksum ) ) ;
break ;
case 8 :
EncodeFixed64 ( checksum_ptr , checksum ) ;
break ;
default :
assert ( false ) ;
}
}
Status MemTable : : Add ( SequenceNumber s , ValueType type ,
Status MemTable : : Add ( SequenceNumber s , ValueType type ,
const Slice & key , /* user key */
const Slice & key , /* user key */
const Slice & value ,
const Slice & value ,
@ -571,12 +696,13 @@ Status MemTable::Add(SequenceNumber s, ValueType type,
// key bytes : char[internal_key.size()]
// key bytes : char[internal_key.size()]
// value_size : varint32 of value.size()
// value_size : varint32 of value.size()
// value bytes : char[value.size()]
// value bytes : char[value.size()]
// checksum : char[moptions_.protection_bytes_per_key]
uint32_t key_size = static_cast < uint32_t > ( key . size ( ) ) ;
uint32_t key_size = static_cast < uint32_t > ( key . size ( ) ) ;
uint32_t val_size = static_cast < uint32_t > ( value . size ( ) ) ;
uint32_t val_size = static_cast < uint32_t > ( value . size ( ) ) ;
uint32_t internal_key_size = key_size + 8 ;
uint32_t internal_key_size = key_size + 8 ;
const uint32_t encoded_len = VarintLength ( internal_key_size ) +
const uint32_t encoded_len = VarintLength ( internal_key_size ) +
internal_key_size + VarintLength ( val_size ) +
internal_key_size + VarintLength ( val_size ) +
val_size ;
val_size + moptions_ . protection_bytes_per_key ;
char * buf = nullptr ;
char * buf = nullptr ;
std : : unique_ptr < MemTableRep > & table =
std : : unique_ptr < MemTableRep > & table =
type = = kTypeRangeDeletion ? range_del_table_ : table_ ;
type = = kTypeRangeDeletion ? range_del_table_ : table_ ;
@ -591,9 +717,13 @@ Status MemTable::Add(SequenceNumber s, ValueType type,
p + = 8 ;
p + = 8 ;
p = EncodeVarint32 ( p , val_size ) ;
p = EncodeVarint32 ( p , val_size ) ;
memcpy ( p , value . data ( ) , val_size ) ;
memcpy ( p , value . data ( ) , val_size ) ;
assert ( ( unsigned ) ( p + val_size - buf ) = = ( unsigned ) encoded_len ) ;
assert ( ( unsigned ) ( p + val_size - buf + moptions_ . protection_bytes_per_key ) = =
( unsigned ) encoded_len ) ;
UpdateEntryChecksum ( kv_prot_info , key , value , type , s ,
buf + encoded_len - moptions_ . protection_bytes_per_key ) ;
Slice encoded ( buf , encoded_len - moptions_ . protection_bytes_per_key ) ;
if ( kv_prot_info ! = nullptr ) {
if ( kv_prot_info ! = nullptr ) {
Slice encoded ( buf , encoded_len ) ;
TEST_SYNC_POINT_CALLBACK ( " MemTable::Add:Encoded " , & encoded ) ;
TEST_SYNC_POINT_CALLBACK ( " MemTable::Add:Encoded " , & encoded ) ;
Status status = VerifyEncodedEntry ( encoded , * kv_prot_info ) ;
Status status = VerifyEncodedEntry ( encoded , * kv_prot_info ) ;
if ( ! status . ok ( ) ) {
if ( ! status . ok ( ) ) {
@ -692,6 +822,8 @@ Status MemTable::Add(SequenceNumber s, ValueType type,
is_range_del_table_empty_ . store ( false , std : : memory_order_relaxed ) ;
is_range_del_table_empty_ . store ( false , std : : memory_order_relaxed ) ;
}
}
UpdateOldestKeyTime ( ) ;
UpdateOldestKeyTime ( ) ;
TEST_SYNC_POINT_CALLBACK ( " MemTable::Add:BeforeReturn:Encoded " , & encoded ) ;
return Status : : OK ( ) ;
return Status : : OK ( ) ;
}
}
@ -720,6 +852,7 @@ struct Saver {
ReadCallback * callback_ ;
ReadCallback * callback_ ;
bool * is_blob_index ;
bool * is_blob_index ;
bool allow_data_in_errors ;
bool allow_data_in_errors ;
size_t protection_bytes_per_key ;
bool CheckCallback ( SequenceNumber _seq ) {
bool CheckCallback ( SequenceNumber _seq ) {
if ( callback_ ) {
if ( callback_ ) {
return callback_ - > IsVisible ( _seq ) ;
return callback_ - > IsVisible ( _seq ) ;
@ -730,23 +863,28 @@ struct Saver {
} // namespace
} // namespace
static bool SaveValue ( void * arg , const char * entry ) {
static bool SaveValue ( void * arg , const char * entry ) {
TEST_SYNC_POINT_CALLBACK ( " Memtable::SaveValue:Begin:entry " , & entry ) ;
Saver * s = reinterpret_cast < Saver * > ( arg ) ;
Saver * s = reinterpret_cast < Saver * > ( arg ) ;
assert ( s ! = nullptr ) ;
assert ( s ! = nullptr ) ;
if ( s - > protection_bytes_per_key > 0 ) {
* ( s - > status ) = MemTable : : VerifyEntryChecksum (
entry , s - > protection_bytes_per_key , s - > allow_data_in_errors ) ;
if ( ! s - > status - > ok ( ) ) {
ROCKS_LOG_ERROR ( s - > logger , " In SaveValue: %s " , s - > status - > getState ( ) ) ;
// Memtable entry corrupted
return false ;
}
}
MergeContext * merge_context = s - > merge_context ;
MergeContext * merge_context = s - > merge_context ;
SequenceNumber max_covering_tombstone_seq = s - > max_covering_tombstone_seq ;
SequenceNumber max_covering_tombstone_seq = s - > max_covering_tombstone_seq ;
const MergeOperator * merge_operator = s - > merge_operator ;
const MergeOperator * merge_operator = s - > merge_operator ;
assert ( merge_context ! = nullptr ) ;
assert ( merge_context ! = nullptr ) ;
// entry format is:
// Refer to comments under MemTable::Add() for entry format.
// klength varint32
// Check that it belongs to same user key.
// userkey char[klength-8]
// tag uint64
// vlength varint32f
// value char[vlength]
// Check that it belongs to same user key. We do not check the
// sequence number since the Seek() call above should have skipped
// all entries with overly large sequence numbers.
uint32_t key_length = 0 ;
uint32_t key_length = 0 ;
const char * key_ptr = GetVarint32Ptr ( entry , entry + 5 , & key_length ) ;
const char * key_ptr = GetVarint32Ptr ( entry , entry + 5 , & key_length ) ;
assert ( key_length > = 8 ) ;
assert ( key_length > = 8 ) ;
@ -972,7 +1110,8 @@ bool MemTable::Get(const LookupKey& key, std::string* value,
}
}
// No change to value, since we have not yet found a Put/Delete
// No change to value, since we have not yet found a Put/Delete
if ( ! found_final_value & & merge_in_progress ) {
// Propagate corruption error
if ( ! found_final_value & & merge_in_progress & & ! s - > IsCorruption ( ) ) {
* s = Status : : MergeInProgress ( ) ;
* s = Status : : MergeInProgress ( ) ;
}
}
PERF_COUNTER_ADD ( get_from_memtable_count , 1 ) ;
PERF_COUNTER_ADD ( get_from_memtable_count , 1 ) ;
@ -1006,6 +1145,7 @@ void MemTable::GetFromTable(const LookupKey& key,
saver . is_blob_index = is_blob_index ;
saver . is_blob_index = is_blob_index ;
saver . do_merge = do_merge ;
saver . do_merge = do_merge ;
saver . allow_data_in_errors = moptions_ . allow_data_in_errors ;
saver . allow_data_in_errors = moptions_ . allow_data_in_errors ;
saver . protection_bytes_per_key = moptions_ . protection_bytes_per_key ;
table_ - > Get ( key , & saver , SaveValue ) ;
table_ - > Get ( key , & saver , SaveValue ) ;
* seq = saver . seq ;
* seq = saver . seq ;
}
}
@ -1104,12 +1244,7 @@ Status MemTable::Update(SequenceNumber seq, ValueType value_type,
iter - > Seek ( lkey . internal_key ( ) , mem_key . data ( ) ) ;
iter - > Seek ( lkey . internal_key ( ) , mem_key . data ( ) ) ;
if ( iter - > Valid ( ) ) {
if ( iter - > Valid ( ) ) {
// entry format is:
// Refer to comments under MemTable::Add() for entry format.
// key_length varint32
// userkey char[klength-8]
// tag uint64
// vlength varint32
// value char[vlength]
// Check that it belongs to same user key. We do not check the
// Check that it belongs to same user key. We do not check the
// sequence number since the Seek() call above should have skipped
// sequence number since the Seek() call above should have skipped
// all entries with overly large sequence numbers.
// all entries with overly large sequence numbers.
@ -1143,8 +1278,13 @@ Status MemTable::Update(SequenceNumber seq, ValueType value_type,
ProtectionInfoKVOS64 updated_kv_prot_info ( * kv_prot_info ) ;
ProtectionInfoKVOS64 updated_kv_prot_info ( * kv_prot_info ) ;
// `seq` is swallowed and `existing_seq` prevails.
// `seq` is swallowed and `existing_seq` prevails.
updated_kv_prot_info . UpdateS ( seq , existing_seq ) ;
updated_kv_prot_info . UpdateS ( seq , existing_seq ) ;
UpdateEntryChecksum ( & updated_kv_prot_info , key , value , type ,
existing_seq , p + value . size ( ) ) ;
Slice encoded ( entry , p + value . size ( ) - entry ) ;
Slice encoded ( entry , p + value . size ( ) - entry ) ;
return VerifyEncodedEntry ( encoded , updated_kv_prot_info ) ;
return VerifyEncodedEntry ( encoded , updated_kv_prot_info ) ;
} else {
UpdateEntryChecksum ( nullptr , key , value , type , existing_seq ,
p + value . size ( ) ) ;
}
}
return Status : : OK ( ) ;
return Status : : OK ( ) ;
}
}
@ -1167,12 +1307,7 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
iter - > Seek ( lkey . internal_key ( ) , memkey . data ( ) ) ;
iter - > Seek ( lkey . internal_key ( ) , memkey . data ( ) ) ;
if ( iter - > Valid ( ) ) {
if ( iter - > Valid ( ) ) {
// entry format is:
// Refer to comments under MemTable::Add() for entry format.
// key_length varint32
// userkey char[klength-8]
// tag uint64
// vlength varint32
// value char[vlength]
// Check that it belongs to same user key. We do not check the
// Check that it belongs to same user key. We do not check the
// sequence number since the Seek() call above should have skipped
// sequence number since the Seek() call above should have skipped
// all entries with overly large sequence numbers.
// all entries with overly large sequence numbers.
@ -1212,14 +1347,19 @@ Status MemTable::UpdateCallback(SequenceNumber seq, const Slice& key,
}
}
RecordTick ( moptions_ . statistics , NUMBER_KEYS_UPDATED ) ;
RecordTick ( moptions_ . statistics , NUMBER_KEYS_UPDATED ) ;
UpdateFlushState ( ) ;
UpdateFlushState ( ) ;
Slice new_value ( prev_buffer , new_prev_size ) ;
if ( kv_prot_info ! = nullptr ) {
if ( kv_prot_info ! = nullptr ) {
ProtectionInfoKVOS64 updated_kv_prot_info ( * kv_prot_info ) ;
ProtectionInfoKVOS64 updated_kv_prot_info ( * kv_prot_info ) ;
// `seq` is swallowed and `existing_seq` prevails.
// `seq` is swallowed and `existing_seq` prevails.
updated_kv_prot_info . UpdateS ( seq , existing_seq ) ;
updated_kv_prot_info . UpdateS ( seq , existing_seq ) ;
updated_kv_prot_info . UpdateV ( delta ,
updated_kv_prot_info . UpdateV ( delta , new_value ) ;
Slice ( prev_buffer , new_prev_size ) ) ;
Slice encoded ( entry , prev_buffer + new_prev_size - entry ) ;
Slice encoded ( entry , prev_buffer + new_prev_size - entry ) ;
UpdateEntryChecksum ( & updated_kv_prot_info , key , new_value , type ,
existing_seq , prev_buffer + new_prev_size ) ;
return VerifyEncodedEntry ( encoded , updated_kv_prot_info ) ;
return VerifyEncodedEntry ( encoded , updated_kv_prot_info ) ;
} else {
UpdateEntryChecksum ( nullptr , key , new_value , type , existing_seq ,
prev_buffer + new_prev_size ) ;
}
}
return Status : : OK ( ) ;
return Status : : OK ( ) ;
} else if ( status = = UpdateStatus : : UPDATED ) {
} else if ( status = = UpdateStatus : : UPDATED ) {