]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Apply staticcheck
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "fmt"
5         "sync"
6
7         "github.com/anacrolix/missinggo/v2/bitmap"
8
9         "github.com/anacrolix/torrent/metainfo"
10         pp "github.com/anacrolix/torrent/peer_protocol"
11         "github.com/anacrolix/torrent/storage"
12 )
13
14 // Describes the importance of obtaining a particular piece.
15 type piecePriority byte
16
17 func (pp *piecePriority) Raise(maybe piecePriority) bool {
18         if maybe > *pp {
19                 *pp = maybe
20                 return true
21         }
22         return false
23 }
24
25 // Priority for use in PriorityBitmap
26 func (me piecePriority) BitmapPriority() int {
27         return -int(me)
28 }
29
30 const (
31         PiecePriorityNone      piecePriority = iota // Not wanted. Must be the zero value.
32         PiecePriorityNormal                         // Wanted.
33         PiecePriorityHigh                           // Wanted a lot.
34         PiecePriorityReadahead                      // May be required soon.
35         // Succeeds a piece where a read occurred. Currently the same as Now,
36         // apparently due to issues with caching.
37         PiecePriorityNext
38         PiecePriorityNow // A Reader is reading in this piece. Highest urgency.
39 )
40
41 type Piece struct {
42         // The completed piece SHA1 hash, from the metainfo "pieces" field.
43         hash  *metainfo.Hash
44         t     *Torrent
45         index pieceIndex
46         files []*File
47         // Chunks we've written to since the last check. The chunk offset and
48         // length can be determined by the request chunkSize in use.
49         _dirtyChunks bitmap.Bitmap
50
51         hashing             bool
52         numVerifies         int64
53         storageCompletionOk bool
54
55         publicPieceState PieceState
56         priority         piecePriority
57
58         pendingWritesMutex sync.Mutex
59         pendingWrites      int
60         noPendingWrites    sync.Cond
61
62         // Connections that have written data to this piece since its last check.
63         // This can include connections that have closed.
64         dirtiers map[*connection]struct{}
65 }
66
67 func (p *Piece) String() string {
68         return fmt.Sprintf("%s/%d", p.t.infoHash.HexString(), p.index)
69 }
70
71 func (p *Piece) Info() metainfo.Piece {
72         return p.t.info.Piece(int(p.index))
73 }
74
75 func (p *Piece) Storage() storage.Piece {
76         return p.t.storage.Piece(p.Info())
77 }
78
79 func (p *Piece) pendingChunkIndex(chunkIndex int) bool {
80         return !p._dirtyChunks.Contains(chunkIndex)
81 }
82
83 func (p *Piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
84         return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
85 }
86
87 func (p *Piece) hasDirtyChunks() bool {
88         return p._dirtyChunks.Len() != 0
89 }
90
91 func (p *Piece) numDirtyChunks() pp.Integer {
92         return pp.Integer(p._dirtyChunks.Len())
93 }
94
95 func (p *Piece) unpendChunkIndex(i int) {
96         p._dirtyChunks.Add(i)
97         p.t.tickleReaders()
98 }
99
100 func (p *Piece) pendChunkIndex(i int) {
101         p._dirtyChunks.Remove(i)
102 }
103
104 func (p *Piece) numChunks() pp.Integer {
105         return p.t.pieceNumChunks(p.index)
106 }
107
108 func (p *Piece) incrementPendingWrites() {
109         p.pendingWritesMutex.Lock()
110         p.pendingWrites++
111         p.pendingWritesMutex.Unlock()
112 }
113
114 func (p *Piece) decrementPendingWrites() {
115         p.pendingWritesMutex.Lock()
116         if p.pendingWrites == 0 {
117                 panic("assertion")
118         }
119         p.pendingWrites--
120         if p.pendingWrites == 0 {
121                 p.noPendingWrites.Broadcast()
122         }
123         p.pendingWritesMutex.Unlock()
124 }
125
126 func (p *Piece) waitNoPendingWrites() {
127         p.pendingWritesMutex.Lock()
128         for p.pendingWrites != 0 {
129                 p.noPendingWrites.Wait()
130         }
131         p.pendingWritesMutex.Unlock()
132 }
133
134 func (p *Piece) chunkIndexDirty(chunk pp.Integer) bool {
135         return p._dirtyChunks.Contains(bitmap.BitIndex(chunk))
136 }
137
138 func (p *Piece) chunkIndexSpec(chunk pp.Integer) chunkSpec {
139         return chunkIndexSpec(chunk, p.length(), p.chunkSize())
140 }
141
142 func (p *Piece) chunkIndexRequest(chunkIndex pp.Integer) request {
143         return request{
144                 pp.Integer(p.index),
145                 chunkIndexSpec(chunkIndex, p.length(), p.chunkSize()),
146         }
147 }
148
149 func (p *Piece) numDirtyBytes() (ret pp.Integer) {
150         // defer func() {
151         //      if ret > p.length() {
152         //              panic("too many dirty bytes")
153         //      }
154         // }()
155         numRegularDirtyChunks := p.numDirtyChunks()
156         if p.chunkIndexDirty(p.numChunks() - 1) {
157                 numRegularDirtyChunks--
158                 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
159         }
160         ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
161         return
162 }
163
164 func (p *Piece) length() pp.Integer {
165         return p.t.pieceLength(p.index)
166 }
167
168 func (p *Piece) chunkSize() pp.Integer {
169         return p.t.chunkSize
170 }
171
172 func (p *Piece) lastChunkIndex() pp.Integer {
173         return p.numChunks() - 1
174 }
175
176 func (p *Piece) bytesLeft() (ret pp.Integer) {
177         if p.t.pieceComplete(p.index) {
178                 return 0
179         }
180         return p.length() - p.numDirtyBytes()
181 }
182
183 // Forces the piece data to be rehashed.
184 func (p *Piece) VerifyData() {
185         p.t.cl.lock()
186         defer p.t.cl.unlock()
187         target := p.numVerifies + 1
188         if p.hashing {
189                 target++
190         }
191         //log.Printf("target: %d", target)
192         p.t.queuePieceCheck(p.index)
193         for {
194                 //log.Printf("got %d verifies", p.numVerifies)
195                 if p.numVerifies >= target {
196                         break
197                 }
198                 p.t.cl.event.Wait()
199         }
200         // log.Print("done")
201 }
202
203 func (p *Piece) queuedForHash() bool {
204         return p.t.piecesQueuedForHash.Get(bitmap.BitIndex(p.index))
205 }
206
207 func (p *Piece) torrentBeginOffset() int64 {
208         return int64(p.index) * p.t.info.PieceLength
209 }
210
211 func (p *Piece) torrentEndOffset() int64 {
212         return p.torrentBeginOffset() + int64(p.length())
213 }
214
215 func (p *Piece) SetPriority(prio piecePriority) {
216         p.t.cl.lock()
217         defer p.t.cl.unlock()
218         p.priority = prio
219         p.t.updatePiecePriority(p.index)
220 }
221
222 func (p *Piece) uncachedPriority() (ret piecePriority) {
223         if p.t.pieceComplete(p.index) || p.t.pieceQueuedForHash(p.index) || p.t.hashingPiece(p.index) {
224                 return PiecePriorityNone
225         }
226         for _, f := range p.files {
227                 ret.Raise(f.prio)
228         }
229         if p.t.readerNowPieces().Contains(int(p.index)) {
230                 ret.Raise(PiecePriorityNow)
231         }
232         // if t._readerNowPieces.Contains(piece - 1) {
233         //      return PiecePriorityNext
234         // }
235         if p.t.readerReadaheadPieces().Contains(bitmap.BitIndex(p.index)) {
236                 ret.Raise(PiecePriorityReadahead)
237         }
238         ret.Raise(p.priority)
239         return
240 }
241
242 func (p *Piece) completion() (ret storage.Completion) {
243         ret.Complete = p.t.pieceComplete(p.index)
244         ret.Ok = p.storageCompletionOk
245         return
246 }
247
248 func (p *Piece) allChunksDirty() bool {
249         return p._dirtyChunks.Len() == int(p.numChunks())
250 }
251
252 func (p *Piece) requestStrategyPiece() requestStrategyPiece {
253         return p
254 }
255
256 func (p *Piece) dirtyChunks() bitmap.Bitmap {
257         return p._dirtyChunks
258 }