X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=file.go;h=ed2f5da9ced0e74c87a903d1b160a3793331701d;hb=d27d1c809ef80cbfafdcffac6f4d18fb1d988a61;hp=e2ebcf4d5c6cf5a2a8c90b1e8a109f8caa4f3282;hpb=67c9021e970a5ec65dee033540826412963d0cfb;p=btrtrc.git diff --git a/file.go b/file.go index e2ebcf4d..ed2f5da9 100644 --- a/file.go +++ b/file.go @@ -1,8 +1,7 @@ package torrent import ( - "strings" - + "github.com/RoaringBitmap/roaring" "github.com/anacrolix/missinggo/v2/bitmap" "github.com/anacrolix/torrent/metainfo" @@ -10,12 +9,13 @@ import ( // Provides access to regions of torrent data that correspond to its files. type File struct { - t *Torrent - path string - offset int64 - length int64 - fi metainfo.FileInfo - prio piecePriority + t *Torrent + path string + offset int64 + length int64 + fi metainfo.FileInfo + displayPath string + prio piecePriority } func (f *File) Torrent() *Torrent { @@ -44,13 +44,14 @@ func (f *File) Length() int64 { // Number of bytes of the entire file we have completed. This is the sum of // completed pieces, and dirtied chunks of incomplete pieces. -func (f *File) BytesCompleted() int64 { +func (f *File) BytesCompleted() (n int64) { f.t.cl.rLock() - defer f.t.cl.rUnlock() - return f.bytesCompleted() + n = f.bytesCompletedLocked() + f.t.cl.rUnlock() + return } -func (f *File) bytesCompleted() int64 { +func (f *File) bytesCompletedLocked() int64 { return f.length - f.bytesLeft() } @@ -60,42 +61,38 @@ func fileBytesLeft( 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(fileFirstPieceIndex) { + if !torrentCompletedPieces.Contains(bitmap.BitIndex(fileFirstPieceIndex)) { left += fileLength } default: - if !torrentCompletedPieces.Get(fileFirstPieceIndex) { + if !torrentCompletedPieces.Contains(bitmap.BitIndex(fileFirstPieceIndex)) { left += torrentUsualPieceSize - (fileTorrentOffset % torrentUsualPieceSize) } - if !torrentCompletedPieces.Get(fileEndPieceIndex - 1) { + if !torrentCompletedPieces.Contains(bitmap.BitIndex(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 + completedMiddlePieces := torrentCompletedPieces.Clone() + completedMiddlePieces.RemoveRange(0, bitmap.BitRange(fileFirstPieceIndex+1)) + completedMiddlePieces.RemoveRange(bitmap.BitRange(fileEndPieceIndex-1), bitmap.ToEnd) + 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.BeginPieceIndex(), f.EndPieceIndex(), f.offset, f.length, &f.t._completedPieces) } // The relative file path for a multi-file torrent, and the torrent name for a -// single-file torrent. +// single-file torrent. Dir separators are '/'. func (f *File) DisplayPath() string { - fip := f.FileInfo().Path - if len(fip) == 0 { - return f.t.info.Name - } - return strings.Join(fip, "/") + return f.displayPath } // The download status of a piece that comprises part of a File. @@ -144,37 +141,29 @@ func (f *File) Cancel() { } func (f *File) NewReader() Reader { - tr := reader{ - mu: f.t.cl.locker(), - t: f.t, - readahead: 5 * 1024 * 1024, - offset: f.Offset(), - length: f.Length(), - } - f.t.addReader(&tr) - return &tr + return f.t.newReader(f.Offset(), f.Length()) } // Sets the minimum priority for pieces in the File. func (f *File) SetPriority(prio piecePriority) { f.t.cl.lock() - defer f.t.cl.unlock() - if prio == f.prio { - return + if prio != f.prio { + f.prio = prio + f.t.updatePiecePriorities(f.BeginPieceIndex(), f.EndPieceIndex(), "File.SetPriority") } - f.prio = prio - f.t.updatePiecePriorities(f.firstPieceIndex(), f.endPieceIndex()) + f.t.cl.unlock() } // Returns the priority per File.SetPriority. -func (f *File) Priority() piecePriority { - f.t.cl.lock() - defer f.t.cl.unlock() - return f.prio +func (f *File) Priority() (prio piecePriority) { + f.t.cl.rLock() + prio = f.prio + f.t.cl.rUnlock() + return } // Returns the index of the first piece containing data for the file. -func (f *File) firstPieceIndex() pieceIndex { +func (f *File) BeginPieceIndex() int { if f.t.usualPieceSize() == 0 { return 0 } @@ -182,7 +171,7 @@ func (f *File) firstPieceIndex() pieceIndex { } // Returns the index of the piece after the last one containing data for the file. -func (f *File) endPieceIndex() pieceIndex { +func (f *File) EndPieceIndex() int { if f.t.usualPieceSize() == 0 { return 0 }