]> Sergey Matveev's repositories - btrtrc.git/blob - worse-conns.go
Retry some utp tests on failure
[btrtrc.git] / worse-conns.go
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 *Peer, 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 worseConn(_l, _r *Peer) bool {
54         // TODO: Use generics for ptr to
55         l := worseConnInputFromPeer(_l, worseConnLensOpts{})
56         r := worseConnInputFromPeer(_r, worseConnLensOpts{})
57         return l.Less(&r)
58 }
59
60 func (l *worseConnInput) Less(r *worseConnInput) bool {
61         less, ok := multiless.New().Bool(
62                 r.BadDirection, l.BadDirection).Bool(
63                 l.Useful, r.Useful).CmpInt64(
64                 l.LastHelpful.Sub(r.LastHelpful).Nanoseconds()).CmpInt64(
65                 l.CompletedHandshake.Sub(r.CompletedHandshake).Nanoseconds()).LazySameLess(
66                 func() (same, less bool) {
67                         l.doGetPeerPriorityOnce()
68                         if l.peerPriorityErr != nil {
69                                 same = true
70                                 return
71                         }
72                         r.doGetPeerPriorityOnce()
73                         if r.peerPriorityErr != nil {
74                                 same = true
75                                 return
76                         }
77                         same = l.peerPriority == r.peerPriority
78                         less = l.peerPriority < r.peerPriority
79                         return
80                 }).Uintptr(
81                 l.Pointer, r.Pointer,
82         ).LessOk()
83         if !ok {
84                 panic(fmt.Sprintf("cannot differentiate %#v and %#v", l, r))
85         }
86         return less
87 }
88
89 type worseConnSlice struct {
90         conns []*PeerConn
91         keys  []worseConnInput
92 }
93
94 func (me *worseConnSlice) initKeys(opts worseConnLensOpts) {
95         me.keys = make([]worseConnInput, len(me.conns))
96         for i, c := range me.conns {
97                 me.keys[i] = worseConnInputFromPeer(&c.Peer, opts)
98         }
99 }
100
101 var _ heap.Interface = &worseConnSlice{}
102
103 func (me worseConnSlice) Len() int {
104         return len(me.conns)
105 }
106
107 func (me worseConnSlice) Less(i, j int) bool {
108         return me.keys[i].Less(&me.keys[j])
109 }
110
111 func (me *worseConnSlice) Pop() interface{} {
112         i := len(me.conns) - 1
113         ret := me.conns[i]
114         me.conns = me.conns[:i]
115         return ret
116 }
117
118 func (me *worseConnSlice) Push(x interface{}) {
119         panic("not implemented")
120 }
121
122 func (me worseConnSlice) Swap(i, j int) {
123         me.conns[i], me.conns[j] = me.conns[j], me.conns[i]
124         me.keys[i], me.keys[j] = me.keys[j], me.keys[i]
125 }