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 void init(int blocks_per_piece
, int total_num_blocks
);
165 int num_pieces() const { return int(m_piece_map
.size()); }
167 bool have_piece(int index
) const
169 TORRENT_ASSERT(index
>= 0);
170 TORRENT_ASSERT(index
< int(m_piece_map
.size()));
171 return m_piece_map
[index
].index
== piece_pos::we_have_index
;
174 // sets the priority of a piece.
175 // returns true if the priority was changed from 0 to non-0
177 bool set_piece_priority(int index
, int prio
);
179 // returns the priority for the piece at 'index'
180 int piece_priority(int index
) const;
182 // returns the current piece priorities for all pieces
183 void piece_priorities(std::vector
<int>& pieces
) const;
185 // ========== start deprecation ==============
187 // fills the bitmask with 1's for pieces that are filtered
188 void filtered_pieces(std::vector
<bool>& mask
) const;
190 // ========== end deprecation ==============
192 // pieces should be the vector that represents the pieces a
193 // client has. It returns a list of all pieces that this client
194 // has and that are interesting to download. It returns them in
195 // priority order. It doesn't care about the download flag.
196 // The user of this function must lookup if any piece is
197 // marked as being downloaded. If the user of this function
198 // decides to download a piece, it must mark it as being downloaded
199 // itself, by using the mark_as_downloading() member function.
200 // THIS IS DONE BY THE peer_connection::send_request() MEMBER FUNCTION!
201 // The last argument is the policy::peer pointer for the peer that
202 // we'll download from.
203 void pick_pieces(bitfield
const& pieces
204 , std::vector
<piece_block
>& interesting_blocks
205 , int num_pieces
, int prefer_whole_pieces
206 , void* peer
, piece_state_t speed
207 , bool rarest_first
, bool on_parole
208 , std::vector
<int> const& suggested_pieces
) const;
210 // picks blocks from each of the pieces in the piece_list
211 // vector that is also in the piece bitmask. The blocks
212 // are added to interesting_blocks, and busy blocks are
213 // added to backup_blocks. num blocks is the number of
214 // blocks to be picked. Blocks are not picked from pieces
215 // that are being downloaded
216 int add_blocks(std::vector
<int> const& piece_list
217 , bitfield
const& pieces
218 , std::vector
<piece_block
>& interesting_blocks
219 , int num_blocks
, int prefer_whole_pieces
220 , void* peer
, std::vector
<int> const& ignore
) const;
222 // picks blocks only from downloading pieces
223 int add_blocks_downloading(
224 bitfield
const& pieces
225 , std::vector
<piece_block
>& interesting_blocks
226 , std::vector
<piece_block
>& backup_blocks
227 , int num_blocks
, int prefer_whole_pieces
228 , void* peer
, piece_state_t speed
229 , bool on_parole
) const;
231 // clears the peer pointer in all downloading pieces with this
233 void clear_peer(void* peer
);
235 // returns true if any client is currently downloading this
236 // piece-block, or if it's queued for downloading by some client
237 // or if it already has been successfully downloaded
238 bool is_requested(piece_block block
) const;
239 // returns true if the block has been downloaded
240 bool is_downloaded(piece_block block
) const;
241 // returns true if the block has been downloaded and written to disk
242 bool is_finished(piece_block block
) const;
244 // marks this piece-block as queued for downloading
245 bool mark_as_downloading(piece_block block
, void* peer
247 void mark_as_writing(piece_block block
, void* peer
);
248 void mark_as_finished(piece_block block
, void* peer
);
249 void write_failed(piece_block block
);
250 int num_peers(piece_block block
) const;
252 // returns information about the given piece
253 void piece_info(int index
, piece_picker::downloading_piece
& st
) const;
255 // if a piece had a hash-failure, it must be restored and
256 // made available for redownloading
257 void restore_piece(int index
);
259 // clears the given piece's download flag
260 // this means that this piece-block can be picked again
261 void abort_download(piece_block block
);
263 bool is_piece_finished(int index
) const;
265 // returns the number of blocks there is in the given piece
266 int blocks_in_piece(int index
) const;
268 // the number of downloaded blocks that hasn't passed
269 // the hash-check yet
270 int unverified_blocks() const;
272 void get_downloaders(std::vector
<void*>& d
, int index
) const;
274 std::vector
<downloading_piece
> const& get_download_queue() const
275 { return m_downloads
; }
277 void* get_downloader(piece_block block
) const;
279 // the number of filtered pieces we don't have
280 int num_filtered() const { return m_num_filtered
; }
282 // the number of filtered pieces we already have
283 int num_have_filtered() const { return m_num_have_filtered
; }
285 int num_have() const { return m_num_have
; }
288 // used in debug mode
289 void verify_priority(int start
, int end
, int prio
) const;
290 void check_invariant(const torrent
* t
= 0) const;
291 void verify_pick(std::vector
<piece_block
> const& picked
292 , bitfield
const& bits
) const;
293 void print_pieces() const;
296 // functor that compares indices on downloading_pieces
299 has_index(int i
): index(i
) { TORRENT_ASSERT(i
>= 0); }
300 bool operator()(const downloading_piece
& p
) const
301 { return p
.index
== index
; }
305 int blocks_in_last_piece() const
306 { return m_blocks_in_last_piece
; }
308 float distributed_copies() const;
312 friend struct piece_pos
;
314 bool can_pick(int piece
, bitfield
const& bitmask
) const;
315 std::pair
<int, int> expand_piece(int piece
, int whole_pieces
316 , bitfield
const& have
) const;
321 piece_pos(int peer_count_
, int index_
)
322 : peer_count(peer_count_
)
327 TORRENT_ASSERT(peer_count_
>= 0);
328 TORRENT_ASSERT(index_
>= 0);
331 // the number of peers that has this piece
333 unsigned peer_count
: 10;
334 // is 1 if the piece is marked as being downloaded
335 unsigned downloading
: 1;
336 // is 0 if the piece is filtered (not to be downloaded)
337 // 1 is normal priority (default)
338 // 2 is higher priority than pieces at the same availability level
339 // 3 is same priority as partial pieces
340 // 4 is higher priority than partial pieces
341 // 5 and 6 same priority as availability 1 (ignores availability)
342 // 7 is maximum priority (ignores availability)
343 unsigned piece_priority
: 3;
344 // index in to the piece_info vector
349 // index is set to this to indicate that we have the
350 // piece. There is no entry for the piece in the
351 // buckets if this is the case.
352 we_have_index
= 0x3ffff,
353 // the priority value that means the piece is filtered
355 // the max number the peer count can hold
356 max_peer_count
= 0x3ff
359 bool have() const { return index
== we_have_index
; }
360 void set_have() { index
= we_have_index
; TORRENT_ASSERT(have()); }
361 void set_not_have() { index
= 0; TORRENT_ASSERT(!have()); }
363 bool filtered() const { return piece_priority
== filter_priority
; }
364 void filtered(bool f
) { piece_priority
= f
? filter_priority
: 0; }
366 int priority(piece_picker
const* picker
) const
368 if (downloading
|| filtered()
369 || have() || peer_count
+ picker
->m_seeds
== 0)
372 // priority 5, 6 and 7 disregards availability of the piece
373 if (piece_priority
> 4) return 7 - piece_priority
;
375 // pieces we are currently downloading have high priority
376 int prio
= peer_count
* 4;
377 // if (prio >= picker->m_prio_limit * 6) prio = picker->m_prio_limit * 6;
379 return prio
+ (4 - piece_priority
);
382 bool operator!=(piece_pos p
) const
383 { return index
!= p
.index
|| peer_count
!= p
.peer_count
; }
385 bool operator==(piece_pos p
) const
386 { return index
== p
.index
&& peer_count
== p
.peer_count
; }
390 BOOST_STATIC_ASSERT(sizeof(piece_pos
) == sizeof(char) * 4);
392 void update_pieces() const;
394 // fills in the range [start, end) of pieces in
395 // m_pieces that have priority 'prio'
396 void priority_range(int prio
, int* start
, int* end
);
398 // adds the piece 'index' to m_pieces
400 // removes the piece with the given priority and the
401 // elem_index in the m_pieces vector
402 void remove(int priority
, int elem_index
);
403 // updates the position of the piece with the given
404 // priority and the elem_index in the m_pieces vector
405 void update(int priority
, int elem_index
);
406 // shuffles the given piece inside it's priority range
407 void shuffle(int priority
, int elem_index
);
409 void sort_piece(std::vector
<downloading_piece
>::iterator dp
);
411 downloading_piece
& add_download_piece();
412 void erase_download_piece(std::vector
<downloading_piece
>::iterator i
);
414 // the number of seeds. These are not added to
415 // the availability counters of the pieces
418 // the following vectors are mutable because they sometimes may
419 // be updated lazily, triggered by const functions
421 // this vector contains all piece indices that are pickable
422 // sorted by priority. Pieces are in random random order
423 // among pieces with the same priority
424 mutable std::vector
<int> m_pieces
;
426 // these are indices to the priority boundries inside
427 // the m_pieces vector. priority 0 always start at
428 // 0, priority 1 starts at m_priority_boundries[0] etc.
429 mutable std::vector
<int> m_priority_boundries
;
431 // this maps indices to number of peers that has this piece and
432 // index into the m_piece_info vectors.
433 // piece_pos::we_have_index means that we have the piece, so it
434 // doesn't exist in the piece_info buckets
435 // pieces with the filtered flag set doesn't have entries in
436 // the m_piece_info buckets either
437 mutable std::vector
<piece_pos
> m_piece_map
;
439 // each piece that's currently being downloaded
440 // has an entry in this list with block allocations.
441 // i.e. it says wich parts of the piece that
442 // is being downloaded
443 std::vector
<downloading_piece
> m_downloads
;
445 // this holds the information of the
446 // blocks in partially downloaded pieces.
447 // the first m_blocks_per_piece entries
448 // in the vector belongs to the first
449 // entry in m_downloads, the second
450 // m_blocks_per_piece entries to the
451 // second entry in m_downloads and so on.
452 std::vector
<block_info
> m_block_info
;
454 int m_blocks_per_piece
;
455 int m_blocks_in_last_piece
;
457 // the number of filtered pieces that we don't already
458 // have. total_number_of_pieces - number_of_pieces_we_have
459 // - num_filtered is supposed to the number of pieces
460 // we still want to download
463 // the number of pieces we have that also are filtered
464 int m_num_have_filtered
;
466 // the number of pieces we have
469 // -1 means sequential download is not active.
470 // >= 0 means that pieces are requested in sequential order
471 // and this variable is the next piece to request.
472 // in that case m_pieces is cleared and not used.
473 int m_sequential_download
;
475 // if this is set to true, it means update_pieces()
476 // has to be called before accessing m_pieces.
477 mutable bool m_dirty
;
480 enum { max_pieces
= piece_pos::we_have_index
- 1 };
484 inline int piece_picker::blocks_in_piece(int index
) const
486 TORRENT_ASSERT(index
>= 0);
487 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
488 if (index
+1 == (int)m_piece_map
.size())
489 return m_blocks_in_last_piece
;
491 return m_blocks_per_piece
;
496 #endif // TORRENT_PIECE_PICKER_HPP_INCLUDED