"sync"
"github.com/anacrolix/multiless"
- "github.com/anacrolix/torrent/storage"
"github.com/anacrolix/torrent/types"
)
type filterTorrent struct {
*Torrent
unverifiedBytes int64
- // Potentially shared with other torrents.
- storageLeft *int64
}
func sortFilterPieces(pieces []filterPiece) {
pieces := make([]filterPiece, 0, maxPieces)
// Storage capacity left for this run, keyed by the storage capacity pointer on the storage
// TorrentImpl. A nil value means no capacity limit.
- storageLeft := make(map[storage.TorrentCapacity]*int64)
+ var storageLeft *int64
+ if input.Capacity != nil {
+ storageLeft = new(int64)
+ *storageLeft = *input.Capacity
+ }
for _t := range input.Torrents {
// TODO: We could do metainfo requests here.
t := &filterTorrent{
Torrent: &input.Torrents[_t],
unverifiedBytes: 0,
}
- key := t.Capacity
- if key != nil {
- if _, ok := storageLeft[key]; !ok {
- capacity, ok := (*key)()
- if ok {
- storageLeft[key] = &capacity
- } else {
- storageLeft[key] = nil
- }
- }
- t.storageLeft = storageLeft[key]
- }
for i := range t.Pieces {
pieces = append(pieces, filterPiece{
t: t,
sortFilterPieces(pieces)
var allTorrentsUnverifiedBytes int64
for _, piece := range pieces {
- if left := piece.t.storageLeft; left != nil {
- if *left < int64(piece.Length) {
+ if left := storageLeft; left != nil {
+ if *left < piece.Length {
continue
}
- *left -= int64(piece.Length)
+ *left -= piece.Length
}
if !piece.Request || piece.NumPendingChunks == 0 {
// TODO: Clarify exactly what is verified. Stuff that's being hashed should be
}
type Input struct {
- Torrents []Torrent
+ // This is all torrents that share the same capacity below (or likely a single torrent if there
+ // is infinite capacity, since you could just run it separately for each Torrent if that's the
+ // case).
+ Torrents []Torrent
+ // Must not be modified. Non-nil if capacity is not infinite, meaning that pieces of torrents
+ // that share the same capacity key must be incorporated in piece ordering.
+ Capacity *int64
+ // Across all the Torrents. This might be partitioned by storage capacity key now.
MaxUnverifiedBytes int64
}
request_strategy "github.com/anacrolix/torrent/request-strategy"
)
-func (cl *Client) getRequestStrategyInput() request_strategy.Input {
- ts := make([]request_strategy.Torrent, 0, len(cl.torrents))
+// Returns what is necessary to run request_strategy.GetRequestablePieces for primaryTorrent.
+func (cl *Client) getRequestStrategyInput(primaryTorrent *Torrent) (input request_strategy.Input) {
+ input.MaxUnverifiedBytes = cl.config.MaxUnverifiedBytes
+ if !primaryTorrent.haveInfo() {
+ return
+ }
+ if capFunc := primaryTorrent.storage.Capacity; capFunc != nil {
+ if cap, ok := (*capFunc)(); ok {
+ input.Capacity = &cap
+ }
+ }
+ if input.Capacity == nil {
+ input.Torrents = []request_strategy.Torrent{primaryTorrent.requestStrategyTorrentInput()}
+ return
+ }
+ input.Torrents = make([]request_strategy.Torrent, 0, len(cl.torrents))
for _, t := range cl.torrents {
if !t.haveInfo() {
- // This would be removed if metadata is handled here. We have to guard against not
- // knowing the piece size. If we have no info, we have no pieces too, so the end result
- // is the same.
+ // This would be removed if metadata is handled here. Determining chunks per piece
+ // requires the info. If we have no info, we have no pieces too, so the end result is
+ // the same.
continue
}
- rst := request_strategy.Torrent{
- InfoHash: t.infoHash,
- ChunksPerPiece: t.chunksPerRegularPiece(),
- }
- if t.storage != nil {
- rst.Capacity = t.storage.Capacity
- }
- rst.Pieces = make([]request_strategy.Piece, 0, len(t.pieces))
- for i := range t.pieces {
- p := &t.pieces[i]
- rst.Pieces = append(rst.Pieces, request_strategy.Piece{
- Request: !t.ignorePieceForRequests(i),
- Priority: p.purePriority(),
- Partial: t.piecePartiallyDownloaded(i),
- Availability: p.availability,
- Length: int64(p.length()),
- NumPendingChunks: int(t.pieceNumPendingChunks(i)),
- IterPendingChunks: &p.undirtiedChunksIter,
- })
+ if t.storage.Capacity != primaryTorrent.storage.Capacity {
+ continue
}
- ts = append(ts, rst)
+ input.Torrents = append(input.Torrents, t.requestStrategyTorrentInput())
+ }
+ return
+}
+
+func (t *Torrent) getRequestStrategyInput() request_strategy.Input {
+ return t.cl.getRequestStrategyInput(t)
+}
+
+func (t *Torrent) requestStrategyTorrentInput() request_strategy.Torrent {
+ rst := request_strategy.Torrent{
+ InfoHash: t.infoHash,
+ ChunksPerPiece: t.chunksPerRegularPiece(),
}
- return request_strategy.Input{
- Torrents: ts,
- MaxUnverifiedBytes: cl.config.MaxUnverifiedBytes,
+ rst.Pieces = make([]request_strategy.Piece, 0, len(t.pieces))
+ for i := range t.pieces {
+ p := &t.pieces[i]
+ rst.Pieces = append(rst.Pieces, request_strategy.Piece{
+ Request: !t.ignorePieceForRequests(i),
+ Priority: p.purePriority(),
+ Partial: t.piecePartiallyDownloaded(i),
+ Availability: p.availability,
+ Length: int64(p.length()),
+ NumPendingChunks: int(t.pieceNumPendingChunks(i)),
+ IterPendingChunks: &p.undirtiedChunksIter,
+ })
}
+ return rst
}
func init() {
}
func (p *Peer) getDesiredRequestState() (desired desiredRequestState) {
- input := p.t.cl.getRequestStrategyInput()
+ input := p.t.getRequestStrategyInput()
requestHeap := peerRequests{
peer: p,
}