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