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