type SpewBencodingCmd struct{}
type DownloadCmd struct {
- Mmap bool `help:"memory-map torrent data"`
- TestPeer []string `help:"addresses of some starting peers"`
- Seed bool `help:"seed after download is complete"`
- Addr string `help:"network listen addr"`
- UploadRate *tagflag.Bytes `help:"max piece bytes to send per second"`
- DownloadRate *tagflag.Bytes `help:"max bytes per second down from peers"`
- PackedBlocklist string
- PublicIP net.IP
- Progress bool `default:"true"`
- PieceStates bool
- Quiet bool `help:"discard client logging"`
- Stats *bool `help:"print stats at termination"`
- Dht bool `default:"true"`
+ Mmap bool `help:"memory-map torrent data"`
+ TestPeer []string `help:"addresses of some starting peers"`
+ Seed bool `help:"seed after download is complete"`
+ Addr string `help:"network listen addr"`
+ MaxUnverifiedBytes tagflag.Bytes `help:"maximum number bytes to have pending verification"`
+ UploadRate *tagflag.Bytes `help:"max piece bytes to send per second"`
+ DownloadRate *tagflag.Bytes `help:"max bytes per second down from peers"`
+ PackedBlocklist string
+ PublicIP net.IP
+ Progress bool `default:"true"`
+ PieceStates bool
+ Quiet bool `help:"discard client logging"`
+ Stats *bool `help:"print stats at termination"`
+ Dht bool `default:"true"`
TcpPeers bool `default:"true"`
UtpPeers bool `default:"true"`
if flags.Quiet {
clientConfig.Logger = log.Discard
}
+ clientConfig.MaxUnverifiedBytes = flags.MaxUnverifiedBytes.Int64()
var stop missinggo.SynchronizedEvent
defer func() {
// (~4096), and the requested chunk size (~16KiB, see
// TorrentSpec.ChunkSize).
DownloadRateLimiter *rate.Limiter
+ // Maximum unverified bytes across all torrents. Not used if zero.
+ MaxUnverifiedBytes int64
// User-provided Client peer ID. If not present, one is generated automatically.
PeerID string
ts := make([]request_strategy.Torrent, 0, len(cl.torrents))
for _, t := range cl.torrents {
rst := request_strategy.Torrent{
- StableId: uintptr(unsafe.Pointer(t)),
- MaxUnverifiedBytes: 10 << 20,
+ StableId: uintptr(unsafe.Pointer(t)),
}
if t.storage != nil {
rst.Capacity = t.storage.Capacity
})
ts = append(ts, rst)
}
- nextPeerStates := cl.pieceRequestOrder.DoRequests(ts)
+ nextPeerStates := request_strategy.Run(request_strategy.Input{
+ Torrents: ts,
+ MaxUnverifiedBytes: cl.config.MaxUnverifiedBytes,
+ })
for p, state := range nextPeerStates {
applyPeerNextRequestState(p, state)
}
Piece
}
-func getRequestablePieces(torrents []Torrent) (ret []requestablePiece) {
+func getRequestablePieces(input Input) (ret []requestablePiece) {
// Storage capacity left for this run, keyed by the storage capacity pointer on the storage
// TorrentImpl.
storageLeft := make(map[*func() *int64]*int64)
var pieces []filterPiece
- for _, _t := range torrents {
+ for _, _t := range input.Torrents {
// TODO: We could do metainfo requests here.
t := &filterTorrent{
Torrent: _t,
}
}
sortFilterPieces(pieces)
+ var allTorrentsUnverifiedBytes int64
for _, piece := range pieces {
if left := piece.t.storageLeft; left != nil {
if *left < int64(piece.Length) {
*left -= int64(piece.Length)
}
if !piece.Request || piece.NumPendingChunks == 0 {
+ // TODO: Clarify exactly what is verified. Stuff that's being hashed should be
+ // considered unverified and hold up further requests.
continue
}
if piece.t.MaxUnverifiedBytes != 0 && piece.t.unverifiedBytes+piece.Length > piece.t.MaxUnverifiedBytes {
continue
}
+ if input.MaxUnverifiedBytes != 0 && allTorrentsUnverifiedBytes+piece.Length > input.MaxUnverifiedBytes {
+ continue
+ }
piece.t.unverifiedBytes += piece.Length
+ allTorrentsUnverifiedBytes += piece.Length
ret = append(ret, requestablePiece{
index: piece.index,
t: piece.t.Torrent,
return
}
+type Input struct {
+ Torrents []Torrent
+ MaxUnverifiedBytes int64
+}
+
// TODO: We could do metainfo requests here.
-func (requestOrder *ClientPieceOrder) DoRequests(torrents []Torrent) map[PeerId]PeerNextRequestState {
- requestPieces := getRequestablePieces(torrents)
+func Run(input Input) map[PeerId]PeerNextRequestState {
+ requestPieces := getRequestablePieces(input)
+ torrents := input.Torrents
allPeers := make(map[uintptr][]*requestsPeer, len(torrents))
for _, t := range torrents {
peers := make([]*requestsPeer, 0, len(t.Peers))
func TestStealingFromSlowerPeer(t *testing.T) {
c := qt.New(t)
- order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
- results := order.DoRequests([]Torrent{{
+ results := Run(Input{Torrents: []Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 5,
firstStealer,
secondStealer,
},
- }})
+ }}})
+
c.Assert(results, qt.HasLen, 3)
check := func(p PeerId, l int) {
c.Check(results[p].Requests, qt.HasLen, l)
func TestStealingFromSlowerPeersBasic(t *testing.T) {
c := qt.New(t)
- order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
- results := order.DoRequests([]Torrent{{
+ results := Run(Input{Torrents: []Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 2,
firstStealer,
secondStealer,
},
- }})
+ }}})
+
checkNumRequestsAndInterest(c, results[firstStealer.Id], 1, true)
checkNumRequestsAndInterest(c, results[secondStealer.Id], 1, true)
checkNumRequestsAndInterest(c, results[stealee.Id], 0, false)
func TestPeerKeepsExistingIfReasonable(t *testing.T) {
c := qt.New(t)
- order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
- results := order.DoRequests([]Torrent{{
+ results := Run(Input{Torrents: []Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 4,
firstStealer,
secondStealer,
},
- }})
+ }}})
+
c.Assert(results, qt.HasLen, 3)
check := func(p PeerId, l int) {
c.Check(results[p].Requests, qt.HasLen, l)
func TestDontStealUnnecessarily(t *testing.T) {
c := qt.New(t)
- order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
- results := order.DoRequests([]Torrent{{
+ results := Run(Input{Torrents: []Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 9,
stealee,
secondStealer,
},
- }})
+ }}})
+
c.Assert(results, qt.HasLen, 3)
check := func(p PeerId, l int) {
c.Check(results[p].Requests, qt.HasLen, l)