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