forked from anacrolix/torrent
/
piece.go
89 lines (77 loc) · 2.13 KB
/
piece.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
package torrent
import (
"math/rand"
"sync"
pp "github.com/anacrolix/torrent/peer_protocol"
)
// Piece priority describes the importance of obtaining a particular piece.
type piecePriority byte
const (
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.
)
type piece struct {
// The completed piece SHA1 hash, from the metainfo "pieces" field.
Hash pieceSum
// Chunks we don't have. The offset and length can be determined by the
// request chunkSize in use.
PendingChunkSpecs []bool
Hashing bool
QueuedForHash bool
EverHashed bool
Event sync.Cond
Priority piecePriority
PublicPieceState PieceState
pendingWritesMutex sync.Mutex
pendingWrites int
noPendingWrites sync.Cond
}
func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
if p.PendingChunkSpecs == nil {
return false
}
return p.PendingChunkSpecs[chunkIndex(cs, chunkSize)]
}
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, chunkSize 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, chunkSize pp.Integer) (css []chunkSpec) {
if p.numPendingChunks() == 0 {
return
}
css = make([]chunkSpec, 0, p.numPendingChunks())
for i, pending := range p.PendingChunkSpecs {
if pending {
css = append(css, chunkIndexSpec(i, pieceLength, chunkSize))
}
}
if len(css) <= 1 {
return
}
for i := range css {
j := rand.Intn(i + 1)
css[i], css[j] = css[j], css[i]
}
return
}