1 package request_strategy
7 "github.com/anacrolix/multiless"
8 "github.com/anacrolix/torrent/metainfo"
9 "github.com/google/btree"
11 "github.com/anacrolix/torrent/types"
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
24 type pieceOrderInput struct {
25 PieceRequestOrderState
29 func pieceOrderLess(i, j pieceOrderInput) multiless.Computation {
30 return multiless.New().Int(
31 int(j.Priority), int(i.Priority),
35 i.Availability, j.Availability,
38 ).Lazy(func() multiless.Computation {
39 return multiless.New().Cmp(bytes.Compare(
46 type requestsPeer struct {
48 nextState PeerNextRequestState
49 requestablePiecesRemaining int
52 func (rp *requestsPeer) canFitRequest() bool {
53 return int(rp.nextState.Requests.GetCardinality()) < rp.MaxRequests
56 func (rp *requestsPeer) addNextRequest(r RequestIndex) {
57 if !rp.nextState.Requests.CheckedAdd(r) {
58 panic("should only add once")
62 type peersForPieceRequests struct {
67 func (me *peersForPieceRequests) addNextRequest(r RequestIndex) {
68 me.requestsPeer.addNextRequest(r)
72 var packageExpvarMap = expvar.NewMap("request-strategy")
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 {
82 var allTorrentsUnverifiedBytes int64
83 pro.tree.Ascend(func(i btree.Item) bool {
84 _i := i.(*pieceRequestOrderItem)
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 {
93 *storageLeft -= pieceLength
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.
100 if input.MaxUnverifiedBytes() != 0 && allTorrentsUnverifiedBytes+pieceLength > input.MaxUnverifiedBytes() {
103 allTorrentsUnverifiedBytes += pieceLength
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