]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Track dirty chunks, instead of pending chunk specs
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "math/rand"
5         "sync"
6
7         "github.com/bradfitz/iter"
8
9         pp "github.com/anacrolix/torrent/peer_protocol"
10 )
11
12 // Piece priority describes the importance of obtaining a particular piece.
13
14 type piecePriority byte
15
16 const (
17         PiecePriorityNone      piecePriority = iota // Not wanted.
18         PiecePriorityNormal                         // Wanted.
19         PiecePriorityReadahead                      // May be required soon.
20         PiecePriorityNext                           // Succeeds a piece where a read occurred.
21         PiecePriorityNow                            // A read occurred in this piece.
22 )
23
24 type piece struct {
25         // The completed piece SHA1 hash, from the metainfo "pieces" field.
26         Hash pieceSum
27         // Chunks we've written to since the last check. The chunk offset and
28         // length can be determined by the request chunkSize in use.
29         DirtyChunks      []bool
30         Hashing          bool
31         QueuedForHash    bool
32         EverHashed       bool
33         Priority         piecePriority
34         PublicPieceState PieceState
35
36         pendingWritesMutex sync.Mutex
37         pendingWrites      int
38         noPendingWrites    sync.Cond
39 }
40
41 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
42         ci := chunkIndex(cs, chunkSize)
43         if ci >= len(p.DirtyChunks) {
44                 return true
45         }
46         return !p.DirtyChunks[ci]
47 }
48
49 func (p *piece) numDirtyChunks() (ret int) {
50         for _, dirty := range p.DirtyChunks {
51                 if dirty {
52                         ret++
53                 }
54         }
55         return
56 }
57
58 func (p *piece) unpendChunkIndex(i int) {
59         for i >= len(p.DirtyChunks) {
60                 p.DirtyChunks = append(p.DirtyChunks, false)
61         }
62         p.DirtyChunks[i] = true
63 }
64
65 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
66         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
67         if ret.Begin+ret.Length > pieceLength {
68                 ret.Length = pieceLength - ret.Begin
69         }
70         return ret
71 }
72
73 func (p *piece) shuffledPendingChunkSpecs(t *torrent, piece int) (css []chunkSpec) {
74         // defer func() {
75         //      log.Println(piece, css)
76         // }()
77         numPending := t.pieceNumPendingChunks(piece)
78         if numPending == 0 {
79                 return
80         }
81         css = make([]chunkSpec, 0, numPending)
82         for ci := range iter.N(t.pieceNumChunks(piece)) {
83                 if ci >= len(p.DirtyChunks) || !p.DirtyChunks[ci] {
84                         css = append(css, t.chunkIndexSpec(ci, piece))
85                 }
86         }
87         if len(css) <= 1 {
88                 return
89         }
90         for i := range css {
91                 j := rand.Intn(i + 1)
92                 css[i], css[j] = css[j], css[i]
93         }
94         return
95 }