6 "github.com/anacrolix/missinggo/bitmap"
8 pp "github.com/anacrolix/torrent/peer_protocol"
11 // Piece priority describes the importance of obtaining a particular piece.
13 type piecePriority byte
15 func (me *piecePriority) Raise(maybe piecePriority) {
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.
30 // The completed piece SHA1 hash, from the metainfo "pieces" field.
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
40 PublicPieceState PieceState
41 priority piecePriority
43 pendingWritesMutex sync.Mutex
45 noPendingWrites sync.Cond
48 func (p *piece) pendingChunkIndex(chunkIndex int) bool {
49 return !p.DirtyChunks.Contains(chunkIndex)
52 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
53 return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
56 func (p *piece) hasDirtyChunks() bool {
57 return p.DirtyChunks.Len() != 0
60 func (p *piece) numDirtyChunks() (ret int) {
61 return p.DirtyChunks.Len()
64 func (p *piece) unpendChunkIndex(i int) {
68 func (p *piece) pendChunkIndex(i int) {
69 p.DirtyChunks.Remove(i)
72 func (p *piece) numChunks() int {
73 return p.t.pieceNumChunks(p.index)
76 func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
77 ret = p.DirtyChunks.Copy()
78 ret.FlipRange(0, p.numChunks())
82 func (p *piece) incrementPendingWrites() {
83 p.pendingWritesMutex.Lock()
85 p.pendingWritesMutex.Unlock()
88 func (p *piece) decrementPendingWrites() {
89 p.pendingWritesMutex.Lock()
90 if p.pendingWrites == 0 {
94 if p.pendingWrites == 0 {
95 p.noPendingWrites.Broadcast()
97 p.pendingWritesMutex.Unlock()
100 func (p *piece) waitNoPendingWrites() {
101 p.pendingWritesMutex.Lock()
102 for p.pendingWrites != 0 {
103 p.noPendingWrites.Wait()
105 p.pendingWritesMutex.Unlock()
108 func (p *piece) chunkIndexDirty(chunk int) bool {
109 return p.DirtyChunks.Contains(chunk)
112 func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
113 return chunkIndexSpec(chunk, p.length(), p.chunkSize())
116 func (p *piece) numDirtyBytes() (ret pp.Integer) {
118 if ret > p.length() {
119 panic("too many dirty bytes")
122 numRegularDirtyChunks := p.numDirtyChunks()
123 if p.chunkIndexDirty(p.numChunks() - 1) {
124 numRegularDirtyChunks--
125 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
127 ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
131 func (p *piece) length() pp.Integer {
132 return p.t.pieceLength(p.index)
135 func (p *piece) chunkSize() pp.Integer {
139 func (p *piece) lastChunkIndex() int {
140 return p.numChunks() - 1
143 func (p *piece) bytesLeft() (ret pp.Integer) {
144 if p.t.pieceComplete(p.index) {
147 return p.length() - p.numDirtyBytes()