7 "github.com/anacrolix/missinggo/v2/bitmap"
8 "github.com/anacrolix/missinggo/v2/prioritybitmap"
10 pp "github.com/anacrolix/torrent/peer_protocol"
13 type requestStrategyPiece interface {
14 numChunks() pp.Integer
15 dirtyChunks() bitmap.Bitmap
16 chunkIndexRequest(i pp.Integer) request
19 type requestStrategyTorrent interface {
23 readerPiecePriorities() (now, readahead bitmap.Bitmap)
24 ignorePieces() bitmap.Bitmap
25 pendingPieces() *prioritybitmap.PriorityBitmap
28 type requestStrategyConnection interface {
29 torrent() requestStrategyTorrent
30 peerPieces() bitmap.Bitmap
31 pieceRequestOrder() *prioritybitmap.PriorityBitmap
34 totalExpectingTime() time.Duration
36 chunksReceivedWhileExpecting() int64
39 type requestStrategyDefaults struct{}
41 func (requestStrategyDefaults) hooks() requestStrategyHooks {
42 return requestStrategyHooks{
43 sentRequest: func(request) {},
44 deletedRequest: func(request) {},
48 type requestStrategy interface {
49 iterPendingPieces(requestStrategyConnection, func(pieceIndex) bool) bool
50 iterUndirtiedChunks(requestStrategyPiece, func(chunkSpec) bool) bool
51 nominalMaxRequests(requestStrategyConnection) int
52 shouldRequestWithoutBias(requestStrategyConnection) bool
53 piecePriority(requestStrategyConnection, pieceIndex, piecePriority, int) int
54 hooks() requestStrategyHooks
57 type requestStrategyHooks struct {
58 sentRequest func(request)
59 deletedRequest func(request)
62 type requestStrategyCallbacks interface {
63 requestTimedOut(request)
66 // Favour higher priority pieces with some fuzzing to reduce overlaps and wastage across
68 type requestStrategyFuzzing struct {
69 requestStrategyDefaults
72 // The fastest connection downloads strictly in order of priority, while all others adhere to their
73 // piece inclinations.
74 type requestStrategyFastest struct {
75 requestStrategyDefaults
78 func newRequestStrategyMaker(rs requestStrategy) RequestStrategyMaker {
79 return func(requestStrategyCallbacks, sync.Locker) requestStrategy {
84 func RequestStrategyFastest() RequestStrategyMaker {
85 return newRequestStrategyMaker(requestStrategyFastest{})
88 func RequestStrategyFuzzing() RequestStrategyMaker {
89 return newRequestStrategyMaker(requestStrategyFuzzing{})
92 func (requestStrategyFastest) ShouldRequestWithoutBias(cn requestStrategyConnection) bool {
93 if cn.torrent().numReaders() == 0 {
96 if cn.torrent().numConns() == 1 {
105 // Requests are strictly by piece priority, and not duplicated until duplicateRequestTimeout is
107 type requestStrategyDuplicateRequestTimeout struct {
108 // How long to avoid duplicating a pending request.
109 duplicateRequestTimeout time.Duration
111 callbacks requestStrategyCallbacks
113 // The last time we requested a chunk. Deleting the request from any connection will clear this
115 lastRequested map[request]*time.Timer
116 // The lock to take when running a request timeout handler.
117 timeoutLocker sync.Locker
120 type RequestStrategyMaker func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy
122 func RequestStrategyDuplicateRequestTimeout(duplicateRequestTimeout time.Duration) RequestStrategyMaker {
123 return func(callbacks requestStrategyCallbacks, clientLocker sync.Locker) requestStrategy {
124 return requestStrategyDuplicateRequestTimeout{
125 duplicateRequestTimeout: duplicateRequestTimeout,
126 callbacks: callbacks,
127 lastRequested: make(map[request]*time.Timer),
128 timeoutLocker: clientLocker,
133 func (rs requestStrategyDuplicateRequestTimeout) hooks() requestStrategyHooks {
134 return requestStrategyHooks{
135 deletedRequest: func(r request) {
136 if t, ok := rs.lastRequested[r]; ok {
138 delete(rs.lastRequested, r)
141 sentRequest: rs.onSentRequest,