]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Add File priorities
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "fmt"
5         "sync"
6
7         "github.com/anacrolix/missinggo/bitmap"
8
9         "github.com/anacrolix/torrent/metainfo"
10         pp "github.com/anacrolix/torrent/peer_protocol"
11         "github.com/anacrolix/torrent/storage"
12 )
13
14 // Piece priority describes the importance of obtaining a particular piece.
15
16 type piecePriority byte
17
18 func (pp *piecePriority) Raise(maybe piecePriority) {
19         if maybe > *pp {
20                 *pp = maybe
21         }
22 }
23
24 // Priority for use in PriorityBitmap
25 func (me piecePriority) BitmapPriority() int {
26         return -int(me)
27 }
28
29 const (
30         PiecePriorityNone      piecePriority = iota // Not wanted. Must be the zero value.
31         PiecePriorityNormal                         // Wanted.
32         PiecePriorityHigh                           // Wanted a lot.
33         PiecePriorityReadahead                      // May be required soon.
34         // Succeeds a piece where a read occurred. Currently the same as Now,
35         // apparently due to issues with caching.
36         PiecePriorityNext
37         PiecePriorityNow // A Reader is reading in this piece. Highest urgency.
38 )
39
40 type Piece struct {
41         // The completed piece SHA1 hash, from the metainfo "pieces" field.
42         hash  metainfo.Hash
43         t     *Torrent
44         index int
45         files []*File
46         // Chunks we've written to since the last check. The chunk offset and
47         // length can be determined by the request chunkSize in use.
48         dirtyChunks bitmap.Bitmap
49
50         hashing             bool
51         everHashed          bool
52         numVerifies         int64
53         storageCompletionOk bool
54
55         publicPieceState PieceState
56         priority         piecePriority
57
58         pendingWritesMutex sync.Mutex
59         pendingWrites      int
60         noPendingWrites    sync.Cond
61 }
62
63 func (p *Piece) String() string {
64         return fmt.Sprintf("%s/%d", p.t.infoHash.HexString(), p.index)
65 }
66
67 func (p *Piece) Info() metainfo.Piece {
68         return p.t.info.Piece(p.index)
69 }
70
71 func (p *Piece) Storage() storage.Piece {
72         return p.t.storage.Piece(p.Info())
73 }
74
75 func (p *Piece) pendingChunkIndex(chunkIndex int) bool {
76         return !p.dirtyChunks.Contains(chunkIndex)
77 }
78
79 func (p *Piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
80         return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
81 }
82
83 func (p *Piece) hasDirtyChunks() bool {
84         return p.dirtyChunks.Len() != 0
85 }
86
87 func (p *Piece) numDirtyChunks() (ret int) {
88         return p.dirtyChunks.Len()
89 }
90
91 func (p *Piece) unpendChunkIndex(i int) {
92         p.dirtyChunks.Add(i)
93 }
94
95 func (p *Piece) pendChunkIndex(i int) {
96         p.dirtyChunks.Remove(i)
97 }
98
99 func (p *Piece) numChunks() int {
100         return p.t.pieceNumChunks(p.index)
101 }
102
103 func (p *Piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
104         ret = p.dirtyChunks.Copy()
105         ret.FlipRange(0, p.numChunks())
106         return
107 }
108
109 func (p *Piece) incrementPendingWrites() {
110         p.pendingWritesMutex.Lock()
111         p.pendingWrites++
112         p.pendingWritesMutex.Unlock()
113 }
114
115 func (p *Piece) decrementPendingWrites() {
116         p.pendingWritesMutex.Lock()
117         if p.pendingWrites == 0 {
118                 panic("assertion")
119         }
120         p.pendingWrites--
121         if p.pendingWrites == 0 {
122                 p.noPendingWrites.Broadcast()
123         }
124         p.pendingWritesMutex.Unlock()
125 }
126
127 func (p *Piece) waitNoPendingWrites() {
128         p.pendingWritesMutex.Lock()
129         for p.pendingWrites != 0 {
130                 p.noPendingWrites.Wait()
131         }
132         p.pendingWritesMutex.Unlock()
133 }
134
135 func (p *Piece) chunkIndexDirty(chunk int) bool {
136         return p.dirtyChunks.Contains(chunk)
137 }
138
139 func (p *Piece) chunkIndexSpec(chunk int) chunkSpec {
140         return chunkIndexSpec(chunk, p.length(), p.chunkSize())
141 }
142
143 func (p *Piece) numDirtyBytes() (ret pp.Integer) {
144         // defer func() {
145         //      if ret > p.length() {
146         //              panic("too many dirty bytes")
147         //      }
148         // }()
149         numRegularDirtyChunks := p.numDirtyChunks()
150         if p.chunkIndexDirty(p.numChunks() - 1) {
151                 numRegularDirtyChunks--
152                 ret += p.chunkIndexSpec(p.lastChunkIndex()).Length
153         }
154         ret += pp.Integer(numRegularDirtyChunks) * p.chunkSize()
155         return
156 }
157
158 func (p *Piece) length() pp.Integer {
159         return p.t.pieceLength(p.index)
160 }
161
162 func (p *Piece) chunkSize() pp.Integer {
163         return p.t.chunkSize
164 }
165
166 func (p *Piece) lastChunkIndex() int {
167         return p.numChunks() - 1
168 }
169
170 func (p *Piece) bytesLeft() (ret pp.Integer) {
171         if p.t.pieceComplete(p.index) {
172                 return 0
173         }
174         return p.length() - p.numDirtyBytes()
175 }
176
177 func (p *Piece) VerifyData() {
178         p.t.cl.mu.Lock()
179         defer p.t.cl.mu.Unlock()
180         target := p.numVerifies + 1
181         if p.hashing {
182                 target++
183         }
184         // log.Printf("target: %d", target)
185         p.t.queuePieceCheck(p.index)
186         for p.numVerifies < target {
187                 // log.Printf("got %d verifies", p.numVerifies)
188                 p.t.cl.event.Wait()
189         }
190         // log.Print("done")
191 }
192
193 func (p *Piece) queuedForHash() bool {
194         return p.t.piecesQueuedForHash.Get(p.index)
195 }
196
197 func (p *Piece) torrentBeginOffset() int64 {
198         return int64(p.index) * p.t.info.PieceLength
199 }
200
201 func (p *Piece) torrentEndOffset() int64 {
202         return p.torrentBeginOffset() + int64(p.length())
203 }