]> Sergey Matveev's repositories - btrtrc.git/blob - piece.go
Use missinggo.bitmap for tracking dirty chunks
[btrtrc.git] / piece.go
1 package torrent
2
3 import (
4         "math/rand"
5         "sync"
6
7         "github.com/anacrolix/missinggo/bitmap"
8         "github.com/bradfitz/iter"
9
10         pp "github.com/anacrolix/torrent/peer_protocol"
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         // 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) shuffledPendingChunkSpecs(t *torrent, piece int) (css []chunkSpec) {
81         // defer func() {
82         //      log.Println(piece, css)
83         // }()
84         numPending := t.pieceNumPendingChunks(piece)
85         if numPending == 0 {
86                 return
87         }
88         css = make([]chunkSpec, 0, numPending)
89         for ci := range iter.N(t.pieceNumChunks(piece)) {
90                 if !p.DirtyChunks.Contains(ci) {
91                         css = append(css, t.chunkIndexSpec(ci, piece))
92                 }
93         }
94         if len(css) <= 1 {
95                 return
96         }
97         for i := range css {
98                 j := rand.Intn(i + 1)
99                 css[i], css[j] = css[j], css[i]
100         }
101         return
102 }
103
104 func (p *piece) incrementPendingWrites() {
105         p.pendingWritesMutex.Lock()
106         p.pendingWrites++
107         p.pendingWritesMutex.Unlock()
108 }
109
110 func (p *piece) decrementPendingWrites() {
111         p.pendingWritesMutex.Lock()
112         if p.pendingWrites == 0 {
113                 panic("assertion")
114         }
115         p.pendingWrites--
116         if p.pendingWrites == 0 {
117                 p.noPendingWrites.Broadcast()
118         }
119         p.pendingWritesMutex.Unlock()
120 }
121
122 func (p *piece) waitNoPendingWrites() {
123         p.pendingWritesMutex.Lock()
124         for p.pendingWrites != 0 {
125                 p.noPendingWrites.Wait()
126         }
127         p.pendingWritesMutex.Unlock()
128 }