]> Sergey Matveev's repositories - btrtrc.git/blob - request-strategy/order.go
67adc8587b9c5a8a0d1c2a2afb06bebd089ad5b8
[btrtrc.git] / request-strategy / order.go
1 package requestStrategy
2
3 import (
4         "bytes"
5
6         "github.com/anacrolix/multiless"
7
8         "github.com/anacrolix/torrent/metainfo"
9         "github.com/anacrolix/torrent/types"
10 )
11
12 type (
13         RequestIndex  uint32
14         ChunkIndex    = RequestIndex
15         Request       = types.Request
16         pieceIndex    = types.PieceIndex
17         piecePriority = types.PiecePriority
18         // This can be made into a type-param later, will be great for testing.
19         ChunkSpec = types.ChunkSpec
20 )
21
22 func pieceOrderLess(i, j *pieceRequestOrderItem) multiless.Computation {
23         return multiless.New().Int(
24                 int(j.state.Priority), int(i.state.Priority),
25                 // TODO: Should we match on complete here to prevent churn when availability changes?
26         ).Bool(
27                 j.state.Partial, i.state.Partial,
28         ).Int(
29                 // If this is done with relative availability, do we lose some determinism? If completeness
30                 // is used, would that push this far enough down?
31                 i.state.Availability, j.state.Availability,
32         ).Int(
33                 i.key.Index, j.key.Index,
34         ).Lazy(func() multiless.Computation {
35                 return multiless.New().Cmp(bytes.Compare(
36                         i.key.InfoHash[:],
37                         j.key.InfoHash[:],
38                 ))
39         })
40 }
41
42 // Calls f with requestable pieces in order.
43 func GetRequestablePieces(
44         input Input, pro *PieceRequestOrder,
45         f func(ih metainfo.Hash, pieceIndex int, orderState PieceRequestOrderState),
46 ) {
47         // Storage capacity left for this run, keyed by the storage capacity pointer on the storage
48         // TorrentImpl. A nil value means no capacity limit.
49         var storageLeft *int64
50         if cap, ok := input.Capacity(); ok {
51                 storageLeft = &cap
52         }
53         var allTorrentsUnverifiedBytes int64
54         pro.tree.Scan(func(_i pieceRequestOrderItem) bool {
55                 ih := _i.key.InfoHash
56                 var t Torrent = input.Torrent(ih)
57                 var piece Piece = t.Piece(_i.key.Index)
58                 pieceLength := t.PieceLength()
59                 if storageLeft != nil {
60                         if *storageLeft < pieceLength {
61                                 return false
62                         }
63                         *storageLeft -= pieceLength
64                 }
65                 if !piece.Request() || piece.NumPendingChunks() == 0 {
66                         // TODO: Clarify exactly what is verified. Stuff that's being hashed should be
67                         // considered unverified and hold up further requests.
68                         return true
69                 }
70                 if input.MaxUnverifiedBytes() != 0 && allTorrentsUnverifiedBytes+pieceLength > input.MaxUnverifiedBytes() {
71                         return false
72                 }
73                 allTorrentsUnverifiedBytes += pieceLength
74                 f(ih, _i.key.Index, _i.state)
75                 return true
76         })
77         return
78 }
79
80 type Input interface {
81         Torrent(metainfo.Hash) Torrent
82         // Storage capacity, shared among all Torrents with the same storage.TorrentCapacity pointer in
83         // their storage.Torrent references.
84         Capacity() (cap int64, capped bool)
85         // Across all the Torrents. This might be partitioned by storage capacity key now.
86         MaxUnverifiedBytes() int64
87 }