From d8beaf70a951dfa1d7e88279955bc3425a1b2a09 Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Tue, 23 Jan 2024 15:27:38 +0300 Subject: [PATCH] morph: Fix subscription deadlock Scenario: 0. at least one subscription has been performed 1. another subscription is being done 2. a notification from one of the `0.` point's subs is received If `2.` happens b/w `0.` and `1.` a deadlock appears since the notification routing process is locked on the subscription lock while the subscription lock cannot be unlocked since the subscription RPC cannot be done before the just-arrived notification is handled (read from the neo-go subscription channel). `switchLock` does the same thing to the `routeNotifications`: it ensures that no routine is doing/will be doing changes with the subscription channels, even though `subs`'s lock was created for this purpose initially. Relates #2559. Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + pkg/morph/client/notifications.go | 8 ++++---- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index be2ec6184a..0fca4f32ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -14,6 +14,7 @@ Changelog for NeoFS Node - Incorrect address mapping of the Alphabet contracts in NNS produced by deployment procedure (#2713) - IR compares and logs public keys difference, not hash of keys difference at SN verification check (#2711) - Incorrect handling of notary request leading to inability to collect signatures in some cases (#2715) +- Deadlock in autodeploy routine (#2720) ### Changed - Created files are not group writable (#2589) diff --git a/pkg/morph/client/notifications.go b/pkg/morph/client/notifications.go index 0c26eca2f2..cf755db2e8 100644 --- a/pkg/morph/client/notifications.go +++ b/pkg/morph/client/notifications.go @@ -206,8 +206,6 @@ func (c *Client) Notifications() (<-chan *state.ContainedNotificationEvent, <-ch } type subscriptions struct { - sync.RWMutex - // notification consumers (Client sends // notifications to these channels) notifyChan chan *state.ContainedNotificationEvent @@ -220,6 +218,8 @@ type subscriptions struct { curBlockChan chan *block.Block curNotaryChan chan *result.NotaryRequestEvent + sync.RWMutex // for subscription fields only + // cached subscription information subscribedEvents map[util.Uint160]struct{} subscribedToAllNotaryEvents bool @@ -237,11 +237,11 @@ func (c *Client) routeNotifications() { routeloop: for { var connLost bool - c.subs.RLock() + c.switchLock.RLock() notifCh := c.subs.curNotifyChan blCh := c.subs.curBlockChan notaryCh := c.subs.curNotaryChan - c.subs.RUnlock() + c.switchLock.RUnlock() select { case <-c.closeChan: break routeloop