package torrent
import (
+ "github.com/RoaringBitmap/roaring"
"github.com/anacrolix/missinggo/v2/bitmap"
"github.com/anacrolix/torrent/metainfo"
fileEndPieceIndex int,
fileTorrentOffset int64,
fileLength int64,
- torrentCompletedPieces bitmap.Bitmap,
+ torrentCompletedPieces *roaring.Bitmap,
) (left int64) {
numPiecesSpanned := fileEndPieceIndex - fileFirstPieceIndex
switch numPiecesSpanned {
case 0:
case 1:
- if !torrentCompletedPieces.Get(bitmap.BitIndex(fileFirstPieceIndex)) {
+ if !torrentCompletedPieces.Contains(bitmap.BitIndex(fileFirstPieceIndex)) {
left += fileLength
}
default:
- if !torrentCompletedPieces.Get(bitmap.BitIndex(fileFirstPieceIndex)) {
+ if !torrentCompletedPieces.Contains(bitmap.BitIndex(fileFirstPieceIndex)) {
left += torrentUsualPieceSize - (fileTorrentOffset % torrentUsualPieceSize)
}
- if !torrentCompletedPieces.Get(bitmap.BitIndex(fileEndPieceIndex - 1)) {
+ if !torrentCompletedPieces.Contains(bitmap.BitIndex(fileEndPieceIndex - 1)) {
left += fileTorrentOffset + fileLength - int64(fileEndPieceIndex-1)*torrentUsualPieceSize
}
- completedMiddlePieces := torrentCompletedPieces.Copy()
+ completedMiddlePieces := torrentCompletedPieces.Clone()
completedMiddlePieces.RemoveRange(0, bitmap.BitRange(fileFirstPieceIndex+1))
completedMiddlePieces.RemoveRange(bitmap.BitRange(fileEndPieceIndex-1), bitmap.ToEnd)
- left += int64(numPiecesSpanned-2-pieceIndex(completedMiddlePieces.Len())) * torrentUsualPieceSize
+ left += int64(numPiecesSpanned-2-pieceIndex(completedMiddlePieces.GetCardinality())) * torrentUsualPieceSize
}
return
}
func (f *File) bytesLeft() (left int64) {
- return fileBytesLeft(int64(f.t.usualPieceSize()), f.firstPieceIndex(), f.endPieceIndex(), f.offset, f.length, f.t._completedPieces)
+ return fileBytesLeft(int64(f.t.usualPieceSize()), f.firstPieceIndex(), f.endPieceIndex(), f.offset, f.length, &f.t._completedPieces)
}
// The relative file path for a multi-file torrent, and the torrent name for a
import (
"testing"
- "github.com/anacrolix/missinggo/v2/bitmap"
+ "github.com/RoaringBitmap/roaring"
"github.com/stretchr/testify/assert"
)
endPieceIndex int
fileOffset int64
fileLength int64
- completedPieces bitmap.Bitmap
+ completedPieces roaring.Bitmap
expected int64
name string
}
func (me testFileBytesLeft) Run(t *testing.T) {
t.Run(me.name, func(t *testing.T) {
- assert.EqualValues(t, me.expected, fileBytesLeft(me.usualPieceSize, me.firstPieceIndex, me.endPieceIndex, me.fileOffset, me.fileLength, me.completedPieces))
+ assert.EqualValues(t, me.expected, fileBytesLeft(me.usualPieceSize, me.firstPieceIndex, me.endPieceIndex, me.fileOffset, me.fileLength, &me.completedPieces))
})
}
fileOffset: 5,
fileLength: 7,
expected: 0,
- completedPieces: func() (ret bitmap.Bitmap) {
+ completedPieces: func() (ret roaring.Bitmap) {
ret.AddRange(0, 5)
return
}(),
Type: pp.Bitfield,
Bitfield: cn.t.bitfield(),
})
- cn.sentHaves = cn.t._completedPieces.Copy()
+ cn.sentHaves = bitmap.Bitmap{cn.t._completedPieces.Clone()}
}
func (cn *PeerConn) updateRequests() {
"time"
"unsafe"
+ "github.com/RoaringBitmap/roaring"
"github.com/anacrolix/dht/v2"
"github.com/anacrolix/log"
"github.com/anacrolix/missinggo/iter"
// file priorities and completion states elsewhere.
_pendingPieces prioritybitmap.PriorityBitmap
// A cache of completed piece indices.
- _completedPieces bitmap.Bitmap
+ _completedPieces roaring.Bitmap
// Pieces that need to be hashed.
piecesQueuedForHash bitmap.Bitmap
activePieceHashes int
}
func (t *Torrent) pieceComplete(piece pieceIndex) bool {
- return t._completedPieces.Get(bitmap.BitIndex(piece))
+ return t._completedPieces.Contains(bitmap.BitIndex(piece))
}
func (t *Torrent) pieceCompleteUncached(piece pieceIndex) storage.Completion {
return t.bytesLeft()
}
+func iterFlipped(b *roaring.Bitmap, end uint64, cb func(uint32) bool) {
+ roaring.Flip(b, 0, end).Iterate(cb)
+}
+
func (t *Torrent) bytesLeft() (left int64) {
- bitmap.Flip(t._completedPieces, 0, bitmap.BitRange(t.numPieces())).IterTyped(func(piece int) bool {
- p := &t.pieces[piece]
+ iterFlipped(&t._completedPieces, uint64(t.numPieces()), func(x uint32) bool {
+ p := t.piece(pieceIndex(x))
left += int64(p.length() - p.numDirtyBytes())
return true
})
}
func (t *Torrent) numPiecesCompleted() (num pieceIndex) {
- return pieceIndex(t._completedPieces.Len())
+ return pieceIndex(t._completedPieces.GetCardinality())
}
func (t *Torrent) close() (err error) {
func (t *Torrent) bitfield() (bf []bool) {
bf = make([]bool, t.numPieces())
- t._completedPieces.IterTyped(func(piece int) (again bool) {
+ t._completedPieces.Iterate(func(piece uint32) (again bool) {
bf[piece] = true
return true
})
}
func (t *Torrent) haveAnyPieces() bool {
- return t._completedPieces.Len() != 0
+ return t._completedPieces.GetCardinality() != 0
}
func (t *Torrent) haveAllPieces() bool {
if !t.haveInfo() {
return false
}
- return t._completedPieces.Len() == bitmap.BitRange(t.numPieces())
+ return t._completedPieces.GetCardinality() == bitmap.BitRange(t.numPieces())
}
func (t *Torrent) havePiece(index pieceIndex) bool {
changed := cached != uncached
complete := uncached.Complete
p.storageCompletionOk = uncached.Ok
- t._completedPieces.Set(bitmap.BitIndex(piece), complete)
+ x := uint32(piece)
+ if complete {
+ t._completedPieces.Add(x)
+ } else {
+ t._completedPieces.Remove(x)
+ }
if complete && len(p.dirtiers) != 0 {
t.logger.Printf("marked piece %v complete but still has dirtiers", piece)
}
if !t.haveInfo() {
return 0
}
- return t.info.TotalLength() - t.bytesLeft()
+ return *t.length - t.bytesLeft()
}
func (t *Torrent) SetInfoBytes(b []byte) (err error) {
}
assert.Len(b, t.readers, 7)
for i := 0; i < t.numPieces(); i += 3 {
- t._completedPieces.Set(bitmap.BitIndex(i), true)
+ t._completedPieces.Add(bitmap.BitIndex(i))
}
t.DownloadPieces(0, t.numPieces())
for range iter.N(b.N) {