github.com/alexflint/go-scalar v1.1.0 // indirect
github.com/anacrolix/mmsg v1.0.0 // indirect
github.com/anacrolix/stm v0.3.0 // indirect
+ github.com/bahlo/generic-list-go v0.2.0 // indirect
github.com/benbjohnson/immutable v0.3.0 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/bits-and-blooms/bitset v1.2.0 // indirect
github.com/anacrolix/utp v0.1.0 h1:FOpQOmIwYsnENnz7tAGohA+r6iXpRjrq8ssKSre2Cp4=
github.com/anacrolix/utp v0.1.0/go.mod h1:MDwc+vsGEq7RMw6lr2GKOEqjWny5hO5OZXRVNaBJ2Dk=
github.com/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ=
+github.com/bahlo/generic-list-go v0.2.0 h1:5sz/EEAK+ls5wF+NeqDpk5+iNdMDXrh3z3nPnH1Wvgk=
+github.com/bahlo/generic-list-go v0.2.0/go.mod h1:2KvAjgMlE5NNynlg/5iLrrCCZ2+5xWbdbCW3pNTGyYg=
github.com/benbjohnson/immutable v0.2.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
github.com/benbjohnson/immutable v0.3.0 h1:TVRhuZx2wG9SZ0LRdqlbs9S5BZ6Y24hJEHTCgWHZEIw=
github.com/benbjohnson/immutable v0.3.0/go.mod h1:uc6OHo6PN2++n98KHLxW8ef4W42ylHiQSENghE1ezxI=
--- /dev/null
+package torrent
+
+import (
+ "github.com/anacrolix/generics"
+ "github.com/anacrolix/torrent/typed-roaring"
+ list "github.com/bahlo/generic-list-go"
+)
+
+type orderedBitmap[T typedRoaring.BitConstraint] struct {
+ bitmap typedRoaring.Bitmap[T]
+ // There should be way more efficient ways to do this.
+ order list.List[T]
+ elements map[T]*list.Element[T]
+}
+
+func (o *orderedBitmap[T]) IterateSnapshot(f func(T) bool) {
+ o.bitmap.Clone().Iterate(f)
+}
+
+func (o *orderedBitmap[T]) IsEmpty() bool {
+ return o.bitmap.IsEmpty()
+}
+
+func (o *orderedBitmap[T]) GetCardinality() uint64 {
+ return uint64(o.order.Len())
+}
+
+func (o *orderedBitmap[T]) Contains(index T) bool {
+ return o.bitmap.Contains(index)
+}
+
+func (o *orderedBitmap[T]) Add(index T) {
+ o.bitmap.Add(index)
+ if _, ok := o.elements[index]; !ok {
+ generics.MakeMapIfNilAndSet(&o.elements, index, o.order.PushBack(index))
+ }
+}
+
+func (o *orderedBitmap[T]) Rank(index T) uint64 {
+ return o.bitmap.Rank(index)
+}
+
+func (o *orderedBitmap[T]) Iterate(f func(T) bool) {
+ for e := o.order.Front(); e != nil; e = e.Next() {
+ if !f(e.Value) {
+ return
+ }
+ }
+}
+
+func (o *orderedBitmap[T]) CheckedRemove(index T) bool {
+ if !o.bitmap.CheckedRemove(index) {
+ return false
+ }
+ o.order.Remove(o.elements[index])
+ delete(o.elements, index)
+ return true
+}
"io"
"math/rand"
"net"
- "sort"
"strconv"
"strings"
"sync/atomic"
logger log.Logger
}
-type peerRequests struct {
- typedRoaring.Bitmap[RequestIndex]
-}
-
-func (p *peerRequests) IterateSnapshot(f func(request_strategy.RequestIndex) bool) {
- p.Clone().Iterate(f)
-}
+type peerRequests = orderedBitmap[RequestIndex]
func (p *Peer) initRequestState() {
p.requestState.Requests = &peerRequests{}
return float64(num) / cn.totalExpectingTime().Seconds()
}
-func (cn *Peer) numRequestsByPiece() (ret map[pieceIndex]int) {
- ret = make(map[pieceIndex]int)
- cn.requestState.Requests.Iterate(func(x RequestIndex) bool {
- ret[cn.t.pieceIndexOfRequestIndex(x)]++
+func (cn *Peer) iterContiguousPieceRequests(f func(piece pieceIndex, count int)) {
+ var last Option[pieceIndex]
+ var count int
+ next := func(item Option[pieceIndex]) {
+ if item == last {
+ count++
+ } else {
+ if count != 0 {
+ f(last.Value(), count)
+ }
+ last = item
+ count = 1
+ }
+ }
+ cn.requestState.Requests.Iterate(func(requestIndex request_strategy.RequestIndex) bool {
+ next(Some(cn.t.pieceIndexOfRequestIndex(requestIndex)))
return true
})
- return
+ next(None[pieceIndex]())
}
func (cn *Peer) writeStatus(w io.Writer, t *Torrent) {
cn.downloadRate()/(1<<10),
)
fmt.Fprintf(w, " requested pieces:")
- type pieceNumRequestsType struct {
- piece pieceIndex
- numRequests int
- }
- var pieceNumRequests []pieceNumRequestsType
- for piece, count := range cn.numRequestsByPiece() {
- pieceNumRequests = append(pieceNumRequests, pieceNumRequestsType{piece, count})
- }
- sort.Slice(pieceNumRequests, func(i, j int) bool {
- return pieceNumRequests[i].piece < pieceNumRequests[j].piece
+ cn.iterContiguousPieceRequests(func(piece pieceIndex, count int) {
+ fmt.Fprintf(w, " %v(%v)", piece, count)
})
- for _, elem := range pieceNumRequests {
- fmt.Fprintf(w, " %v(%v)", elem.piece, elem.numRequests)
- }
fmt.Fprintf(w, "\n")
}
type PeerRequestState struct {
Interested bool
- // Expecting. TODO: This should be ordered so webseed requesters initiate in the same order they
- // were assigned.
- Requests PeerRequests
+ Requests PeerRequests
// Cancelled and waiting response
Cancelled typedRoaring.Bitmap[RequestIndex]
}