@@ -667,7 +667,7 @@ func (g *lockTableGuardImpl) CheckOptimisticNoConflicts(
667667 ltRange := & lockState {key : startKey , endKey : span .EndKey }
668668 for iter .FirstOverlap (ltRange ); iter .Valid (); iter .NextOverlap (ltRange ) {
669669 l := iter .Cur ()
670- if ! l .isNonConflictingLock (g , g . curStrength () ) {
670+ if ! l .isNonConflictingLock (g ) {
671671 return false
672672 }
673673 }
@@ -2359,7 +2359,7 @@ func (l *lockState) claimBeforeProceeding(g *lockTableGuardImpl) {
23592359 panic ("lock table bug: did not find enqueued request" )
23602360}
23612361
2362- func (l * lockState ) isNonConflictingLock (g * lockTableGuardImpl , str lock. Strength ) bool {
2362+ func (l * lockState ) isNonConflictingLock (g * lockTableGuardImpl ) bool {
23632363 l .mu .Lock ()
23642364 defer l .mu .Unlock ()
23652365
@@ -2368,13 +2368,12 @@ func (l *lockState) isNonConflictingLock(g *lockTableGuardImpl, str lock.Strengt
23682368 return true
23692369 }
23702370 // Lock is not empty.
2371- lockHolderTxn , lockHolderTS := l .getLockHolder ()
2372- if lockHolderTxn == nil {
2373- // Transactions that have claimed the lock, but have not acquired it yet,
2374- // are considered non-conflicting.
2375- //
2376- // Optimistic evaluation may call into this function with or without holding
2377- // latches. It's worth considering both these cases separately:
2371+ if ! l .isHeld () {
2372+ // If the lock is neither empty nor held it must be the case that another
2373+ // transaction has claimed the lock. Locks that have been claimed, but have
2374+ // not been acquired yet, are considered non-conflicting. Optimistic
2375+ // evaluation may call into this function with or without holding latches.
2376+ // It's worth considering both these cases separately:
23782377 //
23792378 // 1. If Optimistic evaluation is holding latches, then there cannot be a
23802379 // conflicting request that has claimed (but not acquired) the lock that is
@@ -2397,19 +2396,29 @@ func (l *lockState) isNonConflictingLock(g *lockTableGuardImpl, str lock.Strengt
23972396 // claimed the lock will know what happened and what to do about it.
23982397 return true
23992398 }
2399+ lockHolderTxn , _ := l .getLockHolder ()
24002400 if g .isSameTxn (lockHolderTxn ) {
2401- // Already locked by this txn.
2401+ // NB: Unlike the pessimistic (normal) evaluation code path, we do not need
2402+ // to check the lock's strength if it is already held by this transaction --
2403+ // it's non-conflicting. There's two cases to consider:
2404+ //
2405+ // 1. If the lock is held with the same/higher lock strength on this key
2406+ // then this optimistic evaluation attempt already has all the protection it
2407+ // needs.
2408+ //
2409+ // 2. If the lock is held with a weaker lock strength other transactions may
2410+ // be able to acquire a lock on this key that conflicts with this optimistic
2411+ // evaluation attempt. This is okay, as we'll detect such cases -- however,
2412+ // the weaker lock in itself is not conflicting with the optimistic
2413+ // evaluation attempt.
24022414 return true
24032415 }
2416+
24042417 // NB: We do not look at the txnStatusCache in this optimistic evaluation
24052418 // path. A conflict with a finalized txn will be noticed when retrying
24062419 // pessimistically.
24072420
2408- if str == lock .None && g .ts .Less (lockHolderTS ) {
2409- return true
2410- }
2411- // Conflicts.
2412- return false
2421+ return ! lock .Conflicts (l .getLockMode (), g .curLockMode (), & g .lt .settings .SV ) // non-conflicting
24132422}
24142423
24152424// Acquires this lock. Any requests that are waiting in the lock's wait queues
0 commit comments