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 }