]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Store chunk data without holding client lock
[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         pendingWrites     sync.WaitGroup
34 }
35
36 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
37         if p.PendingChunkSpecs == nil {
38                 return false
39         }
40         return p.PendingChunkSpecs[chunkIndex(cs, chunkSize)]
41 }
42
43 func (p *piece) numPendingChunks() (ret int) {
44         for _, pending := range p.PendingChunkSpecs {
45                 if pending {
46                         ret++
47                 }
48         }
49         return
50 }
51
52 func (p *piece) unpendChunkIndex(i int) {
53         if p.PendingChunkSpecs == nil {
54                 return
55         }
56         p.PendingChunkSpecs[i] = false
57 }
58
59 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
60         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
61         if ret.Begin+ret.Length > pieceLength {
62                 ret.Length = pieceLength - ret.Begin
63         }
64         return ret
65 }
66
67 func (p *piece) shuffledPendingChunkSpecs(pieceLength, chunkSize pp.Integer) (css []chunkSpec) {
68         if p.numPendingChunks() == 0 {
69                 return
70         }
71         css = make([]chunkSpec, 0, p.numPendingChunks())
72         for i, pending := range p.PendingChunkSpecs {
73                 if pending {
74                         css = append(css, chunkIndexSpec(i, pieceLength, chunkSize))
75                 }
76         }
77         if len(css) <= 1 {
78                 return
79         }
80         for i := range css {
81                 j := rand.Intn(i + 1)
82                 css[i], css[j] = css[j], css[i]
83         }
84         return
85 }