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  }