2015-04-08 00:14:35 +08:00
|
|
|
package torrent
|
|
|
|
|
|
|
|
import (
|
|
|
|
"sync"
|
2015-05-16 08:51:48 +08:00
|
|
|
|
2016-02-05 12:45:32 +08:00
|
|
|
"github.com/anacrolix/missinggo/bitmap"
|
2016-01-13 14:11:59 +08:00
|
|
|
|
2016-03-28 17:38:30 +08:00
|
|
|
"github.com/anacrolix/torrent/metainfo"
|
2015-05-16 08:51:48 +08:00
|
|
|
pp "github.com/anacrolix/torrent/peer_protocol"
|
2016-03-28 17:38:30 +08:00
|
|
|
"github.com/anacrolix/torrent/storage"
|
2015-04-08 00:14:35 +08:00
|
|
|
)
|
|
|
|
|
2015-06-01 16:17:14 +08:00
|
|
|
// Piece priority describes the importance of obtaining a particular piece.
|
|
|
|
|
2015-04-08 00:14:35 +08:00
|
|
|
type piecePriority byte
|
|
|
|
|
2016-04-19 12:11:11 +08:00
|
|
|
func (pp *piecePriority) Raise(maybe piecePriority) {
|
|
|
|
if maybe > *pp {
|
|
|
|
*pp = maybe
|
2016-02-01 19:06:13 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-04-08 00:14:35 +08:00
|
|
|
const (
|
2015-06-01 16:22:12 +08:00
|
|
|
PiecePriorityNone piecePriority = iota // Not wanted.
|
|
|
|
PiecePriorityNormal // Wanted.
|
|
|
|
PiecePriorityReadahead // May be required soon.
|
|
|
|
PiecePriorityNext // Succeeds a piece where a read occurred.
|
|
|
|
PiecePriorityNow // A read occurred in this piece.
|
2015-04-08 00:14:35 +08:00
|
|
|
)
|
|
|
|
|
|
|
|
type piece struct {
|
2015-06-16 14:57:47 +08:00
|
|
|
// The completed piece SHA1 hash, from the metainfo "pieces" field.
|
2016-04-04 11:01:31 +08:00
|
|
|
Hash metainfo.Hash
|
2016-04-03 16:40:43 +08:00
|
|
|
t *Torrent
|
2016-02-07 18:58:48 +08:00
|
|
|
index int
|
2016-01-13 14:11:59 +08:00
|
|
|
// Chunks we've written to since the last check. The chunk offset and
|
|
|
|
// length can be determined by the request chunkSize in use.
|
2016-02-05 12:45:32 +08:00
|
|
|
DirtyChunks bitmap.Bitmap
|
2016-01-13 14:11:59 +08:00
|
|
|
Hashing bool
|
|
|
|
QueuedForHash bool
|
|
|
|
EverHashed bool
|
|
|
|
PublicPieceState PieceState
|
2016-02-01 18:11:41 +08:00
|
|
|
priority piecePriority
|
2015-08-05 00:40:46 +08:00
|
|
|
|
|
|
|
pendingWritesMutex sync.Mutex
|
|
|
|
pendingWrites int
|
|
|
|
noPendingWrites sync.Cond
|
2015-04-08 00:14:35 +08:00
|
|
|
}
|
|
|
|
|
2016-03-28 17:38:30 +08:00
|
|
|
func (p *piece) Info() metainfo.Piece {
|
2016-04-03 14:50:53 +08:00
|
|
|
return p.t.info.Piece(p.index)
|
2016-03-28 17:38:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *piece) Storage() storage.Piece {
|
|
|
|
return p.t.storage.Piece(p.Info())
|
|
|
|
}
|
|
|
|
|
2016-02-05 12:45:32 +08:00
|
|
|
func (p *piece) pendingChunkIndex(chunkIndex int) bool {
|
|
|
|
return !p.DirtyChunks.Contains(chunkIndex)
|
|
|
|
}
|
|
|
|
|
2015-07-15 13:31:18 +08:00
|
|
|
func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
|
2016-02-05 12:45:32 +08:00
|
|
|
return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
|
2015-05-16 08:51:48 +08:00
|
|
|
}
|
|
|
|
|
2016-02-04 22:18:54 +08:00
|
|
|
func (p *piece) hasDirtyChunks() bool {
|
2016-02-05 12:45:32 +08:00
|
|
|
return p.DirtyChunks.Len() != 0
|
2016-02-04 22:18:54 +08:00
|
|
|
}
|
|
|
|
|
2016-01-13 14:11:59 +08:00
|
|
|
func (p *piece) numDirtyChunks() (ret int) {
|
2016-02-05 12:45:32 +08:00
|
|
|
return p.DirtyChunks.Len()
|
2015-05-16 08:51:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
func (p *piece) unpendChunkIndex(i int) {
|
2016-02-05 12:45:32 +08:00
|
|
|
p.DirtyChunks.Add(i)
|
2015-05-16 08:51:48 +08:00
|
|
|
}
|
|
|
|
|
2016-01-28 02:54:48 +08:00
|
|
|
func (p *piece) pendChunkIndex(i int) {
|
2016-02-05 12:45:32 +08:00
|
|
|
p.DirtyChunks.Remove(i)
|
2016-01-28 02:54:48 +08:00
|
|
|
}
|
|
|
|
|
2016-02-07 18:58:48 +08:00
|
|
|
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-08 00:14:35 +08:00
|
|
|
return
|
|
|
|
}
|
2016-01-25 04:22:33 +08: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()
|
|
|
|
}
|
2016-03-22 10:11:36 +08:00
|
|
|
|
|
|
|
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()
|
|
|
|
}
|