说明:通过ChunkStatistics统计出所有chunk的供应数后,下一步就是要针对peer将其拥有的chunk按照稀缺度分layer,形象一点就是将chunk按照贵重程度放到7(num_layers)层玲珑宝塔(m_layers)中,不过这个宝塔有点特别,越往下越贵重。(重的东西是应该放下面)。每层的区间范围分别为 第0层到第7层
[0,1) [1,3) [3,7) [7,15) [15,31) [31,63) [63,127) [127,255)
注意:
1. 每层(layer)的数目有限m_maxLayerSize,seeder 32个,leecher 8个,但是在同一层中的chunk可能大于m_maxLayerSize,这称为overflowing,算法的处理是不弹出上一层的chunk,而是返回false,参考prepare_pop函数
2. 第0层(最底层)含义:chunk统计数为0的(只有seeder才可能插入)
成员变量:
mapped_type* m_data; //按层排列的chunk index列表 size_type m_maxLayerSize;//每层的最大个数 size_type m_index; //当前拥有成员的最底层,从第0层开始 size_type m_ceiling; //可插入层的最大统计值,从最高层的最大值开始 size_pair_type m_layers[num_layers];//first 本层已经pop的chunk数,second 本层总共的chunk数
核心函数:
//构造,ls: 每层最大允许的chunk index数 inline void partial_queue::enable(size_type ls) { if (ls == 0) throw std::logic_error("partial_queue::enable(...) ls == 0."); delete [] m_data; m_data = new mapped_type[ls * num_layers]; m_maxLayerSize = ls; } //销毁 inline void partial_queue::disable() { delete [] m_data; m_data = NULL; m_maxLayerSize = 0; } //清空 inline void partial_queue::clear() { if (m_data == NULL) return; m_index = 0; m_ceiling = ceiling(num_layers - 1); std::memset(m_layers, 0, num_layers * sizeof(size_pair_type)); }
/************************************************************************
增加一个成员
参数: key: 成员身价,chunk的统计数,值越少越值钱
value: 成员ID号,chunk index
说明:
本算法按照chunk统计数,将chunk放到不同的层,如果中间某一层满了,继续往低一层放,直到使最低层满了,则整个queue满了(只有seeder可能做到),插入后m_index指向有chunk的最低层,m_ceiling表示可插入的层最高统计值
本函数由ChunkSelector调用
************************************************************************/
inline bool partial_queue::insert(key_type key, mapped_type value) {
if(key>= m_ceiling)
return false;
size_type idx= 0;
//找到layer
while(key>= ceiling(idx))
++idx;
m_index= std::min(m_index, idx);
// Currently don't allow overflow.
if(is_layer_full(idx))
throwstd::logic_error("partial_queue::insert(...) layer already full.");
//记录chunk index
m_data[m_maxLayerSize* idx+ m_layers[idx].second] = value;
m_layers[idx].second++;
if(is_layer_full(idx))
// 如果是第0层满了,则表示整个queue满了,否则到低一层
m_ceiling= idx> 0 ? ceiling(idx- 1) : 0;
return true;
}
//定位到有un-popped chunk的最低层 inline bool partial_queue::prepare_pop() { while (m_layers[m_index].first == m_layers[m_index].second) { //is_layer_full(m_index)表示overflowed,表示在当前layer的chunk大于m_maxLayerSize if (is_layer_full(m_index) || m_index + 1 == num_layers) return false; m_index++; } return true; } //获得chunk index inline partial_queue::mapped_type partial_queue::pop() { if (m_index >= num_layers || m_layers[m_index].first >= m_layers[m_index].second) throw std::logic_error("partial_queue::pop() bad state."); return m_data[m_index * m_maxLayerSize + m_layers[m_index].first++]; }