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.
33 #include "libtorrent/pch.hpp"
40 #include "libtorrent/piece_picker.hpp"
41 #include "libtorrent/aux_/session_impl.hpp"
42 #include "libtorrent/bitfield.hpp"
45 #include "libtorrent/peer_connection.hpp"
46 #include "libtorrent/torrent.hpp"
49 //#define TORRENT_PIECE_PICKER_INVARIANT_CHECK INVARIANT_CHECK
50 //#define TORRENT_NO_EXPENSIVE_INVARIANT_CHECK
51 #define TORRENT_PIECE_PICKER_INVARIANT_CHECK
53 //#define TORRENT_PICKER_LOG
58 piece_picker::piece_picker()
60 , m_priority_boundries(1, int(m_pieces
.size()))
62 , m_num_have_filtered(0)
64 , m_sequential_download(-1)
67 #ifdef TORRENT_PICKER_LOG
68 std::cerr
<< "new piece_picker" << std::endl
;
75 void piece_picker::init(int blocks_per_piece
, int total_num_blocks
)
77 TORRENT_ASSERT(blocks_per_piece
> 0);
78 TORRENT_ASSERT(total_num_blocks
>= 0);
80 // allocate the piece_map to cover all pieces
81 // and make them invalid (as if we don't have a single piece)
82 m_piece_map
.resize((total_num_blocks
+ blocks_per_piece
-1) / blocks_per_piece
85 // the piece index is stored in 20 bits, which limits the allowed
86 // number of pieces somewhat
87 if (m_piece_map
.size() >= piece_pos::we_have_index
)
88 throw std::runtime_error("too many pieces in torrent");
90 m_blocks_per_piece
= blocks_per_piece
;
91 m_blocks_in_last_piece
= total_num_blocks
% blocks_per_piece
;
92 if (m_blocks_in_last_piece
== 0) m_blocks_in_last_piece
= blocks_per_piece
;
94 TORRENT_ASSERT(m_blocks_in_last_piece
<= m_blocks_per_piece
);
97 void piece_picker::sequential_download(bool sd
)
99 if (sd
== sequential_download()) return;
101 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
105 std::vector
<int>().swap(m_pieces
);
106 std::vector
<int>().swap(m_priority_boundries
);
108 // initialize m_sdquential_download
109 m_sequential_download
= 0;
110 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin()
111 , end(m_piece_map
.end()); i
!= end
&& (i
->have() || i
->filtered());
112 ++i
, ++m_sequential_download
);
116 m_sequential_download
= -1;
121 void piece_picker::piece_info(int index
, piece_picker::downloading_piece
& st
) const
123 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
125 TORRENT_ASSERT(index
>= 0);
126 TORRENT_ASSERT(index
< int(m_piece_map
.size()));
128 if (m_piece_map
[index
].downloading
)
130 std::vector
<downloading_piece
>::const_iterator piece
= std::find_if(
131 m_downloads
.begin(), m_downloads
.end()
132 , bind(&downloading_piece::index
, _1
) == index
);
133 TORRENT_ASSERT(piece
!= m_downloads
.end());
142 if (m_piece_map
[index
].have())
144 st
.finished
= blocks_in_piece(index
);
150 piece_picker::downloading_piece
& piece_picker::add_download_piece()
152 int num_downloads
= m_downloads
.size();
153 int block_index
= num_downloads
* m_blocks_per_piece
;
154 if (int(m_block_info
.size()) < block_index
+ m_blocks_per_piece
)
156 block_info
* base
= 0;
157 if (!m_block_info
.empty()) base
= &m_block_info
[0];
158 m_block_info
.resize(block_index
+ m_blocks_per_piece
);
159 if (!m_downloads
.empty() && &m_block_info
[0] != base
)
161 // this means the memory was reallocated, update the pointers
162 for (int i
= 0; i
< int(m_downloads
.size()); ++i
)
163 m_downloads
[i
].info
= &m_block_info
[m_downloads
[i
].info
- base
];
166 m_downloads
.push_back(downloading_piece());
167 downloading_piece
& ret
= m_downloads
.back();
168 ret
.info
= &m_block_info
[block_index
];
169 for (int i
= 0; i
< m_blocks_per_piece
; ++i
)
171 ret
.info
[i
].num_peers
= 0;
172 ret
.info
[i
].state
= block_info::state_none
;
173 ret
.info
[i
].peer
= 0;
178 void piece_picker::erase_download_piece(std::vector
<downloading_piece
>::iterator i
)
180 std::vector
<downloading_piece
>::iterator other
= std::find_if(
181 m_downloads
.begin(), m_downloads
.end()
182 , bind(&downloading_piece::info
, _1
)
183 == &m_block_info
[(m_downloads
.size() - 1) * m_blocks_per_piece
]);
184 TORRENT_ASSERT(other
!= m_downloads
.end());
188 std::copy(other
->info
, other
->info
+ m_blocks_per_piece
, i
->info
);
189 other
->info
= i
->info
;
191 m_downloads
.erase(i
);
196 void piece_picker::verify_pick(std::vector
<piece_block
> const& picked
197 , bitfield
const& bits
) const
199 TORRENT_ASSERT(bits
.size() == m_piece_map
.size());
200 for (std::vector
<piece_block
>::const_iterator i
= picked
.begin()
201 , end(picked
.end()); i
!= end
; ++i
)
203 TORRENT_ASSERT(i
->piece_index
>= 0);
204 TORRENT_ASSERT(i
->piece_index
< int(bits
.size()));
205 TORRENT_ASSERT(bits
[i
->piece_index
]);
206 TORRENT_ASSERT(!m_piece_map
[i
->piece_index
].have());
210 void piece_picker::verify_priority(int range_start
, int range_end
, int prio
) const
212 TORRENT_ASSERT(range_start
<= range_end
);
213 TORRENT_ASSERT(range_end
<= int(m_pieces
.size()));
214 for (std::vector
<int>::const_iterator i
= m_pieces
.begin() + range_start
215 , end(m_pieces
.begin() + range_end
); i
!= end
; ++i
)
218 TORRENT_ASSERT(index
>= 0);
219 TORRENT_ASSERT(index
< int(m_piece_map
.size()));
220 int p
= m_piece_map
[index
].priority(this);
221 TORRENT_ASSERT(p
== prio
);
225 void piece_picker::print_pieces() const
227 for (std::vector
<int>::const_iterator i
= m_priority_boundries
.begin()
228 , end(m_priority_boundries
.end()); i
!= end
; ++i
)
230 std::cerr
<< *i
<< " ";
232 std::cout
<< std::endl
;
234 std::vector
<int>::const_iterator j
= m_priority_boundries
.begin();
235 for (std::vector
<int>::const_iterator i
= m_pieces
.begin()
236 , end(m_pieces
.end()); i
!= end
; ++i
, ++index
)
239 while (j
!= m_priority_boundries
.end() && *j
<= index
)
244 std::cerr
<< *i
<< "(" << m_piece_map
[*i
].index
<< ") ";
246 std::cerr
<< std::endl
;
249 void piece_picker::check_invariant(const torrent
* t
) const
251 TORRENT_ASSERT(sizeof(piece_pos
) == 4);
252 TORRENT_ASSERT(m_num_have
>= 0);
253 TORRENT_ASSERT(m_num_have_filtered
>= 0);
254 TORRENT_ASSERT(m_num_filtered
>= 0);
255 TORRENT_ASSERT(m_seeds
>= 0);
257 if (!m_downloads
.empty())
259 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin();
260 i
!= m_downloads
.end() - 1; ++i
)
262 downloading_piece
const& dp
= *i
;
263 downloading_piece
const& next
= *(i
+ 1);
264 TORRENT_ASSERT(dp
.finished
+ dp
.writing
>= next
.finished
+ next
.writing
);
269 TORRENT_ASSERT((int)m_piece_map
.size() == t
->torrent_file().num_pieces());
271 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin()
272 , end(m_downloads
.end()); i
!= end
; ++i
)
274 bool blocks_requested
= false;
275 int num_blocks
= blocks_in_piece(i
->index
);
276 int num_requested
= 0;
277 int num_finished
= 0;
279 for (int k
= 0; k
< num_blocks
; ++k
)
281 if (i
->info
[k
].state
== block_info::state_finished
)
284 TORRENT_ASSERT(i
->info
[k
].num_peers
== 0);
286 else if (i
->info
[k
].state
== block_info::state_requested
)
289 blocks_requested
= true;
290 TORRENT_ASSERT(i
->info
[k
].num_peers
> 0);
292 else if (i
->info
[k
].state
== block_info::state_writing
)
295 TORRENT_ASSERT(i
->info
[k
].num_peers
== 0);
298 TORRENT_ASSERT(blocks_requested
== (i
->state
!= none
));
299 TORRENT_ASSERT(num_requested
== i
->requested
);
300 TORRENT_ASSERT(num_writing
== i
->writing
);
301 TORRENT_ASSERT(num_finished
== i
->finished
);
303 #ifdef TORRENT_NO_EXPENSIVE_INVARIANT_CHECK
307 if (m_sequential_download
== -1 && !m_dirty
)
309 TORRENT_ASSERT(!m_priority_boundries
.empty());
312 for (std::vector
<int>::const_iterator i
= m_priority_boundries
.begin()
313 , end(m_priority_boundries
.end()); i
!= end
; ++i
)
315 verify_priority(start
, *i
, prio
);
319 TORRENT_ASSERT(m_priority_boundries
.back() == int(m_pieces
.size()));
321 else if (m_sequential_download
>= 0)
324 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin()
325 , end(m_piece_map
.end()); i
!= end
&& (i
->have() || i
->filtered());
327 TORRENT_ASSERT(m_sequential_download
== index
);
330 int num_filtered
= 0;
331 int num_have_filtered
= 0;
333 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin();
334 i
!= m_piece_map
.end(); ++i
)
336 int index
= static_cast<int>(i
- m_piece_map
.begin());
337 piece_pos
const& p
= *i
;
341 if (p
.index
!= piece_pos::we_have_index
)
346 if (p
.index
== piece_pos::we_have_index
)
352 int actual_peer_count
= 0;
353 for (torrent::const_peer_iterator peer
= t
->begin();
354 peer
!= t
->end(); ++peer
)
356 if (peer
->second
->has_piece(index
)) actual_peer_count
++;
359 TORRENT_ASSERT((int)i
->peer_count
== actual_peer_count
);
361 int num_downloaders = 0;
362 for (std::vector<peer_connection*>::const_iterator peer = t->begin();
366 const std::vector<piece_block>& queue = (*peer)->download_queue();
367 if (std::find_if(queue.begin(), queue.end(), has_index(index)) == queue.end()) continue;
374 TORRENT_ASSERT(num_downloaders == 1);
378 TORRENT_ASSERT(num_downloaders == 0);
384 if (p
.index
== piece_pos::we_have_index
)
386 TORRENT_ASSERT(t
== 0 || t
->have_piece(index
));
387 TORRENT_ASSERT(p
.downloading
== 0);
391 TORRENT_ASSERT(!t
->have_piece(index
));
393 if (m_sequential_download
== -1 && !m_dirty
)
395 int prio
= p
.priority(this);
396 TORRENT_ASSERT(prio
< int(m_priority_boundries
.size())
400 TORRENT_ASSERT(p
.index
< m_pieces
.size());
401 TORRENT_ASSERT(m_pieces
[p
.index
] == index
);
405 TORRENT_ASSERT(prio
== -1);
406 // make sure there's no entry
407 // with this index. (there shouldn't
408 // be since the priority is -1)
409 TORRENT_ASSERT(std::find(m_pieces
.begin(), m_pieces
.end(), index
)
413 else if (m_sequential_download
>= 0)
415 TORRENT_ASSERT(m_pieces
.empty());
416 TORRENT_ASSERT(m_priority_boundries
.empty());
419 int count
= std::count_if(m_downloads
.begin(), m_downloads
.end()
421 if (i
->downloading
== 1)
423 TORRENT_ASSERT(count
== 1);
427 TORRENT_ASSERT(count
== 0);
430 TORRENT_ASSERT(num_have
== m_num_have
);
431 TORRENT_ASSERT(num_filtered
== m_num_filtered
);
432 TORRENT_ASSERT(num_have_filtered
== m_num_have_filtered
);
436 for (std::vector
<int>::const_iterator i
= m_pieces
.begin()
437 , end(m_pieces
.end()); i
!= end
; ++i
)
439 TORRENT_ASSERT(m_piece_map
[*i
].priority(this) >= 0);
445 float piece_picker::distributed_copies() const
447 TORRENT_ASSERT(m_seeds
>= 0);
448 const float num_pieces
= static_cast<float>(m_piece_map
.size());
450 int min_availability
= piece_pos::max_peer_count
;
451 // find the lowest availability count
452 // count the number of pieces that have that availability
453 // and also the number of pieces that have more than that.
454 int integer_part
= 0;
455 int fraction_part
= 0;
456 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin()
457 , end(m_piece_map
.end()); i
!= end
; ++i
)
459 int peer_count
= int(i
->peer_count
);
460 // take ourself into account
461 if (i
->have()) ++peer_count
;
462 if (min_availability
> peer_count
)
464 min_availability
= peer_count
;
465 fraction_part
+= integer_part
;
468 else if (peer_count
== min_availability
)
474 TORRENT_ASSERT(peer_count
> min_availability
);
478 TORRENT_ASSERT(integer_part
+ fraction_part
== num_pieces
);
479 return float(min_availability
+ m_seeds
) + (fraction_part
/ num_pieces
);
482 void piece_picker::priority_range(int prio
, int* start
, int* end
)
484 TORRENT_ASSERT(prio
>= 0);
485 TORRENT_ASSERT(prio
< int(m_priority_boundries
.size())
487 if (prio
== 0) *start
= 0;
488 else *start
= m_priority_boundries
[prio
- 1];
489 *end
= m_priority_boundries
[prio
];
490 TORRENT_ASSERT(*start
<= *end
);
493 void piece_picker::add(int index
)
495 TORRENT_ASSERT(!m_dirty
);
496 TORRENT_ASSERT(index
>= 0);
497 TORRENT_ASSERT(index
< int(m_piece_map
.size()));
498 piece_pos
& p
= m_piece_map
[index
];
499 TORRENT_ASSERT(!p
.filtered());
500 TORRENT_ASSERT(!p
.have());
501 TORRENT_ASSERT(m_sequential_download
== -1);
503 int priority
= p
.priority(this);
504 TORRENT_ASSERT(priority
>= 0);
505 if (int(m_priority_boundries
.size()) <= priority
)
506 m_priority_boundries
.resize(priority
+ 1, m_pieces
.size());
508 TORRENT_ASSERT(int(m_priority_boundries
.size()) >= priority
);
510 int range_start
, range_end
;
511 priority_range(priority
, &range_start
, &range_end
);
513 if (range_end
== range_start
) new_index
= range_start
;
514 else new_index
= rand() % (range_end
- range_start
) + range_start
;
516 #ifdef TORRENT_PICKER_LOG
517 std::cerr
<< "add " << index
<< " (" << priority
<< ")" << std::endl
;
520 m_pieces
.push_back(-1);
524 TORRENT_ASSERT(new_index
< int(m_pieces
.size()));
525 int temp
= m_pieces
[new_index
];
526 m_pieces
[new_index
] = index
;
527 m_piece_map
[index
].index
= new_index
;
531 temp
= m_priority_boundries
[priority
]++;
533 } while (temp
== new_index
&& priority
< int(m_priority_boundries
.size()));
535 #ifdef TORRENT_PICKER_LOG
537 std::cerr
<< " index: " << index
538 << " prio: " << priority
539 << " new_index: " << new_index
542 if (priority
>= int(m_priority_boundries
.size())) break;
543 TORRENT_ASSERT(temp
>= 0);
547 TORRENT_ASSERT(new_index
== int(m_pieces
.size() - 1));
548 m_pieces
[new_index
] = index
;
549 m_piece_map
[index
].index
= new_index
;
551 #ifdef TORRENT_PICKER_LOG
557 void piece_picker::remove(int priority
, int elem_index
)
559 TORRENT_ASSERT(!m_dirty
);
560 TORRENT_ASSERT(priority
>= 0);
561 TORRENT_ASSERT(m_sequential_download
== -1);
563 #ifdef TORRENT_PICKER_LOG
564 std::cerr
<< "remove " << m_pieces
[elem_index
] << " (" << priority
<< ")" << std::endl
;
566 int next_index
= elem_index
;
567 TORRENT_ASSERT(m_piece_map
[m_pieces
[elem_index
]].priority(this) == -1);
570 #ifdef TORRENT_PICKER_LOG
573 TORRENT_ASSERT(elem_index
< int(m_pieces
.size()));
577 temp
= --m_priority_boundries
[priority
];
579 } while (next_index
== temp
&& priority
< int(m_priority_boundries
.size()));
580 if (next_index
== temp
) break;
583 int piece
= m_pieces
[next_index
];
584 m_pieces
[elem_index
] = piece
;
585 m_piece_map
[piece
].index
= elem_index
;
586 TORRENT_ASSERT(m_piece_map
[piece
].priority(this) == priority
- 1);
587 TORRENT_ASSERT(elem_index
< int(m_pieces
.size() - 1));
588 elem_index
= next_index
;
590 if (priority
== int(m_priority_boundries
.size()))
594 TORRENT_ASSERT(next_index
== int(m_pieces
.size()));
595 #ifdef TORRENT_PICKER_LOG
600 // will update the piece with the given properties (priority, elem_index)
601 // to place it at the correct position
602 void piece_picker::update(int priority
, int elem_index
)
604 TORRENT_ASSERT(!m_dirty
);
605 TORRENT_ASSERT(priority
>= 0);
606 TORRENT_ASSERT(elem_index
>= 0);
607 TORRENT_ASSERT(m_sequential_download
== -1);
609 TORRENT_ASSERT(int(m_priority_boundries
.size()) > priority
);
611 int index
= m_pieces
[elem_index
];
612 // update the piece_map
613 piece_pos
& p
= m_piece_map
[index
];
614 TORRENT_ASSERT(int(p
.index
) == elem_index
|| p
.have());
616 int new_priority
= p
.priority(this);
618 if (new_priority
== priority
) return;
620 if (new_priority
== -1)
622 remove(priority
, elem_index
);
626 if (int(m_priority_boundries
.size()) <= new_priority
)
627 m_priority_boundries
.resize(new_priority
+ 1, m_pieces
.size());
629 #ifdef TORRENT_PICKER_LOG
630 std::cerr
<< "update " << index
<< " (" << priority
<< "->" << new_priority
<< ")" << std::endl
;
632 if (priority
> new_priority
)
638 #ifdef TORRENT_PICKER_LOG
642 new_index
= m_priority_boundries
[priority
]++;
643 TORRENT_ASSERT(new_index
< int(m_pieces
.size()));
644 if (temp
!= m_pieces
[new_index
])
646 temp
= m_pieces
[new_index
];
647 m_pieces
[elem_index
] = temp
;
648 m_piece_map
[temp
].index
= elem_index
;
649 TORRENT_ASSERT(elem_index
< int(m_pieces
.size()));
651 elem_index
= new_index
;
652 if (priority
== new_priority
) break;
654 #ifdef TORRENT_PICKER_LOG
657 m_pieces
[elem_index
] = index
;
658 m_piece_map
[index
].index
= elem_index
;
659 TORRENT_ASSERT(elem_index
< int(m_pieces
.size()));
660 #ifdef TORRENT_PICKER_LOG
663 shuffle(priority
, elem_index
);
664 #ifdef TORRENT_PICKER_LOG
667 TORRENT_ASSERT(m_piece_map
[index
].priority(this) == priority
);
675 #ifdef TORRENT_PICKER_LOG
678 new_index
= --m_priority_boundries
[priority
];
679 TORRENT_ASSERT(new_index
< int(m_pieces
.size()));
680 if (temp
!= m_pieces
[new_index
])
682 temp
= m_pieces
[new_index
];
683 m_pieces
[elem_index
] = temp
;
684 m_piece_map
[temp
].index
= elem_index
;
685 TORRENT_ASSERT(elem_index
< int(m_pieces
.size()));
687 elem_index
= new_index
;
689 if (priority
== new_priority
) break;
691 #ifdef TORRENT_PICKER_LOG
694 m_pieces
[elem_index
] = index
;
695 m_piece_map
[index
].index
= elem_index
;
696 TORRENT_ASSERT(elem_index
< int(m_pieces
.size()));
697 #ifdef TORRENT_PICKER_LOG
700 shuffle(priority
, elem_index
);
701 #ifdef TORRENT_PICKER_LOG
704 TORRENT_ASSERT(m_piece_map
[index
].priority(this) == priority
);
708 void piece_picker::shuffle(int priority
, int elem_index
)
710 TORRENT_ASSERT(!m_dirty
);
711 TORRENT_ASSERT(priority
>= 0);
712 TORRENT_ASSERT(elem_index
>= 0);
713 TORRENT_ASSERT(m_sequential_download
== -1);
715 int range_start
, range_end
;
716 priority_range(priority
, &range_start
, &range_end
);
717 TORRENT_ASSERT(range_start
< range_end
);
718 int other_index
= rand() % (range_end
- range_start
) + range_start
;
720 if (other_index
== elem_index
) return;
722 // swap other_index with elem_index
723 piece_pos
& p1
= m_piece_map
[m_pieces
[other_index
]];
724 piece_pos
& p2
= m_piece_map
[m_pieces
[elem_index
]];
729 std::swap(m_pieces
[other_index
], m_pieces
[elem_index
]);
732 void piece_picker::sort_piece(std::vector
<downloading_piece
>::iterator dp
)
734 TORRENT_ASSERT(m_piece_map
[dp
->index
].downloading
);
735 if (dp
== m_downloads
.begin()) return;
736 int complete
= dp
->writing
+ dp
->finished
;
737 for (std::vector
<downloading_piece
>::iterator i
= dp
, j(dp
-1);
738 i
!= m_downloads
.begin(); --i
, --j
)
740 TORRENT_ASSERT(j
>= m_downloads
.begin());
741 if (j
->finished
+ j
->writing
>= complete
) return;
744 if (j
== m_downloads
.begin()) break;
748 void piece_picker::restore_piece(int index
)
750 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
752 TORRENT_ASSERT(index
>= 0);
753 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
755 TORRENT_ASSERT(m_piece_map
[index
].downloading
== 1);
757 std::vector
<downloading_piece
>::iterator i
758 = std::find_if(m_downloads
.begin(), m_downloads
.end()
761 TORRENT_ASSERT(i
!= m_downloads
.end());
762 erase_download_piece(i
);
764 piece_pos
& p
= m_piece_map
[index
];
765 int prev_priority
= p
.priority(this);
767 int new_priority
= p
.priority(this);
769 if (new_priority
== prev_priority
) return;
771 if (m_sequential_download
>= 0)
776 if (prev_priority
== -1)
782 update(prev_priority
, p
.index
);
786 void piece_picker::inc_refcount_all()
788 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
792 // when m_seeds is increased from 0 to 1
793 // we may have to add pieces that previously
794 // didn't have any peers
799 void piece_picker::dec_refcount_all()
801 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
808 // when m_seeds is decreased from 1 to 0
809 // we may have to remove pieces that previously
810 // didn't have any peers
815 TORRENT_ASSERT(m_seeds
== 0);
817 for (std::vector
<piece_pos
>::iterator i
= m_piece_map
.begin()
818 , end(m_piece_map
.end()); i
!= end
; ++i
)
820 TORRENT_ASSERT(i
->peer_count
> 0);
827 void piece_picker::inc_refcount(int index
)
829 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
831 piece_pos
& p
= m_piece_map
[index
];
832 if (m_sequential_download
>= 0)
839 int prev_priority
= p
.priority(this);
842 int new_priority
= p
.priority(this);
843 if (prev_priority
== new_priority
) return;
844 if (prev_priority
== -1)
847 update(prev_priority
, p
.index
);
850 void piece_picker::dec_refcount(int index
)
852 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
854 piece_pos
& p
= m_piece_map
[index
];
855 if (m_sequential_download
>= 0)
857 TORRENT_ASSERT(p
.peer_count
> 0);
862 int prev_priority
= p
.priority(this);
863 TORRENT_ASSERT(p
.peer_count
> 0);
866 if (prev_priority
>= 0) update(prev_priority
, p
.index
);
869 void piece_picker::inc_refcount(bitfield
const& bitmask
)
871 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
872 TORRENT_ASSERT(bitmask
.size() == m_piece_map
.size());
875 bool updated
= false;
876 for (bitfield::const_iterator i
= bitmask
.begin()
877 , end(bitmask
.end()); i
!= end
; ++i
, ++index
)
881 ++m_piece_map
[index
].peer_count
;
886 if (updated
&& m_sequential_download
== -1) m_dirty
= true;
889 void piece_picker::dec_refcount(bitfield
const& bitmask
)
891 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
892 TORRENT_ASSERT(bitmask
.size() == m_piece_map
.size());
895 bool updated
= false;
896 for (bitfield::const_iterator i
= bitmask
.begin()
897 , end(bitmask
.end()); i
!= end
; ++i
, ++index
)
901 --m_piece_map
[index
].peer_count
;
906 if (updated
&& m_sequential_download
== -1) m_dirty
= true;
909 void piece_picker::update_pieces() const
911 TORRENT_ASSERT(m_dirty
);
912 TORRENT_ASSERT(m_sequential_download
== -1);
913 if (m_priority_boundries
.empty()) m_priority_boundries
.resize(1, 0);
914 #ifdef TORRENT_PICKER_LOG
915 std::cerr
<< "update_pieces" << std::endl
;
917 std::fill(m_priority_boundries
.begin(), m_priority_boundries
.end(), 0);
918 for (std::vector
<piece_pos
>::iterator i
= m_piece_map
.begin()
919 , end(m_piece_map
.end()); i
!= end
; ++i
)
921 int prio
= i
->priority(this);
922 if (prio
== -1) continue;
923 if (prio
>= int(m_priority_boundries
.size()))
924 m_priority_boundries
.resize(prio
+ 1, 0);
925 i
->index
= m_priority_boundries
[prio
];
926 ++m_priority_boundries
[prio
];
929 #ifdef TORRENT_PICKER_LOG
934 for (std::vector
<int>::iterator i
= m_priority_boundries
.begin()
935 , end(m_priority_boundries
.end()); i
!= end
; ++i
)
940 m_pieces
.resize(index
, 0);
942 #ifdef TORRENT_PICKER_LOG
947 for (std::vector
<piece_pos
>::iterator i
= m_piece_map
.begin()
948 , end(m_piece_map
.end()); i
!= end
; ++i
, ++index
)
951 int prio
= p
.priority(this);
952 if (prio
== -1) continue;
953 int new_index
= (prio
== 0 ? 0 : m_priority_boundries
[prio
- 1]) + p
.index
;
954 m_pieces
[new_index
] = index
;
958 for (std::vector
<int>::iterator i
= m_priority_boundries
.begin()
959 , end(m_priority_boundries
.end()); i
!= end
; ++i
)
961 if (start
== *i
) continue;
962 std::random_shuffle(&m_pieces
[0] + start
, &m_pieces
[0] + *i
);
967 for (std::vector
<int>::const_iterator i
= m_pieces
.begin()
968 , end(m_pieces
.end()); i
!= end
; ++i
, ++index
)
970 TORRENT_ASSERT(*i
>= 0 && *i
< int(m_piece_map
.size()));
971 m_piece_map
[*i
].index
= index
;
975 #ifdef TORRENT_PICKER_LOG
984 void piece_picker::we_dont_have(int index
)
986 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
987 TORRENT_ASSERT(index
>= 0);
988 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
990 piece_pos
& p
= m_piece_map
[index
];
991 TORRENT_ASSERT(p
.downloading
== 0);
993 if (!p
.have()) return;
995 if (m_sequential_download
> index
)
996 m_sequential_download
= index
;
1001 --m_num_have_filtered
;
1007 if (m_dirty
) return;
1008 if (p
.priority(this) >= 0) add(index
);
1011 // this is used to indicate that we succesfully have
1012 // downloaded a piece, and that no further attempts
1013 // to pick that piece should be made. The piece will
1014 // be removed from the available piece list.
1015 void piece_picker::we_have(int index
)
1017 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1018 TORRENT_ASSERT(index
>= 0);
1019 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
1021 piece_pos
& p
= m_piece_map
[index
];
1022 int info_index
= p
.index
;
1023 int priority
= p
.priority(this);
1024 TORRENT_ASSERT(priority
< int(m_priority_boundries
.size()));
1028 std::vector
<downloading_piece
>::iterator i
1029 = std::find_if(m_downloads
.begin()
1031 , has_index(index
));
1032 TORRENT_ASSERT(i
!= m_downloads
.end());
1033 erase_download_piece(i
);
1037 TORRENT_ASSERT(std::find_if(m_downloads
.begin(), m_downloads
.end()
1038 , has_index(index
)) == m_downloads
.end());
1040 if (m_sequential_download
== index
)
1042 ++m_sequential_download
;
1043 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin() + m_sequential_download
1044 , end(m_piece_map
.end()); i
!= end
&& (i
->have() || i
->filtered());
1045 ++i
, ++m_sequential_download
);
1047 if (p
.have()) return;
1051 ++m_num_have_filtered
;
1055 if (priority
== -1) return;
1056 if (m_dirty
) return;
1057 remove(priority
, info_index
);
1058 TORRENT_ASSERT(p
.priority(this) == -1);
1061 bool piece_picker::set_piece_priority(int index
, int new_piece_priority
)
1063 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1064 TORRENT_ASSERT(new_piece_priority
>= 0);
1065 TORRENT_ASSERT(new_piece_priority
<= 7);
1066 TORRENT_ASSERT(index
>= 0);
1067 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
1069 piece_pos
& p
= m_piece_map
[index
];
1071 // if the priority isn't changed, don't do anything
1072 if (new_piece_priority
== int(p
.piece_priority
)) return false;
1074 int prev_priority
= p
.priority(this);
1075 TORRENT_ASSERT(prev_priority
< int(m_priority_boundries
.size()));
1078 if (new_piece_priority
== piece_pos::filter_priority
1079 && p
.piece_priority
!= piece_pos::filter_priority
)
1081 // the piece just got filtered
1082 if (p
.have()) ++m_num_have_filtered
;
1083 else ++m_num_filtered
;
1086 else if (new_piece_priority
!= piece_pos::filter_priority
1087 && p
.piece_priority
== piece_pos::filter_priority
)
1089 // the piece just got unfiltered
1090 if (p
.have()) --m_num_have_filtered
;
1091 else --m_num_filtered
;
1094 TORRENT_ASSERT(m_num_filtered
>= 0);
1095 TORRENT_ASSERT(m_num_have_filtered
>= 0);
1097 p
.piece_priority
= new_piece_priority
;
1098 int new_priority
= p
.priority(this);
1100 if (prev_priority
== new_priority
) return false;
1102 TORRENT_ASSERT(prev_priority
< int(m_priority_boundries
.size()));
1104 if (m_dirty
) return ret
;
1105 if (prev_priority
== -1)
1111 update(prev_priority
, p
.index
);
1116 int piece_picker::piece_priority(int index
) const
1118 TORRENT_ASSERT(index
>= 0);
1119 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
1121 return m_piece_map
[index
].piece_priority
;
1124 void piece_picker::piece_priorities(std::vector
<int>& pieces
) const
1126 pieces
.resize(m_piece_map
.size());
1127 std::vector
<int>::iterator j
= pieces
.begin();
1128 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin(),
1129 end(m_piece_map
.end()); i
!= end
; ++i
, ++j
)
1131 *j
= i
->piece_priority
;
1135 // ============ start deprecation ==============
1137 void piece_picker::filtered_pieces(std::vector
<bool>& mask
) const
1139 mask
.resize(m_piece_map
.size());
1140 std::vector
<bool>::iterator j
= mask
.begin();
1141 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin(),
1142 end(m_piece_map
.end()); i
!= end
; ++i
, ++j
)
1148 // ============ end deprecation ==============
1150 // pieces describes which pieces the peer we're requesting from
1152 // interesting_blocks is an out parameter, and will be filled
1153 // with (up to) num_blocks of interesting blocks that the peer has.
1154 // prefer_whole_pieces can be set if this peer should download
1155 // whole pieces rather than trying to download blocks from the
1156 // same piece as other peers.
1157 // the void* is the pointer to the policy::peer of the peer we're
1158 // picking pieces from. This is used when downloading whole pieces,
1159 // to only pick from the same piece the same peer is downloading
1160 // from. state is supposed to be set to fast if the peer is downloading
1161 // relatively fast, by some notion. Slow peers will prefer not
1162 // to pick blocks from the same pieces as fast peers, and vice
1163 // versa. Downloading pieces are marked as being fast, medium
1164 // or slow once they're started.
1165 void piece_picker::pick_pieces(bitfield
const& pieces
1166 , std::vector
<piece_block
>& interesting_blocks
1167 , int num_blocks
, int prefer_whole_pieces
1168 , void* peer
, piece_state_t speed
, bool rarest_first
1169 , bool on_parole
, std::vector
<int> const& suggested_pieces
) const
1171 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1172 TORRENT_ASSERT(num_blocks
> 0);
1173 TORRENT_ASSERT(pieces
.size() == m_piece_map
.size());
1175 TORRENT_ASSERT(!m_priority_boundries
.empty()
1176 || m_sequential_download
>= 0
1179 // this will be filled with blocks that we should not request
1180 // unless we can't find num_blocks among the other ones.
1181 // blocks that belong to pieces with a mismatching speed
1182 // category for instance, or if we prefer whole pieces,
1183 // blocks belonging to a piece that others have
1185 std::vector
<piece_block
> backup_blocks
;
1186 const std::vector
<int> empty_vector
;
1188 // When prefer_whole_pieces is set (usually set when downloading from
1189 // fast peers) the partial pieces will not be prioritized, but actually
1190 // ignored as long as possible. All blocks found in downloading
1191 // pieces are regarded as backup blocks
1193 num_blocks
= add_blocks_downloading(pieces
1194 , interesting_blocks
, backup_blocks
, num_blocks
1195 , prefer_whole_pieces
, peer
, speed
, on_parole
);
1197 if (num_blocks
<= 0) return;
1199 if (!suggested_pieces
.empty())
1201 num_blocks
= add_blocks(suggested_pieces
, pieces
1202 , interesting_blocks
, num_blocks
1203 , prefer_whole_pieces
, peer
, empty_vector
);
1204 if (num_blocks
== 0) return;
1207 if (m_sequential_download
>= 0)
1209 for (int i
= m_sequential_download
;
1210 i
< int(m_piece_map
.size()) && num_blocks
> 0; ++i
)
1212 if (!can_pick(i
, pieces
)) continue;
1213 int num_blocks_in_piece
= blocks_in_piece(i
);
1214 if (prefer_whole_pieces
== 0 && num_blocks_in_piece
> num_blocks
)
1215 num_blocks_in_piece
= num_blocks
;
1216 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1218 interesting_blocks
.push_back(piece_block(i
, j
));
1223 else if (rarest_first
)
1225 if (m_dirty
) update_pieces();
1226 num_blocks
= add_blocks(m_pieces
, pieces
1227 , interesting_blocks
, num_blocks
1228 , prefer_whole_pieces
, peer
, suggested_pieces
);
1229 TORRENT_ASSERT(num_blocks
>= 0);
1233 // we're not using rarest first (only for the first
1234 // bucket, since that's where the currently downloading
1236 int start_piece
= rand() % m_piece_map
.size();
1238 // if we have suggested pieces, try to find one of those instead
1239 for (std::vector
<int>::const_iterator i
= suggested_pieces
.begin()
1240 , end(suggested_pieces
.end()); i
!= end
; ++i
)
1242 if (!can_pick(*i
, pieces
)) continue;
1246 int piece
= start_piece
;
1247 while (num_blocks
> 0)
1249 while (!can_pick(piece
, pieces
))
1252 if (piece
== int(m_piece_map
.size())) piece
= 0;
1253 // could not find any more pieces
1254 if (piece
== start_piece
) return;
1258 boost::tie(start
, end
) = expand_piece(piece
, prefer_whole_pieces
, pieces
);
1259 for (int k
= start
; k
< end
; ++k
)
1261 TORRENT_ASSERT(m_piece_map
[piece
].downloading
== false);
1262 TORRENT_ASSERT(m_piece_map
[k
].priority(this) >= 0);
1263 int num_blocks_in_piece
= blocks_in_piece(k
);
1264 if (prefer_whole_pieces
== 0 && num_blocks_in_piece
> num_blocks
)
1265 num_blocks_in_piece
= num_blocks
;
1266 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1268 interesting_blocks
.push_back(piece_block(k
, j
));
1273 if (piece
== int(m_piece_map
.size())) piece
= 0;
1274 // could not find any more pieces
1275 if (piece
== start_piece
) return;
1280 if (num_blocks
<= 0) return;
1282 if (!backup_blocks
.empty())
1283 interesting_blocks
.insert(interesting_blocks
.end()
1284 , backup_blocks
.begin(), backup_blocks
.end());
1287 bool piece_picker::can_pick(int piece
, bitfield
const& bitmask
) const
1289 TORRENT_ASSERT(piece
>= 0 && piece
< int(m_piece_map
.size()));
1290 return bitmask
[piece
]
1291 && !m_piece_map
[piece
].have()
1292 && !m_piece_map
[piece
].downloading
1293 && !m_piece_map
[piece
].filtered();
1296 void piece_picker::clear_peer(void* peer
)
1298 for (std::vector
<block_info
>::iterator i
= m_block_info
.begin()
1299 , end(m_block_info
.end()); i
!= end
; ++i
)
1300 if (i
->peer
== peer
) i
->peer
= 0;
1305 // the first bool is true if this is the only peer that has requested and downloaded
1306 // blocks from this piece.
1307 // the second bool is true if this is the only active peer that is requesting
1308 // and downloading blocks from this piece. Active means having a connection.
1309 boost::tuple
<bool, bool> requested_from(piece_picker::downloading_piece
const& p
1310 , int num_blocks_in_piece
, void* peer
)
1312 bool exclusive
= true;
1313 bool exclusive_active
= true;
1314 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1316 piece_picker::block_info
const& info
= p
.info
[j
];
1317 if (info
.state
!= piece_picker::block_info::state_none
1318 && info
.peer
!= peer
)
1321 if (info
.state
== piece_picker::block_info::state_requested
1324 exclusive_active
= false;
1325 return boost::make_tuple(exclusive
, exclusive_active
);
1329 return boost::make_tuple(exclusive
, exclusive_active
);
1333 int piece_picker::add_blocks(std::vector
<int> const& piece_list
1334 , bitfield
const& pieces
1335 , std::vector
<piece_block
>& interesting_blocks
1336 , int num_blocks
, int prefer_whole_pieces
1337 , void* peer
, std::vector
<int> const& ignore
) const
1339 for (std::vector
<int>::const_iterator i
= piece_list
.begin();
1340 i
!= piece_list
.end(); ++i
)
1342 TORRENT_ASSERT(*i
>= 0);
1343 TORRENT_ASSERT(*i
< (int)m_piece_map
.size());
1345 // if the peer doesn't have the piece
1346 // or if it's set to 0 priority
1348 if (!can_pick(*i
, pieces
)) continue;
1350 // ignore pieces found in the ignore list
1351 if (std::find(ignore
.begin(), ignore
.end(), *i
) != ignore
.end()) continue;
1353 TORRENT_ASSERT(m_piece_map
[*i
].priority(this) >= 0);
1354 TORRENT_ASSERT(m_piece_map
[*i
].downloading
== 0);
1356 int num_blocks_in_piece
= blocks_in_piece(*i
);
1359 if (prefer_whole_pieces
== 0)
1361 if (num_blocks_in_piece
> num_blocks
)
1362 num_blocks_in_piece
= num_blocks
;
1363 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1364 interesting_blocks
.push_back(piece_block(*i
, j
));
1365 num_blocks
-= num_blocks_in_piece
;
1370 boost::tie(start
, end
) = expand_piece(*i
, prefer_whole_pieces
, pieces
);
1371 for (int k
= start
; k
< end
; ++k
)
1373 TORRENT_ASSERT(m_piece_map
[k
].priority(this) > 0);
1374 num_blocks_in_piece
= blocks_in_piece(k
);
1375 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1377 interesting_blocks
.push_back(piece_block(k
, j
));
1382 if (num_blocks
<= 0)
1385 verify_pick(interesting_blocks
, pieces
);
1391 verify_pick(interesting_blocks
, pieces
);
1396 int piece_picker::add_blocks_downloading(bitfield
const& pieces
1397 , std::vector
<piece_block
>& interesting_blocks
1398 , std::vector
<piece_block
>& backup_blocks
1399 , int num_blocks
, int prefer_whole_pieces
1400 , void* peer
, piece_state_t speed
, bool on_parole
) const
1402 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin()
1403 , end(m_downloads
.end()); i
!= end
; ++i
)
1405 if (!pieces
[i
->index
]) continue;
1407 int num_blocks_in_piece
= blocks_in_piece(i
->index
);
1409 // is true if all the other pieces that are currently
1410 // requested from this piece are from the same
1413 bool exclusive_active
;
1414 boost::tie(exclusive
, exclusive_active
)
1415 = requested_from(*i
, num_blocks_in_piece
, peer
);
1417 // peers on parole are only allowed to pick blocks from
1418 // pieces that only they have downloaded/requested from
1419 if (on_parole
&& !exclusive
) continue;
1421 if (prefer_whole_pieces
> 0 && !exclusive_active
) continue;
1423 // don't pick too many back-up blocks
1424 if (i
->state
!= none
1425 && i
->state
!= speed
1426 && !exclusive_active
1427 && int(backup_blocks
.size()) >= num_blocks
)
1430 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1432 // ignore completed blocks and already requested blocks
1433 block_info
const& info
= i
->info
[j
];
1434 if (info
.state
!= block_info::state_none
)
1437 TORRENT_ASSERT(i
->info
[j
].state
== block_info::state_none
);
1439 // if the piece is fast and the peer is slow, or vice versa,
1440 // add the block as a backup.
1441 // override this behavior if all the other blocks
1442 // have been requested from the same peer or
1443 // if the state of the piece is none (the
1444 // piece will in that case change state).
1445 if (i
->state
!= none
&& i
->state
!= speed
1446 && !exclusive_active
)
1448 backup_blocks
.push_back(piece_block(i
->index
, j
));
1452 // this block is interesting (we don't have it
1454 interesting_blocks
.push_back(piece_block(i
->index
, j
));
1455 // we have found a block that's free to download
1457 // if we prefer whole pieces, continue picking from this
1458 // piece even though we have num_blocks
1459 if (prefer_whole_pieces
> 0) continue;
1460 TORRENT_ASSERT(num_blocks
>= 0);
1461 if (num_blocks
<= 0) break;
1463 if (num_blocks
<= 0) break;
1466 TORRENT_ASSERT(num_blocks
>= 0 || prefer_whole_pieces
> 0);
1469 verify_pick(interesting_blocks
, pieces
);
1470 verify_pick(backup_blocks
, pieces
);
1473 if (num_blocks
<= 0) return 0;
1474 if (on_parole
) return num_blocks
;
1477 if (prefer_whole_pieces
== 0)
1478 to_copy
= (std::min
)(int(backup_blocks
.size()), num_blocks
);
1480 to_copy
= int(backup_blocks
.size());
1482 interesting_blocks
.insert(interesting_blocks
.end()
1483 , backup_blocks
.begin(), backup_blocks
.begin() + to_copy
);
1484 num_blocks
-= to_copy
;
1485 backup_blocks
.clear();
1487 if (num_blocks
<= 0) return 0;
1489 if (prefer_whole_pieces
> 0)
1491 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin()
1492 , end(m_downloads
.end()); i
!= end
; ++i
)
1494 if (!pieces
[i
->index
]) continue;
1495 int num_blocks_in_piece
= blocks_in_piece(i
->index
);
1497 bool exclusive_active
;
1498 boost::tie(exclusive
, exclusive_active
)
1499 = requested_from(*i
, num_blocks_in_piece
, peer
);
1501 if (exclusive_active
) continue;
1503 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1505 block_info
const& info
= i
->info
[j
];
1506 if (info
.state
!= block_info::state_none
) continue;
1507 backup_blocks
.push_back(piece_block(i
->index
, j
));
1512 if (int(backup_blocks
.size()) >= num_blocks
) return num_blocks
;
1516 // make sure that we at this point has added requests to all unrequested blocks
1517 // in all downloading pieces
1519 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin()
1520 , end(m_downloads
.end()); i
!= end
; ++i
)
1522 if (!pieces
[i
->index
]) continue;
1524 int num_blocks_in_piece
= blocks_in_piece(i
->index
);
1525 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1527 block_info
const& info
= i
->info
[j
];
1528 if (info
.state
!= block_info::state_none
) continue;
1529 std::vector
<piece_block
>::iterator k
= std::find(
1530 interesting_blocks
.begin(), interesting_blocks
.end()
1531 , piece_block(i
->index
, j
));
1532 if (k
!= interesting_blocks
.end()) continue;
1534 k
= std::find(backup_blocks
.begin()
1535 , backup_blocks
.end(), piece_block(i
->index
, j
));
1536 if (k
!= backup_blocks
.end()) continue;
1538 std::cerr
<< "interesting blocks:" << std::endl
;
1539 for (k
= interesting_blocks
.begin(); k
!= interesting_blocks
.end(); ++k
)
1540 std::cerr
<< "(" << k
->piece_index
<< ", " << k
->block_index
<< ") ";
1541 std::cerr
<< std::endl
;
1542 std::cerr
<< "backup blocks:" << std::endl
;
1543 for (k
= backup_blocks
.begin(); k
!= backup_blocks
.end(); ++k
)
1544 std::cerr
<< "(" << k
->piece_index
<< ", " << k
->block_index
<< ") ";
1545 std::cerr
<< std::endl
;
1546 std::cerr
<< "num_blocks: " << num_blocks
<< std::endl
;
1548 for (std::vector
<downloading_piece
>::const_iterator l
= m_downloads
.begin()
1549 , end(m_downloads
.end()); l
!= end
; ++l
)
1551 std::cerr
<< l
->index
<< " : ";
1552 int num_blocks_in_piece
= blocks_in_piece(l
->index
);
1553 for (int m
= 0; m
< num_blocks_in_piece
; ++m
)
1554 std::cerr
<< l
->info
[m
].state
;
1555 std::cerr
<< std::endl
;
1558 TORRENT_ASSERT(false);
1563 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin()
1564 , end(m_downloads
.end()); i
!= end
; ++i
)
1566 if (!pieces
[i
->index
]) continue;
1568 int num_blocks_in_piece
= blocks_in_piece(i
->index
);
1570 // fill in with blocks requested from other peers
1572 for (int j
= 0; j
< num_blocks_in_piece
; ++j
)
1574 block_info
const& info
= i
->info
[j
];
1575 if (info
.state
!= block_info::state_requested
1576 || info
.peer
== peer
)
1578 backup_blocks
.push_back(piece_block(i
->index
, j
));
1582 verify_pick(backup_blocks
, pieces
);
1587 std::pair
<int, int> piece_picker::expand_piece(int piece
, int whole_pieces
1588 , bitfield
const& have
) const
1590 if (whole_pieces
== 0) return std::make_pair(piece
, piece
+ 1);
1592 int start
= piece
- 1;
1593 int lower_limit
= piece
- whole_pieces
;
1594 if (lower_limit
< -1) lower_limit
= -1;
1595 while (start
> lower_limit
1596 && can_pick(start
, have
))
1599 TORRENT_ASSERT(start
>= 0);
1600 int end
= piece
+ 1;
1601 int upper_limit
= start
+ whole_pieces
;
1602 if (upper_limit
> int(m_piece_map
.size())) upper_limit
= int(m_piece_map
.size());
1603 while (end
< upper_limit
1604 && can_pick(end
, have
))
1606 return std::make_pair(start
, end
);
1609 bool piece_picker::is_piece_finished(int index
) const
1611 TORRENT_ASSERT(index
< (int)m_piece_map
.size());
1612 TORRENT_ASSERT(index
>= 0);
1614 if (m_piece_map
[index
].downloading
== 0)
1616 TORRENT_ASSERT(std::find_if(m_downloads
.begin(), m_downloads
.end()
1617 , has_index(index
)) == m_downloads
.end());
1620 std::vector
<downloading_piece
>::const_iterator i
1621 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(index
));
1622 TORRENT_ASSERT(i
!= m_downloads
.end());
1623 TORRENT_ASSERT((int)i
->finished
<= m_blocks_per_piece
);
1624 int max_blocks
= blocks_in_piece(index
);
1625 if ((int)i
->finished
< max_blocks
) return false;
1628 for (int k
= 0; k
< max_blocks
; ++k
)
1630 TORRENT_ASSERT(i
->info
[k
].state
== block_info::state_finished
);
1634 TORRENT_ASSERT((int)i
->finished
== max_blocks
);
1638 bool piece_picker::is_requested(piece_block block
) const
1640 TORRENT_ASSERT(block
.piece_index
>= 0);
1641 TORRENT_ASSERT(block
.block_index
>= 0);
1642 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1644 if (m_piece_map
[block
.piece_index
].downloading
== 0) return false;
1645 std::vector
<downloading_piece
>::const_iterator i
1649 , has_index(block
.piece_index
));
1651 TORRENT_ASSERT(i
!= m_downloads
.end());
1652 return i
->info
[block
.block_index
].state
== block_info::state_requested
;
1655 bool piece_picker::is_downloaded(piece_block block
) const
1657 TORRENT_ASSERT(block
.piece_index
>= 0);
1658 TORRENT_ASSERT(block
.block_index
>= 0);
1659 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1661 if (m_piece_map
[block
.piece_index
].index
== piece_pos::we_have_index
) return true;
1662 if (m_piece_map
[block
.piece_index
].downloading
== 0) return false;
1663 std::vector
<downloading_piece
>::const_iterator i
1664 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1665 TORRENT_ASSERT(i
!= m_downloads
.end());
1666 return i
->info
[block
.block_index
].state
== block_info::state_finished
1667 || i
->info
[block
.block_index
].state
== block_info::state_writing
;
1670 bool piece_picker::is_finished(piece_block block
) const
1672 TORRENT_ASSERT(block
.piece_index
>= 0);
1673 TORRENT_ASSERT(block
.block_index
>= 0);
1674 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1676 if (m_piece_map
[block
.piece_index
].index
== piece_pos::we_have_index
) return true;
1677 if (m_piece_map
[block
.piece_index
].downloading
== 0) return false;
1678 std::vector
<downloading_piece
>::const_iterator i
1679 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1680 TORRENT_ASSERT(i
!= m_downloads
.end());
1681 return i
->info
[block
.block_index
].state
== block_info::state_finished
;
1684 bool piece_picker::mark_as_downloading(piece_block block
1685 , void* peer
, piece_state_t state
)
1687 TORRENT_ASSERT(block
.piece_index
>= 0);
1688 TORRENT_ASSERT(block
.block_index
>= 0);
1689 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1690 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1691 TORRENT_ASSERT(!m_piece_map
[block
.piece_index
].have());
1693 piece_pos
& p
= m_piece_map
[block
.piece_index
];
1694 if (p
.downloading
== 0)
1696 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1697 int prio
= p
.priority(this);
1698 TORRENT_ASSERT(prio
< int(m_priority_boundries
.size())
1699 || m_sequential_download
>= 0
1701 TORRENT_ASSERT(prio
> 0);
1703 if (prio
>= 0 && m_sequential_download
== -1 && !m_dirty
) update(prio
, p
.index
);
1705 downloading_piece
& dp
= add_download_piece();
1707 dp
.index
= block
.piece_index
;
1708 block_info
& info
= dp
.info
[block
.block_index
];
1709 info
.state
= block_info::state_requested
;
1716 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1717 std::vector
<downloading_piece
>::iterator i
1718 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1719 TORRENT_ASSERT(i
!= m_downloads
.end());
1720 block_info
& info
= i
->info
[block
.block_index
];
1721 if (info
.state
== block_info::state_writing
1722 || info
.state
== block_info::state_finished
)
1724 TORRENT_ASSERT(info
.state
== block_info::state_none
1725 || (info
.state
== block_info::state_requested
1726 && (info
.num_peers
> 0)));
1728 if (info
.state
!= block_info::state_requested
)
1730 info
.state
= block_info::state_requested
;
1734 if (i
->state
== none
) i
->state
= state
;
1739 int piece_picker::num_peers(piece_block block
) const
1741 TORRENT_ASSERT(block
.piece_index
>= 0);
1742 TORRENT_ASSERT(block
.block_index
>= 0);
1743 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1744 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1746 piece_pos
const& p
= m_piece_map
[block
.piece_index
];
1747 if (!p
.downloading
) return 0;
1749 std::vector
<downloading_piece
>::const_iterator i
1750 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1751 TORRENT_ASSERT(i
!= m_downloads
.end());
1753 block_info
const& info
= i
->info
[block
.block_index
];
1754 return info
.num_peers
;
1757 void piece_picker::get_availability(std::vector
<int>& avail
) const
1759 TORRENT_ASSERT(m_seeds
>= 0);
1760 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1762 avail
.resize(m_piece_map
.size());
1763 std::vector
<int>::iterator j
= avail
.begin();
1764 for (std::vector
<piece_pos
>::const_iterator i
= m_piece_map
.begin()
1765 , end(m_piece_map
.end()); i
!= end
; ++i
, ++j
)
1766 *j
= i
->peer_count
+ m_seeds
;
1769 void piece_picker::mark_as_writing(piece_block block
, void* peer
)
1771 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1773 TORRENT_ASSERT(block
.piece_index
>= 0);
1774 TORRENT_ASSERT(block
.block_index
>= 0);
1775 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1776 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1778 TORRENT_ASSERT(m_piece_map
[block
.piece_index
].downloading
);
1780 std::vector
<downloading_piece
>::iterator i
1781 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1782 TORRENT_ASSERT(i
!= m_downloads
.end());
1783 block_info
& info
= i
->info
[block
.block_index
];
1786 TORRENT_ASSERT(info
.state
== block_info::state_requested
);
1787 if (info
.state
== block_info::state_requested
) --i
->requested
;
1788 TORRENT_ASSERT(i
->requested
>= 0);
1789 TORRENT_ASSERT(info
.state
!= block_info::state_writing
);
1791 info
.state
= block_info::state_writing
;
1792 TORRENT_ASSERT(info
.num_peers
> 0);
1795 if (i
->requested
== 0)
1797 // there are no blocks requested in this piece.
1798 // remove the fast/slow state from it
1804 void piece_picker::write_failed(piece_block block
)
1806 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1808 std::vector
<downloading_piece
>::iterator i
1809 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1810 TORRENT_ASSERT(i
!= m_downloads
.end());
1811 block_info
& info
= i
->info
[block
.block_index
];
1812 TORRENT_ASSERT(info
.state
== block_info::state_writing
);
1815 if (info
.num_peers
> 0)
1817 // there are other peers on this block
1818 // turn it back into requested
1820 info
.state
= block_info::state_requested
;
1824 info
.state
= block_info::state_none
;
1829 void piece_picker::mark_as_finished(piece_block block
, void* peer
)
1831 TORRENT_ASSERT(block
.piece_index
>= 0);
1832 TORRENT_ASSERT(block
.block_index
>= 0);
1833 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1834 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1836 piece_pos
& p
= m_piece_map
[block
.piece_index
];
1838 if (p
.downloading
== 0)
1840 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1842 TORRENT_ASSERT(peer
== 0);
1843 int prio
= p
.priority(this);
1844 TORRENT_ASSERT(prio
< int(m_priority_boundries
.size())
1847 if (prio
>= 0 && !m_dirty
) update(prio
, p
.index
);
1849 downloading_piece
& dp
= add_download_piece();
1851 dp
.index
= block
.piece_index
;
1852 block_info
& info
= dp
.info
[block
.block_index
];
1854 TORRENT_ASSERT(info
.state
== block_info::state_none
);
1855 TORRENT_ASSERT(info
.num_peers
== 0);
1856 if (info
.state
!= block_info::state_finished
)
1859 sort_piece(m_downloads
.end() - 1);
1861 info
.state
= block_info::state_finished
;
1865 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1867 std::vector
<downloading_piece
>::iterator i
1868 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(block
.piece_index
));
1869 TORRENT_ASSERT(i
!= m_downloads
.end());
1870 block_info
& info
= i
->info
[block
.block_index
];
1871 TORRENT_ASSERT(info
.num_peers
== 0);
1873 TORRENT_ASSERT(info
.state
== block_info::state_writing
1875 TORRENT_ASSERT(i
->writing
>= 0);
1877 if (info
.state
== block_info::state_writing
)
1880 info
.state
= block_info::state_finished
;
1884 info
.state
= block_info::state_finished
;
1890 void piece_picker::get_downloaders(std::vector
<void*>& d
, int index
) const
1892 TORRENT_ASSERT(index
>= 0 && index
<= (int)m_piece_map
.size());
1893 std::vector
<downloading_piece
>::const_iterator i
1894 = std::find_if(m_downloads
.begin(), m_downloads
.end(), has_index(index
));
1895 TORRENT_ASSERT(i
!= m_downloads
.end());
1898 for (int j
= 0; j
< blocks_in_piece(index
); ++j
)
1900 d
.push_back(i
->info
[j
].peer
);
1904 void* piece_picker::get_downloader(piece_block block
) const
1906 std::vector
<downloading_piece
>::const_iterator i
= std::find_if(
1909 , has_index(block
.piece_index
));
1911 if (i
== m_downloads
.end()) return 0;
1913 TORRENT_ASSERT(block
.block_index
>= 0);
1915 if (i
->info
[block
.block_index
].state
== block_info::state_none
)
1918 return i
->info
[block
.block_index
].peer
;
1921 // this is called when a request is rejected or when
1922 // a peer disconnects. The piece might be in any state
1923 void piece_picker::abort_download(piece_block block
)
1925 TORRENT_PIECE_PICKER_INVARIANT_CHECK
;
1927 TORRENT_ASSERT(block
.piece_index
>= 0);
1928 TORRENT_ASSERT(block
.block_index
>= 0);
1929 TORRENT_ASSERT(block
.piece_index
< (int)m_piece_map
.size());
1930 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1932 if (m_piece_map
[block
.piece_index
].downloading
== 0)
1934 TORRENT_ASSERT(std::find_if(m_downloads
.begin(), m_downloads
.end()
1935 , has_index(block
.piece_index
)) == m_downloads
.end());
1939 std::vector
<downloading_piece
>::iterator i
= std::find_if(m_downloads
.begin()
1940 , m_downloads
.end(), has_index(block
.piece_index
));
1941 TORRENT_ASSERT(i
!= m_downloads
.end());
1943 block_info
& info
= i
->info
[block
.block_index
];
1945 if (i
->info
[block
.block_index
].state
!= block_info::state_requested
)
1948 if (info
.num_peers
> 0) --info
.num_peers
;
1950 TORRENT_ASSERT(block
.block_index
< blocks_in_piece(block
.piece_index
));
1952 // if there are other peers, leave the block requested
1953 if (info
.num_peers
> 0) return;
1955 // clear the downloader of this block
1958 // clear this block as being downloaded
1959 info
.state
= block_info::state_none
;
1962 // if there are no other blocks in this piece
1963 // that's being downloaded, remove it from the list
1964 if (i
->requested
+ i
->finished
+ i
->writing
== 0)
1966 erase_download_piece(i
);
1967 piece_pos
& p
= m_piece_map
[block
.piece_index
];
1968 int prev_prio
= p
.priority(this);
1969 TORRENT_ASSERT(prev_prio
< int(m_priority_boundries
.size())
1972 if (m_sequential_download
== -1 && !m_dirty
)
1974 int prio
= p
.priority(this);
1975 if (prev_prio
== -1 && prio
>= 0) add(block
.piece_index
);
1976 else if (prev_prio
>= 0) update(prev_prio
, p
.index
);
1979 TORRENT_ASSERT(std::find_if(m_downloads
.begin(), m_downloads
.end()
1980 , has_index(block
.piece_index
)) == m_downloads
.end());
1982 else if (i
->requested
== 0)
1984 // there are no blocks requested in this piece.
1985 // remove the fast/slow state from it
1990 int piece_picker::unverified_blocks() const
1993 for (std::vector
<downloading_piece
>::const_iterator i
= m_downloads
.begin();
1994 i
!= m_downloads
.end(); ++i
)
1996 counter
+= (int)i
->finished
;