说明: 在peer所拥有的chunk中,找到优先级最高,最稀缺的chunk。
成员变量:
Bitfield m_bitfield; //想要下载的,是以下载的补集 ChunkStatistics* m_statistics; priority_ranges m_highPriority; //高优先级range priority_ranges m_normalPriority; rak::partial_queue m_sharedQueue; //所有的seeder共用 uint32_t m_position; //随机chunk index
核心函数:
//由Delegator::new_chunk 调用 uint32_t ChunkSelector::find(PeerChunks* pc, __UNUSED bool highPriority) { // This needs to be re-enabled. if (m_position == invalid_chunk) return invalid_chunk; //seeder和leecher采用同样的算法,有一点性能损失,因为我们已知seeder所有bit都设置了 rak::partial_queue* queue = pc->is_seeder() &m_sharedQueue : pc->download_cache(); //随机化位置,使得bitfield queue化平均一些,不要总从同一个位置开始 if ((random() & 63) == 0) { m_position = random() % size(); queue->clear(); } if (queue->is_enabled()) { // First check the cached queue. while (queue->prepare_pop()) { uint32_t pos = queue->pop(); if (!m_bitfield.get(pos)) continue; return pos; } } else { //只有leecher能到达这个分支,因为m_sharedQueue已经构造了 queue->enable(8); } queue->clear(); //将m_highPriority的chunk queue化 (search_linear(pc->bitfield(), queue, &m_highPriority, m_position, size()) && search_linear(pc->bitfield(), queue, &m_highPriority, 0, m_position)); if (queue->prepare_pop()) { // Set that the peer has high priority pieces cached. } else { // Set that the peer has normal priority pieces cached. queue->clear(); //将m_normalPriority的chunk queue化 (search_linear(pc->bitfield(), queue, &m_normalPriority, m_position, size()) && search_linear(pc->bitfield(), queue, &m_normalPriority, 0, m_position)); if (!queue->prepare_pop()) return invalid_chunk; } uint32_t pos = queue->pop(); if (!m_bitfield.get(pos)) throw internal_error("ChunkSelector::find(...) bad index."); return pos; }
// 收到hava message ,如果是想要的,直接加到queue中 bool ChunkSelector::received_have_chunk(PeerChunks* pc, uint32_t index) { if (!m_bitfield.get(index)) return false; // Also check if the peer only has high-priority chunks. if (!m_highPriority.has(index) && !m_normalPriority.has(index)) return false; //加入到peer的queue if (pc->download_cache()->is_enabled()) pc->download_cache()->insert(m_statistics->rarity(index), index); return true; }
//检查是否感兴趣index chunk bool ChunkSelector::is_wanted(uint32_t index) const { return m_bitfield.get(index) && (m_normalPriority.has(index) || m_highPriority.has(index)); } //TransferList::insert 调用,index准备下载,更新m_bitfield void ChunkSelector::using_index(uint32_t index) { if (index >= size()) throw internal_error("ChunkSelector::select_index(...) index out of range."); if (!m_bitfield.get(index)) throw internal_error("ChunkSelector::select_index(...) index already set."); m_bitfield.unset(index); // We always know 'm_position' points to a wanted chunk. If it // changes, we need to move m_position to the next one. if (index == m_position) advance_position(); } //TransferList::clear()调用 void ChunkSelector::not_using_index(uint32_t index) { if (index >= size()) throw internal_error("ChunkSelector::deselect_index(...) index out of range."); if (m_bitfield.get(index)) throw internal_error("ChunkSelector::deselect_index(...) index already unset."); m_bitfield.set(index); // This will make sure that if we enable new chunks, it will start // downloading them event when 'index == invalid_chunk'. if (m_position == invalid_chunk) m_position = index; }
辅助函数
void ChunkSelector::initialize(Bitfield* bf, ChunkStatistics* cs) { m_position = invalid_chunk; m_statistics = cs; //获得bf的补集 m_bitfield.set_size_bits(bf->size_bits()); m_bitfield.allocate(); std::transform(bf->begin(), bf->end(), m_bitfield.begin(), rak::invert<Bitfield::value_type>()); m_bitfield.update(); //seeder的queue,允许个 m_sharedQueue.enable(32); m_sharedQueue.clear(); }
//在bitfield 的[first,last) (为何不是闭区间,因为bitfield下标从开始) 区间与range 取交集 bool ChunkSelector::search_linear(const Bitfield* bf, rak::partial_queue* pq, priority_ranges* ranges, uint32_t first, uint32_t last) { priority_ranges::iterator itr = ranges->find(first); while (itr != ranges->end() && itr->first < last) { //取交集 if (!search_linear_range(bf, pq, std::max(first, itr->first), std::min(last, itr->second))) return false; ++itr; } return true; } //在[first,last) 区间中,m_bitfield 和peer 的bitfield (m_bitfield 中1表示想下载的,peer 的bitfield中1表示有这个chunk,二者相&正好是wanted) //注意一下按字节的头尾处理 inline bool ChunkSelector::search_linear_range(const Bitfield* bf, rak::partial_queue* pq, uint32_t first, uint32_t last) { if (first >= last || last > size()) throw internal_error("ChunkSelector::search_linear_range(...) received an invalid range."); Bitfield::const_iterator local = m_bitfield.begin() + first / 8; Bitfield::const_iterator source = bf->begin() + first / 8; // Unset any bits before 'first'. Bitfield::value_type wanted = (*source & *local) & Bitfield::mask_from(first % 8); while (m_bitfield.position(local + 1) < last) { if (wanted && !search_linear_byte(pq, m_bitfield.position(local), wanted)) return false; wanted = (*++source & *++local); } // Unset any bits from 'last'. wanted &= Bitfield::mask_before(last - m_bitfield.position(local)); if (wanted) return search_linear_byte(pq, m_bitfield.position(local), wanted); else return true; } // 增加wanted的chunk到queue中 inline bool ChunkSelector::search_linear_byte(rak::partial_queue* pq, uint32_t index, Bitfield::value_type wanted) { for (int i = 0; i < 8; ++i) { if (!(wanted & Bitfield::mask_at(i))) continue; if (!pq->insert(m_statistics->rarity(index + i), index + i) && pq->is_full()) return false; } return true; }