工具类分析-rak::ChunkStatistics

P2P的核心特点决定了P2P必须从多个peer下载,这样必然要求将下载的内容分段-chunk,在这些chunk中先下哪一个呢?或者说哪一个chunk最宝贵呢,市场经济早就告诉了我们,物以稀为贵。这也是BT chunk选择算法最重要最基本的,当然在不同的应用中还会加上一些权重(比如视音频的索引chunk,谁让人家是衔玉而生呢),为了确定稀缺度,我们需要进行精确的汇总统计,torrent::ChunkStatistics 类就完成这个工作.

原型: class ChunkStatistics: public std::vector<uint8_t>

说明: vector派生类,下标为chunk index, 值为“市场上”货物数目,如[1]=10 表示index为1的chunk有10个peer拥有。既然是统计chunk数的,其必然是归download,所有peer共享一个,在实际中是DownloadMain的成员变量m_chunkStatistics

调用时机:在BT协议中,当peer握手成功后,交换bitfield会调用received_connect;在收到HAV Message时会调用received_have_chunk;在Peer断开时会调用received_disconnect。

注意:因为是 uint8_t的vector,这表示最大的统计数是 255个,由函数 should_add(PeerChunks* pc) 进行检查

成员变量:

   size_type           m_complete;      //拥有所有chunk的peer数,即seeder数 
 
size_type           m_accounted;    //拥有部分chunk的peer数,即leecher数

核心函数:

//初始化vector 大小,参数:chunk 数目 ,由 DownloadMain::open调用
void ChunkStatistics::initialize(size_type s) {
  if(!empty())
    throwinternal_error("ChunkStatistics::initialize(...) called on an initialized object.");

  base_type::resize(s);
}

//PeerConnectionBase::initialize 函数中调用,pc->using_counter记录是否被统计过
void ChunkStatistics::received_connect(PeerChunks* pc) {
  if (pc->using_counter())
    throw internal_error("ChunkStatistics::received_connect(...) pc->using_counter() == true.");
    //peer是seeder
  if (pc->bitfield()->is_all_set()) {
    pc->set_using_counter(true);
    m_complete++;

  } else if (!pc->bitfield()->is_all_unset() && should_add(pc)) {
    //peer是leech
    pc->set_using_counter(true);
    m_accounted++;
    
    iterator itr = base_type::begin();

    //加
    for (Bitfield::size_type index = 0; index < pc->bitfield()->size_bits(); ++index, ++itr)
      *itr += pc->bitfield()->get(index);
  }
}
//PeerConnectionBase::cleanup调用
void
ChunkStatistics::received_disconnect(PeerChunks* pc) {

  //没有统计过.
  if (!pc->using_counter())
    return;

  pc->set_using_counter(false);

  if (pc->bitfield()->is_all_set()) {
    m_complete--;

  } else {
    if (m_accounted == 0)
      throw internal_error("ChunkStatistics::received_disconnect(...) m_accounted == 0.");

    m_accounted--;

    iterator itr = base_type::begin();

    //减.
    for (Bitfield::size_type index = 0; index < pc->bitfield()->size_bits(); ++index, ++itr)
      *itr -= pc->bitfield()->get(index);
  }
}
//PeerConnection
  
  
   
   ::read_have_chunk(uint32_t index) 调用

  
  void
ChunkStatistics::received_have_chunk(PeerChunks* pc, uint32_t index, uint32_t length) {
  // When the bitfield is empty, it is very cheap to add the peer to
  // the statistics. It needs to be done here else we need to check if
  // a connection has sent any messages, else it might send a bitfield.
  if (pc->bitfield()->is_all_unset() && should_add(pc)) {

    if (pc->using_counter())
      throw internal_error("ChunkStatistics::received_have_chunk(...) pc->using_counter() == true.");

    pc->set_using_counter(true);
    m_accounted++;
  }

  pc->bitfield()->set(index);
  pc->peer_rate()->insert(length);
  
  if (pc->using_counter()) {

    base_type::operator[](index)++;

    //peer由leech 转变为 seeder 
    if (pc->bitfield()->is_all_set()) {
      if (m_accounted == 0)
    throw internal_error("ChunkStatistics::received_disconnect(...) m_accounted == 0.");
      
      m_complete++;
      m_accounted--;
      
      for (iterator itr = base_type::begin(), last = base_type::end(); itr != last; ++itr)
    *itr -= 1;
    }

  } else {

    if (pc->bitfield()->is_all_set()) {
      pc->set_using_counter(true);
      m_complete++;
    }
  }
}
   //获得index的统计数
  const_reference     rarity(size_type n) const       { return base_type::operator[](n); }
  const_reference     operator [] (size_type n) const { return base_type::operator[](n); }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值