]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Merge branch 'master' of github.com:anacrolix/torrent
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "math/rand"
5         "sync"
6
7         pp "github.com/anacrolix/torrent/peer_protocol"
8 )
9
10 // Piece priority describes the importance of obtaining a particular piece.
11
12 type piecePriority byte
13
14 const (
15         PiecePriorityNone      piecePriority = iota // Not wanted.
16         PiecePriorityNormal                         // Wanted.
17         PiecePriorityReadahead                      // May be required soon.
18         PiecePriorityNext                           // Succeeds a piece where a read occurred.
19         PiecePriorityNow                            // A read occurred in this piece.
20 )
21
22 type piece struct {
23         Hash pieceSum // The completed piece SHA1 hash, from the metainfo "pieces" field.
24         // Chunks we don't have. The offset and length can be determined by the
25         // request chunkSize in use.
26         PendingChunkSpecs []bool
27         Hashing           bool
28         QueuedForHash     bool
29         EverHashed        bool
30         Event             sync.Cond
31         Priority          piecePriority
32 }
33
34 func (p *piece) pendingChunk(cs chunkSpec) bool {
35         if p.PendingChunkSpecs == nil {
36                 return false
37         }
38         return p.PendingChunkSpecs[chunkIndex(cs)]
39 }
40
41 func (p *piece) numPendingChunks() (ret int) {
42         for _, pending := range p.PendingChunkSpecs {
43                 if pending {
44                         ret++
45                 }
46         }
47         return
48 }
49
50 func (p *piece) unpendChunkIndex(i int) {
51         if p.PendingChunkSpecs == nil {
52                 return
53         }
54         p.PendingChunkSpecs[i] = false
55 }
56
57 func chunkIndexSpec(index int, pieceLength pp.Integer) chunkSpec {
58         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
59         if ret.Begin+ret.Length > pieceLength {
60                 ret.Length = pieceLength - ret.Begin
61         }
62         return ret
63 }
64
65 func (p *piece) shuffledPendingChunkSpecs(pieceLength pp.Integer) (css []chunkSpec) {
66         if p.numPendingChunks() == 0 {
67                 return
68         }
69         css = make([]chunkSpec, 0, p.numPendingChunks())
70         for i, pending := range p.PendingChunkSpecs {
71                 if pending {
72                         css = append(css, chunkIndexSpec(i, pieceLength))
73                 }
74         }
75         if len(css) <= 1 {
76                 return
77         }
78         for i := range css {
79                 j := rand.Intn(i + 1)
80                 css[i], css[j] = css[j], css[i]
81         }
82         return
83 }