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.

77 lines
1.6 KiB

11 years ago
11 years ago
  1. package p2p
  2. import (
  3. "sync"
  4. )
  5. /*
  6. PeerSet is a special structure for keeping a table of peers.
  7. Iteration over the peers is super fast and thread-safe.
  8. */
  9. type PeerSet struct {
  10. mtx sync.Mutex
  11. lookup map[string]*peerSetItem
  12. list []*Peer
  13. }
  14. type peerSetItem struct {
  15. peer *Peer
  16. index int
  17. }
  18. func NewPeerSet() *PeerSet {
  19. return &PeerSet{
  20. lookup: make(map[string]*peerSetItem),
  21. list: make([]*Peer, 0, 256),
  22. }
  23. }
  24. func (ps *PeerSet) Add(peer *Peer) bool {
  25. ps.mtx.Lock()
  26. defer ps.mtx.Unlock()
  27. addr := peer.RemoteAddress().String()
  28. if ps.lookup[addr] != nil {
  29. return false
  30. }
  31. index := len(ps.list)
  32. // Appending is safe even with other goroutines
  33. // iterating over the ps.list slice.
  34. ps.list = append(ps.list, peer)
  35. ps.lookup[addr] = &peerSetItem{peer, index}
  36. return true
  37. }
  38. func (ps *PeerSet) Remove(peer *Peer) {
  39. ps.mtx.Lock()
  40. defer ps.mtx.Unlock()
  41. addr := peer.RemoteAddress().String()
  42. item := ps.lookup[addr]
  43. if item == nil {
  44. return
  45. }
  46. index := item.index
  47. // Copy the list but without the last element.
  48. // (we must copy because we're mutating the list)
  49. newList := make([]*Peer, len(ps.list)-1)
  50. copy(newList, ps.list)
  51. // If it's the last peer, that's an easy special case.
  52. if index == len(ps.list)-1 {
  53. ps.list = newList
  54. return
  55. }
  56. // Move the last item from ps.list to "index" in list.
  57. lastPeer := ps.list[len(ps.list)-1]
  58. lastPeerAddr := lastPeer.RemoteAddress().String()
  59. lastPeerItem := ps.lookup[lastPeerAddr]
  60. newList[index] = lastPeer
  61. lastPeerItem.index = index
  62. ps.list = newList
  63. delete(ps.lookup, addr)
  64. }
  65. // threadsafe list of peers.
  66. func (ps *PeerSet) List() []*Peer {
  67. ps.mtx.Lock()
  68. defer ps.mtx.Unlock()
  69. return ps.list
  70. }