]> Sergey Matveev's repositories - btrtrc.git/blob - request-strategy/order.go
Use interfaces to lazily expose the bare minimum inputs to GetRequestablePieces
[btrtrc.git] / request-strategy / order.go
1 package request_strategy
2
3 import (
4         "bytes"
5         "expvar"
6
7         "github.com/anacrolix/multiless"
8         "github.com/anacrolix/torrent/metainfo"
9         "github.com/google/btree"
10
11         "github.com/anacrolix/torrent/types"
12 )
13
14 type (
15         RequestIndex  = uint32
16         ChunkIndex    = uint32
17         Request       = types.Request
18         pieceIndex    = types.PieceIndex
19         piecePriority = types.PiecePriority
20         // This can be made into a type-param later, will be great for testing.
21         ChunkSpec = types.ChunkSpec
22 )
23
24 type pieceOrderInput struct {
25         PieceRequestOrderState
26         PieceRequestOrderKey
27 }
28
29 func pieceOrderLess(i, j pieceOrderInput) multiless.Computation {
30         return multiless.New().Int(
31                 int(j.Priority), int(i.Priority),
32         ).Bool(
33                 j.Partial, i.Partial,
34         ).Int64(
35                 i.Availability, j.Availability,
36         ).Int(
37                 i.Index, j.Index,
38         ).Lazy(func() multiless.Computation {
39                 return multiless.New().Cmp(bytes.Compare(
40                         i.InfoHash[:],
41                         j.InfoHash[:],
42                 ))
43         })
44 }
45
46 type requestsPeer struct {
47         Peer
48         nextState                  PeerNextRequestState
49         requestablePiecesRemaining int
50 }
51
52 func (rp *requestsPeer) canFitRequest() bool {
53         return int(rp.nextState.Requests.GetCardinality()) < rp.MaxRequests
54 }
55
56 func (rp *requestsPeer) addNextRequest(r RequestIndex) {
57         if !rp.nextState.Requests.CheckedAdd(r) {
58                 panic("should only add once")
59         }
60 }
61
62 type peersForPieceRequests struct {
63         requestsInPiece int
64         *requestsPeer
65 }
66
67 func (me *peersForPieceRequests) addNextRequest(r RequestIndex) {
68         me.requestsPeer.addNextRequest(r)
69         me.requestsInPiece++
70 }
71
72 var packageExpvarMap = expvar.NewMap("request-strategy")
73
74 // Calls f with requestable pieces in order.
75 func GetRequestablePieces(input Input, pro *PieceRequestOrder, f func(ih metainfo.Hash, pieceIndex int)) {
76         // Storage capacity left for this run, keyed by the storage capacity pointer on the storage
77         // TorrentImpl. A nil value means no capacity limit.
78         var storageLeft *int64
79         if cap, ok := input.Capacity(); ok {
80                 storageLeft = &cap
81         }
82         var allTorrentsUnverifiedBytes int64
83         pro.tree.Ascend(func(i btree.Item) bool {
84                 _i := i.(pieceRequestOrderItem)
85                 ih := _i.key.InfoHash
86                 var t Torrent = input.Torrent(ih)
87                 var piece Piece = t.Piece(_i.key.Index)
88                 pieceLength := t.PieceLength()
89                 if storageLeft != nil {
90                         if *storageLeft < pieceLength {
91                                 return true
92                         }
93                         *storageLeft -= pieceLength
94                 }
95                 if !piece.Request() || piece.NumPendingChunks() == 0 {
96                         // TODO: Clarify exactly what is verified. Stuff that's being hashed should be
97                         // considered unverified and hold up further requests.
98                         return true
99                 }
100                 if input.MaxUnverifiedBytes() != 0 && allTorrentsUnverifiedBytes+pieceLength > input.MaxUnverifiedBytes() {
101                         return true
102                 }
103                 allTorrentsUnverifiedBytes += pieceLength
104                 f(ih, _i.key.Index)
105                 return true
106         })
107         return
108 }
109
110 type Input interface {
111         Torrent(metainfo.Hash) Torrent
112         // Storage capacity, shared among all Torrents with the same storage.TorrentCapacity pointer in
113         // their storage.Torrent references.
114         Capacity() (cap int64, capped bool)
115         // Across all the Torrents. This might be partitioned by storage capacity key now.
116         MaxUnverifiedBytes() int64
117 }