panic("unwanted piece in connection request order")
}
piece := t.Pieces[pieceIndex]
- for _, cs := range piece.shuffledPendingChunkSpecs() {
+ for _, cs := range piece.shuffledPendingChunkSpecs(t.pieceLength(pieceIndex)) {
r := request{pp.Integer(pieceIndex), cs}
if !addRequest(r) {
return
// log.Println("got chunk", req)
piece.Event.Broadcast()
// Record that we have the chunk.
- delete(piece.PendingChunkSpecs, req.chunkSpec)
+ piece.unpendChunkIndex(chunkIndex(req.chunkSpec))
delete(t.urgent, req)
- if len(piece.PendingChunkSpecs) == 0 {
+ if piece.numPendingChunks() == 0 {
for _, c := range t.Conns {
c.pieceRequestOrder.DeletePiece(int(req.Index))
}
}
p.Event.Broadcast()
} else {
- if len(p.PendingChunkSpecs) == 0 {
+ if p.numPendingChunks() == 0 {
t.pendAllChunkSpecs(int(piece))
}
if t.wantPiece(piece) {
}
p := tor.Pieces[0]
tor.pendAllChunkSpecs(0)
- if len(p.PendingChunkSpecs) != 1 {
+ if p.numPendingChunks() != 1 {
t.Fatalf("should only be 1 chunk: %v", p.PendingChunkSpecs)
}
// TODO: Set chunkSize to 2, to test odd/even silliness.
- if false {
- if _, ok := p.PendingChunkSpecs[chunkSpec{
- Length: 13,
- }]; !ok {
- t.Fatal("pending chunk spec is incorrect")
- }
+ if chunkIndexSpec(0, tor.pieceLength(0)).Length != 5 {
+ t.Fatal("pending chunk spec is incorrect")
}
}
import (
"math/rand"
"sync"
+
+ pp "github.com/anacrolix/torrent/peer_protocol"
)
type piecePriority byte
)
type piece struct {
- Hash pieceSum
- PendingChunkSpecs map[chunkSpec]struct{}
+ Hash pieceSum
+ // Chunks we don't have. The offset and length can be determined by our
+ // request chunkSize in use.
+ PendingChunkSpecs []bool
Hashing bool
QueuedForHash bool
EverHashed bool
Priority piecePriority
}
-func (p *piece) shuffledPendingChunkSpecs() (css []chunkSpec) {
- if len(p.PendingChunkSpecs) == 0 {
+func (p *piece) pendingChunk(cs chunkSpec) bool {
+ if p.PendingChunkSpecs == nil {
+ return false
+ }
+ return p.PendingChunkSpecs[chunkIndex(cs)]
+}
+
+func (p *piece) numPendingChunks() (ret int) {
+ for _, pending := range p.PendingChunkSpecs {
+ if pending {
+ ret++
+ }
+ }
+ return
+}
+
+func (p *piece) unpendChunkIndex(i int) {
+ if p.PendingChunkSpecs == nil {
+ return
+ }
+ p.PendingChunkSpecs[i] = false
+}
+
+func chunkIndexSpec(index int, pieceLength pp.Integer) chunkSpec {
+ ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
+ if ret.Begin+ret.Length > pieceLength {
+ ret.Length = pieceLength - ret.Begin
+ }
+ return ret
+}
+
+func (p *piece) shuffledPendingChunkSpecs(pieceLength pp.Integer) (css []chunkSpec) {
+ if p.numPendingChunks() == 0 {
return
}
- css = make([]chunkSpec, 0, len(p.PendingChunkSpecs))
- for cs := range p.PendingChunkSpecs {
- css = append(css, cs)
+ css = make([]chunkSpec, 0, p.numPendingChunks())
+ for i, pending := range p.PendingChunkSpecs {
+ if pending {
+ css = append(css, chunkIndexSpec(i, pieceLength))
+ }
}
if len(css) <= 1 {
return
return 0
}
piece := t.Pieces[index]
+ pieceLength := t.pieceLength(index)
if !piece.EverHashed {
- return t.pieceLength(index)
- }
- pendingChunks := t.Pieces[index].PendingChunkSpecs
- count = pp.Integer(len(pendingChunks)) * chunkSize
- _lastChunkSpec := lastChunkSpec(t.pieceLength(index))
- if _lastChunkSpec.Length != chunkSize {
- if _, ok := pendingChunks[_lastChunkSpec]; ok {
- count += _lastChunkSpec.Length - chunkSize
+ return pieceLength
+ }
+ for i, pending := range piece.PendingChunkSpecs {
+ if pending {
+ count += chunkIndexSpec(i, pieceLength).Length
}
}
return
func (t *torrent) bitfield() (bf []bool) {
for _, p := range t.Pieces {
// TODO: Check this logic.
- bf = append(bf, p.EverHashed && len(p.PendingChunkSpecs) == 0)
+ bf = append(bf, p.EverHashed && p.numPendingChunks() == 0)
}
return
}
+func (t *torrent) validOutgoingRequest(r request) bool {
+ if r.Index >= pp.Integer(t.Info.NumPieces()) {
+ return false
+ }
+ if r.Begin%chunkSize != 0 {
+ return false
+ }
+ if r.Length > chunkSize {
+ return false
+ }
+ pieceLength := t.pieceLength(int(r.Index))
+ if r.Begin+r.Length > pieceLength {
+ return false
+ }
+ return r.Length == chunkSize || r.Begin+r.Length == pieceLength
+}
+
func (t *torrent) pieceChunks(piece int) (css []chunkSpec) {
css = make([]chunkSpec, 0, (t.pieceLength(piece)+chunkSize-1)/chunkSize)
var cs chunkSpec
return
}
-func (t *torrent) pendAllChunkSpecs(index int) {
- piece := t.Pieces[index]
+func (t *torrent) pendAllChunkSpecs(pieceIndex int) {
+ piece := t.Pieces[pieceIndex]
if piece.PendingChunkSpecs == nil {
- piece.PendingChunkSpecs = make(
- map[chunkSpec]struct{},
- (t.pieceLength(index)+chunkSize-1)/chunkSize)
+ // Allocate to exact size.
+ piece.PendingChunkSpecs = make([]bool, (t.pieceLength(pieceIndex)+chunkSize-1)/chunkSize)
}
+ // Pend all the chunks.
pcss := piece.PendingChunkSpecs
- for _, cs := range t.pieceChunks(int(index)) {
- pcss[cs] = struct{}{}
+ for i := range pcss {
+ pcss[i] = true
}
return
}
if !t.haveInfo() {
return false
}
- piece := t.Pieces[r.Index]
- _, ok := piece.PendingChunkSpecs[r.chunkSpec]
- // log.Println("have chunk", r, !ok)
- return !ok
+ return !t.Pieces[r.Index].pendingChunk(r.chunkSpec)
+}
+
+func chunkIndex(cs chunkSpec) int {
+ return int(cs.Begin / chunkSize)
}
+// TODO: This should probably be called wantPiece.
func (t *torrent) wantChunk(r request) bool {
if !t.wantPiece(int(r.Index)) {
return false
}
- _, ok := t.Pieces[r.Index].PendingChunkSpecs[r.chunkSpec]
- if ok {
+ if t.Pieces[r.Index].pendingChunk(r.chunkSpec) {
return true
}
- _, ok = t.urgent[r]
+ _, ok := t.urgent[r]
return ok
}
return false
}
+// TODO: This should be called wantPieceIndex.
func (t *torrent) wantPiece(index int) bool {
if !t.haveInfo() {
return false