@ -160,8 +160,11 @@ WriteBatch::WriteBatch(size_t reserved_bytes, size_t max_bytes)
}
}
WriteBatch : : WriteBatch ( size_t reserved_bytes , size_t max_bytes ,
WriteBatch : : WriteBatch ( size_t reserved_bytes , size_t max_bytes ,
size_t protection_bytes_per_key )
size_t protection_bytes_per_key , size_t default_cf_ts_sz )
: content_flags_ ( 0 ) , max_bytes_ ( max_bytes ) , rep_ ( ) {
: content_flags_ ( 0 ) ,
max_bytes_ ( max_bytes ) ,
default_cf_ts_sz_ ( default_cf_ts_sz ) ,
rep_ ( ) {
// Currently `protection_bytes_per_key` can only be enabled at 8 bytes per
// Currently `protection_bytes_per_key` can only be enabled at 8 bytes per
// entry.
// entry.
assert ( protection_bytes_per_key = = 0 | | protection_bytes_per_key = = 8 ) ;
assert ( protection_bytes_per_key = = 0 | | protection_bytes_per_key = = 8 ) ;
@ -186,6 +189,7 @@ WriteBatch::WriteBatch(const WriteBatch& src)
: wal_term_point_ ( src . wal_term_point_ ) ,
: wal_term_point_ ( src . wal_term_point_ ) ,
content_flags_ ( src . content_flags_ . load ( std : : memory_order_relaxed ) ) ,
content_flags_ ( src . content_flags_ . load ( std : : memory_order_relaxed ) ) ,
max_bytes_ ( src . max_bytes_ ) ,
max_bytes_ ( src . max_bytes_ ) ,
default_cf_ts_sz_ ( src . default_cf_ts_sz_ ) ,
rep_ ( src . rep_ ) {
rep_ ( src . rep_ ) {
if ( src . save_points_ ! = nullptr ) {
if ( src . save_points_ ! = nullptr ) {
save_points_ . reset ( new SavePoints ( ) ) ;
save_points_ . reset ( new SavePoints ( ) ) ;
@ -203,6 +207,7 @@ WriteBatch::WriteBatch(WriteBatch&& src) noexcept
content_flags_ ( src . content_flags_ . load ( std : : memory_order_relaxed ) ) ,
content_flags_ ( src . content_flags_ . load ( std : : memory_order_relaxed ) ) ,
max_bytes_ ( src . max_bytes_ ) ,
max_bytes_ ( src . max_bytes_ ) ,
prot_info_ ( std : : move ( src . prot_info_ ) ) ,
prot_info_ ( std : : move ( src . prot_info_ ) ) ,
default_cf_ts_sz_ ( src . default_cf_ts_sz_ ) ,
rep_ ( std : : move ( src . rep_ ) ) { }
rep_ ( std : : move ( src . rep_ ) ) { }
WriteBatch & WriteBatch : : operator = ( const WriteBatch & src ) {
WriteBatch & WriteBatch : : operator = ( const WriteBatch & src ) {
@ -250,6 +255,7 @@ void WriteBatch::Clear() {
prot_info_ - > entries_ . clear ( ) ;
prot_info_ - > entries_ . clear ( ) ;
}
}
wal_term_point_ . clear ( ) ;
wal_term_point_ . clear ( ) ;
default_cf_ts_sz_ = 0 ;
}
}
uint32_t WriteBatch : : Count ( ) const { return WriteBatchInternal : : Count ( this ) ; }
uint32_t WriteBatch : : Count ( ) const { return WriteBatchInternal : : Count ( this ) ; }
@ -700,6 +706,45 @@ size_t WriteBatchInternal::GetFirstOffset(WriteBatch* /*b*/) {
return WriteBatchInternal : : kHeader ;
return WriteBatchInternal : : kHeader ;
}
}
std : : tuple < Status , uint32_t , size_t >
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize (
WriteBatch * b , ColumnFamilyHandle * column_family ) {
uint32_t cf_id = GetColumnFamilyID ( column_family ) ;
size_t ts_sz = 0 ;
Status s ;
if ( column_family ) {
const Comparator * const ucmp = column_family - > GetComparator ( ) ;
if ( ucmp ) {
ts_sz = ucmp - > timestamp_size ( ) ;
if ( 0 = = cf_id & & b - > default_cf_ts_sz_ ! = ts_sz ) {
s = Status : : InvalidArgument ( " Default cf timestamp size mismatch " ) ;
}
}
} else if ( b - > default_cf_ts_sz_ > 0 ) {
ts_sz = b - > default_cf_ts_sz_ ;
}
return std : : make_tuple ( s , cf_id , ts_sz ) ;
}
namespace {
Status CheckColumnFamilyTimestampSize ( ColumnFamilyHandle * column_family ,
const Slice & ts ) {
if ( ! column_family ) {
return Status : : InvalidArgument ( " column family handle cannot be null " ) ;
}
const Comparator * const ucmp = column_family - > GetComparator ( ) ;
assert ( ucmp ) ;
size_t cf_ts_sz = ucmp - > timestamp_size ( ) ;
if ( 0 = = cf_ts_sz ) {
return Status : : InvalidArgument ( " timestamp disabled " ) ;
}
if ( cf_ts_sz ! = ts . size ( ) ) {
return Status : : InvalidArgument ( " timestamp size mismatch " ) ;
}
return Status : : OK ( ) ;
}
} // namespace
Status WriteBatchInternal : : Put ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : Put ( WriteBatch * b , uint32_t column_family_id ,
const Slice & key , const Slice & value ) {
const Slice & key , const Slice & value ) {
if ( key . size ( ) > size_t { port : : kMaxUint32 } ) {
if ( key . size ( ) > size_t { port : : kMaxUint32 } ) {
@ -738,8 +783,40 @@ Status WriteBatchInternal::Put(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : Put ( ColumnFamilyHandle * column_family , const Slice & key ,
Status WriteBatch : : Put ( ColumnFamilyHandle * column_family , const Slice & key ,
const Slice & value ) {
const Slice & value ) {
return WriteBatchInternal : : Put ( this , GetColumnFamilyID ( column_family ) , key ,
size_t ts_sz = 0 ;
value ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : Put ( this , cf_id , key , value ) ;
}
needs_in_place_update_ts_ = true ;
std : : string dummy_ts ( ts_sz , ' \0 ' ) ;
std : : array < Slice , 2 > key_with_ts { { key , dummy_ts } } ;
return WriteBatchInternal : : Put ( this , cf_id , SliceParts ( key_with_ts . data ( ) , 2 ) ,
SliceParts ( & value , 1 ) ) ;
}
Status WriteBatch : : Put ( ColumnFamilyHandle * column_family , const Slice & key ,
const Slice & ts , const Slice & value ) {
const Status s = CheckColumnFamilyTimestampSize ( column_family , ts ) ;
if ( ! s . ok ( ) ) {
return s ;
}
assert ( column_family ) ;
uint32_t cf_id = column_family - > GetID ( ) ;
std : : array < Slice , 2 > key_with_ts { { key , ts } } ;
return WriteBatchInternal : : Put ( this , cf_id , SliceParts ( key_with_ts . data ( ) , 2 ) ,
SliceParts ( & value , 1 ) ) ;
}
}
Status WriteBatchInternal : : CheckSlicePartsLength ( const SliceParts & key ,
Status WriteBatchInternal : : CheckSlicePartsLength ( const SliceParts & key ,
@ -794,8 +871,24 @@ Status WriteBatchInternal::Put(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : Put ( ColumnFamilyHandle * column_family , const SliceParts & key ,
Status WriteBatch : : Put ( ColumnFamilyHandle * column_family , const SliceParts & key ,
const SliceParts & value ) {
const SliceParts & value ) {
return WriteBatchInternal : : Put ( this , GetColumnFamilyID ( column_family ) , key ,
size_t ts_sz = 0 ;
value ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( ts_sz = = 0 ) {
return WriteBatchInternal : : Put ( this , cf_id , key , value ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : InsertNoop ( WriteBatch * b ) {
Status WriteBatchInternal : : InsertNoop ( WriteBatch * b ) {
@ -892,8 +985,40 @@ Status WriteBatchInternal::Delete(WriteBatch* b, uint32_t column_family_id,
}
}
Status WriteBatch : : Delete ( ColumnFamilyHandle * column_family , const Slice & key ) {
Status WriteBatch : : Delete ( ColumnFamilyHandle * column_family , const Slice & key ) {
return WriteBatchInternal : : Delete ( this , GetColumnFamilyID ( column_family ) ,
size_t ts_sz = 0 ;
key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : Delete ( this , cf_id , key ) ;
}
needs_in_place_update_ts_ = true ;
std : : string dummy_ts ( ts_sz , ' \0 ' ) ;
std : : array < Slice , 2 > key_with_ts { { key , dummy_ts } } ;
return WriteBatchInternal : : Delete ( this , cf_id ,
SliceParts ( key_with_ts . data ( ) , 2 ) ) ;
}
Status WriteBatch : : Delete ( ColumnFamilyHandle * column_family , const Slice & key ,
const Slice & ts ) {
const Status s = CheckColumnFamilyTimestampSize ( column_family , ts ) ;
if ( ! s . ok ( ) ) {
return s ;
}
assert ( column_family ) ;
uint32_t cf_id = column_family - > GetID ( ) ;
std : : array < Slice , 2 > key_with_ts { { key , ts } } ;
return WriteBatchInternal : : Delete ( this , cf_id ,
SliceParts ( key_with_ts . data ( ) , 2 ) ) ;
}
}
Status WriteBatchInternal : : Delete ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : Delete ( WriteBatch * b , uint32_t column_family_id ,
@ -925,8 +1050,24 @@ Status WriteBatchInternal::Delete(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : Delete ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : Delete ( ColumnFamilyHandle * column_family ,
const SliceParts & key ) {
const SliceParts & key ) {
return WriteBatchInternal : : Delete ( this , GetColumnFamilyID ( column_family ) ,
size_t ts_sz = 0 ;
key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : Delete ( this , cf_id , key ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : SingleDelete ( WriteBatch * b ,
Status WriteBatchInternal : : SingleDelete ( WriteBatch * b ,
@ -957,8 +1098,40 @@ Status WriteBatchInternal::SingleDelete(WriteBatch* b,
Status WriteBatch : : SingleDelete ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : SingleDelete ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
const Slice & key ) {
return WriteBatchInternal : : SingleDelete (
size_t ts_sz = 0 ;
this , GetColumnFamilyID ( column_family ) , key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : SingleDelete ( this , cf_id , key ) ;
}
needs_in_place_update_ts_ = true ;
std : : string dummy_ts ( ts_sz , ' \0 ' ) ;
std : : array < Slice , 2 > key_with_ts { { key , dummy_ts } } ;
return WriteBatchInternal : : SingleDelete ( this , cf_id ,
SliceParts ( key_with_ts . data ( ) , 2 ) ) ;
}
Status WriteBatch : : SingleDelete ( ColumnFamilyHandle * column_family ,
const Slice & key , const Slice & ts ) {
const Status s = CheckColumnFamilyTimestampSize ( column_family , ts ) ;
if ( ! s . ok ( ) ) {
return s ;
}
assert ( column_family ) ;
uint32_t cf_id = column_family - > GetID ( ) ;
std : : array < Slice , 2 > key_with_ts { { key , ts } } ;
return WriteBatchInternal : : SingleDelete ( this , cf_id ,
SliceParts ( key_with_ts . data ( ) , 2 ) ) ;
}
}
Status WriteBatchInternal : : SingleDelete ( WriteBatch * b ,
Status WriteBatchInternal : : SingleDelete ( WriteBatch * b ,
@ -992,8 +1165,24 @@ Status WriteBatchInternal::SingleDelete(WriteBatch* b,
Status WriteBatch : : SingleDelete ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : SingleDelete ( ColumnFamilyHandle * column_family ,
const SliceParts & key ) {
const SliceParts & key ) {
return WriteBatchInternal : : SingleDelete (
size_t ts_sz = 0 ;
this , GetColumnFamilyID ( column_family ) , key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : SingleDelete ( this , cf_id , key ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : DeleteRange ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : DeleteRange ( WriteBatch * b , uint32_t column_family_id ,
@ -1026,8 +1215,24 @@ Status WriteBatchInternal::DeleteRange(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : DeleteRange ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : DeleteRange ( ColumnFamilyHandle * column_family ,
const Slice & begin_key , const Slice & end_key ) {
const Slice & begin_key , const Slice & end_key ) {
return WriteBatchInternal : : DeleteRange ( this , GetColumnFamilyID ( column_family ) ,
size_t ts_sz = 0 ;
begin_key , end_key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : DeleteRange ( this , cf_id , begin_key , end_key ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : DeleteRange ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : DeleteRange ( WriteBatch * b , uint32_t column_family_id ,
@ -1061,8 +1266,24 @@ Status WriteBatchInternal::DeleteRange(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : DeleteRange ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : DeleteRange ( ColumnFamilyHandle * column_family ,
const SliceParts & begin_key ,
const SliceParts & begin_key ,
const SliceParts & end_key ) {
const SliceParts & end_key ) {
return WriteBatchInternal : : DeleteRange ( this , GetColumnFamilyID ( column_family ) ,
size_t ts_sz = 0 ;
begin_key , end_key ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : DeleteRange ( this , cf_id , begin_key , end_key ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : Merge ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : Merge ( WriteBatch * b , uint32_t column_family_id ,
@ -1099,8 +1320,24 @@ Status WriteBatchInternal::Merge(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : Merge ( ColumnFamilyHandle * column_family , const Slice & key ,
Status WriteBatch : : Merge ( ColumnFamilyHandle * column_family , const Slice & key ,
const Slice & value ) {
const Slice & value ) {
return WriteBatchInternal : : Merge ( this , GetColumnFamilyID ( column_family ) , key ,
size_t ts_sz = 0 ;
value ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : Merge ( this , cf_id , key , value ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : Merge ( WriteBatch * b , uint32_t column_family_id ,
Status WriteBatchInternal : : Merge ( WriteBatch * b , uint32_t column_family_id ,
@ -1136,8 +1373,24 @@ Status WriteBatchInternal::Merge(WriteBatch* b, uint32_t column_family_id,
Status WriteBatch : : Merge ( ColumnFamilyHandle * column_family ,
Status WriteBatch : : Merge ( ColumnFamilyHandle * column_family ,
const SliceParts & key , const SliceParts & value ) {
const SliceParts & key , const SliceParts & value ) {
return WriteBatchInternal : : Merge ( this , GetColumnFamilyID ( column_family ) , key ,
size_t ts_sz = 0 ;
value ) ;
uint32_t cf_id = 0 ;
Status s ;
std : : tie ( s , cf_id , ts_sz ) =
WriteBatchInternal : : GetColumnFamilyIdAndTimestampSize ( this ,
column_family ) ;
if ( ! s . ok ( ) ) {
return s ;
}
if ( 0 = = ts_sz ) {
return WriteBatchInternal : : Merge ( this , cf_id , key , value ) ;
}
return Status : : InvalidArgument (
" Cannot call this method on column family enabling timestamp " ) ;
}
}
Status WriteBatchInternal : : PutBlobIndex ( WriteBatch * b ,
Status WriteBatchInternal : : PutBlobIndex ( WriteBatch * b ,
@ -1223,18 +1476,15 @@ Status WriteBatch::PopSavePoint() {
return Status : : OK ( ) ;
return Status : : OK ( ) ;
}
}
Status WriteBatch : : AssignTimestamp (
Status WriteBatch : : UpdateTimestamps (
const Slice & ts , std : : function < Status ( uint32_t , size_t & ) > checker ) {
const Slice & ts , std : : function < size_t ( uint32_t ) > ts_sz_func ) {
TimestampAssigner ts_assigner ( prot_info_ . get ( ) , std : : move ( checker ) , ts ) ;
TimestampUpdater < decltype ( ts_sz_func ) > ts_updater ( prot_info_ . get ( ) ,
return Iterate ( & ts_assigner ) ;
std : : move ( ts_sz_func ) , ts ) ;
}
const Status s = Iterate ( & ts_updater ) ;
if ( s . ok ( ) ) {
Status WriteBatch : : AssignTimestamps (
needs_in_place_update_ts_ = false ;
const std : : vector < Slice > & ts_list ,
}
std : : function < Status ( uint32_t , size_t & ) > checker ) {
return s ;
SimpleListTimestampAssigner ts_assigner ( prot_info_ . get ( ) , std : : move ( checker ) ,
ts_list ) ;
return Iterate ( & ts_assigner ) ;
}
}
class MemTableInserter : public WriteBatch : : Handler {
class MemTableInserter : public WriteBatch : : Handler {
@ -2189,24 +2439,20 @@ class MemTableInserter : public WriteBatch::Handler {
const auto & batch_info = trx - > batches_ . begin ( ) - > second ;
const auto & batch_info = trx - > batches_ . begin ( ) - > second ;
// all inserts must reference this trx log number
// all inserts must reference this trx log number
log_number_ref_ = batch_info . log_number_ ;
log_number_ref_ = batch_info . log_number_ ;
const auto checker = [ this ] ( uint32_t cf , size_t & ts_sz ) {
assert ( db_ ) ;
s = batch_info . batch_ - > UpdateTimestamps (
VersionSet * const vset = db_ - > GetVersionSet ( ) ;
commit_ts , [ this ] ( uint32_t cf ) {
assert ( vset ) ;
assert ( db_ ) ;
ColumnFamilySet * const cf_set = vset - > GetColumnFamilySet ( ) ;
VersionSet * const vset = db_ - > GetVersionSet ( ) ;
assert ( cf_set ) ;
assert ( vset ) ;
ColumnFamilyData * cfd = cf_set - > GetColumnFamily ( cf ) ;
ColumnFamilySet * const cf_set = vset - > GetColumnFamilySet ( ) ;
assert ( cfd ) ;
assert ( cf_set ) ;
const auto * const ucmp = cfd - > user_comparator ( ) ;
ColumnFamilyData * cfd = cf_set - > GetColumnFamily ( cf ) ;
assert ( ucmp ) ;
assert ( cfd ) ;
if ( ucmp - > timestamp_size ( ) = = 0 ) {
const auto * const ucmp = cfd - > user_comparator ( ) ;
ts_sz = 0 ;
assert ( ucmp ) ;
} else if ( ucmp - > timestamp_size ( ) ! = ts_sz ) {
return ucmp - > timestamp_size ( ) ;
return Status : : InvalidArgument ( " Timestamp size mismatch " ) ;
} ) ;
}
return Status : : OK ( ) ;
} ;
s = batch_info . batch_ - > AssignTimestamp ( commit_ts , checker ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
s = batch_info . batch_ - > Iterate ( this ) ;
s = batch_info . batch_ - > Iterate ( this ) ;
log_number_ref_ = 0 ;
log_number_ref_ = 0 ;