// See doc/dev/osd_internals/last_epoch_started
if (oinfo.last_epoch_started > info.last_epoch_started)
{
info.last_epoch_started = oinfo.last_epoch_started;
dirty_info = true;
}
if (info.history.merge(oinfo.history)) //对history信息进行合并。
dirty_info = true;
assert(cct->_conf->osd_find_best_info_ignore_history_les ||
info.last_epoch_started >= info.history.last_epoch_started);
peer_missing[from].swap(omissing);//将missing结构统计到本地的peer_missing结构中。
}
auth_log:一个是auth_log的合并,最大最权威的log,恢复数据要根据这里进行。
missing:另外就是合并log过程中发现本地副本需要恢复的object集合。
omissing:auth_osd需要进行恢复的object集合。
3、GetMissing:
3.1、遍历acting_backfill,向与primary pg log有交集的pg所在的osd发送Query Log请求;将剩余没有交集的pg放入peer_missing,生成missing set用于后续recovery;
context< RecoveryMachine >().send_query(
*i,
pg_query_t(
pg_query_t::LOG,
i->shard, pg->pg_whoami.shard,
since, pg->info.history,
pg->get_osdmap()->get_epoch()));
3.2、将收到的每一个应答merge到本地,如果在此期间有osd down掉,这个PG的状态将持续等待;收到所有的应答后,当前pg的状态机进入Activate状态,peering过程结束;
boost::statechart::result PG::RecoveryState::GetMissing::react(const MLogRec &logevt)
{
PG *pg = context< RecoveryMachine >().pg;
peer_missing_requested.erase(logevt.from);
pg->proc_replica_log(*context<RecoveryMachine>().get_cur_transaction(),
logevt.msg->info, logevt.msg->log, logevt.msg->missing, logevt.from);//接收到其他osd发回的log信息并且进行处理。在proc_replica_log中对peer_log进行修剪,丢弃那些不完整不可用的log。整理接收到的oinfo到peerinfo中,omissing到peer_missing中。直接来到active状态。
if (peer_missing_requested.empty())
{
if (pg->need_up_thru)
{
dout(10) << " still need up_thru update before going active" << dendl;
post_event(NeedUpThru());
}
else
{
dout(10) << "Got last missing, don't need missing "
<< "posting Activate" << dendl;
post_event(Activate(pg->get_osdmap()->get_epoch()));
}
}
return discard_event();
}
从以上分析来看,整个peering过程主要分为三个阶段,GetInfo -> GetLog -> GetMissing,首先向prior set、acting set、up set中的每个osd请求pg infos, 选出authoritative log对应的pg;其次向authoritative log所在的osd请求authoritative log;最后获取recovery过程需要的missing set;
peering时间的长短并不可控,主要是在于请求的osd是否能够及时响应;如果这个阶段某个osd down掉,很可能导致部分pg一直处在peering状态,即所有分布到这个pg上的IO都会阻塞。
此文仅讲述了peering过程,peering之后还会进行recovery操作,recovery操作由处理线程直接调用函数void OSD::do_recovery(PG *pg, ThreadPool::TPHandle &handle)进行,后续再总结总结recovery过程和PG的状态机。
先附两张PG状态机的类型以及流程图: