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.

143 lines
3.2 KiB

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