torrent::ChunkSelector

说明: 在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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值