]> Sergey Matveev's repositories - btrtrc.git/commitdiff
Consider dirty chunks in apriori webseed request generation
authorMatt Joiner <anacrolix@gmail.com>
Wed, 2 Jul 2025 05:06:34 +0000 (15:06 +1000)
committerMatt Joiner <anacrolix@gmail.com>
Wed, 2 Jul 2025 05:12:59 +0000 (15:12 +1000)
piece.go
typed-roaring/bitmap.go
webseed-requesting.go

index ce98e8a00e328319d4a71dc5d0967890a10763ff..4d6985c1dc8282fad039112044161cf40c42fca8 100644 (file)
--- a/piece.go
+++ b/piece.go
@@ -155,6 +155,19 @@ func (p *Piece) chunkIndexDirty(chunk chunkIndexType) bool {
        return p.t.dirtyChunks.Contains(p.requestIndexBegin() + chunk)
 }
 
+func (p *Piece) firstCleanChunk() (_ g.Option[chunkIndexType]) {
+       it := p.t.dirtyChunks.Iterator()
+       begin := uint32(p.requestIndexBegin())
+       end := uint32(p.requestIndexMaxEnd())
+       it.AdvanceIfNeeded(begin)
+       for next := begin; next < end; next++ {
+               if !it.HasNext() || it.Next() != next {
+                       return g.Some(chunkIndexType(next - begin))
+               }
+       }
+       return
+}
+
 func (p *Piece) chunkIndexSpec(chunk chunkIndexType) ChunkSpec {
        return chunkIndexSpec(pp.Integer(chunk), p.length(), p.chunkSize())
 }
@@ -426,9 +439,9 @@ func (p *Piece) publishStateChange() {
        }
 }
 
-func (p *Piece) fileExtents() iter.Seq2[int, segments.Extent] {
+func (p *Piece) fileExtents(offsetIntoPiece int64) iter.Seq2[int, segments.Extent] {
        return p.t.info.FileSegmentsIndex().LocateIter(segments.Extent{
-               p.torrentBeginOffset(),
-               segments.Int(p.length()),
+               p.torrentBeginOffset() + offsetIntoPiece,
+               int64(p.length()) - offsetIntoPiece,
        })
 }
index 7f7b1a7e7077b3a27cbd3a01d80fe132e5f650c3..4e42dda704b29d1724c1dfff1a5293332689be2a 100644 (file)
@@ -46,3 +46,5 @@ func (me *Bitmap[T]) Remove(x T) {
 func (Bitmap[T]) IteratorType() Iterator[T] {
        return Iterator[T]{}
 }
+
+// TODO: Override Bitmap.Iterator.
index 0a7c0333e86478bda77b6cc4cd5c6a1ed4d788f4..7a001603ddb2f52c0c2b6d00e4cb9479bf1ede4d 100644 (file)
@@ -180,10 +180,20 @@ func (cl *Client) iterWebseed() iter.Seq2[webseedUniqueRequestKey, webseedReques
                                value.pieces,
                                func(ih metainfo.Hash, pieceIndex int, orderState requestStrategy.PieceRequestOrderState) bool {
                                        t := cl.torrentsByShortHash[ih]
-                                       for i, e := range t.piece(pieceIndex).fileExtents() {
+                                       p := t.piece(pieceIndex)
+                                       cleanOpt := p.firstCleanChunk()
+                                       if !cleanOpt.Ok {
+                                               // Could almost return true here, as clearly something is going on with the piece.
+                                               return false
+                                       }
+                                       // Pretty sure we want this and not the order state priority. That one is for
+                                       // client piece request order and ignores other states like hashing, marking
+                                       // etc. Order state priority would be faster otherwise.
+                                       priority := p.effectivePriority()
+                                       for i, e := range p.fileExtents(int64(cleanOpt.Value) * int64(t.chunkSize)) {
                                                for url, ws := range t.webSeeds {
-                                                       // Return value from this function doesn't terminate, so don't pretend
-                                                       // it does here either.
+                                                       // Return value from this function (RequestPieceFunc) doesn't terminate
+                                                       // iteration, so propagate that to not handling the yield return value.
                                                        yield(
                                                                webseedUniqueRequestKey{
                                                                        aprioriWebseedRequestKey{
@@ -194,7 +204,7 @@ func (cl *Client) iterWebseed() iter.Seq2[webseedUniqueRequestKey, webseedReques
                                                                        e.Start,
                                                                },
                                                                webseedRequestOrderValue{
-                                                                       priority: orderState.Priority,
+                                                                       priority: priority,
                                                                        costKey:  ws.hostKey,
                                                                },
                                                        )