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