]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
It's working and the tests are usually passing
[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         PublicPieceState PieceState
34
35         pendingWritesMutex sync.Mutex
36         pendingWrites      int
37         noPendingWrites    sync.Cond
38 }
39
40 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
41         ci := chunkIndex(cs, chunkSize)
42         if ci >= len(p.DirtyChunks) {
43                 return true
44         }
45         return !p.DirtyChunks[ci]
46 }
47
48 func (p *piece) numDirtyChunks() (ret int) {
49         for _, dirty := range p.DirtyChunks {
50                 if dirty {
51                         ret++
52                 }
53         }
54         return
55 }
56
57 func (p *piece) unpendChunkIndex(i int) {
58         for i >= len(p.DirtyChunks) {
59                 p.DirtyChunks = append(p.DirtyChunks, false)
60         }
61         p.DirtyChunks[i] = true
62 }
63
64 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
65         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
66         if ret.Begin+ret.Length > pieceLength {
67                 ret.Length = pieceLength - ret.Begin
68         }
69         return ret
70 }
71
72 func (p *piece) shuffledPendingChunkSpecs(t *torrent, piece int) (css []chunkSpec) {
73         // defer func() {
74         //      log.Println(piece, css)
75         // }()
76         numPending := t.pieceNumPendingChunks(piece)
77         if numPending == 0 {
78                 return
79         }
80         css = make([]chunkSpec, 0, numPending)
81         for ci := range iter.N(t.pieceNumChunks(piece)) {
82                 if ci >= len(p.DirtyChunks) || !p.DirtyChunks[ci] {
83                         css = append(css, t.chunkIndexSpec(ci, piece))
84                 }
85         }
86         if len(css) <= 1 {
87                 return
88         }
89         for i := range css {
90                 j := rand.Intn(i + 1)
91                 css[i], css[j] = css[j], css[i]
92         }
93         return
94 }