mirror of
https://github.com/MHSanaei/3x-ui.git
synced 2026-07-15 17:16:07 +00:00
fix(client): stop holding the inbound-lock registry mutex while waiting on one inbound
lockInbound acquired the global registry mutex and then blocked on the per-inbound mutex without releasing the registry first. A slow client operation holding one inbound's mutex (for example a bulk delete pushing to an unreachable node) made the next waiter park on that inbound while still holding the registry mutex, which in turn blocked lockInbound for every other inbound — freezing client mutations panel-wide. Release the registry mutex before taking the per-inbound lock.
This commit is contained in:
@@ -28,12 +28,12 @@ var (
|
||||
|
||||
func lockInbound(inboundId int) *sync.Mutex {
|
||||
inboundMutationLocksMu.Lock()
|
||||
defer inboundMutationLocksMu.Unlock()
|
||||
m, ok := inboundMutationLocks[inboundId]
|
||||
if !ok {
|
||||
m = &sync.Mutex{}
|
||||
inboundMutationLocks[inboundId] = m
|
||||
}
|
||||
inboundMutationLocksMu.Unlock()
|
||||
m.Lock()
|
||||
return m
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
// lockInbound must not hold the global registry mutex while it waits on a busy
|
||||
// inbound's own mutex, otherwise one slow client operation on a single inbound
|
||||
// freezes client mutations on every other inbound panel-wide.
|
||||
func TestLockInboundReleasesRegistryMutexWhileWaiting(t *testing.T) {
|
||||
const id = 990006
|
||||
held := lockInbound(id)
|
||||
|
||||
parked := make(chan struct{})
|
||||
go func() {
|
||||
close(parked)
|
||||
lockInbound(id).Unlock()
|
||||
}()
|
||||
<-parked
|
||||
time.Sleep(50 * time.Millisecond)
|
||||
|
||||
if !inboundMutationLocksMu.TryLock() {
|
||||
held.Unlock()
|
||||
t.Fatal("registry mutex is held while a lockInbound caller waits on a busy inbound")
|
||||
}
|
||||
inboundMutationLocksMu.Unlock()
|
||||
held.Unlock()
|
||||
}
|
||||
Reference in New Issue
Block a user