@ -463,7 +463,7 @@ Status PessimisticTransaction::LockBatch(WriteBatch* batch,
// the snapshot time.
Status PessimisticTransaction : : TryLock ( ColumnFamilyHandle * column_family ,
const Slice & key , bool read_only ,
bool exclusive , bool untracked ) {
bool exclusive , bool skip_validate ) {
uint32_t cfh_id = GetColumnFamilyID ( column_family ) ;
std : : string key_str = key . ToString ( ) ;
bool previously_locked ;
@ -471,8 +471,7 @@ Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
Status s ;
// lock this key if this transactions hasn't already locked it
SequenceNumber current_seqno = kMaxSequenceNumber ;
SequenceNumber new_seqno = kMaxSequenceNumber ;
SequenceNumber tracked_at_seq = kMaxSequenceNumber ;
const auto & tracked_keys = GetTrackedKeys ( ) ;
const auto tracked_keys_cf = tracked_keys . find ( cfh_id ) ;
@ -487,7 +486,7 @@ Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
lock_upgrade = true ;
}
previously_locked = true ;
current_seqno = iter - > second . seq ;
tracked_at_seq = iter - > second . seq ;
}
}
@ -505,23 +504,28 @@ Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
// any writes since this transaction's snapshot.
// TODO(agiardullo): could optimize by supporting shared txn locks in the
// future
if ( untracked | | snapshot_ = = nullptr ) {
if ( skip_validate | | snapshot_ = = nullptr ) {
// Need to remember the earliest sequence number that we know that this
// key has not been modified after. This is useful if this same
// transaction
// later tries to lock this key again.
if ( current_seqno = = kMaxSequenceNumber ) {
if ( tracked_at_seq = = kMaxSequenceNumber ) {
// Since we haven't checked a snapshot, we only know this key has not
// been modified since after we locked it.
new_seqno = db_ - > GetLatestSequenceNumber ( ) ;
} else {
new_seqno = current_seqno ;
// Note: when allocate_seq_only_for_data_==false this is less than the
// latest allocated seq but it is ok since i) this is just a heuristic
// used only as a hint to avoid actual check for conflicts, ii) this would
// cause a false positive only if the snapthot is taken right after the
// lock, which would be an unusual sequence.
tracked_at_seq = db_ - > GetLatestSequenceNumber ( ) ;
}
} else {
// If a snapshot is set, we need to make sure the key hasn't been modified
// since the snapshot. This must be done after we locked the key.
// If we already have validated an earilier snapshot it must has been
// reflected in tracked_at_seq and ValidateSnapshot will return OK.
if ( s . ok ( ) ) {
s = ValidateSnapshot ( column_family , key , current_seqno , & new_seqno ) ;
s = ValidateSnapshot ( column_family , key , & tracked_at_seq ) ;
if ( ! s . ok ( ) ) {
// Failed to validate key
@ -540,8 +544,11 @@ Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
}
if ( s . ok ( ) ) {
// Let base class know we've conflict checked this key.
TrackKey ( cfh_id , key_str , new_seqno , read_only , exclusive ) ;
// We must track all the locked keys so that we can unlock them later. If
// the key is already locked, this func will update some stats on the
// tracked key. It could also update the tracked_at_seq if it is lower than
// the existing trackey seq.
TrackKey ( cfh_id , key_str , tracked_at_seq , read_only , exclusive ) ;
}
return s ;
@ -549,27 +556,33 @@ Status PessimisticTransaction::TryLock(ColumnFamilyHandle* column_family,
// Return OK() if this key has not been modified more recently than the
// transaction snapshot_.
// tracked_at_seq is the global seq at which we either locked the key or already
// have done ValidateSnapshot.
Status PessimisticTransaction : : ValidateSnapshot (
ColumnFamilyHandle * column_family , const Slice & key ,
SequenceNumber prev_seqno , SequenceNumber * new_seqno ) {
SequenceNumber * tracked_at_seq ) {
assert ( snapshot_ ) ;
SequenceNumber seq = snapshot_ - > GetSequenceNumber ( ) ;
if ( prev_seqno < = seq ) {
// If the key has been previous validated at a sequence number earli er
// than the curent snapshot's sequence number, we already know it has no t
// been modified.
SequenceNumber snap_s eq = snapshot_ - > GetSequenceNumber ( ) ;
if ( * tracked_at_seq < = snap_ seq) {
// If the key has been previous validated (or locked) at a sequence number
// earlier than the cur rent snapshot's sequence number, we already know it
// has not been modified aftter snap_seq either .
return Status : : OK ( ) ;
}
// Otherwise we have either
// 1: tracked_at_seq == kMaxSequenceNumber, i.e., first time tracking the key
// 2: snap_seq < tracked_at_seq: last time we lock the key was via
// skip_validate option which means we had skipped ValidateSnapshot. In both
// cases we should do ValidateSnapshot now.
* new_seqno = seq ;
* tracked_at_seq = snap_ seq;
ColumnFamilyHandle * cfh =
column_family ? column_family : db_impl_ - > DefaultColumnFamily ( ) ;
return TransactionUtil : : CheckKeyForConflicts ( db_impl_ , cfh , key . ToString ( ) ,
snapshot_ - > GetSequenceNumber ( ) ,
false /* cache_only */ ) ;
return TransactionUtil : : CheckKeyForConflicts (
db_impl_ , cfh , key . ToString ( ) , snap_seq , false /* cache_only */ ) ;
}
bool PessimisticTransaction : : TryStealingLocks ( ) {