2015-04-07 16:14:35 +00:00
|
|
|
package torrent
|
|
|
|
|
|
|
|
import (
|
|
|
|
"math/rand"
|
|
|
|
"sync"
|
2015-05-16 00:51:48 +00:00
|
|
|
|
|
|
|
pp "github.com/anacrolix/torrent/peer_protocol"
|
2015-04-07 16:14:35 +00:00
|
|
|
)
|
|
|
|
|
2015-06-01 08:17:14 +00:00
|
|
|
// Piece priority describes the importance of obtaining a particular piece.
|
|
|
|
|
2015-04-07 16:14:35 +00:00
|
|
|
type piecePriority byte
|
|
|
|
|
|
|
|
const (
|
2015-06-01 08:22:12 +00:00
|
|
|
PiecePriorityNone piecePriority = iota // Not wanted.
|
|
|
|
PiecePriorityNormal // Wanted.
|
|
|
|
PiecePriorityReadahead // May be required soon.
|
|
|
|
PiecePriorityNext // Succeeds a piece where a read occurred.
|
|
|
|
PiecePriorityNow // A read occurred in this piece.
|
2015-04-07 16:14:35 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type piece struct {
|
2015-06-16 06:57:47 +00:00
|
|
|
// The completed piece SHA1 hash, from the metainfo "pieces" field.
|
|
|
|
Hash pieceSum
|
2015-06-01 08:17:14 +00:00
|
|
|
// Chunks we don't have. The offset and length can be determined by the
|
2015-05-16 00:51:48 +00:00
|
|
|
// request chunkSize in use.
|
|
|
|
PendingChunkSpecs []bool
|
2015-04-07 16:14:35 +00:00
|
|
|
Hashing bool
|
|
|
|
QueuedForHash bool
|
|
|
|
EverHashed bool
|
|
|
|
Event sync.Cond
|
|
|
|
Priority piecePriority
|
|
|
|
}
|
|
|
|
|
2015-05-16 00:51:48 +00:00
|
|
|
func (p *piece) pendingChunk(cs chunkSpec) bool {
|
|
|
|
if p.PendingChunkSpecs == nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
return p.PendingChunkSpecs[chunkIndex(cs)]
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *piece) numPendingChunks() (ret int) {
|
|
|
|
for _, pending := range p.PendingChunkSpecs {
|
|
|
|
if pending {
|
|
|
|
ret++
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *piece) unpendChunkIndex(i int) {
|
|
|
|
if p.PendingChunkSpecs == nil {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
p.PendingChunkSpecs[i] = false
|
|
|
|
}
|
|
|
|
|
|
|
|
func chunkIndexSpec(index int, pieceLength pp.Integer) chunkSpec {
|
|
|
|
ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
|
|
|
|
if ret.Begin+ret.Length > pieceLength {
|
|
|
|
ret.Length = pieceLength - ret.Begin
|
|
|
|
}
|
|
|
|
return ret
|
|
|
|
}
|
|
|
|
|
|
|
|
func (p *piece) shuffledPendingChunkSpecs(pieceLength pp.Integer) (css []chunkSpec) {
|
|
|
|
if p.numPendingChunks() == 0 {
|
2015-04-07 16:14:35 +00:00
|
|
|
return
|
|
|
|
}
|
2015-05-16 00:51:48 +00:00
|
|
|
css = make([]chunkSpec, 0, p.numPendingChunks())
|
|
|
|
for i, pending := range p.PendingChunkSpecs {
|
|
|
|
if pending {
|
|
|
|
css = append(css, chunkIndexSpec(i, pieceLength))
|
|
|
|
}
|
2015-04-07 16:14:35 +00:00
|
|
|
}
|
|
|
|
if len(css) <= 1 {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
for i := range css {
|
|
|
|
j := rand.Intn(i + 1)
|
|
|
|
css[i], css[j] = css[j], css[i]
|
|
|
|
}
|
|
|
|
return
|
|
|
|
}
|