]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Fix downloading of unwanted chunks, and write out downloaded chunks using the connect...
[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 (p *piece) pendChunkIndex(i int) {
65         if i >= len(p.DirtyChunks) {
66                 return
67         }
68         p.DirtyChunks[i] = false
69 }
70
71 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
72         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
73         if ret.Begin+ret.Length > pieceLength {
74                 ret.Length = pieceLength - ret.Begin
75         }
76         return ret
77 }
78
79 func (p *piece) shuffledPendingChunkSpecs(t *torrent, piece int) (css []chunkSpec) {
80         // defer func() {
81         //      log.Println(piece, css)
82         // }()
83         numPending := t.pieceNumPendingChunks(piece)
84         if numPending == 0 {
85                 return
86         }
87         css = make([]chunkSpec, 0, numPending)
88         for ci := range iter.N(t.pieceNumChunks(piece)) {
89                 if ci >= len(p.DirtyChunks) || !p.DirtyChunks[ci] {
90                         css = append(css, t.chunkIndexSpec(ci, piece))
91                 }
92         }
93         if len(css) <= 1 {
94                 return
95         }
96         for i := range css {
97                 j := rand.Intn(i + 1)
98                 css[i], css[j] = css[j], css[i]
99         }
100         return
101 }
102
103 func (p *piece) incrementPendingWrites() {
104         p.pendingWritesMutex.Lock()
105         p.pendingWrites++
106         p.pendingWritesMutex.Unlock()
107 }
108
109 func (p *piece) decrementPendingWrites() {
110         p.pendingWritesMutex.Lock()
111         if p.pendingWrites == 0 {
112                 panic("assertion")
113         }
114         p.pendingWrites--
115         if p.pendingWrites == 0 {
116                 p.noPendingWrites.Broadcast()
117         }
118         p.pendingWritesMutex.Unlock()
119 }
120
121 func (p *piece) waitNoPendingWrites() {
122         p.pendingWritesMutex.Lock()
123         for p.pendingWrites != 0 {
124                 p.noPendingWrites.Wait()
125         }
126         p.pendingWritesMutex.Unlock()
127 }