]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Comment on PiecePriorityNext
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "sync"
5
6         "github.com/anacrolix/missinggo/bitmap"
7
8         "github.com/anacrolix/torrent/metainfo"
9         pp "github.com/anacrolix/torrent/peer_protocol"
10         "github.com/anacrolix/torrent/storage"
11 )
12
13 // Piece priority describes the importance of obtaining a particular piece.
14
15 type piecePriority byte
16
17 func (pp *piecePriority) Raise(maybe piecePriority) {
18         if maybe > *pp {
19                 *pp = maybe
20         }
21 }
22
23 const (
24         PiecePriorityNone      piecePriority = iota // Not wanted.
25         PiecePriorityNormal                         // Wanted.
26         PiecePriorityReadahead                      // May be required soon.
27         // Succeeds a piece where a read occurred. Currently the same as Now, apparently due to issues with caching.
28         PiecePriorityNext
29         PiecePriorityNow // A Reader is reading in this piece.
30 )
31
32 type piece struct {
33         // The completed piece SHA1 hash, from the metainfo "pieces" field.
34         Hash  metainfo.Hash
35         t     *Torrent
36         index int
37         // Chunks we've written to since the last check. The chunk offset and
38         // length can be determined by the request chunkSize in use.
39         DirtyChunks      bitmap.Bitmap
40         Hashing          bool
41         QueuedForHash    bool
42         EverHashed       bool
43         PublicPieceState PieceState
44         priority         piecePriority
45
46         pendingWritesMutex sync.Mutex
47         pendingWrites      int
48         noPendingWrites    sync.Cond
49 }
50
51 func (p *piece) Info() metainfo.Piece {
52         return p.t.info.Piece(p.index)
53 }
54
55 func (p *piece) Storage() storage.Piece {
56         return p.t.storage.Piece(p.Info())
57 }
58
59 func (p *piece) pendingChunkIndex(chunkIndex int) bool {
60         return !p.DirtyChunks.Contains(chunkIndex)
61 }
62
63 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
64         return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
65 }
66
67 func (p *piece) hasDirtyChunks() bool {
68         return p.DirtyChunks.Len() != 0
69 }
70
71 func (p *piece) numDirtyChunks() (ret int) {
72         return p.DirtyChunks.Len()
73 }
74
75 func (p *piece) unpendChunkIndex(i int) {
76         p.DirtyChunks.Add(i)
77 }
78
79 func (p *piece) pendChunkIndex(i int) {
80         p.DirtyChunks.Remove(i)
81 }
82
83 func (p *piece) numChunks() int {
84         return p.t.pieceNumChunks(p.index)
85 }
86
87 func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
88         ret = p.DirtyChunks.Copy()
89         ret.FlipRange(0, p.numChunks())
90         return
91 }
92
93 func (p *piece) incrementPendingWrites() {
94         p.pendingWritesMutex.Lock()
95         p.pendingWrites++
96         p.pendingWritesMutex.Unlock()
97 }
98
99 func (p *piece) decrementPendingWrites() {
100         p.pendingWritesMutex.Lock()
101         if p.pendingWrites == 0 {
102                 panic("assertion")
103         }
104         p.pendingWrites--
105         if p.pendingWrites == 0 {
106                 p.noPendingWrites.Broadcast()
107         }
108         p.pendingWritesMutex.Unlock()
109 }
110
111 func (p *piece) waitNoPendingWrites() {
112         p.pendingWritesMutex.Lock()
113         for p.pendingWrites != 0 {
114                 p.noPendingWrites.Wait()
115         }
116         p.pendingWritesMutex.Unlock()
117 }
118
119 func (p *piece) chunkIndexDirty(chunk int) bool {
120         return p.DirtyChunks.Contains(chunk)
121 }
122
123 func (p *piece) chunkIndexSpec(chunk int) chunkSpec {
124         return chunkIndexSpec(chunk, p.length(), p.chunkSize())
125 }
126
127 func (p *piece) numDirtyBytes() (ret pp.Integer) {
128         defer func() {
129                 if ret > p.length() {
130                         panic("too many dirty bytes")
131                 }
132         }()
133         numRegularDirtyChunks := p.numDirtyChunks()
134         if p.chunkIndexDirty(p.numChunks() - 1) {
135                 numRegularDirtyChunks--
136                 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
137         }
138         ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
139         return
140 }
141
142 func (p *piece) length() pp.Integer {
143         return p.t.pieceLength(p.index)
144 }
145
146 func (p *piece) chunkSize() pp.Integer {
147         return p.t.chunkSize
148 }
149
150 func (p *piece) lastChunkIndex() int {
151         return p.numChunks() - 1
152 }
153
154 func (p *piece) bytesLeft() (ret pp.Integer) {
155         if p.t.pieceComplete(p.index) {
156                 return 0
157         }
158         return p.length() - p.numDirtyBytes()
159 }