| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394 |
- 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
- }
|