You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

149 lines
3.5 KiB

9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
9 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
7 years ago
7 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
7 years ago
7 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
7 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
7 years ago
9 years ago
  1. package p2p
  2. import (
  3. "net"
  4. tmsync "github.com/tendermint/tendermint/internal/libs/sync"
  5. "github.com/tendermint/tendermint/types"
  6. )
  7. // IPeerSet has a (immutable) subset of the methods of PeerSet.
  8. type IPeerSet interface {
  9. Has(key types.NodeID) bool
  10. HasIP(ip net.IP) bool
  11. Get(key types.NodeID) Peer
  12. List() []Peer
  13. Size() int
  14. }
  15. //-----------------------------------------------------------------------------
  16. // PeerSet is a special structure for keeping a table of peers.
  17. // Iteration over the peers is super fast and thread-safe.
  18. type PeerSet struct {
  19. mtx tmsync.Mutex
  20. lookup map[types.NodeID]*peerSetItem
  21. list []Peer
  22. }
  23. type peerSetItem struct {
  24. peer Peer
  25. index int
  26. }
  27. // NewPeerSet creates a new peerSet with a list of initial capacity of 256 items.
  28. func NewPeerSet() *PeerSet {
  29. return &PeerSet{
  30. lookup: make(map[types.NodeID]*peerSetItem),
  31. list: make([]Peer, 0, 256),
  32. }
  33. }
  34. // Add adds the peer to the PeerSet.
  35. // It returns an error carrying the reason, if the peer is already present.
  36. func (ps *PeerSet) Add(peer Peer) error {
  37. ps.mtx.Lock()
  38. defer ps.mtx.Unlock()
  39. if ps.lookup[peer.ID()] != nil {
  40. return ErrSwitchDuplicatePeerID{peer.ID()}
  41. }
  42. index := len(ps.list)
  43. // Appending is safe even with other goroutines
  44. // iterating over the ps.list slice.
  45. ps.list = append(ps.list, peer)
  46. ps.lookup[peer.ID()] = &peerSetItem{peer, index}
  47. return nil
  48. }
  49. // Has returns true if the set contains the peer referred to by this
  50. // peerKey, otherwise false.
  51. func (ps *PeerSet) Has(peerKey types.NodeID) bool {
  52. ps.mtx.Lock()
  53. _, ok := ps.lookup[peerKey]
  54. ps.mtx.Unlock()
  55. return ok
  56. }
  57. // HasIP returns true if the set contains the peer referred to by this IP
  58. // address, otherwise false.
  59. func (ps *PeerSet) HasIP(peerIP net.IP) bool {
  60. ps.mtx.Lock()
  61. defer ps.mtx.Unlock()
  62. return ps.hasIP(peerIP)
  63. }
  64. // hasIP does not acquire a lock so it can be used in public methods which
  65. // already lock.
  66. func (ps *PeerSet) hasIP(peerIP net.IP) bool {
  67. for _, item := range ps.lookup {
  68. if item.peer.RemoteIP().Equal(peerIP) {
  69. return true
  70. }
  71. }
  72. return false
  73. }
  74. // Get looks up a peer by the provided peerKey. Returns nil if peer is not
  75. // found.
  76. func (ps *PeerSet) Get(peerKey types.NodeID) Peer {
  77. ps.mtx.Lock()
  78. defer ps.mtx.Unlock()
  79. item, ok := ps.lookup[peerKey]
  80. if ok {
  81. return item.peer
  82. }
  83. return nil
  84. }
  85. // Remove discards peer by its Key, if the peer was previously memoized.
  86. // Returns true if the peer was removed, and false if it was not found.
  87. // in the set.
  88. func (ps *PeerSet) Remove(peer Peer) bool {
  89. ps.mtx.Lock()
  90. defer ps.mtx.Unlock()
  91. item := ps.lookup[peer.ID()]
  92. if item == nil {
  93. return false
  94. }
  95. index := item.index
  96. // Create a new copy of the list but with one less item.
  97. // (we must copy because we'll be mutating the list).
  98. newList := make([]Peer, len(ps.list)-1)
  99. copy(newList, ps.list)
  100. // If it's the last peer, that's an easy special case.
  101. if index == len(ps.list)-1 {
  102. ps.list = newList
  103. delete(ps.lookup, peer.ID())
  104. return true
  105. }
  106. // Replace the popped item with the last item in the old list.
  107. lastPeer := ps.list[len(ps.list)-1]
  108. lastPeerKey := lastPeer.ID()
  109. lastPeerItem := ps.lookup[lastPeerKey]
  110. newList[index] = lastPeer
  111. lastPeerItem.index = index
  112. ps.list = newList
  113. delete(ps.lookup, peer.ID())
  114. return true
  115. }
  116. // Size returns the number of unique items in the peerSet.
  117. func (ps *PeerSet) Size() int {
  118. ps.mtx.Lock()
  119. defer ps.mtx.Unlock()
  120. return len(ps.list)
  121. }
  122. // List returns the threadsafe list of peers.
  123. func (ps *PeerSet) List() []Peer {
  124. ps.mtx.Lock()
  125. defer ps.mtx.Unlock()
  126. return ps.list
  127. }