@ -220,16 +220,10 @@ Status TransactionImpl::TryLock(ColumnFamilyHandle* column_family,
bool previously_locked ;
bool previously_locked ;
Status s ;
Status s ;
// Even though we do not care about doing conflict checking for this write,
// lock this key if this transactions hasn't already locked it
// we still need to take a lock to make sure we do not cause a conflict with
SequenceNumber current_seqno = kMaxSequenceNumber ;
// some other write. However, we do not need to check if there have been
SequenceNumber new_seqno = kMaxSequenceNumber ;
// any writes since this transaction's snapshot.
// TODO(agiardullo): could optimize by supporting shared txn locks in the
// future
bool check_snapshot = ! untracked ;
SequenceNumber tracked_seqno = kMaxSequenceNumber ;
// Lookup whether this key has already been locked by this transaction
const auto & tracked_keys = GetTrackedKeys ( ) ;
const auto & tracked_keys = GetTrackedKeys ( ) ;
const auto tracked_keys_cf = tracked_keys . find ( cfh_id ) ;
const auto tracked_keys_cf = tracked_keys . find ( cfh_id ) ;
if ( tracked_keys_cf = = tracked_keys . end ( ) ) {
if ( tracked_keys_cf = = tracked_keys . end ( ) ) {
@ -240,7 +234,7 @@ Status TransactionImpl::TryLock(ColumnFamilyHandle* column_family,
previously_locked = false ;
previously_locked = false ;
} else {
} else {
previously_locked = true ;
previously_locked = true ;
tracked _seqno = iter - > second ;
current _seqno = iter - > second ;
}
}
}
}
@ -249,34 +243,33 @@ Status TransactionImpl::TryLock(ColumnFamilyHandle* column_family,
s = txn_db_impl_ - > TryLock ( this , cfh_id , key_str ) ;
s = txn_db_impl_ - > TryLock ( this , cfh_id , key_str ) ;
}
}
if ( s . ok ( ) ) {
SetSnapshotIfNeeded ( ) ;
// 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.
// Even though we do not care about doing conflict checking for this write,
if ( ! check_snapshot | | snapshot_ = = nullptr ) {
// we still need to take a lock to make sure we do not cause a conflict with
// some other write. However, we do not need to check if there have been
// any writes since this transaction's snapshot.
// TODO(agiardullo): could optimize by supporting shared txn locks in the
// future
if ( untracked | | snapshot_ = = nullptr ) {
// Need to remember the earliest sequence number that we know that this
// Need to remember the earliest sequence number that we know that this
// key has not been modified after. This is useful if this same
// key has not been modified after. This is useful if this same
// transaction
// transaction
// later tries to lock this key again.
// later tries to lock this key again.
if ( tracked_seqno = = kMaxSequenceNumber ) {
if ( current _seqno = = kMaxSequenceNumber ) {
// Since we haven't checked a snapshot, we only know this key has not
// Since we haven't checked a snapshot, we only know this key has not
// been modified since after we locked it.
// been modified since after we locked it.
tracked_seqno = db_ - > GetLatestSequenceNumber ( ) ;
new_seqno = db_ - > GetLatestSequenceNumber ( ) ;
} else {
new_seqno = current_seqno ;
}
}
} else {
} else {
// If the key has been previous validated at a sequence number earlier
// If a snapshot is set, we need to make sure the key hasn't been modified
// than the curent snapshot's sequence number, we already know it has not
// since the snapshot. This must be done after we locked the key.
// been modified.
SequenceNumber seq = snapshot_ - > snapshot ( ) - > GetSequenceNumber ( ) ;
bool already_validated = tracked_seqno < = seq ;
if ( ! already_validated ) {
s = CheckKeySequence ( column_family , key ) ;
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
// Record that there have been no writes to this key after this
s = ValidateSnapshot ( column_family , key , current_seqno , & new_seqno ) ;
// sequence.
tracked_seqno = seq ;
if ( ! s . ok ( ) ) {
} else {
// Failed to validate key
// Failed to validate key
if ( ! previously_locked ) {
if ( ! previously_locked ) {
// Unlock key we just locked
// Unlock key we just locked
@ -285,11 +278,10 @@ Status TransactionImpl::TryLock(ColumnFamilyHandle* column_family,
}
}
}
}
}
}
}
if ( s . ok ( ) ) {
if ( s . ok ( ) ) {
// Let base class know we've conflict checked this key.
// Let base class know we've conflict checked this key.
TrackKey ( cfh_id , key_str , tracked _seqno) ;
TrackKey ( cfh_id , key_str , new _seqno) ;
}
}
return s ;
return s ;
@ -297,22 +289,30 @@ Status TransactionImpl::TryLock(ColumnFamilyHandle* column_family,
// Return OK() if this key has not been modified more recently than the
// Return OK() if this key has not been modified more recently than the
// transaction snapshot_.
// transaction snapshot_.
Status TransactionImpl : : CheckKeySequence ( ColumnFamilyHandle * column_family ,
Status TransactionImpl : : ValidateSnapshot ( ColumnFamilyHandle * column_family ,
const Slice & key ) {
const Slice & key ,
Status result ;
SequenceNumber prev_seqno ,
if ( snapshot_ ! = nullptr ) {
SequenceNumber * new_seqno ) {
assert ( snapshot_ ) ;
SequenceNumber seq = snapshot_ - > snapshot ( ) - > GetSequenceNumber ( ) ;
if ( prev_seqno < = seq ) {
// If the key has been previous validated at a sequence number earlier
// than the curent snapshot's sequence number, we already know it has not
// been modified.
return Status : : OK ( ) ;
}
* new_seqno = seq ;
assert ( dynamic_cast < DBImpl * > ( db_ ) ! = nullptr ) ;
assert ( dynamic_cast < DBImpl * > ( db_ ) ! = nullptr ) ;
auto db_impl = reinterpret_cast < DBImpl * > ( db_ ) ;
auto db_impl = reinterpret_cast < DBImpl * > ( db_ ) ;
ColumnFamilyHandle * cfh = column_family ? column_family :
ColumnFamilyHandle * cfh =
db_impl - > DefaultColumnFamily ( ) ;
column_family ? column_family : db_impl - > DefaultColumnFamily ( ) ;
result = TransactionUtil : : CheckKeyForConflicts (
db_impl , cfh , key . ToString ( ) ,
snapshot_ - > snapshot ( ) - > GetSequenceNumber ( ) ) ;
}
return result ;
return TransactionUtil : : CheckKeyForConflicts (
db_impl , cfh , key . ToString ( ) , snapshot_ - > snapshot ( ) - > GetSequenceNumber ( ) ) ;
}
}
} // namespace rocksdb
} // namespace rocksdb