]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Merge pull request #9 from gitter-badger/gitter-badge
[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         // The completed piece SHA1 hash, from the metainfo "pieces" field.
24         Hash pieceSum
25         // Chunks we don't have. The offset and length can be determined by the
26         // request chunkSize in use.
27         PendingChunkSpecs []bool
28         Hashing           bool
29         QueuedForHash     bool
30         EverHashed        bool
31         Event             sync.Cond
32         Priority          piecePriority
33 }
34
35 func (p *piece) pendingChunk(cs chunkSpec) bool {
36         if p.PendingChunkSpecs == nil {
37                 return false
38         }
39         return p.PendingChunkSpecs[chunkIndex(cs)]
40 }
41
42 func (p *piece) numPendingChunks() (ret int) {
43         for _, pending := range p.PendingChunkSpecs {
44                 if pending {
45                         ret++
46                 }
47         }
48         return
49 }
50
51 func (p *piece) unpendChunkIndex(i int) {
52         if p.PendingChunkSpecs == nil {
53                 return
54         }
55         p.PendingChunkSpecs[i] = false
56 }
57
58 func chunkIndexSpec(index int, pieceLength pp.Integer) chunkSpec {
59         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
60         if ret.Begin+ret.Length > pieceLength {
61                 ret.Length = pieceLength - ret.Begin
62         }
63         return ret
64 }
65
66 func (p *piece) shuffledPendingChunkSpecs(pieceLength pp.Integer) (css []chunkSpec) {
67         if p.numPendingChunks() == 0 {
68                 return
69         }
70         css = make([]chunkSpec, 0, p.numPendingChunks())
71         for i, pending := range p.PendingChunkSpecs {
72                 if pending {
73                         css = append(css, chunkIndexSpec(i, pieceLength))
74                 }
75         }
76         if len(css) <= 1 {
77                 return
78         }
79         for i := range css {
80                 j := rand.Intn(i + 1)
81                 css[i], css[j] = css[j], css[i]
82         }
83         return
84 }