@ -66,7 +66,8 @@ void TransactionBaseImpl::SetSnapshotIfNeeded() {
}
}
Status TransactionBaseImpl : : TryLock ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : TryLock ( ColumnFamilyHandle * column_family ,
const SliceParts & key , bool untracked ) {
const SliceParts & key , bool read_only ,
bool untracked ) {
size_t key_size = 0 ;
size_t key_size = 0 ;
for ( int i = 0 ; i < key . num_parts ; + + i ) {
for ( int i = 0 ; i < key . num_parts ; + + i ) {
key_size + = key . parts [ i ] . size ( ) ;
key_size + = key . parts [ i ] . size ( ) ;
@ -79,7 +80,7 @@ Status TransactionBaseImpl::TryLock(ColumnFamilyHandle* column_family,
str . append ( key . parts [ i ] . data ( ) , key . parts [ i ] . size ( ) ) ;
str . append ( key . parts [ i ] . data ( ) , key . parts [ i ] . size ( ) ) ;
}
}
return TryLock ( column_family , str , untracked ) ;
return TryLock ( column_family , str , read_only , untracked ) ;
}
}
void TransactionBaseImpl : : SetSavePoint ( ) {
void TransactionBaseImpl : : SetSavePoint ( ) {
@ -107,15 +108,35 @@ Status TransactionBaseImpl::RollbackToSavePoint() {
assert ( s . ok ( ) ) ;
assert ( s . ok ( ) ) ;
// Rollback any keys that were tracked since the last savepoint
// Rollback any keys that were tracked since the last savepoint
const TransactionKeyMap * key_map = GetTrackedKeysSinceSavePoint ( ) ;
const TransactionKeyMap & key_map = save_point . new_keys_ ;
assert ( key_map ) ;
for ( const auto & key_map_iter : key_map ) {
for ( auto & key_map_iter : * key_map ) {
uint32_t column_family_id = key_map_iter . first ;
uint32_t column_family_id = key_map_iter . first ;
auto & keys = key_map_iter . second ;
auto & keys = key_map_iter . second ;
for ( auto & key_iter : keys ) {
auto & cf_tracked_keys = tracked_keys_ [ column_family_id ] ;
for ( const auto & key_iter : keys ) {
const std : : string & key = key_iter . first ;
const std : : string & key = key_iter . first ;
tracked_keys_ [ column_family_id ] . erase ( key ) ;
uint32_t num_reads = key_iter . second . num_reads ;
uint32_t num_writes = key_iter . second . num_writes ;
auto tracked_keys_iter = cf_tracked_keys . find ( key ) ;
assert ( tracked_keys_iter ! = cf_tracked_keys . end ( ) ) ;
// Decrement the total reads/writes of this key by the number of
// reads/writes done since the last SavePoint.
if ( num_reads > 0 ) {
assert ( tracked_keys_iter - > second . num_reads > = num_reads ) ;
tracked_keys_iter - > second . num_reads - = num_reads ;
}
if ( num_writes > 0 ) {
assert ( tracked_keys_iter - > second . num_writes > = num_writes ) ;
tracked_keys_iter - > second . num_writes - = num_writes ;
}
if ( tracked_keys_iter - > second . num_reads = = 0 & &
tracked_keys_iter - > second . num_writes = = 0 ) {
tracked_keys_ [ column_family_id ] . erase ( tracked_keys_iter ) ;
}
}
}
}
}
@ -138,7 +159,7 @@ Status TransactionBaseImpl::Get(const ReadOptions& read_options,
Status TransactionBaseImpl : : GetForUpdate ( const ReadOptions & read_options ,
Status TransactionBaseImpl : : GetForUpdate ( const ReadOptions & read_options ,
ColumnFamilyHandle * column_family ,
ColumnFamilyHandle * column_family ,
const Slice & key , std : : string * value ) {
const Slice & key , std : : string * value ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , true /* read_only */ ) ;
if ( s . ok ( ) & & value ! = nullptr ) {
if ( s . ok ( ) & & value ! = nullptr ) {
s = Get ( read_options , column_family , key , value ) ;
s = Get ( read_options , column_family , key , value ) ;
@ -172,7 +193,7 @@ std::vector<Status> TransactionBaseImpl::MultiGetForUpdate(
// Lock all keys
// Lock all keys
for ( size_t i = 0 ; i < num_keys ; + + i ) {
for ( size_t i = 0 ; i < num_keys ; + + i ) {
Status s = TryLock ( column_family [ i ] , keys [ i ] ) ;
Status s = TryLock ( column_family [ i ] , keys [ i ] , true /* read_only */ ) ;
if ( ! s . ok ( ) ) {
if ( ! s . ok ( ) ) {
// Fail entire multiget if we cannot lock all keys
// Fail entire multiget if we cannot lock all keys
return std : : vector < Status > ( num_keys , s ) ;
return std : : vector < Status > ( num_keys , s ) ;
@ -206,7 +227,7 @@ Iterator* TransactionBaseImpl::GetIterator(const ReadOptions& read_options,
Status TransactionBaseImpl : : Put ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : Put ( ColumnFamilyHandle * column_family ,
const Slice & key , const Slice & value ) {
const Slice & key , const Slice & value ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
@ -219,7 +240,7 @@ Status TransactionBaseImpl::Put(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : Put ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : Put ( ColumnFamilyHandle * column_family ,
const SliceParts & key ,
const SliceParts & key ,
const SliceParts & value ) {
const SliceParts & value ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
@ -231,7 +252,7 @@ Status TransactionBaseImpl::Put(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : Merge ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : Merge ( ColumnFamilyHandle * column_family ,
const Slice & key , const Slice & value ) {
const Slice & key , const Slice & value ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Merge ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Merge ( column_family , key , value ) ;
@ -243,7 +264,7 @@ Status TransactionBaseImpl::Merge(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : Delete ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : Delete ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
const Slice & key ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
@ -255,7 +276,7 @@ Status TransactionBaseImpl::Delete(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : Delete ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : Delete ( ColumnFamilyHandle * column_family ,
const SliceParts & key ) {
const SliceParts & key ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
@ -267,7 +288,7 @@ Status TransactionBaseImpl::Delete(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : SingleDelete ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : SingleDelete ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
const Slice & key ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > SingleDelete ( column_family , key ) ;
GetBatchForWrite ( ) - > SingleDelete ( column_family , key ) ;
@ -279,7 +300,7 @@ Status TransactionBaseImpl::SingleDelete(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : SingleDelete ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : SingleDelete ( ColumnFamilyHandle * column_family ,
const SliceParts & key ) {
const SliceParts & key ) {
Status s = TryLock ( column_family , key ) ;
Status s = TryLock ( column_family , key , false /* read_only */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > SingleDelete ( column_family , key ) ;
GetBatchForWrite ( ) - > SingleDelete ( column_family , key ) ;
@ -291,8 +312,8 @@ Status TransactionBaseImpl::SingleDelete(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : PutUntracked ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : PutUntracked ( ColumnFamilyHandle * column_family ,
const Slice & key , const Slice & value ) {
const Slice & key , const Slice & value ) {
bool untracked = true ;
Status s =
Status s = TryLock ( column_family , key , untracked ) ;
TryLock ( column_family , key , false /* read_only */ , true /* untracked */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
@ -305,8 +326,8 @@ Status TransactionBaseImpl::PutUntracked(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : PutUntracked ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : PutUntracked ( ColumnFamilyHandle * column_family ,
const SliceParts & key ,
const SliceParts & key ,
const SliceParts & value ) {
const SliceParts & value ) {
bool untracked = true ;
Status s =
Status s = TryLock ( column_family , key , untracked ) ;
TryLock ( column_family , key , false /* read_only */ , true /* untracked */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Put ( column_family , key , value ) ;
@ -319,8 +340,8 @@ Status TransactionBaseImpl::PutUntracked(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : MergeUntracked ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : MergeUntracked ( ColumnFamilyHandle * column_family ,
const Slice & key ,
const Slice & key ,
const Slice & value ) {
const Slice & value ) {
bool untracked = true ;
Status s =
Status s = TryLock ( column_family , key , untracked ) ;
TryLock ( column_family , key , false /* read_only */ , true /* untracked */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Merge ( column_family , key , value ) ;
GetBatchForWrite ( ) - > Merge ( column_family , key , value ) ;
@ -332,8 +353,8 @@ Status TransactionBaseImpl::MergeUntracked(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : DeleteUntracked ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : DeleteUntracked ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
const Slice & key ) {
bool untracked = true ;
Status s =
Status s = TryLock ( column_family , key , untracked ) ;
TryLock ( column_family , key , false /* read_only */ , true /* untracked */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
@ -345,8 +366,8 @@ Status TransactionBaseImpl::DeleteUntracked(ColumnFamilyHandle* column_family,
Status TransactionBaseImpl : : DeleteUntracked ( ColumnFamilyHandle * column_family ,
Status TransactionBaseImpl : : DeleteUntracked ( ColumnFamilyHandle * column_family ,
const SliceParts & key ) {
const SliceParts & key ) {
bool untracked = true ;
Status s =
Status s = TryLock ( column_family , key , untracked ) ;
TryLock ( column_family , key , false /* read_only */ , true /* untracked */ ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
GetBatchForWrite ( ) - > Delete ( column_family , key ) ;
@ -387,26 +408,73 @@ uint64_t TransactionBaseImpl::GetNumKeys() const {
}
}
void TransactionBaseImpl : : TrackKey ( uint32_t cfh_id , const std : : string & key ,
void TransactionBaseImpl : : TrackKey ( uint32_t cfh_id , const std : : string & key ,
SequenceNumber seq ) {
SequenceNumber seq , bool read_only ) {
auto iter = tracked_keys_ [ cfh_id ] . find ( key ) ;
// Update map of all tracked keys for this transaction
if ( iter = = tracked_keys_ [ cfh_id ] . end ( ) ) {
TrackKey ( & tracked_keys_ , cfh_id , key , seq , read_only ) ;
tracked_keys_ [ cfh_id ] . insert ( { key , seq } ) ;
if ( save_points_ ! = nullptr & & ! save_points_ - > empty ( ) ) {
if ( save_points_ ! = nullptr & & ! save_points_ - > empty ( ) ) {
// Update map of tracked keys in this SavePoint
// Aren't tracking this key, add it.
TrackKey ( & save_points_ - > top ( ) . new_keys_ , cfh_id , key , seq , read_only ) ;
save_points_ - > top ( ) . new_keys_ [ cfh_id ] [ key ] = seq ;
}
}
}
} else if ( seq < iter - > second ) {
// Add a key to the given TransactionKeyMap
void TransactionBaseImpl : : TrackKey ( TransactionKeyMap * key_map , uint32_t cfh_id ,
const std : : string & key , SequenceNumber seq ,
bool read_only ) {
auto & cf_key_map = ( * key_map ) [ cfh_id ] ;
auto iter = cf_key_map . find ( key ) ;
if ( iter = = cf_key_map . end ( ) ) {
auto result = cf_key_map . insert ( { key , TransactionKeyMapInfo ( seq ) } ) ;
iter = result . first ;
} else if ( seq < iter - > second . seq ) {
// Now tracking this key with an earlier sequence number
// Now tracking this key with an earlier sequence number
iter - > second = seq ;
iter - > second . seq = seq ;
}
if ( read_only ) {
iter - > second . num_reads + + ;
} else {
iter - > second . num_writes + + ;
}
}
}
}
const TransactionKeyMap * TransactionBaseImpl : : GetTrackedKeysSinceSavePoint ( ) {
std : : unique_ptr < TransactionKeyMap >
TransactionBaseImpl : : GetTrackedKeysSinceSavePoint ( ) {
if ( save_points_ ! = nullptr & & ! save_points_ - > empty ( ) ) {
if ( save_points_ ! = nullptr & & ! save_points_ - > empty ( ) ) {
return & save_points_ - > top ( ) . new_keys_ ;
// Examine the number of reads/writes performed on all keys written
// since the last SavePoint and compare to the total number of reads/writes
// for each key.
TransactionKeyMap * result = new TransactionKeyMap ( ) ;
for ( const auto & key_map_iter : save_points_ - > top ( ) . new_keys_ ) {
uint32_t column_family_id = key_map_iter . first ;
auto & keys = key_map_iter . second ;
auto & cf_tracked_keys = tracked_keys_ [ column_family_id ] ;
for ( const auto & key_iter : keys ) {
const std : : string & key = key_iter . first ;
uint32_t num_reads = key_iter . second . num_reads ;
uint32_t num_writes = key_iter . second . num_writes ;
auto total_key_info = cf_tracked_keys . find ( key ) ;
assert ( total_key_info ! = cf_tracked_keys . end ( ) ) ;
assert ( total_key_info - > second . num_reads > = num_reads ) ;
assert ( total_key_info - > second . num_writes > = num_writes ) ;
if ( total_key_info - > second . num_reads = = num_reads & &
total_key_info - > second . num_writes = = num_writes ) {
// All the reads/writes to this key were done in the last savepoint.
bool read_only = ( num_writes = = 0 ) ;
TrackKey ( result , column_family_id , key , key_iter . second . seq ,
read_only ) ;
}
}
}
return std : : unique_ptr < TransactionKeyMap > ( result ) ;
}
}
// No SavePoint
return nullptr ;
return nullptr ;
}
}
@ -428,6 +496,60 @@ void TransactionBaseImpl::ReleaseSnapshot(const Snapshot* snapshot, DB* db) {
db - > ReleaseSnapshot ( snapshot ) ;
db - > ReleaseSnapshot ( snapshot ) ;
}
}
void TransactionBaseImpl : : UndoGetForUpdate ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
uint32_t column_family_id = GetColumnFamilyID ( column_family ) ;
auto & cf_tracked_keys = tracked_keys_ [ column_family_id ] ;
std : : string key_str = key . ToString ( ) ;
bool can_decrement = false ;
bool can_unlock = false ;
if ( save_points_ ! = nullptr & & ! save_points_ - > empty ( ) ) {
// Check if this key was fetched ForUpdate in this SavePoint
auto & cf_savepoint_keys = save_points_ - > top ( ) . new_keys_ [ column_family_id ] ;
auto savepoint_iter = cf_savepoint_keys . find ( key_str ) ;
if ( savepoint_iter ! = cf_savepoint_keys . end ( ) ) {
if ( savepoint_iter - > second . num_reads > 0 ) {
savepoint_iter - > second . num_reads - - ;
can_decrement = true ;
if ( savepoint_iter - > second . num_reads = = 0 & &
savepoint_iter - > second . num_writes = = 0 ) {
// No other GetForUpdates or write on this key in this SavePoint
cf_savepoint_keys . erase ( savepoint_iter ) ;
can_unlock = true ;
}
}
}
} else {
// No SavePoint set
can_decrement = true ;
can_unlock = true ;
}
// We can only decrement the read count for this key if we were able to
// decrement the read count in the current SavePoint, OR if there is no
// SavePoint set.
if ( can_decrement ) {
auto key_iter = cf_tracked_keys . find ( key_str ) ;
if ( key_iter ! = cf_tracked_keys . end ( ) ) {
if ( key_iter - > second . num_reads > 0 ) {
key_iter - > second . num_reads - - ;
if ( key_iter - > second . num_reads = = 0 & &
key_iter - > second . num_writes = = 0 ) {
// No other GetForUpdates or writes on this key
assert ( can_unlock ) ;
cf_tracked_keys . erase ( key_iter ) ;
UnlockGetForUpdate ( column_family , key ) ;
}
}
}
}
}
} // namespace rocksdb
} // namespace rocksdb
# endif // ROCKSDB_LITE
# endif // ROCKSDB_LITE