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.

109 lines
2.3 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package p2p
  2. import (
  3. "sync"
  4. )
  5. // IPeerSet has a (immutable) subset of the methods of PeerSet.
  6. type IPeerSet interface {
  7. Has(key string) bool
  8. Get(key string) *Peer
  9. List() []*Peer
  10. Size() int
  11. }
  12. //-----------------------------------------------------------------------------
  13. // PeerSet is a special structure for keeping a table of peers.
  14. // Iteration over the peers is super fast and thread-safe.
  15. type PeerSet struct {
  16. mtx sync.Mutex
  17. lookup map[string]*peerSetItem
  18. list []*Peer
  19. }
  20. type peerSetItem struct {
  21. peer *Peer
  22. index int
  23. }
  24. func NewPeerSet() *PeerSet {
  25. return &PeerSet{
  26. lookup: make(map[string]*peerSetItem),
  27. list: make([]*Peer, 0, 256),
  28. }
  29. }
  30. // Returns false if peer with key (address) is already in set.
  31. func (ps *PeerSet) Add(peer *Peer) bool {
  32. ps.mtx.Lock()
  33. defer ps.mtx.Unlock()
  34. if ps.lookup[peer.Key] != nil {
  35. return false
  36. }
  37. index := len(ps.list)
  38. // Appending is safe even with other goroutines
  39. // iterating over the ps.list slice.
  40. ps.list = append(ps.list, peer)
  41. ps.lookup[peer.Key] = &peerSetItem{peer, index}
  42. return true
  43. }
  44. func (ps *PeerSet) Has(peerKey string) bool {
  45. ps.mtx.Lock()
  46. defer ps.mtx.Unlock()
  47. _, ok := ps.lookup[peerKey]
  48. return ok
  49. }
  50. func (ps *PeerSet) Get(peerKey string) *Peer {
  51. ps.mtx.Lock()
  52. defer ps.mtx.Unlock()
  53. item, ok := ps.lookup[peerKey]
  54. if ok {
  55. return item.peer
  56. } else {
  57. return nil
  58. }
  59. }
  60. func (ps *PeerSet) Remove(peer *Peer) {
  61. ps.mtx.Lock()
  62. defer ps.mtx.Unlock()
  63. item := ps.lookup[peer.Key]
  64. if item == nil {
  65. return
  66. }
  67. index := item.index
  68. // Copy the list but without the last element.
  69. // (we must copy because we're mutating the list)
  70. newList := make([]*Peer, len(ps.list)-1)
  71. copy(newList, ps.list)
  72. // If it's the last peer, that's an easy special case.
  73. if index == len(ps.list)-1 {
  74. ps.list = newList
  75. delete(ps.lookup, peer.Key)
  76. return
  77. }
  78. // Move the last item from ps.list to "index" in list.
  79. lastPeer := ps.list[len(ps.list)-1]
  80. lastPeerKey := lastPeer.Key
  81. lastPeerItem := ps.lookup[lastPeerKey]
  82. newList[index] = lastPeer
  83. lastPeerItem.index = index
  84. ps.list = newList
  85. delete(ps.lookup, peer.Key)
  86. }
  87. func (ps *PeerSet) Size() int {
  88. ps.mtx.Lock()
  89. defer ps.mtx.Unlock()
  90. return len(ps.list)
  91. }
  92. // threadsafe list of peers.
  93. func (ps *PeerSet) List() []*Peer {
  94. ps.mtx.Lock()
  95. defer ps.mtx.Unlock()
  96. return ps.list
  97. }