github.com/anacrolix/torrent@v1.61.0/torrent-piece-request-order.go (about)

     1  package torrent
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/RoaringBitmap/roaring"
     7  	g "github.com/anacrolix/generics"
     8  	"github.com/anacrolix/torrent/internal/amortize"
     9  	requestStrategy "github.com/anacrolix/torrent/internal/request-strategy"
    10  )
    11  
    12  // It's probably possible to track whether the piece moves around in the btree to be more efficient
    13  // about triggering request updates.
    14  func (t *Torrent) updatePieceRequestOrderPiece(pieceIndex int) (changed bool) {
    15  	if t.storage == nil {
    16  		return false
    17  	}
    18  	pro, ok := t.cl.pieceRequestOrder[t.clientPieceRequestOrderKey()]
    19  	if !ok {
    20  		return false
    21  	}
    22  	key := t.pieceRequestOrderKey(pieceIndex)
    23  	if t.hasStorageCap() {
    24  		return pro.pieces.Update(key, t.requestStrategyPieceOrderState(pieceIndex))
    25  	}
    26  	// TODO: This might eject a piece that could count toward being unverified?
    27  	pending := !t.ignorePieceForRequests(pieceIndex)
    28  	if pending {
    29  		newState := t.requestStrategyPieceOrderState(pieceIndex)
    30  		old := pro.pieces.Add(key, newState)
    31  		return old.Ok && old.Value != newState
    32  	} else {
    33  		return pro.pieces.Delete(key)
    34  	}
    35  }
    36  
    37  func (t *Torrent) clientPieceRequestOrderKey() clientPieceRequestOrderKeySumType {
    38  	if t.storage.Capacity == nil {
    39  		return clientPieceRequestOrderRegularTorrentKey{t}
    40  	}
    41  	return clientPieceRequestOrderSharedStorageTorrentKey{t.storage.Capacity}
    42  }
    43  
    44  func (t *Torrent) deletePieceRequestOrder() {
    45  	if t.storage == nil {
    46  		return
    47  	}
    48  	cpro := t.cl.pieceRequestOrder
    49  	key := t.clientPieceRequestOrderKey()
    50  	pro := cpro[key]
    51  	for i := range t.numPieces() {
    52  		pro.pieces.Delete(t.pieceRequestOrderKey(i))
    53  	}
    54  	delete(pro.torrents, t)
    55  	if pro.pieces.Len() == 0 {
    56  		delete(cpro, key)
    57  	}
    58  }
    59  
    60  func (t *Torrent) initPieceRequestOrder() {
    61  	if t.storage == nil {
    62  		return
    63  	}
    64  	g.MakeMapIfNil(&t.cl.pieceRequestOrder)
    65  	key := t.clientPieceRequestOrderKey()
    66  	cpro := t.cl.pieceRequestOrder
    67  	if _, ok := cpro[key]; !ok {
    68  		value := clientPieceRequestOrderValue{
    69  			pieces: requestStrategy.NewPieceOrder(requestStrategy.NewAjwernerBtree(), t.numPieces()),
    70  		}
    71  		g.MakeMap(&value.torrents)
    72  		cpro[key] = value
    73  	}
    74  	g.MapMustAssignNew(cpro[key].torrents, t, struct{}{})
    75  }
    76  
    77  func (t *Torrent) addRequestOrderPiece(i int) {
    78  	if t.storage == nil {
    79  		return
    80  	}
    81  	pro := t.getPieceRequestOrder()
    82  	key := t.pieceRequestOrderKey(i)
    83  	if t.hasStorageCap() || !t.ignorePieceForRequests(i) {
    84  		pro.Add(key, t.requestStrategyPieceOrderState(i))
    85  	}
    86  }
    87  
    88  func (t *Torrent) getPieceRequestOrder() *requestStrategy.PieceRequestOrder {
    89  	if t.storage == nil {
    90  		return nil
    91  	}
    92  	return t.cl.pieceRequestOrder[t.clientPieceRequestOrderKey()].pieces
    93  }
    94  
    95  func (t *Torrent) checkPendingPiecesMatchesRequestOrder() {
    96  	if !amortize.Try() {
    97  		return
    98  	}
    99  	short := *t.canonicalShortInfohash()
   100  	var proBitmap roaring.Bitmap
   101  	for item := range t.getPieceRequestOrder().Iter {
   102  		if item.Key.InfoHash.Value() != short {
   103  			continue
   104  		}
   105  		if item.State.Priority == PiecePriorityNone {
   106  			continue
   107  		}
   108  		if t.ignorePieceForRequests(item.Key.Index) {
   109  			continue
   110  		}
   111  		proBitmap.Add(uint32(item.Key.Index))
   112  	}
   113  	if !proBitmap.Equals(&t._pendingPieces) {
   114  		intersection := roaring.And(&proBitmap, &t._pendingPieces)
   115  		exclPro := roaring.AndNot(&proBitmap, intersection)
   116  		exclPending := roaring.AndNot(&t._pendingPieces, intersection)
   117  		panic(fmt.Sprintf("piece request order has %v and pending pieces has %v", exclPro.String(), exclPending.String()))
   118  	}
   119  }