3 Copyright (c) 2003, Arvid Norberg
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
10 * Redistributions of source code must retain the above copyright
11 notice, this list of conditions and the following disclaimer.
12 * Redistributions in binary form must reproduce the above copyright
13 notice, this list of conditions and the following disclaimer in
14 the documentation and/or other materials provided with the distribution.
15 * Neither the name of the author nor the names of its
16 contributors may be used to endorse or promote products derived
17 from this software without specific prior written permission.
19 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
20 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
23 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 POSSIBILITY OF SUCH DAMAGE.
32 #ifndef TORRENT_PIECE_PICKER_HPP_INCLUDED
33 #define TORRENT_PIECE_PICKER_HPP_INCLUDED
41 #pragma warning(push, 1)
44 #include <boost/static_assert.hpp>
50 #include "libtorrent/peer_id.hpp"
51 #include "libtorrent/socket.hpp"
52 #include "libtorrent/session_settings.hpp"
53 #include "libtorrent/config.hpp"
54 #include "libtorrent/assert.hpp"
60 class peer_connection
;
63 struct TORRENT_EXPORT piece_block
65 piece_block(int p_index
, int b_index
)
66 : piece_index(p_index
)
67 , block_index(b_index
)
72 bool operator<(piece_block
const& b
) const
74 if (piece_index
< b
.piece_index
) return true;
75 if (piece_index
== b
.piece_index
) return block_index
< b
.block_index
;
79 bool operator==(piece_block
const& b
) const
80 { return piece_index
== b
.piece_index
&& block_index
== b
.block_index
; }
82 bool operator!=(piece_block
const& b
) const
83 { return piece_index
!= b
.piece_index
|| block_index
!= b
.block_index
; }
87 class TORRENT_EXPORT piece_picker
93 block_info(): peer(0), num_peers(0), state(state_none
) {}
94 // the peer this block was requested or
95 // downloaded from. This is a pointer to
96 // a policy::peer object
98 // the number of peers that has this block in their
99 // download or request queues
100 unsigned num_peers
:14;
101 // the state of this block
102 enum { state_none
, state_requested
, state_writing
, state_finished
};
106 // the peers that are downloading this piece
107 // are considered fast peers or slow peers.
108 // none is set if the blocks were downloaded
109 // in a previous session
111 { none
, slow
, medium
, fast
};
113 struct downloading_piece
115 downloading_piece(): finished(0), writing(0), requested(0) {}
118 // the index of the piece
120 // info about each block
121 // this is a pointer into the m_block_info
122 // vector owned by the piece_picker
124 // the number of blocks in the finished state
125 boost::int16_t finished
;
126 // the number of blocks in the writing state
127 boost::int16_t writing
;
128 // the number of blocks in the requested state
129 boost::int16_t requested
;
134 void get_availability(std::vector
<int>& avail
) const;
136 void sequential_download(bool sd
);
137 bool sequential_download() const { return m_sequential_download
>= 0; }
139 // increases the peer count for the given piece
140 // (is used when a HAVE message is received)
141 void inc_refcount(int index
);
142 void dec_refcount(int index
);
144 // increases the peer count for the given piece
145 // (is used when a BITFIELD message is received)
146 void inc_refcount(bitfield
const& bitmask
);
147 // decreases the peer count for the given piece
148 // (used when a peer disconnects)
149 void dec_refcount(bitfield
const& bitmask
);
151 // these will increase and decrease the peer count
152 // of all pieces. They are used when seeds join
153 // or leave the swarm.
154 void inc_refcount_all();
155 void dec_refcount_all();
157 // This indicates that we just received this piece
158 // it means that the refcounter will indicate that
159 // we are not interested in this piece anymore
160 // (i.e. we don't have to maintain a refcount)
161 void we_have(int index
);
162 void we_dont_have(int index
);
164 // sets all pieces to dont-have
165 void init(int blocks_per_piece
, int total_num_blocks
);
166 int num_pieces() const { return int(m_piece_map
.size()); }
168 bool have_piece(int index
) const
170 TORRENT_ASSERT(index
>= 0);
171 TORRENT_ASSERT(index
< int(m_piece_map
.size()));
172 return m_piece_map
[index
].index
== piece_pos::we_have_index
;
175 // sets the priority of a piece.
176 // returns true if the priority was changed from 0 to non-0
178 bool set_piece_priority(int index
, int prio
);
180 // returns the priority for the piece at 'index'
181 int piece_priority(int index
) const;
183 // returns the current piece priorities for all pieces
184 void piece_priorities(std::vector
<int>& pieces
) const;
186 // ========== start deprecation ==============
188 // fills the bitmask with 1's for pieces that are filtered
189 void filtered_pieces(std::vector
<bool>& mask
) const;
191 // ========== end deprecation ==============
193 // pieces should be the vector that represents the pieces a
194 // client has. It returns a list of all pieces that this client
195 // has and that are interesting to download. It returns them in
196 // priority order. It doesn't care about the download flag.
197 // The user of this function must lookup if any piece is
198 // marked as being downloaded. If the user of this function
199 // decides to download a piece, it must mark it as being downloaded
200 // itself, by using the mark_as_downloading() member function.
201 // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
202 // The last argument is the policy::peer pointer for the peer that
203 // we'll download from.
204 void pick_pieces(bitfield
const& pieces
205 , std::vector
<piece_block
>& interesting_blocks
206 , int num_pieces
, int prefer_whole_pieces
207 , void* peer
, piece_state_t speed
208 , bool rarest_first
, bool on_parole
209 , std::vector
<int> const& suggested_pieces
) const;
211 // picks blocks from each of the pieces in the piece_list
212 // vector that is also in the piece bitmask. The blocks
213 // are added to interesting_blocks, and busy blocks are
214 // added to backup_blocks. num blocks is the number of
215 // blocks to be picked. Blocks are not picked from pieces
216 // that are being downloaded
217 int add_blocks(std::vector
<int> const& piece_list
218 , bitfield
const& pieces
219 , std::vector
<piece_block
>& interesting_blocks
220 , int num_blocks
, int prefer_whole_pieces
221 , void* peer
, std::vector
<int> const& ignore
) const;
223 // picks blocks only from downloading pieces
224 int add_blocks_downloading(
225 bitfield
const& pieces
226 , std::vector
<piece_block
>& interesting_blocks
227 , std::vector
<piece_block
>& backup_blocks
228 , int num_blocks
, int prefer_whole_pieces
229 , void* peer
, piece_state_t speed
230 , bool on_parole
) const;
232 // clears the peer pointer in all downloading pieces with this
234 void clear_peer(void* peer
);
236 // returns true if any client is currently downloading this
237 // piece-block, or if it's queued for downloading by some client
238 // or if it already has been successfully downloaded
239 bool is_requested(piece_block block
) const;
240 // returns true if the block has been downloaded
241 bool is_downloaded(piece_block block
) const;
242 // returns true if the block has been downloaded and written to disk
243 bool is_finished(piece_block block
) const;
245 // marks this piece-block as queued for downloading
246 bool mark_as_downloading(piece_block block
, void* peer
248 void mark_as_writing(piece_block block
, void* peer
);
249 void mark_as_finished(piece_block block
, void* peer
);
250 void write_failed(piece_block block
);
251 int num_peers(piece_block block
) const;
253 // returns information about the given piece
254 void piece_info(int index
, piece_picker::downloading_piece
& st
) const;
256 // if a piece had a hash-failure, it must be restored and
257 // made available for redownloading
258 void restore_piece(int index
);
260 // clears the given piece's download flag
261 // this means that this piece-block can be picked again
262 void abort_download(piece_block block
);
264 bool is_piece_finished(int index
) const;
266 // returns the number of blocks there is in the given piece
267 int blocks_in_piece(int index
) const;
269 // the number of downloaded blocks that hasn't passed
270 // the hash-check yet
271 int unverified_blocks() const;
273 void get_downloaders(std::vector
<void*>& d
, int index
) const;
275 std::vector
<downloading_piece
> const& get_download_queue() const
276 { return m_downloads
; }
278 void* get_downloader(piece_block block
) const;
280 // the number of filtered pieces we don't have
281 int num_filtered() const { return m_num_filtered
; }
283 // the number of filtered pieces we already have
284 int num_have_filtered() const { return m_num_have_filtered
; }
286 int num_have() const { return m_num_have
; }
289 // used in debug mode
290 void verify_priority(int start
, int end
, int prio
) const;
291 void check_invariant(const torrent
* t
= 0) const;
292 void verify_pick(std::vector
<piece_block
> const& picked
293 , bitfield
const& bits
) const;
294 void print_pieces() const;
297 // functor that compares indices on downloading_pieces
300 has_index(int i
): index(i
) { TORRENT_ASSERT(i
>= 0); }
301 bool operator()(const downloading_piece
& p
) const
302 { return p
.index
== index
; }
306 int blocks_in_last_piece() const
307 { return m_blocks_in_last_piece
; }
309 float distributed_copies() const;
313 friend struct piece_pos
;
315 bool can_pick(int piece
, bitfield
const& bitmask
) const;
316 std::pair
<int, int> expand_piece(int piece
, int whole_pieces
317 , bitfield
const& have
) const;
322 piece_pos(int peer_count_
, int index_
)
323 : peer_count(peer_count_
)
328 TORRENT_ASSERT(peer_count_
>= 0);
329 TORRENT_ASSERT(index_
>= 0);
332 // the number of peers that has this piece
334 unsigned peer_count
: 10;
335 // is 1 if the piece is marked as being downloaded
336 unsigned downloading
: 1;
337 // is 0 if the piece is filtered (not to be downloaded)
338 // 1 is normal priority (default)
339 // 2 is higher priority than pieces at the same availability level
340 // 3 is same priority as partial pieces
341 // 4 is higher priority than partial pieces
342 // 5 and 6 same priority as availability 1 (ignores availability)
343 // 7 is maximum priority (ignores availability)
344 unsigned piece_priority
: 3;
345 // index in to the piece_info vector
350 // index is set to this to indicate that we have the
351 // piece. There is no entry for the piece in the
352 // buckets if this is the case.
353 we_have_index
= 0x3ffff,
354 // the priority value that means the piece is filtered
356 // the max number the peer count can hold
357 max_peer_count
= 0x3ff
360 bool have() const { return index
== we_have_index
; }
361 void set_have() { index
= we_have_index
; TORRENT_ASSERT(have()); }
362 void set_not_have() { index
= 0; TORRENT_ASSERT(!have()); }
364 bool filtered() const { return piece_priority
== filter_priority
; }
365 void filtered(bool f
) { piece_priority
= f
? filter_priority
: 0; }
367 int priority(piece_picker
const* picker
) const
369 if (downloading
|| filtered()
370 || have() || peer_count
+ picker
->m_seeds
== 0)
373 // priority 5, 6 and 7 disregards availability of the piece
374 if (piece_priority
> 4) return 7 - piece_priority
;
376 // pieces we are currently downloading have high priority
377 int prio
= peer_count
* 4;
378 // if (prio >= picker->m_prio_limit * 6) prio = picker->m_prio_limit * 6;
380 return prio
+ (4 - piece_priority
);
383 bool operator!=(piece_pos p
) const
384 { return index
!= p
.index
|| peer_count
!= p
.peer_count
; }
386 bool operator==(piece_pos p
) const
387 { return index
== p
.index
&& peer_count
== p
.peer_count
; }
391 BOOST_STATIC_ASSERT(sizeof(piece_pos
) == sizeof(char) * 4);
393 void update_pieces() const;
395 // fills in the range [start, end) of pieces in
396 // m_pieces that have priority 'prio'
397 void priority_range(int prio
, int* start
, int* end
);
399 // adds the piece 'index' to m_pieces
401 // removes the piece with the given priority and the
402 // elem_index in the m_pieces vector
403 void remove(int priority
, int elem_index
);
404 // updates the position of the piece with the given
405 // priority and the elem_index in the m_pieces vector
406 void update(int priority
, int elem_index
);
407 // shuffles the given piece inside it's priority range
408 void shuffle(int priority
, int elem_index
);
410 void sort_piece(std::vector
<downloading_piece
>::iterator dp
);
412 downloading_piece
& add_download_piece();
413 void erase_download_piece(std::vector
<downloading_piece
>::iterator i
);
415 // the number of seeds. These are not added to
416 // the availability counters of the pieces
419 // the following vectors are mutable because they sometimes may
420 // be updated lazily, triggered by const functions
422 // this vector contains all piece indices that are pickable
423 // sorted by priority. Pieces are in random random order
424 // among pieces with the same priority
425 mutable std::vector
<int> m_pieces
;
427 // these are indices to the priority boundries inside
428 // the m_pieces vector. priority 0 always start at
429 // 0, priority 1 starts at m_priority_boundries[0] etc.
430 mutable std::vector
<int> m_priority_boundries
;
432 // this maps indices to number of peers that has this piece and
433 // index into the m_piece_info vectors.
434 // piece_pos::we_have_index means that we have the piece, so it
435 // doesn't exist in the piece_info buckets
436 // pieces with the filtered flag set doesn't have entries in
437 // the m_piece_info buckets either
438 mutable std::vector
<piece_pos
> m_piece_map
;
440 // each piece that's currently being downloaded
441 // has an entry in this list with block allocations.
442 // i.e. it says wich parts of the piece that
443 // is being downloaded
444 std::vector
<downloading_piece
> m_downloads
;
446 // this holds the information of the
447 // blocks in partially downloaded pieces.
448 // the first m_blocks_per_piece entries
449 // in the vector belongs to the first
450 // entry in m_downloads, the second
451 // m_blocks_per_piece entries to the
452 // second entry in m_downloads and so on.
453 std::vector
<block_info
> m_block_info
;
455 int m_blocks_per_piece
;
456 int m_blocks_in_last_piece
;
458 // the number of filtered pieces that we don't already
459 // have. total_number_of_pieces - number_of_pieces_we_have
460 // - num_filtered is supposed to the number of pieces
461 // we still want to download
464 // the number of pieces we have that also are filtered
465 int m_num_have_filtered
;
467 // the number of pieces we have
470 // -1 means sequential download is not active.
471 // >= 0 means that pieces are requested in sequential order
472 // and this variable is the next piece to request.
473 // in that case m_pieces is cleared and not used.
474 int m_sequential_download
;
476 // if this is set to true, it means update_pieces()
477 // has to be called before accessing m_pieces.
478 mutable bool m_dirty
;
481 enum { max_pieces
= piece_pos::we_have_index
- 1 };
485 inline int piece_picker::blocks_in_piece(int index
) const
487 TORRENT_ASSERT(index
>= 0);
488 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
489 if (index
+1 == (int)m_piece_map
.size())
490 return m_blocks_in_last_piece
;
492 return m_blocks_per_piece
;
497 #endif // TORRENT_PIECE_PICKER_HPP_INCLUDED