@@ -30,9 +30,6 @@ import (
3030 "github.com/cockroachdb/redact"
3131)
3232
33- // Default upper bound on the number of locks in a lockTable.
34- const defaultLockTableSize = 10000
35-
3633// The kind of waiting that the request is subject to.
3734type waitKind int
3835
@@ -182,10 +179,6 @@ type treeMu struct {
182179 // primarily used for constraining memory consumption. Ideally, we should be
183180 // doing better memory accounting than this.
184181 numKeysLocked atomic.Int64
185-
186- // For dampening the frequency with which we enforce
187- // lockTableImpl.maxKeysLocked.
188- lockAddMaxLocksCheckInterval uint64
189182}
190183
191184// lockTableImpl is an implementation of lockTable.
@@ -266,15 +259,21 @@ type lockTableImpl struct {
266259 // table. Locks on both Global and Local keys are stored in the same btree.
267260 locks treeMu
268261
269- // maxKeysLocked is a soft maximum on amount of per-key lock information
270- // tracking[1]. When it is exceeded, and subject to the dampening in
271- // lockAddMaxLocksCheckInterval, locks will be cleared.
272- //
273- // [1] Simply put, the number of keyLocks objects in the lockTable btree.
274- maxKeysLocked int64
275- // When maxKeysLocked is exceeded, will attempt to clear down to minKeysLocked,
276- // instead of clearing everything.
277- minKeysLocked int64
262+ // lockTableLimitsMu contains the lock table limit fields protected by a mutex.
263+ lockTableLimitsMu struct {
264+ syncutil.Mutex
265+ // maxKeysLocked is a soft maximum on amount of per-key lock information
266+ // tracking[1]. When it is exceeded, and subject to the dampening in
267+ // lockAddMaxLocksCheckInterval, locks will be cleared.
268+ //
269+ // [1] Simply put, the number of keyLocks objects in the lockTable btree.
270+ maxKeysLocked int64
271+ // When maxKeysLocked is exceeded, will attempt to clear down to minKeysLocked,
272+ // instead of clearing everything.
273+ minKeysLocked int64
274+ // For dampening the frequency with which we enforce maxKeysLocked.
275+ lockAddMaxLocksCheckInterval uint64
276+ }
278277
279278 // txnStatusCache is a small LRU cache that tracks the status of
280279 // transactions that have been successfully pushed.
@@ -321,14 +320,27 @@ func newLockTable(
321320}
322321
323322func (t * lockTableImpl ) setMaxKeysLocked (maxKeysLocked int64 ) {
323+ t .lockTableLimitsMu .Lock ()
324+ defer t .lockTableLimitsMu .Unlock ()
325+
324326 // Check at 5% intervals of the max count.
325327 lockAddMaxLocksCheckInterval := maxKeysLocked / int64 (20 )
326328 if lockAddMaxLocksCheckInterval == 0 {
327329 lockAddMaxLocksCheckInterval = 1
328330 }
329- t .maxKeysLocked = maxKeysLocked
330- t .minKeysLocked = maxKeysLocked / 2
331- t .locks .lockAddMaxLocksCheckInterval = uint64 (lockAddMaxLocksCheckInterval )
331+ t .lockTableLimitsMu .maxKeysLocked = maxKeysLocked
332+ t .lockTableLimitsMu .minKeysLocked = maxKeysLocked / 2
333+ t .lockTableLimitsMu .lockAddMaxLocksCheckInterval = uint64 (lockAddMaxLocksCheckInterval )
334+ }
335+
336+ // shouldCheckMaxLocks returns true if allocating the supplied sequence number
337+ // implies that we should check whether the lock table has exceeded its max
338+ // locks limit or not. We dampen how often the check is performed.
339+ func (t * lockTableImpl ) shouldCheckMaxLocks (seqNum uint64 ) bool {
340+ t .lockTableLimitsMu .Lock ()
341+ defer t .lockTableLimitsMu .Unlock ()
342+ interval := t .lockTableLimitsMu .lockAddMaxLocksCheckInterval
343+ return seqNum % interval == 0
332344}
333345
334346// lockTableGuardImpl is an implementation of lockTableGuard.
@@ -4161,10 +4173,9 @@ func (t *treeMu) Reset() {
41614173 t .btree .Reset ()
41624174}
41634175
4164- func (t * treeMu ) nextLockSeqNum () ( seqNum uint64 , checkMaxLocks bool ) {
4176+ func (t * treeMu ) nextLockSeqNum () uint64 {
41654177 t .lockIDSeqNum ++
4166- checkMaxLocks = t .lockIDSeqNum % t .lockAddMaxLocksCheckInterval == 0
4167- return t .lockIDSeqNum , checkMaxLocks
4178+ return t .lockIDSeqNum
41684179}
41694180
41704181func (t * lockTableImpl ) ScanOptimistic (req Request ) lockTableGuard {
@@ -4352,10 +4363,9 @@ func (t *lockTableImpl) AddDiscoveredLock(
43524363 t .locks .mu .Lock ()
43534364 iter := t .locks .MakeIter ()
43544365 iter .FirstOverlap (& keyLocks {key : key })
4355- checkMaxLocks := false
4366+ var lockSeqNum uint64
43564367 if ! iter .Valid () {
4357- var lockSeqNum uint64
4358- lockSeqNum , checkMaxLocks = t .locks .nextLockSeqNum ()
4368+ lockSeqNum = t .locks .nextLockSeqNum ()
43594369 l = & keyLocks {id : lockSeqNum , key : key }
43604370 l .queuedLockingRequests .Init ()
43614371 l .waitingReaders .Init ()
@@ -4379,7 +4389,7 @@ func (t *lockTableImpl) AddDiscoveredLock(
43794389 // Can't release tree.mu until call l.discoveredLock() since someone may
43804390 // find an empty lock and remove it from the tree.
43814391 t .locks .mu .Unlock ()
4382- if checkMaxLocks {
4392+ if t . shouldCheckMaxLocks ( lockSeqNum ) {
43834393 t .checkMaxKeysLockedAndTryClear ()
43844394 }
43854395 if err != nil {
@@ -4416,7 +4426,7 @@ func (t *lockTableImpl) AcquireLock(acq *roachpb.LockAcquisition) error {
44164426 // tree.mu.RLock().
44174427 iter := t .locks .MakeIter ()
44184428 iter .FirstOverlap (& keyLocks {key : acq .Key })
4419- checkMaxLocks := false
4429+ var lockSeqNum uint64
44204430 if ! iter .Valid () {
44214431 if acq .Durability == lock .Replicated {
44224432 // Don't remember uncontended replicated locks. The downside is that
@@ -4428,8 +4438,7 @@ func (t *lockTableImpl) AcquireLock(acq *roachpb.LockAcquisition) error {
44284438 t .locks .mu .Unlock ()
44294439 return nil
44304440 }
4431- var lockSeqNum uint64
4432- lockSeqNum , checkMaxLocks = t .locks .nextLockSeqNum ()
4441+ lockSeqNum = t .locks .nextLockSeqNum ()
44334442 kl = & keyLocks {id : lockSeqNum , key : acq .Key }
44344443 kl .queuedLockingRequests .Init ()
44354444 kl .waitingReaders .Init ()
@@ -4462,7 +4471,7 @@ func (t *lockTableImpl) AcquireLock(acq *roachpb.LockAcquisition) error {
44624471 err := kl .acquireLock (acq , t .clock , t .settings )
44634472 t .locks .mu .Unlock ()
44644473
4465- if checkMaxLocks {
4474+ if t . shouldCheckMaxLocks ( lockSeqNum ) {
44664475 t .checkMaxKeysLockedAndTryClear ()
44674476 }
44684477 if err != nil {
@@ -4506,9 +4515,12 @@ func (t *lockTableImpl) MarkIneligibleForExport(acq *roachpb.LockAcquisition) er
45064515// method relieves memory pressure by clearing as much per-key tracking as it
45074516// can to bring things under budget.
45084517func (t * lockTableImpl ) checkMaxKeysLockedAndTryClear () {
4518+ t .lockTableLimitsMu .Lock ()
4519+ defer t .lockTableLimitsMu .Unlock ()
4520+
45094521 totalLocks := t .locks .numKeysLocked .Load ()
4510- if totalLocks > t .maxKeysLocked {
4511- numToClear := totalLocks - t .minKeysLocked
4522+ if totalLocks > t .lockTableLimitsMu . maxKeysLocked {
4523+ numToClear := totalLocks - t .lockTableLimitsMu . minKeysLocked
45124524 numCleared := t .tryClearLocks (false /* force */ , int (numToClear ))
45134525 // Update metrics if we successfully cleared any number of locks.
45144526 if numCleared != 0 {
@@ -4948,8 +4960,8 @@ func (t *lockTableImpl) stringRLocked() string {
49484960 return sb .String ()
49494961}
49504962
4951- // TestingSetMaxLocks implements the lockTable interface.
4952- func (t * lockTableImpl ) TestingSetMaxLocks (maxKeysLocked int64 ) {
4963+ // SetMaxLockTableSize implements the lockTable interface.
4964+ func (t * lockTableImpl ) SetMaxLockTableSize (maxKeysLocked int64 ) {
49534965 t .setMaxKeysLocked (maxKeysLocked )
49544966}
49554967
0 commit comments