X-Git-Url: http://www.git.stargrave.org/?a=blobdiff_plain;f=file.go;h=bea4b13655d6024915434eecc66eeb0cab6524ad;hb=HEAD;hp=4775b4ff0e8d55e3781971c53af5297a2958b93b;hpb=f22acca80406929d414ef0d16c223da508d405a6;p=btrtrc.git diff --git a/file.go b/file.go index 4775b4ff..bea4b136 100644 --- a/file.go +++ b/file.go @@ -1,22 +1,21 @@ package torrent import ( - "strings" - - "github.com/anacrolix/missinggo/bitmap" + "github.com/RoaringBitmap/roaring" + "github.com/anacrolix/missinggo/v2/bitmap" "github.com/anacrolix/torrent/metainfo" - pp "github.com/anacrolix/torrent/peer_protocol" ) // 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 { @@ -45,53 +44,82 @@ 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() } -func (f *File) bytesLeft() (left int64) { - firstPieceIndex := f.firstPieceIndex() - endPieceIndex := f.endPieceIndex() - bitmap.Flip(f.t.completedPieces, firstPieceIndex, endPieceIndex+1).IterTyped(func(piece int) bool { - p := &f.t.pieces[piece] - left += int64(p.length() - p.numDirtyBytes()) - return true - }) - startPiece := f.t.piece(firstPieceIndex) - endChunk := int(f.offset%f.t.info.PieceLength) * int(startPiece.numChunks()) / int(startPiece.length()) - bitmap.Flip(startPiece.dirtyChunks, 0, endChunk).IterTyped(func(chunk int) bool { - left -= int64(startPiece.chunkSize()) - return true - }) - endPiece := f.t.piece(endPieceIndex) - startChunk := int((f.offset+f.length)%f.t.info.PieceLength) * int(endPiece.numChunks()) / int(endPiece.length()) - lastChunkIndex := int(endPiece.lastChunkIndex()) - bitmap.Flip(endPiece.dirtyChunks, startChunk, int(endPiece.numChunks())).IterTyped(func(chunk int) bool { - if chunk == lastChunkIndex { - left -= int64(endPiece.chunkIndexSpec(pp.Integer(chunk)).Length) +func fileBytesLeft( + torrentUsualPieceSize int64, + fileFirstPieceIndex int, + fileEndPieceIndex int, + fileTorrentOffset int64, + fileLength int64, + torrentCompletedPieces *roaring.Bitmap, + pieceSizeCompletedFn func(pieceIndex int) int64, +) (left int64) { + if fileLength == 0 { + return + } + + noCompletedMiddlePieces := roaring.New() + noCompletedMiddlePieces.AddRange(bitmap.BitRange(fileFirstPieceIndex), bitmap.BitRange(fileEndPieceIndex)) + noCompletedMiddlePieces.AndNot(torrentCompletedPieces) + noCompletedMiddlePieces.Iterate(func(pieceIndex uint32) bool { + i := int(pieceIndex) + pieceSizeCompleted := pieceSizeCompletedFn(i) + if i == fileFirstPieceIndex { + beginOffset := fileTorrentOffset % torrentUsualPieceSize + beginSize := torrentUsualPieceSize - beginOffset + beginDownLoaded := pieceSizeCompleted - beginOffset + if beginDownLoaded < 0 { + beginDownLoaded = 0 + } + left += beginSize - beginDownLoaded + } else if i == fileEndPieceIndex-1 { + endSize := (fileTorrentOffset + fileLength) % torrentUsualPieceSize + if endSize == 0 { + endSize = torrentUsualPieceSize + } + endDownloaded := pieceSizeCompleted + if endDownloaded > endSize { + endDownloaded = endSize + } + left += endSize - endDownloaded } else { - left -= int64(endPiece.chunkSize()) + left += torrentUsualPieceSize - pieceSizeCompleted } return true }) + + if left > fileLength { + left = fileLength + } + // + //numPiecesSpanned := f.EndPieceIndex() - f.BeginPieceIndex() + //completedMiddlePieces := f.t._completedPieces.Clone() + //completedMiddlePieces.RemoveRange(0, bitmap.BitRange(f.BeginPieceIndex()+1)) + //completedMiddlePieces.RemoveRange(bitmap.BitRange(f.EndPieceIndex()-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.BeginPieceIndex(), f.EndPieceIndex(), f.offset, f.length, &f.t._completedPieces, func(pieceIndex int) int64 { + return int64(f.t.piece(pieceIndex).numDirtyBytes()) + }) +} + // 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. @@ -140,45 +168,39 @@ 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 } -func (f *File) firstPieceIndex() pieceIndex { +// Returns the index of the first piece containing data for the file. +func (f *File) BeginPieceIndex() int { if f.t.usualPieceSize() == 0 { return 0 } return pieceIndex(f.offset / int64(f.t.usualPieceSize())) } -func (f *File) endPieceIndex() pieceIndex { +// Returns the index of the piece after the last one containing data for the file. +func (f *File) EndPieceIndex() int { if f.t.usualPieceSize() == 0 { return 0 } - return pieceIndex((f.offset+f.length-1)/int64(f.t.usualPieceSize())) + 1 + return pieceIndex((f.offset + f.length + int64(f.t.usualPieceSize()) - 1) / int64(f.t.usualPieceSize())) }