Skip to content

Commit 83ee351

Browse files
committed
ccl/sqlproxyccl: avoid holding onto the lock in ListenForDenied
Previously, ListenForDenied would grab the watcher's lock (which is tied to the scope of the proxy) before calling checkConnection. As part of the updated ACL work, checkConnection now will grab a lock when it calls Initialize on a given tenant. Given that checkConnection can be blocking, grabbing onto the global watcher lock isn't ideal as it could hold up new connections, leading to timeout issues. This commit updates ListenForDenied such that the watcher's lock gets released before invoking checkConnection. Release note: None Epic: none
1 parent 9cabe8c commit 83ee351

File tree

1 file changed

+27
-22
lines changed

1 file changed

+27
-22
lines changed

pkg/ccl/sqlproxyccl/acl/watcher.go

Lines changed: 27 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -244,42 +244,45 @@ func (w *Watcher) updateAccessController(
244244
checkListeners(ctx, copy, controllers)
245245
}
246246

247-
// ListenForDenied Adds a listener to the watcher for the given connection. If the
248-
// connection is already blocked a nil remove function is returned and an error
249-
// is returned immediately.
247+
// ListenForDenied Adds a listener to the watcher for the given connection. If
248+
// the connection is already blocked a nil remove function is returned and an
249+
// error is returned immediately.
250250
//
251251
// Example Usage:
252252
//
253-
// remove, err := w.ListenForDenied(ctx, connection, func(err error) {
253+
// removeFn, err := w.ListenForDenied(ctx, connection, func(err error) {
254254
// /* connection was blocked by change */
255255
// })
256256
//
257-
// if err != nil { /*connection already blocked*/ }
258-
// defer remove()
257+
// if err != nil { /*connection already blocked*/ }
258+
// defer removeFn()
259259
//
260-
// Warning:
261-
// Do not call remove() within the error callback. It would deadlock.
260+
// WARNING: Do not call removeFn() within the error callback. It would deadlock.
262261
func (w *Watcher) ListenForDenied(
263262
ctx context.Context, connection ConnectionTags, callback func(error),
264263
) (func(), error) {
265-
w.mu.Lock()
266-
defer w.mu.Unlock()
264+
lst, controllers := func() (*listener, []AccessController) {
265+
w.mu.Lock()
266+
defer w.mu.Unlock()
267267

268-
if err := checkConnection(ctx, connection, w.controllers); err != nil {
269-
return nil, err
270-
}
268+
id := w.nextID
269+
w.nextID++
271270

272-
id := w.nextID
273-
w.nextID++
271+
l := &listener{
272+
id: id,
273+
connection: connection,
274+
}
275+
l.mu.denied = callback
274276

275-
l := &listener{
276-
id: id,
277-
connection: connection,
278-
}
279-
l.mu.denied = callback
277+
w.listeners.ReplaceOrInsert(l)
280278

281-
w.listeners.ReplaceOrInsert(l)
282-
return func() { w.removeListener(l) }, nil
279+
return l, w.controllers
280+
}()
281+
if err := checkConnection(ctx, connection, controllers); err != nil {
282+
w.removeListener(lst)
283+
return nil, err
284+
}
285+
return func() { w.removeListener(lst) }, nil
283286
}
284287

285288
func (w *Watcher) removeListener(l *listener) {
@@ -315,6 +318,8 @@ func checkListeners(ctx context.Context, listeners *btree.BTree, controllers []A
315318
})
316319
}
317320

321+
// NOTE: checkConnection may grab a lock, and could be blocked waiting for it,
322+
// so callers should not hold a global lock while calling this.
318323
func checkConnection(
319324
ctx context.Context, connection ConnectionTags, controllers []AccessController,
320325
) error {

0 commit comments

Comments
 (0)