7 "github.com/anacrolix/missinggo/bitmap"
9 "github.com/anacrolix/torrent/metainfo"
10 pp "github.com/anacrolix/torrent/peer_protocol"
11 "github.com/anacrolix/torrent/storage"
14 // Describes the importance of obtaining a particular piece.
15 type piecePriority byte
17 func (pp *piecePriority) Raise(maybe piecePriority) bool {
25 // Priority for use in PriorityBitmap
26 func (me piecePriority) BitmapPriority() int {
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.
38 PiecePriorityNow // A Reader is reading in this piece. Highest urgency.
42 // The completed piece SHA1 hash, from the metainfo "pieces" field.
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
54 storageCompletionOk bool
56 publicPieceState PieceState
57 priority piecePriority
59 pendingWritesMutex sync.Mutex
61 noPendingWrites sync.Cond
64 func (p *Piece) String() string {
65 return fmt.Sprintf("%s/%d", p.t.infoHash.HexString(), p.index)
68 func (p *Piece) Info() metainfo.Piece {
69 return p.t.info.Piece(p.index)
72 func (p *Piece) Storage() storage.Piece {
73 return p.t.storage.Piece(p.Info())
76 func (p *Piece) pendingChunkIndex(chunkIndex int) bool {
77 return !p.dirtyChunks.Contains(chunkIndex)
80 func (p *Piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
81 return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
84 func (p *Piece) hasDirtyChunks() bool {
85 return p.dirtyChunks.Len() != 0
88 func (p *Piece) numDirtyChunks() (ret int) {
89 return p.dirtyChunks.Len()
92 func (p *Piece) unpendChunkIndex(i int) {
96 func (p *Piece) pendChunkIndex(i int) {
97 p.dirtyChunks.Remove(i)
100 func (p *Piece) numChunks() int {
101 return p.t.pieceNumChunks(p.index)
104 func (p *Piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
105 ret = p.dirtyChunks.Copy()
106 ret.FlipRange(0, p.numChunks())
110 func (p *Piece) incrementPendingWrites() {
111 p.pendingWritesMutex.Lock()
113 p.pendingWritesMutex.Unlock()
116 func (p *Piece) decrementPendingWrites() {
117 p.pendingWritesMutex.Lock()
118 if p.pendingWrites == 0 {
122 if p.pendingWrites == 0 {
123 p.noPendingWrites.Broadcast()
125 p.pendingWritesMutex.Unlock()
128 func (p *Piece) waitNoPendingWrites() {
129 p.pendingWritesMutex.Lock()
130 for p.pendingWrites != 0 {
131 p.noPendingWrites.Wait()
133 p.pendingWritesMutex.Unlock()
136 func (p *Piece) chunkIndexDirty(chunk int) bool {
137 return p.dirtyChunks.Contains(chunk)
140 func (p *Piece) chunkIndexSpec(chunk int) chunkSpec {
141 return chunkIndexSpec(chunk, p.length(), p.chunkSize())
144 func (p *Piece) numDirtyBytes() (ret pp.Integer) {
146 // if ret > p.length() {
147 // panic("too many dirty bytes")
150 numRegularDirtyChunks := p.numDirtyChunks()
151 if p.chunkIndexDirty(p.numChunks() - 1) {
152 numRegularDirtyChunks--
153 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
155 ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
159 func (p *Piece) length() pp.Integer {
160 return p.t.pieceLength(p.index)
163 func (p *Piece) chunkSize() pp.Integer {
167 func (p *Piece) lastChunkIndex() int {
168 return p.numChunks() - 1
171 func (p *Piece) bytesLeft() (ret pp.Integer) {
172 if p.t.pieceComplete(p.index) {
175 return p.length() - p.numDirtyBytes()
178 func (p *Piece) VerifyData() {
180 defer p.t.cl.mu.Unlock()
181 target := p.numVerifies + 1
185 // log.Printf("target: %d", target)
186 p.t.queuePieceCheck(p.index)
187 for p.numVerifies < target {
188 // log.Printf("got %d verifies", p.numVerifies)
194 func (p *Piece) queuedForHash() bool {
195 return p.t.piecesQueuedForHash.Get(p.index)
198 func (p *Piece) torrentBeginOffset() int64 {
199 return int64(p.index) * p.t.info.PieceLength
202 func (p *Piece) torrentEndOffset() int64 {
203 return p.torrentBeginOffset() + int64(p.length())
206 func (p *Piece) SetPriority(prio piecePriority) {
208 defer p.t.cl.mu.Unlock()
210 p.t.updatePiecePriority(p.index)
213 func (p *Piece) uncachedPriority() (ret piecePriority) {
214 if p.t.pieceComplete(p.index) {
215 return PiecePriorityNone
217 for _, f := range p.files {
220 if p.t.readerNowPieces.Contains(p.index) {
221 ret.Raise(PiecePriorityNow)
223 // if t.readerNowPieces.Contains(piece - 1) {
224 // return PiecePriorityNext
226 if p.t.readerReadaheadPieces.Contains(p.index) {
227 ret.Raise(PiecePriorityReadahead)
229 ret.Raise(p.priority)