From 4527e4d6e61f6e4538bdc9b27de43f541fdacbad Mon Sep 17 00:00:00 2001 From: George Knee Date: Fri, 6 Oct 2023 09:33:35 +0100 Subject: [PATCH 1/2] add concurrency control to all listeners methods --- node/notifier/listeners.go | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/node/notifier/listeners.go b/node/notifier/listeners.go index 3fcb98fac..5c9a075b0 100644 --- a/node/notifier/listeners.go +++ b/node/notifier/listeners.go @@ -12,7 +12,7 @@ type paymentChannelListeners struct { listeners []chan query.PaymentChannelInfo // prev is the previous payment channel info that was sent to the listeners. prev query.PaymentChannelInfo - // listenersLock is used to protect against concurrent access to the listeners slice. + // listenersLock is used to protect against concurrent access to to sibling struct members. listenersLock *sync.Mutex } @@ -24,6 +24,8 @@ func newPaymentChannelListeners() *paymentChannelListeners { // Notify notifies all listeners of a payment channel update. // It only notifies listeners if the new info is different from the previous info. func (li *paymentChannelListeners) Notify(info query.PaymentChannelInfo) { + li.listenersLock.Lock() + defer li.listenersLock.Unlock() if li.prev.Equal(info) { return } @@ -45,6 +47,8 @@ func (li *paymentChannelListeners) createNewListener() <-chan query.PaymentChann // getOrCreateListener returns the first listener, creating one if none exist. func (li *paymentChannelListeners) getOrCreateListener() <-chan query.PaymentChannelInfo { + li.listenersLock.Lock() + defer li.listenersLock.Unlock() if len(li.listeners) != 0 { return li.listeners[0] } @@ -69,7 +73,7 @@ type ledgerChannelListeners struct { listeners []chan query.LedgerChannelInfo // prev is the previous ledger channel info that was sent to the listeners. prev query.LedgerChannelInfo - // listenersLock is used to protect against concurrent access to the listeners slice. + // listenersLock is used to protect against concurrent access to sibling struct members. listenersLock sync.Mutex } @@ -81,6 +85,8 @@ func newLedgerChannelListeners() *ledgerChannelListeners { // Notify notifies all listeners of a ledger channel update. // It only notifies listeners if the new info is different from the previous info. func (li *ledgerChannelListeners) Notify(info query.LedgerChannelInfo) { + li.listenersLock.Lock() + defer li.listenersLock.Unlock() if li.prev.Equal(info) { return } @@ -103,6 +109,8 @@ func (li *ledgerChannelListeners) createNewListener() <-chan query.LedgerChannel // getOrCreateListener returns the first listener, creating one if none exist. func (li *ledgerChannelListeners) getOrCreateListener() <-chan query.LedgerChannelInfo { + li.listenersLock.Lock() + defer li.listenersLock.Unlock() if len(li.listeners) != 0 { return li.listeners[0] } From 6030044a341e1095697757ea466f6e1fed6d0e06 Mon Sep 17 00:00:00 2001 From: George Knee Date: Fri, 6 Oct 2023 10:00:27 +0100 Subject: [PATCH 2/2] take more care releasing locks --- node/notifier/listeners.go | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/node/notifier/listeners.go b/node/notifier/listeners.go index 5c9a075b0..ace3be949 100644 --- a/node/notifier/listeners.go +++ b/node/notifier/listeners.go @@ -48,11 +48,12 @@ func (li *paymentChannelListeners) createNewListener() <-chan query.PaymentChann // getOrCreateListener returns the first listener, creating one if none exist. func (li *paymentChannelListeners) getOrCreateListener() <-chan query.PaymentChannelInfo { li.listenersLock.Lock() - defer li.listenersLock.Unlock() if len(li.listeners) != 0 { - return li.listeners[0] + l := li.listeners[0] + li.listenersLock.Unlock() + return l } - + li.listenersLock.Unlock() return li.createNewListener() } @@ -110,11 +111,12 @@ func (li *ledgerChannelListeners) createNewListener() <-chan query.LedgerChannel // getOrCreateListener returns the first listener, creating one if none exist. func (li *ledgerChannelListeners) getOrCreateListener() <-chan query.LedgerChannelInfo { li.listenersLock.Lock() - defer li.listenersLock.Unlock() if len(li.listeners) != 0 { - return li.listeners[0] + l := li.listeners[0] + li.listenersLock.Unlock() + return l } - + li.listenersLock.Unlock() return li.createNewListener() }