]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Tidy up bytesLeft calculations
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "sync"
5
6         "github.com/anacrolix/missinggo/bitmap"
7
8         pp "github.com/anacrolix/torrent/peer_protocol"
9 )
10
11 // Piece priority describes the importance of obtaining a particular piece.
12
13 type piecePriority byte
14
15 func (me *piecePriority) Raise(maybe piecePriority) {
16         if maybe > *me {
17                 *me = maybe
18         }
19 }
20
21 const (
22         PiecePriorityNone      piecePriority = iota // Not wanted.
23         PiecePriorityNormal                         // Wanted.
24         PiecePriorityReadahead                      // May be required soon.
25         PiecePriorityNext                           // Succeeds a piece where a read occurred.
26         PiecePriorityNow                            // A read occurred in this piece.
27 )
28
29 type piece struct {
30         // The completed piece SHA1 hash, from the metainfo "pieces" field.
31         Hash  pieceSum
32         t     *torrent
33         index int
34         // Chunks we've written to since the last check. The chunk offset and
35         // length can be determined by the request chunkSize in use.
36         DirtyChunks      bitmap.Bitmap
37         Hashing          bool
38         QueuedForHash    bool
39         EverHashed       bool
40         PublicPieceState PieceState
41         priority         piecePriority
42
43         pendingWritesMutex sync.Mutex
44         pendingWrites      int
45         noPendingWrites    sync.Cond
46 }
47
48 func (p *piece) pendingChunkIndex(chunkIndex int) bool {
49         return !p.DirtyChunks.Contains(chunkIndex)
50 }
51
52 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
53         return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
54 }
55
56 func (p *piece) hasDirtyChunks() bool {
57         return p.DirtyChunks.Len() != 0
58 }
59
60 func (p *piece) numDirtyChunks() (ret int) {
61         return p.DirtyChunks.Len()
62 }
63
64 func (p *piece) unpendChunkIndex(i int) {
65         p.DirtyChunks.Add(i)
66 }
67
68 func (p *piece) pendChunkIndex(i int) {
69         p.DirtyChunks.Remove(i)
70 }
71
72 func (p *piece) numChunks() int {
73         return p.t.pieceNumChunks(p.index)
74 }
75
76 func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
77         ret = p.DirtyChunks.Copy()
78         ret.FlipRange(0, p.numChunks())
79         return
80 }
81
82 func (p *piece) incrementPendingWrites() {
83         p.pendingWritesMutex.Lock()
84         p.pendingWrites++
85         p.pendingWritesMutex.Unlock()
86 }
87
88 func (p *piece) decrementPendingWrites() {
89         p.pendingWritesMutex.Lock()
90         if p.pendingWrites == 0 {
91                 panic("assertion")
92         }
93         p.pendingWrites--
94         if p.pendingWrites == 0 {
95                 p.noPendingWrites.Broadcast()
96         }
97         p.pendingWritesMutex.Unlock()
98 }
99
100 func (p *piece) waitNoPendingWrites() {
101         p.pendingWritesMutex.Lock()
102         for p.pendingWrites != 0 {
103                 p.noPendingWrites.Wait()
104         }
105         p.pendingWritesMutex.Unlock()
106 }
107
108 func (p *piece) chunkIndexDirty(chunk int) bool {
109         return p.DirtyChunks.Contains(chunk)
110 }
111
112 func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
113         return chunkIndexSpec(chunk, p.length(), p.chunkSize())
114 }
115
116 func (p *piece) numDirtyBytes() (ret pp.Integer) {
117         defer func() {
118                 if ret > p.length() {
119                         panic("too many dirty bytes")
120                 }
121         }()
122         numRegularDirtyChunks := p.numDirtyChunks()
123         if p.chunkIndexDirty(p.numChunks() - 1) {
124                 numRegularDirtyChunks--
125                 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
126         }
127         ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
128         return
129 }
130
131 func (p *piece) length() pp.Integer {
132         return p.t.pieceLength(p.index)
133 }
134
135 func (p *piece) chunkSize() pp.Integer {
136         return p.t.chunkSize
137 }
138
139 func (p *piece) lastChunkIndex() int {
140         return p.numChunks() - 1
141 }
142
143 func (p *piece) bytesLeft() (ret pp.Integer) {
144         if p.t.pieceComplete(p.index) {
145                 return 0
146         }
147         return p.length() - p.numDirtyBytes()
148 }