New tests and fixes for them

Not complete. There's still a request-stealing balancing issue, but it's functional for now.
This commit is contained in:
Matt Joiner 2021-05-13 13:50:41 +10:00
parent e7c5ed679f
commit 07ba6e9210
2 changed files with 99 additions and 5 deletions

View File

@ -1,12 +1,12 @@
package request_strategy
import (
"math"
"sort"
"github.com/anacrolix/multiless"
pp "github.com/anacrolix/torrent/peer_protocol"
"github.com/anacrolix/torrent/types"
"github.com/davecgh/go-spew/spew"
)
type (
@ -164,24 +164,28 @@ func (requestOrder *ClientPieceOrder) DoRequests(torrents []*Torrent) map[PeerId
if f := torrentPiece.IterPendingChunks; f != nil {
f(func(chunk types.ChunkSpec) {
req := Request{pp.Integer(p.index), chunk}
pendingChunksRemaining--
defer func() { pendingChunksRemaining-- }()
sortPeersForPiece()
spew.Dump(peersForPiece)
skipped := 0
// Try up to the number of peers that could legitimately receive the request equal to
// the number of chunks left. This should ensure that only the best peers serve the last
// few chunks in a piece.
lowestNumRequestsInPiece := math.MaxInt16
for _, peer := range peersForPiece {
if !peer.canFitRequest() || !peer.HasPiece(p.index) || (!peer.pieceAllowedFastOrDefault(p.index) && peer.Choking) {
continue
}
if skipped >= pendingChunksRemaining {
if skipped+1 >= pendingChunksRemaining {
break
}
if f := peer.HasExistingRequest; f == nil || !f(req) {
skipped++
lowestNumRequestsInPiece = peer.requestsInPiece
continue
}
if peer.requestsInPiece > lowestNumRequestsInPiece {
break
}
if !peer.pieceAllowedFastOrDefault(p.index) {
// We must stay interested for this.
peer.nextState.Interested = true

View File

@ -34,7 +34,50 @@ func (i intPeerId) Uintptr() uintptr {
return uintptr(i)
}
func TestStealingFromSlowerPeers(t *testing.T) {
func TestStealingFromSlowerPeer(t *testing.T) {
c := qt.New(t)
order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
},
MaxRequests: math.MaxInt16,
DownloadRate: 2,
}
// Slower than the stealers, but has all requests already.
stealee := basePeer
stealee.DownloadRate = 1
stealee.HasExistingRequest = func(r Request) bool {
return true
}
stealee.Id = intPeerId(1)
firstStealer := basePeer
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
results := order.DoRequests([]*Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 5,
IterPendingChunks: chunkIter(0, 1, 2, 3, 4),
}},
Peers: []Peer{
stealee,
firstStealer,
secondStealer,
},
}})
c.Assert(results, qt.HasLen, 3)
check := func(p PeerId, l int) {
c.Check(results[p].Requests, qt.HasLen, l)
c.Check(results[p].Interested, qt.Equals, l > 0)
}
check(stealee.Id, 1)
check(firstStealer.Id, 2)
check(secondStealer.Id, 2)
}
func TestStealingFromSlowerPeersBasic(t *testing.T) {
c := qt.New(t)
order := ClientPieceOrder{}
basePeer := Peer{
@ -80,3 +123,50 @@ func TestStealingFromSlowerPeers(t *testing.T) {
},
})
}
func TestPeerKeepsExistingIfReasonable(t *testing.T) {
c := qt.New(t)
order := ClientPieceOrder{}
basePeer := Peer{
HasPiece: func(i pieceIndex) bool {
return true
},
MaxRequests: math.MaxInt16,
DownloadRate: 2,
}
// Slower than the stealers, but has all requests already.
stealee := basePeer
stealee.DownloadRate = 1
keepReq := r(0, 0)
stealee.HasExistingRequest = func(r Request) bool {
return r == keepReq
}
stealee.Id = intPeerId(1)
firstStealer := basePeer
firstStealer.Id = intPeerId(2)
secondStealer := basePeer
secondStealer.Id = intPeerId(3)
results := order.DoRequests([]*Torrent{{
Pieces: []Piece{{
Request: true,
NumPendingChunks: 4,
IterPendingChunks: chunkIter(0, 1, 3, 4),
}},
Peers: []Peer{
stealee,
firstStealer,
secondStealer,
},
}})
c.Assert(results, qt.HasLen, 3)
check := func(p PeerId, l int) {
c.Check(results[p].Requests, qt.HasLen, l)
c.Check(results[p].Interested, qt.Equals, l > 0)
}
check(firstStealer.Id, 2)
check(secondStealer.Id, 1)
c.Check(results[stealee.Id], qt.ContentEquals, PeerNextRequestState{
Interested: true,
Requests: requestSetFromSlice(keepReq),
})
}