]> Sergey Matveev's repositories - btrtrc.git/blob - worse-conns.go
Optimize the use of worstConnSlice again
[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         Useful              bool
15         LastHelpful         time.Time
16         CompletedHandshake  time.Time
17         GetPeerPriority     func() (peerPriority, error)
18         getPeerPriorityOnce sync.Once
19         peerPriority        peerPriority
20         peerPriorityErr     error
21         Pointer             uintptr
22 }
23
24 func (me *worseConnInput) doGetPeerPriority() {
25         me.peerPriority, me.peerPriorityErr = me.GetPeerPriority()
26 }
27
28 func (me *worseConnInput) doGetPeerPriorityOnce() {
29         me.getPeerPriorityOnce.Do(me.doGetPeerPriority)
30 }
31
32 func worseConnInputFromPeer(p *Peer) worseConnInput {
33         ret := worseConnInput{
34                 Useful:             p.useful(),
35                 LastHelpful:        p.lastHelpful(),
36                 CompletedHandshake: p.completedHandshake,
37                 Pointer:            uintptr(unsafe.Pointer(p)),
38                 GetPeerPriority:    p.peerPriority,
39         }
40         return ret
41 }
42
43 func worseConn(_l, _r *Peer) bool {
44         // TODO: Use generics for ptr to
45         l := worseConnInputFromPeer(_l)
46         r := worseConnInputFromPeer(_r)
47         return l.Less(&r)
48 }
49
50 func (l *worseConnInput) Less(r *worseConnInput) bool {
51         less, ok := multiless.New().Bool(
52                 l.Useful, r.Useful).CmpInt64(
53                 l.LastHelpful.Sub(r.LastHelpful).Nanoseconds()).CmpInt64(
54                 l.CompletedHandshake.Sub(r.CompletedHandshake).Nanoseconds()).LazySameLess(
55                 func() (same, less bool) {
56                         l.doGetPeerPriorityOnce()
57                         if l.peerPriorityErr != nil {
58                                 same = true
59                                 return
60                         }
61                         r.doGetPeerPriorityOnce()
62                         if r.peerPriorityErr != nil {
63                                 same = true
64                                 return
65                         }
66                         same = l.peerPriority == r.peerPriority
67                         less = l.peerPriority < r.peerPriority
68                         return
69                 }).Uintptr(
70                 l.Pointer, r.Pointer,
71         ).LessOk()
72         if !ok {
73                 panic(fmt.Sprintf("cannot differentiate %#v and %#v", l, r))
74         }
75         return less
76 }
77
78 type worseConnSlice struct {
79         conns []*PeerConn
80         keys  []worseConnInput
81 }
82
83 func (me *worseConnSlice) initKeys() {
84         me.keys = make([]worseConnInput, len(me.conns))
85         for i, c := range me.conns {
86                 me.keys[i] = worseConnInputFromPeer(&c.Peer)
87         }
88 }
89
90 var _ heap.Interface = &worseConnSlice{}
91
92 func (me worseConnSlice) Len() int {
93         return len(me.conns)
94 }
95
96 func (me worseConnSlice) Less(i, j int) bool {
97         return me.keys[i].Less(&me.keys[j])
98 }
99
100 func (me *worseConnSlice) Pop() interface{} {
101         i := len(me.conns) - 1
102         ret := me.conns[i]
103         me.conns = me.conns[:i]
104         return ret
105 }
106
107 func (me *worseConnSlice) Push(x interface{}) {
108         panic("not implemented")
109 }
110
111 func (me worseConnSlice) Swap(i, j int) {
112         me.conns[i], me.conns[j] = me.conns[j], me.conns[i]
113         me.keys[i], me.keys[j] = me.keys[j], me.keys[i]
114 }