worse-conns.go 2.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118
  1. package torrent
  2. import (
  3. "container/heap"
  4. "fmt"
  5. "time"
  6. "unsafe"
  7. "github.com/anacrolix/multiless"
  8. "github.com/anacrolix/sync"
  9. )
  10. type worseConnInput struct {
  11. BadDirection bool
  12. Useful bool
  13. LastHelpful time.Time
  14. CompletedHandshake time.Time
  15. GetPeerPriority func() (peerPriority, error)
  16. getPeerPriorityOnce sync.Once
  17. peerPriority peerPriority
  18. peerPriorityErr error
  19. Pointer uintptr
  20. }
  21. func (me *worseConnInput) doGetPeerPriority() {
  22. me.peerPriority, me.peerPriorityErr = me.GetPeerPriority()
  23. }
  24. func (me *worseConnInput) doGetPeerPriorityOnce() {
  25. me.getPeerPriorityOnce.Do(me.doGetPeerPriority)
  26. }
  27. type worseConnLensOpts struct {
  28. incomingIsBad, outgoingIsBad bool
  29. }
  30. func worseConnInputFromPeer(p *PeerConn, opts worseConnLensOpts) *worseConnInput {
  31. ret := &worseConnInput{
  32. Useful: p.useful(),
  33. LastHelpful: p.lastHelpful(),
  34. CompletedHandshake: p.completedHandshake,
  35. Pointer: uintptr(unsafe.Pointer(p)),
  36. GetPeerPriority: p.peerPriority,
  37. }
  38. if opts.incomingIsBad && !p.outgoing {
  39. ret.BadDirection = true
  40. } else if opts.outgoingIsBad && p.outgoing {
  41. ret.BadDirection = true
  42. }
  43. return ret
  44. }
  45. func (l *worseConnInput) Less(r *worseConnInput) bool {
  46. less, ok := multiless.New().Bool(
  47. r.BadDirection, l.BadDirection).Bool(
  48. l.Useful, r.Useful).CmpInt64(
  49. l.LastHelpful.Sub(r.LastHelpful).Nanoseconds()).CmpInt64(
  50. l.CompletedHandshake.Sub(r.CompletedHandshake).Nanoseconds()).LazySameLess(
  51. func() (same, less bool) {
  52. l.doGetPeerPriorityOnce()
  53. if l.peerPriorityErr != nil {
  54. same = true
  55. return
  56. }
  57. r.doGetPeerPriorityOnce()
  58. if r.peerPriorityErr != nil {
  59. same = true
  60. return
  61. }
  62. same = l.peerPriority == r.peerPriority
  63. less = l.peerPriority < r.peerPriority
  64. return
  65. }).Uintptr(
  66. l.Pointer, r.Pointer,
  67. ).LessOk()
  68. if !ok {
  69. panic(fmt.Sprintf("cannot differentiate %#v and %#v", l, r))
  70. }
  71. return less
  72. }
  73. type worseConnSlice struct {
  74. conns []*PeerConn
  75. keys []*worseConnInput
  76. }
  77. func (me *worseConnSlice) initKeys(opts worseConnLensOpts) {
  78. me.keys = make([]*worseConnInput, len(me.conns))
  79. for i, c := range me.conns {
  80. me.keys[i] = worseConnInputFromPeer(c, opts)
  81. }
  82. }
  83. var _ heap.Interface = (*worseConnSlice)(nil)
  84. func (me *worseConnSlice) Len() int {
  85. return len(me.conns)
  86. }
  87. func (me *worseConnSlice) Less(i, j int) bool {
  88. return me.keys[i].Less(me.keys[j])
  89. }
  90. func (me *worseConnSlice) Pop() interface{} {
  91. i := len(me.conns) - 1
  92. ret := me.conns[i]
  93. me.conns = me.conns[:i]
  94. return ret
  95. }
  96. func (me *worseConnSlice) Push(x interface{}) {
  97. panic("not implemented")
  98. }
  99. func (me *worseConnSlice) Swap(i, j int) {
  100. me.conns[i], me.conns[j] = me.conns[j], me.conns[i]
  101. me.keys[i], me.keys[j] = me.keys[j], me.keys[i]
  102. }