-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add a "Limited" network connectivity state (#2696)
Rename the Transient state on connection to Limited. This is more appropriate and also doesn't conflict with the transient resource manager scope. Adds a Limited connectedness state for peers connected to us over Limited connections. This allows users to ignore such peers if they are interested in only peers connected to us over Unlimited connections. For some peers who disconnect before we sent a Connectedness event, we will now only send a Disconnected event. --------- Co-authored-by: guillaumemichel <[email protected]> Co-authored-by: sukun <[email protected]> Co-authored-by: Marco Munizaga <[email protected]>
- Loading branch information
1 parent
0385ec9
commit af0161e
Showing
20 changed files
with
520 additions
and
107 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
package swarm | ||
|
||
import ( | ||
"context" | ||
"sync" | ||
|
||
"github.com/libp2p/go-libp2p/core/event" | ||
"github.com/libp2p/go-libp2p/core/network" | ||
"github.com/libp2p/go-libp2p/core/peer" | ||
) | ||
|
||
// connectednessEventEmitter emits PeerConnectednessChanged events. | ||
// We ensure that for any peer we connected to we always sent atleast 1 NotConnected Event after | ||
// the peer disconnects. This is because peers can observe a connection before they are notified | ||
// of the connection by a peer connectedness changed event. | ||
type connectednessEventEmitter struct { | ||
mx sync.RWMutex | ||
// newConns is the channel that holds the peerIDs we recently connected to | ||
newConns chan peer.ID | ||
removeConnsMx sync.Mutex | ||
// removeConns is a slice of peerIDs we have recently closed connections to | ||
removeConns []peer.ID | ||
// lastEvent is the last connectedness event sent for a particular peer. | ||
lastEvent map[peer.ID]network.Connectedness | ||
// connectedness is the function that gives the peers current connectedness state | ||
connectedness func(peer.ID) network.Connectedness | ||
// emitter is the PeerConnectednessChanged event emitter | ||
emitter event.Emitter | ||
wg sync.WaitGroup | ||
removeConnNotif chan struct{} | ||
ctx context.Context | ||
cancel context.CancelFunc | ||
} | ||
|
||
func newConnectednessEventEmitter(connectedness func(peer.ID) network.Connectedness, emitter event.Emitter) *connectednessEventEmitter { | ||
ctx, cancel := context.WithCancel(context.Background()) | ||
c := &connectednessEventEmitter{ | ||
newConns: make(chan peer.ID, 32), | ||
lastEvent: make(map[peer.ID]network.Connectedness), | ||
removeConnNotif: make(chan struct{}, 1), | ||
connectedness: connectedness, | ||
emitter: emitter, | ||
ctx: ctx, | ||
cancel: cancel, | ||
} | ||
c.wg.Add(1) | ||
go c.runEmitter() | ||
return c | ||
} | ||
|
||
func (c *connectednessEventEmitter) AddConn(p peer.ID) { | ||
c.mx.RLock() | ||
defer c.mx.RUnlock() | ||
if c.ctx.Err() != nil { | ||
return | ||
} | ||
|
||
c.newConns <- p | ||
} | ||
|
||
func (c *connectednessEventEmitter) RemoveConn(p peer.ID) { | ||
c.mx.RLock() | ||
defer c.mx.RUnlock() | ||
if c.ctx.Err() != nil { | ||
return | ||
} | ||
|
||
c.removeConnsMx.Lock() | ||
// This queue is roughly bounded by the total number of added connections we | ||
// have. If consumers of connectedness events are slow, we apply | ||
// backpressure to AddConn operations. | ||
// | ||
// We purposefully don't block/backpressure here to avoid deadlocks, since it's | ||
// reasonable for a consumer of the event to want to remove a connection. | ||
c.removeConns = append(c.removeConns, p) | ||
|
||
c.removeConnsMx.Unlock() | ||
|
||
select { | ||
case c.removeConnNotif <- struct{}{}: | ||
default: | ||
} | ||
} | ||
|
||
func (c *connectednessEventEmitter) Close() { | ||
c.cancel() | ||
c.wg.Wait() | ||
} | ||
|
||
func (c *connectednessEventEmitter) runEmitter() { | ||
defer c.wg.Done() | ||
for { | ||
select { | ||
case p := <-c.newConns: | ||
c.notifyPeer(p, true) | ||
case <-c.removeConnNotif: | ||
c.sendConnRemovedNotifications() | ||
case <-c.ctx.Done(): | ||
c.mx.Lock() // Wait for all pending AddConn & RemoveConn operations to complete | ||
defer c.mx.Unlock() | ||
for { | ||
select { | ||
case p := <-c.newConns: | ||
c.notifyPeer(p, true) | ||
case <-c.removeConnNotif: | ||
c.sendConnRemovedNotifications() | ||
default: | ||
return | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
// notifyPeer sends the peer connectedness event using the emitter. | ||
// Use forceNotConnectedEvent = true to send a NotConnected event even if | ||
// no Connected event was sent for this peer. | ||
// In case a peer is disconnected before we sent the Connected event, we still | ||
// send the Disconnected event because a connection to the peer can be observed | ||
// in such cases. | ||
func (c *connectednessEventEmitter) notifyPeer(p peer.ID, forceNotConnectedEvent bool) { | ||
oldState := c.lastEvent[p] | ||
c.lastEvent[p] = c.connectedness(p) | ||
if c.lastEvent[p] == network.NotConnected { | ||
delete(c.lastEvent, p) | ||
} | ||
if (forceNotConnectedEvent && c.lastEvent[p] == network.NotConnected) || c.lastEvent[p] != oldState { | ||
c.emitter.Emit(event.EvtPeerConnectednessChanged{ | ||
Peer: p, | ||
Connectedness: c.lastEvent[p], | ||
}) | ||
} | ||
} | ||
|
||
func (c *connectednessEventEmitter) sendConnRemovedNotifications() { | ||
c.removeConnsMx.Lock() | ||
removeConns := c.removeConns | ||
c.removeConns = nil | ||
c.removeConnsMx.Unlock() | ||
for _, p := range removeConns { | ||
c.notifyPeer(p, false) | ||
} | ||
} |
Oops, something went wrong.