Add torrent.completedPieces bitmap
Reduce load on data.PieceComplete for torrents with lots of pieces, when reader position changes. Not sure of the improvement yet.
This commit is contained in:
parent
be6052912f
commit
0f9f7ba01b
28
client.go
28
client.go
@ -1783,34 +1783,9 @@ func (cl *Client) saveTorrentFile(t *torrent) error {
|
|||||||
return nil
|
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) {
|
func (cl *Client) setStorage(t *torrent, td Data) (err error) {
|
||||||
err = t.setStorage(td)
|
t.setStorage(td)
|
||||||
cl.event.Broadcast()
|
cl.event.Broadcast()
|
||||||
if err != nil {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
cl.startTorrent(t)
|
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2450,6 +2425,7 @@ func (me *Client) pieceHashed(t *torrent, piece int, correct bool) {
|
|||||||
log.Printf("%T: error completing piece %d: %s", t.data, piece, err)
|
log.Printf("%T: error completing piece %d: %s", t.data, piece, err)
|
||||||
correct = false
|
correct = false
|
||||||
}
|
}
|
||||||
|
t.updatePieceCompletion(piece)
|
||||||
} else if len(touchers) != 0 {
|
} else if len(touchers) != 0 {
|
||||||
log.Printf("dropping %d conns that touched piece", len(touchers))
|
log.Printf("dropping %d conns that touched piece", len(touchers))
|
||||||
for _, c := range touchers {
|
for _, c := range touchers {
|
||||||
|
@ -434,7 +434,11 @@ func (me badData) WriteAt(b []byte, off int64) (int, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (me badData) WriteSectionTo(w io.Writer, off, n int64) (int64, error) {
|
func (me badData) WriteSectionTo(w io.Writer, off, n int64) (int64, error) {
|
||||||
return 0, nil
|
written, err := w.Write([]byte("hello"))
|
||||||
|
if err == nil {
|
||||||
|
err = io.ErrUnexpectedEOF
|
||||||
|
}
|
||||||
|
return int64(written), err
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me badData) PieceComplete(piece int) bool {
|
func (me badData) PieceComplete(piece int) bool {
|
||||||
|
64
torrent.go
64
torrent.go
@ -17,7 +17,6 @@ import (
|
|||||||
"github.com/anacrolix/missinggo/itertools"
|
"github.com/anacrolix/missinggo/itertools"
|
||||||
"github.com/anacrolix/missinggo/perf"
|
"github.com/anacrolix/missinggo/perf"
|
||||||
"github.com/anacrolix/missinggo/pubsub"
|
"github.com/anacrolix/missinggo/pubsub"
|
||||||
"github.com/bradfitz/iter"
|
|
||||||
|
|
||||||
"github.com/anacrolix/torrent/bencode"
|
"github.com/anacrolix/torrent/bencode"
|
||||||
"github.com/anacrolix/torrent/metainfo"
|
"github.com/anacrolix/torrent/metainfo"
|
||||||
@ -104,7 +103,8 @@ type torrent struct {
|
|||||||
|
|
||||||
readers map[*Reader]struct{}
|
readers map[*Reader]struct{}
|
||||||
|
|
||||||
pendingPieces bitmap.Bitmap
|
pendingPieces bitmap.Bitmap
|
||||||
|
completedPieces bitmap.Bitmap
|
||||||
|
|
||||||
connPieceInclinationPool sync.Pool
|
connPieceInclinationPool sync.Pool
|
||||||
}
|
}
|
||||||
@ -120,6 +120,10 @@ func (t *torrent) setDisplayName(dn string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) pieceComplete(piece int) bool {
|
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
|
// TODO: This is called when setting metadata, and before storage is
|
||||||
// assigned, which doesn't seem right.
|
// assigned, which doesn't seem right.
|
||||||
return t.data != nil && t.data.PieceComplete(piece)
|
return t.data != nil && t.data.PieceComplete(piece)
|
||||||
@ -267,12 +271,24 @@ func (t *torrent) setMetadata(md *metainfo.Info, infoBytes []byte) (err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) setStorage(td Data) (err error) {
|
func (t *torrent) setStorage(td Data) {
|
||||||
if t.data != nil {
|
if t.data != nil {
|
||||||
t.data.Close()
|
t.data.Close()
|
||||||
}
|
}
|
||||||
t.data = td
|
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) haveAllMetadataPieces() bool {
|
||||||
@ -532,12 +548,7 @@ func (t *torrent) numPieces() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) numPiecesCompleted() (num int) {
|
func (t *torrent) numPiecesCompleted() (num int) {
|
||||||
for i := range iter.N(t.Info.NumPieces()) {
|
return t.completedPieces.Len()
|
||||||
if t.pieceComplete(i) {
|
|
||||||
num++
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) isClosed() bool {
|
func (t *torrent) isClosed() bool {
|
||||||
@ -588,9 +599,11 @@ func (t *torrent) writeChunk(piece int, begin int64, data []byte) (err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) bitfield() (bf []bool) {
|
func (t *torrent) bitfield() (bf []bool) {
|
||||||
for i := range t.Pieces {
|
bf = make([]bool, t.numPieces())
|
||||||
bf = append(bf, t.havePiece(i))
|
t.completedPieces.IterTyped(func(piece int) (again bool) {
|
||||||
}
|
bf[piece] = true
|
||||||
|
return true
|
||||||
|
})
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -678,12 +691,7 @@ func (t *torrent) haveAllPieces() bool {
|
|||||||
if !t.haveInfo() {
|
if !t.haveInfo() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
for i := range t.Pieces {
|
return t.completedPieces.Len() == t.numPieces()
|
||||||
if !t.pieceComplete(i) {
|
|
||||||
return false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return true
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (me *torrent) haveAnyPieces() bool {
|
func (me *torrent) haveAnyPieces() bool {
|
||||||
@ -877,10 +885,11 @@ func (t *torrent) updatePiecePriorities() {
|
|||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
})
|
})
|
||||||
|
t.completedPieces.IterTyped(func(piece int) (more bool) {
|
||||||
|
newPrios[piece] = PiecePriorityNone
|
||||||
|
return true
|
||||||
|
})
|
||||||
for i, prio := range newPrios {
|
for i, prio := range newPrios {
|
||||||
if t.pieceComplete(i) {
|
|
||||||
prio = PiecePriorityNone
|
|
||||||
}
|
|
||||||
if prio != t.Pieces[i].priority {
|
if prio != t.Pieces[i].priority {
|
||||||
t.Pieces[i].priority = prio
|
t.Pieces[i].priority = prio
|
||||||
t.piecePriorityChanged(i)
|
t.piecePriorityChanged(i)
|
||||||
@ -970,12 +979,7 @@ func (t *torrent) pendPiece(piece int) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) getCompletedPieces() (ret bitmap.Bitmap) {
|
func (t *torrent) getCompletedPieces() (ret bitmap.Bitmap) {
|
||||||
for i := range iter.N(t.numPieces()) {
|
return t.completedPieces.Copy()
|
||||||
if t.pieceComplete(i) {
|
|
||||||
ret.Add(i)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *torrent) unpendPieces(unpend *bitmap.Bitmap) {
|
func (t *torrent) unpendPieces(unpend *bitmap.Bitmap) {
|
||||||
@ -1033,3 +1037,7 @@ func (t *torrent) putPieceInclination(pi []int) {
|
|||||||
t.connPieceInclinationPool.Put(pi)
|
t.connPieceInclinationPool.Put(pi)
|
||||||
pieceInclinationsPut.Add(1)
|
pieceInclinationsPut.Add(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (t *torrent) updatePieceCompletion(piece int) {
|
||||||
|
t.completedPieces.Set(piece, t.pieceCompleteUncached(piece))
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user