2020-01-10 04:09:21 +00:00
|
|
|
package torrent
|
|
|
|
|
|
|
|
import (
|
2021-05-09 04:14:11 +00:00
|
|
|
"sort"
|
2020-01-10 04:09:21 +00:00
|
|
|
"time"
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
"github.com/anacrolix/multiless"
|
2020-01-10 04:09:21 +00:00
|
|
|
pp "github.com/anacrolix/torrent/peer_protocol"
|
2021-05-09 04:14:11 +00:00
|
|
|
"github.com/bradfitz/iter"
|
2020-01-10 04:09:21 +00:00
|
|
|
)
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
type clientPieceRequestOrder struct {
|
|
|
|
pieces []pieceRequestOrderPiece
|
2020-01-24 04:09:39 +00:00
|
|
|
}
|
2020-01-10 04:09:21 +00:00
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
type pieceRequestOrderPiece struct {
|
|
|
|
t *Torrent
|
|
|
|
index pieceIndex
|
|
|
|
prio piecePriority
|
|
|
|
partial bool
|
|
|
|
availability int
|
2020-01-24 04:09:39 +00:00
|
|
|
}
|
2020-01-10 04:09:21 +00:00
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (me *clientPieceRequestOrder) addPieces(t *Torrent, numPieces pieceIndex) {
|
|
|
|
for i := range iter.N(numPieces) {
|
|
|
|
me.pieces = append(me.pieces, pieceRequestOrderPiece{
|
|
|
|
t: t,
|
|
|
|
index: i,
|
|
|
|
})
|
2020-01-24 06:30:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (me *clientPieceRequestOrder) removePieces(t *Torrent) {
|
|
|
|
newPieces := make([]pieceRequestOrderPiece, 0, len(me.pieces)-t.numPieces())
|
|
|
|
for _, p := range me.pieces {
|
|
|
|
if p.t != t {
|
|
|
|
newPieces = append(newPieces, p)
|
|
|
|
}
|
2020-01-10 04:09:21 +00:00
|
|
|
}
|
2021-05-09 04:14:11 +00:00
|
|
|
me.pieces = newPieces
|
2020-01-10 04:09:21 +00:00
|
|
|
}
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (me clientPieceRequestOrder) sort() {
|
|
|
|
sort.SliceStable(me.pieces, me.less)
|
2020-01-10 05:18:55 +00:00
|
|
|
}
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (me clientPieceRequestOrder) update() {
|
|
|
|
for i := range me.pieces {
|
|
|
|
p := &me.pieces[i]
|
|
|
|
p.prio = p.t.piece(p.index).uncachedPriority()
|
|
|
|
p.partial = p.t.piecePartiallyDownloaded(p.index)
|
|
|
|
p.availability = p.t.pieceAvailability(p.index)
|
2020-01-10 05:18:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (me clientPieceRequestOrder) less(_i, _j int) bool {
|
|
|
|
i := me.pieces[_i]
|
|
|
|
j := me.pieces[_j]
|
|
|
|
ml := multiless.New()
|
|
|
|
ml.Int(int(j.prio), int(i.prio))
|
|
|
|
ml.Bool(j.partial, i.partial)
|
|
|
|
ml.Int(i.availability, j.availability)
|
|
|
|
return ml.Less()
|
|
|
|
}
|
|
|
|
|
|
|
|
func (cl *Client) requester() {
|
|
|
|
for {
|
|
|
|
func() {
|
|
|
|
cl.lock()
|
|
|
|
defer cl.unlock()
|
|
|
|
cl.doRequests()
|
|
|
|
}()
|
|
|
|
select {
|
|
|
|
case <-cl.closed.LockedChan(cl.locker()):
|
|
|
|
return
|
|
|
|
case <-time.After(10 * time.Millisecond):
|
|
|
|
}
|
2020-01-10 05:18:55 +00:00
|
|
|
}
|
|
|
|
}
|
2020-01-24 06:55:20 +00:00
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
func (cl *Client) doRequests() {
|
|
|
|
requestOrder := clientPieceRequestOrder{}
|
|
|
|
allPeers := make(map[*Torrent][]*Peer)
|
|
|
|
storageCapacity := make(map[*Torrent]*int64)
|
|
|
|
for _, t := range cl.torrents {
|
|
|
|
// TODO: We could do metainfo requests here.
|
|
|
|
if t.haveInfo() {
|
|
|
|
value := int64(t.usualPieceSize())
|
|
|
|
storageCapacity[t] = &value
|
|
|
|
requestOrder.addPieces(t, t.numPieces())
|
2020-01-24 06:55:20 +00:00
|
|
|
}
|
2021-05-09 04:14:11 +00:00
|
|
|
var peers []*Peer
|
|
|
|
t.iterPeers(func(p *Peer) {
|
|
|
|
peers = append(peers, p)
|
|
|
|
})
|
|
|
|
allPeers[t] = peers
|
|
|
|
}
|
|
|
|
requestOrder.update()
|
|
|
|
requestOrder.sort()
|
|
|
|
for _, p := range requestOrder.pieces {
|
|
|
|
if p.t.ignorePieceForRequests(p.index) {
|
2020-01-24 06:55:20 +00:00
|
|
|
continue
|
|
|
|
}
|
2021-05-09 04:14:11 +00:00
|
|
|
peers := allPeers[p.t]
|
|
|
|
torrentPiece := p.t.piece(p.index)
|
|
|
|
if left := storageCapacity[p.t]; left != nil {
|
|
|
|
if *left < int64(torrentPiece.length()) {
|
|
|
|
continue
|
|
|
|
}
|
|
|
|
*left -= int64(torrentPiece.length())
|
2020-01-24 06:55:20 +00:00
|
|
|
}
|
2021-05-09 04:14:11 +00:00
|
|
|
p.t.piece(p.index).iterUndirtiedChunks(func(chunk ChunkSpec) bool {
|
|
|
|
for _, peer := range peers {
|
|
|
|
req := Request{pp.Integer(p.index), chunk}
|
|
|
|
_, err := peer.request(req)
|
|
|
|
if err == nil {
|
2021-05-09 04:41:03 +00:00
|
|
|
//log.Printf("requested %v", req)
|
2021-05-09 04:14:11 +00:00
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true
|
|
|
|
})
|
2020-01-24 06:55:20 +00:00
|
|
|
}
|
2021-05-09 04:14:11 +00:00
|
|
|
for _, t := range cl.torrents {
|
|
|
|
t.iterPeers(func(p *Peer) {
|
|
|
|
if !p.peerChoking && p.numLocalRequests() == 0 && !p.writeBufferFull() {
|
|
|
|
p.setInterested(false)
|
|
|
|
}
|
2020-01-24 06:55:20 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-09 04:14:11 +00:00
|
|
|
//func (requestStrategyDefaults) iterUndirtiedChunks(p requestStrategyPiece, f func(ChunkSpec) bool) bool {
|
|
|
|
// chunkIndices := p.dirtyChunks().Copy()
|
|
|
|
// chunkIndices.FlipRange(0, bitmap.BitIndex(p.numChunks()))
|
|
|
|
// return iter.ForPerm(chunkIndices.Len(), func(i int) bool {
|
|
|
|
// ci, err := chunkIndices.RB.Select(uint32(i))
|
|
|
|
// if err != nil {
|
|
|
|
// panic(err)
|
|
|
|
// }
|
|
|
|
// return f(p.chunkIndexRequest(pp.Integer(ci)).ChunkSpec)
|
|
|
|
// })
|
|
|
|
//}
|
|
|
|
|
|
|
|
//
|
|
|
|
//func iterUnbiasedPieceRequestOrder(
|
|
|
|
// cn requestStrategyConnection,
|
|
|
|
// f func(piece pieceIndex) bool,
|
|
|
|
// pieceRequestOrder []pieceIndex,
|
|
|
|
//) bool {
|
|
|
|
// cn.torrent().sortPieceRequestOrder(pieceRequestOrder)
|
|
|
|
// for _, i := range pieceRequestOrder {
|
|
|
|
// if !cn.peerHasPiece(i) || cn.torrent().ignorePieceForRequests(i) {
|
|
|
|
// continue
|
|
|
|
// }
|
|
|
|
// if !f(i) {
|
|
|
|
// return false
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return true
|
|
|
|
//}
|