return nil
}
-func (cl *Client) startTorrent(t *torrent) {
- if t.Info == nil || t.data == nil {
- panic("nope")
- }
- // If the client intends to upload, it needs to know what state pieces are
- // in.
- if !cl.config.NoUpload {
- // Queue all pieces for hashing. This is done sequentially to avoid
- // spamming goroutines.
- for i := range t.Pieces {
- t.Pieces[i].QueuedForHash = true
- }
- go func() {
- for i := range t.Pieces {
- cl.verifyPiece(t, i)
- }
- }()
- }
-}
-
-// Storage cannot be changed once it's set.
func (cl *Client) setStorage(t *torrent, td Data) (err error) {
- err = t.setStorage(td)
+ t.setStorage(td)
cl.event.Broadcast()
- if err != nil {
- return
- }
- cl.startTorrent(t)
return
}
log.Printf("%T: error completing piece %d: %s", t.data, piece, err)
correct = false
}
+ t.updatePieceCompletion(piece)
} else if len(touchers) != 0 {
log.Printf("dropping %d conns that touched piece", len(touchers))
for _, c := range touchers {
"github.com/anacrolix/missinggo/itertools"
"github.com/anacrolix/missinggo/perf"
"github.com/anacrolix/missinggo/pubsub"
- "github.com/bradfitz/iter"
"github.com/anacrolix/torrent/bencode"
"github.com/anacrolix/torrent/metainfo"
readers map[*Reader]struct{}
- pendingPieces bitmap.Bitmap
+ pendingPieces bitmap.Bitmap
+ completedPieces bitmap.Bitmap
connPieceInclinationPool sync.Pool
}
}
func (t *torrent) pieceComplete(piece int) bool {
+ return t.completedPieces.Get(piece)
+}
+
+func (t *torrent) pieceCompleteUncached(piece int) bool {
// TODO: This is called when setting metadata, and before storage is
// assigned, which doesn't seem right.
return t.data != nil && t.data.PieceComplete(piece)
return
}
-func (t *torrent) setStorage(td Data) (err error) {
+func (t *torrent) setStorage(td Data) {
if t.data != nil {
t.data.Close()
}
t.data = td
- return
+ t.completedPieces.Clear()
+ for i := range t.Pieces {
+ t.Pieces[i].QueuedForHash = true
+ }
+ go func() {
+ for i := range t.Pieces {
+ t.verifyPiece(i)
+ }
+ }()
+}
+
+func (t *torrent) verifyPiece(piece int) {
+ t.cl.verifyPiece(t, piece)
}
func (t *torrent) haveAllMetadataPieces() bool {
}
func (t *torrent) numPiecesCompleted() (num int) {
- for i := range iter.N(t.Info.NumPieces()) {
- if t.pieceComplete(i) {
- num++
- }
- }
- return
+ return t.completedPieces.Len()
}
func (t *torrent) isClosed() bool {
}
func (t *torrent) bitfield() (bf []bool) {
- for i := range t.Pieces {
- bf = append(bf, t.havePiece(i))
- }
+ bf = make([]bool, t.numPieces())
+ t.completedPieces.IterTyped(func(piece int) (again bool) {
+ bf[piece] = true
+ return true
+ })
return
}
if !t.haveInfo() {
return false
}
- for i := range t.Pieces {
- if !t.pieceComplete(i) {
- return false
- }
- }
- return true
+ return t.completedPieces.Len() == t.numPieces()
}
func (me *torrent) haveAnyPieces() bool {
}
return true
})
+ t.completedPieces.IterTyped(func(piece int) (more bool) {
+ newPrios[piece] = PiecePriorityNone
+ return true
+ })
for i, prio := range newPrios {
- if t.pieceComplete(i) {
- prio = PiecePriorityNone
- }
if prio != t.Pieces[i].priority {
t.Pieces[i].priority = prio
t.piecePriorityChanged(i)
}
func (t *torrent) getCompletedPieces() (ret bitmap.Bitmap) {
- for i := range iter.N(t.numPieces()) {
- if t.pieceComplete(i) {
- ret.Add(i)
- }
- }
- return
+ return t.completedPieces.Copy()
}
func (t *torrent) unpendPieces(unpend *bitmap.Bitmap) {
t.connPieceInclinationPool.Put(pi)
pieceInclinationsPut.Add(1)
}
+
+func (t *torrent) updatePieceCompletion(piece int) {
+ t.completedPieces.Set(piece, t.pieceCompleteUncached(piece))
+}