torrent/piece.go

176 lines
3.8 KiB
Go
Raw Normal View History

2015-04-07 16:14:35 +00:00
package torrent
import (
"sync"
"github.com/anacrolix/missinggo/bitmap"
2016-03-28 09:38:30 +00:00
"github.com/anacrolix/torrent/metainfo"
pp "github.com/anacrolix/torrent/peer_protocol"
2016-03-28 09:38:30 +00:00
"github.com/anacrolix/torrent/storage"
2015-04-07 16:14:35 +00:00
)
2015-06-01 08:17:14 +00:00
// Piece priority describes the importance of obtaining a particular piece.
2015-04-07 16:14:35 +00:00
type piecePriority byte
func (pp *piecePriority) Raise(maybe piecePriority) {
if maybe > *pp {
*pp = maybe
}
}
2015-04-07 16:14:35 +00:00
const (
PiecePriorityNone piecePriority = iota // Not wanted.
PiecePriorityNormal // Wanted.
PiecePriorityReadahead // May be required soon.
2016-08-30 06:55:50 +00:00
// Succeeds a piece where a read occurred. Currently the same as Now, apparently due to issues with caching.
PiecePriorityNext
PiecePriorityNow // A Reader is reading in this piece.
2015-04-07 16:14:35 +00:00
)
type piece struct {
2015-06-16 06:57:47 +00:00
// The completed piece SHA1 hash, from the metainfo "pieces" field.
Hash metainfo.Hash
2016-04-03 08:40:43 +00:00
t *Torrent
index int
// Chunks we've written to since the last check. The chunk offset and
// length can be determined by the request chunkSize in use.
DirtyChunks bitmap.Bitmap
Hashing bool
QueuedForHash bool
EverHashed bool
numVerifies int64
PublicPieceState PieceState
priority piecePriority
pendingWritesMutex sync.Mutex
pendingWrites int
noPendingWrites sync.Cond
2015-04-07 16:14:35 +00:00
}
2016-03-28 09:38:30 +00:00
func (p *piece) Info() metainfo.Piece {
return p.t.info.Piece(p.index)
2016-03-28 09:38:30 +00:00
}
func (p *piece) Storage() storage.Piece {
return p.t.storage.Piece(p.Info())
}
func (p *piece) pendingChunkIndex(chunkIndex int) bool {
return !p.DirtyChunks.Contains(chunkIndex)
}
func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
}
2016-02-04 14:18:54 +00:00
func (p *piece) hasDirtyChunks() bool {
return p.DirtyChunks.Len() != 0
2016-02-04 14:18:54 +00:00
}
func (p *piece) numDirtyChunks() (ret int) {
return p.DirtyChunks.Len()
}
func (p *piece) unpendChunkIndex(i int) {
p.DirtyChunks.Add(i)
}
func (p *piece) pendChunkIndex(i int) {
p.DirtyChunks.Remove(i)
}
func (p *piece) numChunks() int {
return p.t.pieceNumChunks(p.index)
}
func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
ret = p.DirtyChunks.Copy()
ret.FlipRange(0, p.numChunks())
2015-04-07 16:14:35 +00:00
return
}
2016-01-24 20:22:33 +00:00
func (p *piece) incrementPendingWrites() {
p.pendingWritesMutex.Lock()
p.pendingWrites++
p.pendingWritesMutex.Unlock()
}
func (p *piece) decrementPendingWrites() {
p.pendingWritesMutex.Lock()
if p.pendingWrites == 0 {
panic("assertion")
}
p.pendingWrites--
if p.pendingWrites == 0 {
p.noPendingWrites.Broadcast()
}
p.pendingWritesMutex.Unlock()
}
func (p *piece) waitNoPendingWrites() {
p.pendingWritesMutex.Lock()
for p.pendingWrites != 0 {
p.noPendingWrites.Wait()
}
p.pendingWritesMutex.Unlock()
}
func (p *piece) chunkIndexDirty(chunk int) bool {
return p.DirtyChunks.Contains(chunk)
}
func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
return chunkIndexSpec(chunk, p.length(), p.chunkSize())
}
func (p *piece) numDirtyBytes() (ret pp.Integer) {
defer func() {
if ret > p.length() {
panic("too many dirty bytes")
}
}()
numRegularDirtyChunks := p.numDirtyChunks()
if p.chunkIndexDirty(p.numChunks() - 1) {
numRegularDirtyChunks--
ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
}
ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
return
}
func (p *piece) length() pp.Integer {
return p.t.pieceLength(p.index)
}
func (p *piece) chunkSize() pp.Integer {
return p.t.chunkSize
}
func (p *piece) lastChunkIndex() int {
return p.numChunks() - 1
}
func (p *piece) bytesLeft() (ret pp.Integer) {
if p.t.pieceComplete(p.index) {
return 0
}
return p.length() - p.numDirtyBytes()
}
func (p *piece) VerifyData() {
p.t.cl.mu.Lock()
defer p.t.cl.mu.Unlock()
target := p.numVerifies + 1
if p.Hashing {
target++
}
p.t.queuePieceCheck(p.index)
for p.numVerifies < target {
p.t.cl.event.Wait()
}
}