11package piecepicker
22
33import (
4+ "math/rand"
45 "sort"
56
67 "github.com/cenkalti/rain/internal/peer"
@@ -16,21 +17,21 @@ type WebseedDownloadSpec struct {
1617
1718// PickWebseed returns the next spec for downloading files from webseed sources.
1819func (p * PiecePicker ) PickWebseed (src * webseedsource.WebseedSource ) * WebseedDownloadSpec {
19- begin , end := p .findPieceRangeForWebseed ()
20- if begin == end {
20+ r := p .findPieceRangeForWebseed ()
21+ if r == nil {
2122 return nil
2223 }
2324 // Mark selected range as being downloaded so we won't select it again.
24- for i := begin ; i < end ; i ++ {
25+ for i := r . Begin ; i < r . End ; i ++ {
2526 if p .pieces [i ].RequestedWebseed != nil {
2627 panic ("already downloading from webseed url" )
2728 }
2829 p .pieces [i ].RequestedWebseed = src
2930 }
3031 return & WebseedDownloadSpec {
3132 Source : src ,
32- Begin : begin ,
33- End : end ,
33+ Begin : r . Begin ,
34+ End : r . End ,
3435 }
3536}
3637
@@ -43,14 +44,24 @@ func (p *PiecePicker) downloadingWebseed() bool {
4344 return false
4445}
4546
46- func (p * PiecePicker ) findPieceRangeForWebseed () ( begin , end uint32 ) {
47+ func (p * PiecePicker ) findPieceRangeForWebseed () * Range {
4748 gaps := p .findGaps ()
4849 if len (gaps ) == 0 {
49- gap := p .webseedStealsFromAnotherWebseed ()
50- return gap .Begin , gap .End
50+ return p .webseedStealsFromAnotherWebseed ()
5151 }
52+ gap := selectRandomLargestGap (gaps )
53+ return & gap
54+ }
55+
56+ func selectRandomLargestGap (gaps []Range ) Range {
5257 sort .Slice (gaps , func (i , j int ) bool { return gaps [i ].Len () > gaps [j ].Len () })
53- return gaps [0 ].Begin , gaps [0 ].End
58+ length := gaps [0 ].Len ()
59+ for i := range gaps {
60+ if gaps [i ].Len () != length {
61+ return gaps [rand .Intn (i )]
62+ }
63+ }
64+ return gaps [rand .Intn (len (gaps ))]
5465}
5566
5667func (p * PiecePicker ) getDownloadingSources () []* webseedsource.WebseedSource {
@@ -63,17 +74,22 @@ func (p *PiecePicker) getDownloadingSources() []*webseedsource.WebseedSource {
6374 return ret
6475}
6576
66- func (p * PiecePicker ) webseedStealsFromAnotherWebseed () ( r Range ) {
77+ func (p * PiecePicker ) webseedStealsFromAnotherWebseed () * Range {
6778 downloading := p .getDownloadingSources ()
6879 if len (downloading ) == 0 {
69- return
80+ return nil
7081 }
7182 sort .Slice (downloading , func (i , j int ) bool { return downloading [i ].Remaining () > downloading [j ].Remaining () })
7283 src := downloading [0 ]
73- r .End = src .Downloader .End
74- r .Begin = (src .Downloader .ReadCurrent () + src .Downloader .End + 1 ) / 2
84+ r := & Range {
85+ Begin : (src .Downloader .ReadCurrent () + src .Downloader .End + 1 ) / 2 ,
86+ End : src .Downloader .End ,
87+ }
88+ if r .Begin >= r .End {
89+ return nil
90+ }
7591 p .WebseedStopAt (src , r .Begin )
76- return
92+ return r
7793}
7894
7995func (p * PiecePicker ) peerStealsFromWebseed (pe * peer.Peer ) * myPiece {
@@ -101,31 +117,23 @@ func (p *PiecePicker) peerStealsFromWebseed(pe *peer.Peer) *myPiece {
101117}
102118
103119func (p * PiecePicker ) findGaps () []Range {
104- gaps := p .findGapsWithDuplicate (false )
105- if len (gaps ) == 0 {
106- gaps = p .findGapsWithDuplicate (true )
107- }
108- return gaps
109- }
110-
111- func (p * PiecePicker ) findGapsWithDuplicate (duplicate bool ) []Range {
112120 a := make ([]Range , 0 , len (p .pieces )/ 2 )
113121 var inGap bool // See BEP19 for definition of "gap".
114122 var begin uint32
115123 for _ , pi := range p .pieces {
116124 if ! inGap {
117- if pi .AvailableForWebseed (duplicate ) {
125+ if pi .AvailableForWebseed () {
118126 begin = pi .Index
119127 inGap = true
120128 }
121129 } else {
122130 r := Range {Begin : begin , End : pi .Index }
123- if r .Len () == p .maxWebseedPieces {
124- a = append (a , r )
125- begin = pi .Index
126- } else if ! pi .AvailableForWebseed (duplicate ) {
131+ if ! pi .AvailableForWebseed () {
127132 a = append (a , r )
128133 inGap = false
134+ } else if r .Len () == p .maxWebseedPieces {
135+ a = append (a , r )
136+ begin = pi .Index
129137 }
130138 }
131139 }
0 commit comments