@@ -158,9 +158,8 @@ type Swarm struct {
158
158
159
159
conns struct {
160
160
sync.RWMutex
161
- m map [peer.ID ][]* Conn
162
- connectednessEventQueue map [peer.ID ][]network.Connectedness
163
- lastConnectednessEvent map [peer.ID ]network.Connectedness
161
+ m map [peer.ID ][]* Conn
162
+ connectednessEvents chan peer.ID
164
163
}
165
164
166
165
listeners struct {
@@ -240,8 +239,7 @@ func NewSwarm(local peer.ID, peers peerstore.Peerstore, eventBus event.Bus, opts
240
239
}
241
240
242
241
s .conns .m = make (map [peer.ID ][]* Conn )
243
- s .conns .connectednessEventQueue = make (map [peer.ID ][]network.Connectedness )
244
- s .conns .lastConnectednessEvent = make (map [peer.ID ]network.Connectedness )
242
+ s .conns .connectednessEvents = make (chan peer.ID , 32 )
245
243
s .listeners .m = make (map [transport.Listener ]struct {})
246
244
s .transports .m = make (map [int ]transport.Transport )
247
245
s .notifs .m = make (map [network.Notifiee ]struct {})
@@ -308,17 +306,10 @@ func (s *Swarm) close() {
308
306
309
307
// Wait for everything to finish.
310
308
s .refs .Wait ()
311
- close (s .connectednessEventCh )
309
+ close (s .conns . connectednessEvents )
312
310
<- s .connectednessEmitterDone
313
311
s .emitter .Close ()
314
312
315
- // Remove the connectedness map only after we have closed the connection and sent all the disconnection
316
- // events
317
- s .conns .Lock ()
318
- s .conns .connectednessEventQueue = nil
319
- s .conns .lastConnectednessEvent = nil
320
- s .conns .Unlock ()
321
-
322
313
// Now close out any transports (if necessary). Do this after closing
323
314
// all connections/listeners.
324
315
s .transports .Lock ()
@@ -402,8 +393,6 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn,
402
393
403
394
c .streams .m = make (map [* Stream ]struct {})
404
395
s .conns .m [p ] = append (s .conns .m [p ], c )
405
- s .maybeEnqueueConnectednessUnlocked (p )
406
-
407
396
// Add two swarm refs:
408
397
// * One will be decremented after the close notifications fire in Conn.doClose
409
398
// * The other will be decremented when Conn.start exits.
@@ -414,6 +403,13 @@ func (s *Swarm) addConn(tc transport.CapableConn, dir network.Direction) (*Conn,
414
403
c .notifyLk .Lock ()
415
404
s .conns .Unlock ()
416
405
406
+ // Block this goroutine till this request is enqueued.
407
+ // This ensures that there are only a finite number of goroutines that are waiting to send
408
+ // the connectedness event on the disconnection side in swarm.removeConn.
409
+ // This is so because the goroutine to enqueue disconnection event can only be started
410
+ // from either a subscriber or a notifier or after calling c.start
411
+ s .conns .connectednessEvents <- p
412
+
417
413
if ! isLimited {
418
414
// Notify goroutines waiting for a direct connection
419
415
//
@@ -790,68 +786,32 @@ func (s *Swarm) removeConn(c *Conn) {
790
786
}
791
787
}
792
788
}
793
- s .maybeEnqueueConnectednessUnlocked (p )
794
789
s .conns .Unlock ()
795
- }
796
-
797
- func (s * Swarm ) lastConnectednessEventUnlocked (p peer.ID ) network.Connectedness {
798
- events := s .conns .connectednessEventQueue [p ]
799
- if len (events ) > 0 {
800
- return events [len (events )- 1 ]
801
- }
802
- return s .conns .lastConnectednessEvent [p ]
803
- }
804
-
805
- func (s * Swarm ) maybeEnqueueConnectednessUnlocked (p peer.ID ) {
806
- oldState := s .lastConnectednessEventUnlocked (p )
807
- newState := s .connectednessUnlocked (p )
808
- if oldState != newState {
809
- if s .conns .connectednessEventQueue != nil {
810
- s .conns .connectednessEventQueue [p ] = append (s .conns .connectednessEventQueue [p ], newState )
811
- select {
812
- case s .connectednessEventCh <- struct {}{}:
813
- default :
814
- }
815
- } else {
816
- log .Errorf ("SWARM BUG: nil connectedness map" )
817
- }
818
- }
790
+ // Do this in a separate go routine to not block the caller.
791
+ // This ensures that if a event subscriber closes the connection from the subscription goroutine
792
+ // this doesn't deadlock
793
+ go func () {
794
+ s .conns .connectednessEvents <- p
795
+ }()
819
796
}
820
797
821
798
func (s * Swarm ) connectednessEventEmitter () {
822
799
defer close (s .connectednessEmitterDone )
823
- for range s .connectednessEventCh {
824
- for {
825
- var c network.Connectedness
826
- var peer peer.ID
827
- s .conns .Lock ()
828
- for p , v := range s .conns .connectednessEventQueue {
829
- if len (v ) == 0 {
830
- // this shouldn't happen
831
- delete (s .conns .connectednessEventQueue , p )
832
- log .Errorf ("SWARM BUG: empty connectedness event slice %v %v" , p , v )
833
- continue
834
- }
835
- c = v [0 ]
836
- peer = p
837
- s .conns .connectednessEventQueue [p ] = v [1 :]
838
- if len (s .conns .connectednessEventQueue [p ]) == 0 {
839
- delete (s .conns .connectednessEventQueue , p )
840
- }
841
- if c == network .NotConnected {
842
- delete (s .conns .lastConnectednessEvent , p )
843
- } else {
844
- s .conns .lastConnectednessEvent [p ] = c
845
- }
846
- break
847
- }
848
- s .conns .Unlock ()
849
- if peer == "" {
850
- break
851
- }
800
+ lastConnectednessEvents := make (map [peer.ID ]network.Connectedness )
801
+ for p := range s .conns .connectednessEvents {
802
+ s .conns .Lock ()
803
+ oldState := lastConnectednessEvents [p ]
804
+ newState := s .connectednessUnlocked (p )
805
+ if newState != network .NotConnected {
806
+ lastConnectednessEvents [p ] = newState
807
+ } else {
808
+ delete (lastConnectednessEvents , p )
809
+ }
810
+ s .conns .Unlock ()
811
+ if newState != oldState {
852
812
s .emitter .Emit (event.EvtPeerConnectednessChanged {
853
- Peer : peer ,
854
- Connectedness : c ,
813
+ Peer : p ,
814
+ Connectedness : newState ,
855
815
})
856
816
}
857
817
}
0 commit comments