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

View File

@ -40,19 +40,31 @@ func (me testFileBytesLeft) Run(t *testing.T) {
}
func TestFileBytesLeft(t *testing.T) {
testFileBytesLeft{
usualPieceSize: 2,
usualPieceSize: 3,
firstPieceIndex: 1,
endPieceIndex: 1,
fileOffset: 1,
fileLength: 0,
expected: 0,
name: "ZeroLengthFile",
}.Run(t)
testFileBytesLeft{
usualPieceSize: 2,
firstPieceIndex: 1,
endPieceIndex: 2,
fileOffset: 1,
fileLength: 1,
expected: 1,
name: "EndOfSecondPiece",
}.Run(t)
testFileBytesLeft{
usualPieceSize: 3,
firstPieceIndex: 0,
endPieceIndex: 0,
endPieceIndex: 1,
fileOffset: 1,
fileLength: 1,
expected: 1,
@ -62,10 +74,44 @@ func TestFileBytesLeft(t *testing.T) {
testFileBytesLeft{
usualPieceSize: 3,
firstPieceIndex: 0,
endPieceIndex: 0,
endPieceIndex: 1,
fileOffset: 1,
fileLength: 1,
expected: 1,
name: "LandLocked",
}.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)
}