8 "github.com/anacrolix/missinggo/bitmap"
10 "github.com/anacrolix/torrent/metainfo"
11 pp "github.com/anacrolix/torrent/peer_protocol"
12 "github.com/anacrolix/torrent/storage"
15 // Piece priority describes the importance of obtaining a particular piece.
17 type piecePriority byte
19 func (pp *piecePriority) Raise(maybe piecePriority) {
26 PiecePriorityNone piecePriority = iota // Not wanted.
27 PiecePriorityNormal // Wanted.
28 PiecePriorityReadahead // May be required soon.
29 // Succeeds a piece where a read occurred. Currently the same as Now, apparently due to issues with caching.
31 PiecePriorityNow // A Reader is reading in this piece.
35 // The completed piece SHA1 hash, from the metainfo "pieces" field.
39 // Chunks we've written to since the last check. The chunk offset and
40 // length can be determined by the request chunkSize in use.
41 dirtyChunks bitmap.Bitmap
46 storageCompletionOk bool
48 publicPieceState PieceState
49 priority piecePriority
51 pendingWritesMutex sync.Mutex
53 noPendingWrites sync.Cond
56 func (p *Piece) String() string {
57 return fmt.Sprintf("%s/%d", p.t.infoHash.HexString(), p.index)
60 func (p *Piece) Info() metainfo.Piece {
61 return p.t.info.Piece(p.index)
64 func (p *Piece) Storage() storage.Piece {
65 return p.t.storage.Piece(p.Info())
68 func (p *Piece) pendingChunkIndex(chunkIndex int) bool {
69 return !p.dirtyChunks.Contains(chunkIndex)
72 func (p *Piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
73 return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
76 func (p *Piece) hasDirtyChunks() bool {
77 return p.dirtyChunks.Len() != 0
80 func (p *Piece) numDirtyChunks() (ret int) {
81 return p.dirtyChunks.Len()
84 func (p *Piece) unpendChunkIndex(i int) {
88 func (p *Piece) pendChunkIndex(i int) {
89 p.dirtyChunks.Remove(i)
92 func (p *Piece) numChunks() int {
93 return p.t.pieceNumChunks(p.index)
96 func (p *Piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
97 ret = p.dirtyChunks.Copy()
98 ret.FlipRange(0, p.numChunks())
102 func (p *Piece) incrementPendingWrites() {
103 p.pendingWritesMutex.Lock()
105 p.pendingWritesMutex.Unlock()
108 func (p *Piece) decrementPendingWrites() {
109 p.pendingWritesMutex.Lock()
110 if p.pendingWrites == 0 {
114 if p.pendingWrites == 0 {
115 p.noPendingWrites.Broadcast()
117 p.pendingWritesMutex.Unlock()
120 func (p *Piece) waitNoPendingWrites() {
121 p.pendingWritesMutex.Lock()
122 for p.pendingWrites != 0 {
123 p.noPendingWrites.Wait()
125 p.pendingWritesMutex.Unlock()
128 func (p *Piece) chunkIndexDirty(chunk int) bool {
129 return p.dirtyChunks.Contains(chunk)
132 func (p *Piece) chunkIndexSpec(chunk int) chunkSpec {
133 return chunkIndexSpec(chunk, p.length(), p.chunkSize())
136 func (p *Piece) numDirtyBytes() (ret pp.Integer) {
138 // if ret > p.length() {
139 // panic("too many dirty bytes")
142 numRegularDirtyChunks := p.numDirtyChunks()
143 if p.chunkIndexDirty(p.numChunks() - 1) {
144 numRegularDirtyChunks--
145 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
147 ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
151 func (p *Piece) length() pp.Integer {
152 return p.t.pieceLength(p.index)
155 func (p *Piece) chunkSize() pp.Integer {
159 func (p *Piece) lastChunkIndex() int {
160 return p.numChunks() - 1
163 func (p *Piece) bytesLeft() (ret pp.Integer) {
164 if p.t.pieceComplete(p.index) {
167 return p.length() - p.numDirtyBytes()
170 func (p *Piece) VerifyData() {
172 defer p.t.cl.mu.Unlock()
173 target := p.numVerifies + 1
177 log.Printf("target: %d", target)
178 p.t.queuePieceCheck(p.index)
179 for p.numVerifies < target {
180 log.Printf("got %d verifies", p.numVerifies)
186 func (p *Piece) queuedForHash() bool {
187 return p.t.piecesQueuedForHash.Get(p.index)