Rewrite file.bytesLeft

Avoids iteration, and should handle files that are entirely inside a single piece, as well as zero-sized at the beginning of a torrent. Should fix #387.
This commit is contained in:
Matt Joiner 2020-03-24 12:15:35 +11:00
parent 4be8b12207
commit 364d3dd208
2 changed files with 65 additions and 16 deletions

29
file.go
View File

@ -62,21 +62,24 @@ func fileBytesLeft(
fileLength int64, fileLength int64,
torrentCompletedPieces bitmap.Bitmap, torrentCompletedPieces bitmap.Bitmap,
) (left int64) { ) (left int64) {
fileEndPieceIndex-- numPiecesSpanned := fileEndPieceIndex - fileFirstPieceIndex
bitmap.Flip(torrentCompletedPieces, fileFirstPieceIndex+1, fileEndPieceIndex).IterTyped(func(piece int) bool { switch numPiecesSpanned {
if piece >= fileEndPieceIndex { case 0:
return false case 1:
if !torrentCompletedPieces.Get(fileFirstPieceIndex) {
left += fileLength
} }
if piece > fileFirstPieceIndex { default:
left += torrentUsualPieceSize if !torrentCompletedPieces.Get(fileFirstPieceIndex) {
left += torrentUsualPieceSize - (fileTorrentOffset % torrentUsualPieceSize)
} }
return true if !torrentCompletedPieces.Get(fileEndPieceIndex - 1) {
}) left += fileTorrentOffset + fileLength - int64(fileEndPieceIndex-1)*torrentUsualPieceSize
if !torrentCompletedPieces.Get(fileFirstPieceIndex) { }
left += torrentUsualPieceSize - (fileTorrentOffset % torrentUsualPieceSize) completedMiddlePieces := torrentCompletedPieces.Copy()
} completedMiddlePieces.RemoveRange(0, fileFirstPieceIndex+1)
if !torrentCompletedPieces.Get(fileEndPieceIndex) { completedMiddlePieces.RemoveRange(fileEndPieceIndex-1, bitmap.ToEnd)
left += (fileTorrentOffset + fileLength) % torrentUsualPieceSize left += int64(numPiecesSpanned-2-completedMiddlePieces.Len()) * torrentUsualPieceSize
} }
return return
} }

View File

@ -40,19 +40,31 @@ func (me testFileBytesLeft) Run(t *testing.T) {
} }
func TestFileBytesLeft(t *testing.T) { func TestFileBytesLeft(t *testing.T) {
testFileBytesLeft{ testFileBytesLeft{
usualPieceSize: 2, usualPieceSize: 3,
firstPieceIndex: 1, firstPieceIndex: 1,
endPieceIndex: 1, endPieceIndex: 1,
fileOffset: 1, fileOffset: 1,
fileLength: 0,
expected: 0,
name: "ZeroLengthFile",
}.Run(t)
testFileBytesLeft{
usualPieceSize: 2,
firstPieceIndex: 1,
endPieceIndex: 2,
fileOffset: 1,
fileLength: 1, fileLength: 1,
expected: 1, expected: 1,
name: "EndOfSecondPiece",
}.Run(t) }.Run(t)
testFileBytesLeft{ testFileBytesLeft{
usualPieceSize: 3, usualPieceSize: 3,
firstPieceIndex: 0, firstPieceIndex: 0,
endPieceIndex: 0, endPieceIndex: 1,
fileOffset: 1, fileOffset: 1,
fileLength: 1, fileLength: 1,
expected: 1, expected: 1,
@ -62,10 +74,44 @@ func TestFileBytesLeft(t *testing.T) {
testFileBytesLeft{ testFileBytesLeft{
usualPieceSize: 3, usualPieceSize: 3,
firstPieceIndex: 0, firstPieceIndex: 0,
endPieceIndex: 0, endPieceIndex: 1,
fileOffset: 1, fileOffset: 1,
fileLength: 1, fileLength: 1,
expected: 1, expected: 1,
name: "LandLocked", name: "LandLocked",
}.Run(t) }.Run(t)
testFileBytesLeft{
usualPieceSize: 3,
firstPieceIndex: 1,
endPieceIndex: 3,
fileOffset: 4,
fileLength: 4,
expected: 4,
name: "TwoPieces",
}.Run(t)
testFileBytesLeft{
usualPieceSize: 3,
firstPieceIndex: 1,
endPieceIndex: 4,
fileOffset: 5,
fileLength: 7,
expected: 7,
name: "ThreePieces",
}.Run(t)
testFileBytesLeft{
usualPieceSize: 3,
firstPieceIndex: 1,
endPieceIndex: 4,
fileOffset: 5,
fileLength: 7,
expected: 0,
completedPieces: func() (ret bitmap.Bitmap) {
ret.AddRange(0, 5)
return
}(),
name: "ThreePiecesCompletedAll",
}.Run(t)
} }