]> Sergey Matveev's repositories - btrtrc.git/blob - worse-conns.go
Drop support for go 1.20
[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 *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{}
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 }