-
-
Notifications
You must be signed in to change notification settings - Fork 629
/
order.go
94 lines (87 loc) · 2.93 KB
/
order.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
package requestStrategy
import (
"bytes"
"github.com/anacrolix/multiless"
"github.com/anacrolix/torrent/metainfo"
"github.com/anacrolix/torrent/types"
)
type (
RequestIndex uint32
ChunkIndex = RequestIndex
Request = types.Request
pieceIndex = types.PieceIndex
piecePriority = types.PiecePriority
// This can be made into a type-param later, will be great for testing.
ChunkSpec = types.ChunkSpec
)
func pieceOrderLess(i, j *pieceRequestOrderItem) multiless.Computation {
return multiless.New().Int(
int(j.state.Priority), int(i.state.Priority),
// TODO: Should we match on complete here to prevent churn when availability changes?
).Bool(
j.state.Partial, i.state.Partial,
).Int(
// If this is done with relative availability, do we lose some determinism? If completeness
// is used, would that push this far enough down?
i.state.Availability, j.state.Availability,
).Int(
i.key.Index, j.key.Index,
).Lazy(func() multiless.Computation {
return multiless.New().Cmp(bytes.Compare(
i.key.InfoHash[:],
j.key.InfoHash[:],
))
})
}
// Calls f with requestable pieces in order.
func GetRequestablePieces(
input Input, pro *PieceRequestOrder,
// Returns true if the piece should be considered against the unverified bytes limit.
requestPiece func(ih metainfo.Hash, pieceIndex int, orderState PieceRequestOrderState) bool,
) {
// Storage capacity left for this run, keyed by the storage capacity pointer on the storage
// TorrentImpl. A nil value means no capacity limit.
var storageLeft *int64
if cap, ok := input.Capacity(); ok {
storageLeft = &cap
}
var (
allTorrentsUnverifiedBytes int64
maxUnverifiedBytes = input.MaxUnverifiedBytes()
)
pro.tree.Scan(func(item pieceRequestOrderItem) bool {
ih := item.key.InfoHash
var t = input.Torrent(ih)
var piece = t.Piece(item.key.Index)
pieceLength := t.PieceLength()
// Storage limits will always apply against requestable pieces, since we need to keep the
// highest priority pieces, even if they're complete or in an undesirable state.
if storageLeft != nil {
if *storageLeft < pieceLength {
return false
}
*storageLeft -= pieceLength
}
if piece.Request() {
if !requestPiece(ih, item.key.Index, item.state) {
// No blocks are being considered from this piece, so it won't result in unverified
// bytes.
return true
}
} else if !piece.CountUnverified() {
// The piece is pristine, and we're not considering it for requests.
return true
}
allTorrentsUnverifiedBytes += pieceLength
return maxUnverifiedBytes == 0 || allTorrentsUnverifiedBytes < maxUnverifiedBytes
})
return
}
type Input interface {
Torrent(metainfo.Hash) Torrent
// Storage capacity, shared among all Torrents with the same storage.TorrentCapacity pointer in
// their storage.Torrent references.
Capacity() (cap int64, capped bool)
// Across all the Torrents. This might be partitioned by storage capacity key now.
MaxUnverifiedBytes() int64
}