tendermint/p2p/peer_set.go

145 lines
3.2 KiB
Go
Raw Normal View History

2015-10-25 18:21:51 -07:00
package p2p
import (
2018-05-07 08:15:12 -07:00
"net"
2015-10-25 18:21:51 -07:00
"sync"
)
// IPeerSet has a (immutable) subset of the methods of PeerSet.
type IPeerSet interface {
2018-01-01 18:27:38 -08:00
Has(key ID) bool
2018-05-07 08:15:12 -07:00
HasIP(ip net.IP) bool
2018-01-01 18:27:38 -08:00
Get(key ID) Peer
2017-09-12 17:49:22 -07:00
List() []Peer
2015-10-25 18:21:51 -07:00
Size() int
}
//-----------------------------------------------------------------------------
// PeerSet is a special structure for keeping a table of peers.
// Iteration over the peers is super fast and thread-safe.
type PeerSet struct {
2018-05-07 08:15:12 -07:00
mtx sync.Mutex
lookup map[ID]*peerSetItem
list []Peer
2015-10-25 18:21:51 -07:00
}
type peerSetItem struct {
2017-09-12 17:49:22 -07:00
peer Peer
2015-10-25 18:21:51 -07:00
index int
}
// NewPeerSet creates a new peerSet with a list of initial capacity of 256 items.
2015-10-25 18:21:51 -07:00
func NewPeerSet() *PeerSet {
return &PeerSet{
2018-05-07 08:15:12 -07:00
lookup: make(map[ID]*peerSetItem),
list: make([]Peer, 0, 256),
2015-10-25 18:21:51 -07:00
}
}
2017-09-06 13:40:21 -07:00
// Add adds the peer to the PeerSet.
2018-05-07 08:15:12 -07:00
// It returns an error carrying the reason, if the peer is already present.
2017-09-12 17:49:22 -07:00
func (ps *PeerSet) Add(peer Peer) error {
2015-10-25 18:21:51 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
2018-05-16 10:13:45 -07:00
2018-01-01 18:27:38 -08:00
if ps.lookup[peer.ID()] != nil {
2018-04-28 13:45:08 -07:00
return ErrSwitchDuplicatePeerID{peer.ID()}
}
2018-05-07 08:15:12 -07:00
2015-10-25 18:21:51 -07:00
index := len(ps.list)
// Appending is safe even with other goroutines
// iterating over the ps.list slice.
ps.list = append(ps.list, peer)
2018-01-01 18:27:38 -08:00
ps.lookup[peer.ID()] = &peerSetItem{peer, index}
2015-10-25 18:21:51 -07:00
return nil
}
// Has returns true if the set contains the peer referred to by this
// peerKey, otherwise false.
2018-01-01 18:27:38 -08:00
func (ps *PeerSet) Has(peerKey ID) bool {
2015-10-25 18:21:51 -07:00
ps.mtx.Lock()
_, ok := ps.lookup[peerKey]
ps.mtx.Unlock()
2015-10-25 18:21:51 -07:00
return ok
}
// HasIP returns true if the set contains the peer referred to by this IP
// address, otherwise false.
2018-05-07 08:15:12 -07:00
func (ps *PeerSet) HasIP(peerIP net.IP) bool {
2018-04-28 13:45:08 -07:00
ps.mtx.Lock()
2018-05-16 10:13:45 -07:00
defer ps.mtx.Unlock()
return ps.hasIP(peerIP)
}
2018-05-07 08:15:12 -07:00
2018-05-16 10:13:45 -07:00
// hasIP does not acquire a lock so it can be used in public methods which
// already lock.
func (ps *PeerSet) hasIP(peerIP net.IP) bool {
2018-05-07 08:15:12 -07:00
for _, item := range ps.lookup {
if item.peer.RemoteIP().Equal(peerIP) {
return true
}
}
return false
2018-04-28 13:45:08 -07:00
}
// Get looks up a peer by the provided peerKey. Returns nil if peer is not
// found.
2018-01-01 18:27:38 -08:00
func (ps *PeerSet) Get(peerKey ID) Peer {
2015-10-25 18:21:51 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
item, ok := ps.lookup[peerKey]
if ok {
return item.peer
}
return nil
2015-10-25 18:21:51 -07:00
}
// Remove discards peer by its Key, if the peer was previously memoized.
2017-09-12 17:49:22 -07:00
func (ps *PeerSet) Remove(peer Peer) {
2015-10-25 18:21:51 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
2018-05-07 08:15:12 -07:00
2018-01-01 18:27:38 -08:00
item := ps.lookup[peer.ID()]
2015-10-25 18:21:51 -07:00
if item == nil {
return
}
index := item.index
// Create a new copy of the list but with one less item.
// (we must copy because we'll be mutating the list).
2017-09-12 17:49:22 -07:00
newList := make([]Peer, len(ps.list)-1)
2015-10-25 18:21:51 -07:00
copy(newList, ps.list)
// If it's the last peer, that's an easy special case.
if index == len(ps.list)-1 {
ps.list = newList
2018-01-01 18:27:38 -08:00
delete(ps.lookup, peer.ID())
2015-10-25 18:21:51 -07:00
return
}
// Replace the popped item with the last item in the old list.
2015-10-25 18:21:51 -07:00
lastPeer := ps.list[len(ps.list)-1]
2018-01-01 18:27:38 -08:00
lastPeerKey := lastPeer.ID()
2015-10-25 18:21:51 -07:00
lastPeerItem := ps.lookup[lastPeerKey]
newList[index] = lastPeer
lastPeerItem.index = index
ps.list = newList
2018-01-01 18:27:38 -08:00
delete(ps.lookup, peer.ID())
2015-10-25 18:21:51 -07:00
}
// Size returns the number of unique items in the peerSet.
2015-10-25 18:21:51 -07:00
func (ps *PeerSet) Size() int {
ps.mtx.Lock()
defer ps.mtx.Unlock()
return len(ps.list)
}
// List returns the threadsafe list of peers.
2017-09-12 17:49:22 -07:00
func (ps *PeerSet) List() []Peer {
2015-10-25 18:21:51 -07:00
ps.mtx.Lock()
defer ps.mtx.Unlock()
return ps.list
}