]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Rework requesting of shuffled pending pieces
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "sync"
5
6         "github.com/anacrolix/missinggo/bitmap"
7
8         pp "github.com/anacrolix/torrent/peer_protocol"
9 )
10
11 // Piece priority describes the importance of obtaining a particular piece.
12
13 type piecePriority byte
14
15 func (me *piecePriority) Raise(maybe piecePriority) {
16         if maybe > *me {
17                 *me = maybe
18         }
19 }
20
21 const (
22         PiecePriorityNone      piecePriority = iota // Not wanted.
23         PiecePriorityNormal                         // Wanted.
24         PiecePriorityReadahead                      // May be required soon.
25         PiecePriorityNext                           // Succeeds a piece where a read occurred.
26         PiecePriorityNow                            // A read occurred in this piece.
27 )
28
29 type piece struct {
30         // The completed piece SHA1 hash, from the metainfo "pieces" field.
31         Hash  pieceSum
32         t     *torrent
33         index int
34         // Chunks we've written to since the last check. The chunk offset and
35         // length can be determined by the request chunkSize in use.
36         DirtyChunks      bitmap.Bitmap
37         Hashing          bool
38         QueuedForHash    bool
39         EverHashed       bool
40         PublicPieceState PieceState
41         priority         piecePriority
42
43         pendingWritesMutex sync.Mutex
44         pendingWrites      int
45         noPendingWrites    sync.Cond
46 }
47
48 func (p *piece) pendingChunkIndex(chunkIndex int) bool {
49         return !p.DirtyChunks.Contains(chunkIndex)
50 }
51
52 func (p *piece) pendingChunk(cs chunkSpec, chunkSize pp.Integer) bool {
53         return p.pendingChunkIndex(chunkIndex(cs, chunkSize))
54 }
55
56 func (p *piece) hasDirtyChunks() bool {
57         return p.DirtyChunks.Len() != 0
58 }
59
60 func (p *piece) numDirtyChunks() (ret int) {
61         return p.DirtyChunks.Len()
62 }
63
64 func (p *piece) unpendChunkIndex(i int) {
65         p.DirtyChunks.Add(i)
66 }
67
68 func (p *piece) pendChunkIndex(i int) {
69         p.DirtyChunks.Remove(i)
70 }
71
72 func chunkIndexSpec(index int, pieceLength, chunkSize pp.Integer) chunkSpec {
73         ret := chunkSpec{pp.Integer(index) * chunkSize, chunkSize}
74         if ret.Begin+ret.Length > pieceLength {
75                 ret.Length = pieceLength - ret.Begin
76         }
77         return ret
78 }
79
80 func (p *piece) numChunks() int {
81         return p.t.pieceNumChunks(p.index)
82 }
83
84 func (p *piece) undirtiedChunkIndices() (ret bitmap.Bitmap) {
85         ret = p.DirtyChunks.Copy()
86         ret.FlipRange(0, p.numChunks())
87         return
88 }
89
90 func (p *piece) incrementPendingWrites() {
91         p.pendingWritesMutex.Lock()
92         p.pendingWrites++
93         p.pendingWritesMutex.Unlock()
94 }
95
96 func (p *piece) decrementPendingWrites() {
97         p.pendingWritesMutex.Lock()
98         if p.pendingWrites == 0 {
99                 panic("assertion")
100         }
101         p.pendingWrites--
102         if p.pendingWrites == 0 {
103                 p.noPendingWrites.Broadcast()
104         }
105         p.pendingWritesMutex.Unlock()
106 }
107
108 func (p *piece) waitNoPendingWrites() {
109         p.pendingWritesMutex.Lock()
110         for p.pendingWrites != 0 {
111                 p.noPendingWrites.Wait()
112         }
113         p.pendingWritesMutex.Unlock()
114 }