client.go | 6 ++++-- misc.go | 15 ++++++++++++++- torrent.go | 4 ++++ diff --git a/client.go b/client.go index e079881ab2b66d06cde800fc70cd49e21715dcee..e86a93a96df412566210be74e4eecd7675ba51d8 100644 --- a/client.go +++ b/client.go @@ -819,8 +819,10 @@ // Stop when we're onto untouched pieces. if t.PieceNumPendingBytes(index) == t.PieceLength(index) { break } - for chunkSpec := range t.Pieces[index].PendingChunkSpecs { - if !c.Request(request{index, chunkSpec}) { + // Request chunks in random order to reduce overlap with other + // connections. + for _, cs := range t.Pieces[index].shuffledPendingChunkSpecs() { + if !c.Request(request{index, cs}) { return } } diff --git a/misc.go b/misc.go index 2e5f02bb8a24c0c86fb3baae343ba06ea4c8cd5e..c53976fab111780ed960fa0e54e983c2b46c78ed 100644 --- a/misc.go +++ b/misc.go @@ -4,6 +4,7 @@ import ( "bitbucket.org/anacrolix/go.torrent/mmap_span" "crypto" "errors" + "math/rand" "os" "path/filepath" "time" @@ -15,7 +16,7 @@ ) const ( pieceHash = crypto.SHA1 - maxRequests = 250 // Maximum pending requests we allow peers to send us. + maxRequests = 250 // Maximum pending requests we allow peers to send us. chunkSize = 0x4000 // 16KiB BEP20 = "-GT0000-" // Peer ID client identifier prefix dialTimeout = time.Second * 15 @@ -44,6 +45,18 @@ PendingChunkSpecs map[chunkSpec]struct{} Hashing bool QueuedForHash bool EverHashed bool +} + +func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) { + css = make([]chunkSpec, 0, len(p.PendingChunkSpecs)) + for cs := range p.PendingChunkSpecs { + css = append(css, cs) + } + for i := range css { + j := rand.Intn(i + 1) + css[i], css[j] = css[j], css[i] + } + return } func (p *piece) Complete() bool { diff --git a/torrent.go b/torrent.go index dfe2431433e109cbda4dcc2114148f37704a5e63..cbb4cd3221cf9494eb158f57dfbb9fa70e6d067c 100644 --- a/torrent.go +++ b/torrent.go @@ -59,6 +59,10 @@ num += NumChunksForPiece(chunkSize, int(t.PieceLength(pp.Integer(t.NumPieces()-1)))) return } +func (t *torrent) UsualPieceSize() int { + return int(t.MetaInfo.PieceLength) +} + func (t *torrent) LastPieceSize() int { return int(t.PieceLength(pp.Integer(t.NumPieces() - 1))) }