背景:分布式存储系统里,文件是分块存储的,如果每个文件块是1M,那么1G的文件就会有1024个文件块。系统需要为每个文件块分配合适的存储节点,这个过程我们称为选举。
问题:如果为每一个文件块都选举一次,那么1G的文件需要选举1024次,这样对系统要求较高,耗时较长。但如果为1024个文件块选举一次,那么会导致文件分布不均匀,同时如果存储节点没有足够的空间,会导致选举失败。
解决思路:默认按64M选举,如每个文件块为1M,则64个文件块分布在相同的存储节点上。如选举因空间不足导致失败,则减少选举文件大小64->32->16->8,直到无法减少。
int AllotPageStoreList(
const list<PageTagInfo>& page_tag_info_list, //文件块列表
const uint32_t replica_factor, //需要的副本数
list<PageForwardNodesInfo>& page_forward_nodes_info_list, //选举出来的存储节点
uint32_t& max_allot_size) //每次选举的文件大小(64M)
{
list<PageTagInfo> allot_page_list; //每次选举的块列表
uint32_t allot_size = 0; //本次选举的文件块大小
for(list<PageTagInfo>::const_iterator it = page_tag_info_list.begin(); it != page_tag_info_list.end();)
{
allot_size += it->page_size; //根据文件块大小,增加本次选举的文件大小
allot_page_list.push_back(*it); //同时记录下本次的文件块
++it;
if((allot_size < max_allot_size) && (it != page_tag_info_list.end()))
{
continue;
}
//直到本次选举的文件大小达到要求,或文件块已选举完,则开始选举
status = root_service_.GetNodeManager()->AllotStoreNode(allot_size,node_list,replica_factor);
//如因存储空间不足导致失败,则将选举的文件大小减半,递归选举
if(error_disk_full == status)
{
if(allot_page_list.size() < 2) //列表里只有一个,无法再分了,直接返回失败
{
return status;
}
max_allot_size = max_allot_size / 2; //将选举的文件大小减半
list<PageForwardNodesInfo> allot_page_forward_nodes_info_list;
status = AllotPageStoreList(allot_page_list,replica_factor,allot_page_forward_nodes_info_list,max_allot_size); //递归选举
//直到选举成功
if(status != btq_error_success)
{
return status;
}
if((allot_page_list.size() != allot_page_forward_nodes_info_list.size())) //如果选举出来的文件块数量不对,则认为失败
{
return error_failed;
}
//将选举好的文件块->存储节点的信息与需要返回的合并
page_forward_nodes_info_list.splice(page_forward_nodes_info_list.end(),allot_page_forward_nodes_info_list);
}
else if(error_success == status)
{
//选举成功,则为每个文件块分配存储节点
for(list<PageTagInfo>::iterator allot_it = allot_page_list.begin(); allot_it != allot_page_list.end(); ++allot_it)
{
page_forward_nodes_info.page_tag = *allot_it; //记录某次文件块
page_forward_nodes_info.node_list = node_list; //将选举成功的存储节点赋值
page_forward_nodes_info_list.push_back(page_forward_nodes_info); //将选举好的文件块->存储节点的信息与需要返回的合并
}
}
else
{
return status;
}
allot_size = 0; //选举的文件大小归零
allot_page_list.clear(); //清空文件块列表
}
if((page_tag_info_list.size() != page_forward_nodes_info_list.size()))
{
return error_failed;
}
return status;
}
</pre><pre>