int PrimaryLogPG::find_object_context(const hobject_t &oid,
ObjectContextRef *pobc,
bool can_create,
bool map_snapid_to_clone,
hobject_t *pmissing)
{
FUNCTRACE(cct);
ceph_assert(oid.pool == static_cast<int64_t>(info.pgid.pool()));
/* 获取header对象 */
if (oid.snap == CEPH_NOSNAP)
{
/*
对于读请求,如果对象不存在,obc为空
对于写请求,如果对象不存在,object context会被创建出来,包括其中的snapset_context
*/
ObjectContextRef obc = get_object_context(oid, can_create);
if (!obc)
{
/* 如果读的对象不存在,那么返回ENOENT */
if (pmissing)
*pmissing = oid;
return -ENOENT;
}
dout(10) << __func__ << " " << oid
<< " @" << oid.snap
<< " oi=" << obc->obs.oi
<< dendl;
*pobc = obc;
return 0;
}
hobject_t head = oid.get_head();
/* 读快照 */
if (!map_snapid_to_clone && pool.info.is_removed_snap(oid.snap))
{
dout(10) << __func__ << " snap " << oid.snap << " is removed" << dendl;
return -ENOENT;
}
/* 先获取snapset attr */
SnapSetContext *ssc = get_snapset_context(oid, can_create);
if (!ssc || !(ssc->exists || can_create))
{
dout(20) << __func__ << " " << oid << " no snapset" << dendl;
if (pmissing)
*pmissing = head; // start by getting the head
if (ssc)
put_snapset_context(ssc);
return -ENOENT;
}
if (map_snapid_to_clone)
{
...
}
dout(10) << __func__ << " " << oid << " @" << oid.snap
<< " snapset " << ssc->snapset << dendl;
/* 要读的快照id大于snapset中的seq,那么我们要读的就是header */
if (oid.snap > ssc->snapset.seq)
{
ObjectContextRef obc = get_object_context(head, false);
dout(10) << __func__ << " " << head
<< " want " << oid.snap << " > snapset seq " << ssc->snapset.seq
<< " -- HIT " << obc->obs
<< dendl;
if (!obc->ssc)
obc->ssc = ssc;
else
{
ceph_assert(ssc == obc->ssc);
put_snapset_context(ssc);
}
*pobc = obc;
return 0;
}
/* 寻找snap实际对应的clone对象,
ssc->snapset.clones是升序排列的,找到小于或者等于待读snap的克隆对象的id,这里只是找到,不一定就存在,下面还需要查找
*/
unsigned k = 0;
while (k < ssc->snapset.clones.size() &&
ssc->snapset.clones[k] < oid.snap)
k++;
if (k == ssc->snapset.clones.size())
{
dout(10) << __func__ << " no clones with last >= oid.snap "
<< oid.snap << " -- DNE" << dendl;
put_snapset_context(ssc);
return -ENOENT;
}
/* 实际要读的clone对象 */
hobject_t soid(oid.oid, oid.get_key(), ssc->snapset.clones[k], oid.get_hash(), info.pgid.pool(), oid.get_namespace());
if (pg_log.get_missing().is_missing(soid))
{
dout(20) << __func__ << " " << soid << " missing, try again later"
<< dendl;
if (pmissing)
*pmissing = soid;
put_snapset_context(ssc);
return -EAGAIN;
}
/* 获取实际要读的快照对象的上下文 */
ObjectContextRef obc = get_object_context(soid, false);
if (!obc || !obc->obs.exists)
{
if (pmissing)
*pmissing = soid;
put_snapset_context(ssc);
if (is_degraded_or_backfilling_object(soid))
{
dout(20) << __func__ << " clone is degraded or backfilling " << soid << dendl;
return -EAGAIN;
}
else if (is_degraded_on_async_recovery_target(soid))
{
dout(20) << __func__ << " clone is recovering " << soid << dendl;
return -EAGAIN;
}
else
{
dout(20) << __func__ << " missing clone " << soid << dendl;
return -ENOENT;
}
}
if (!obc->ssc)
{
obc->ssc = ssc;
}
else
{
ceph_assert(obc->ssc == ssc);
put_snapset_context(ssc);
}
ssc = 0;
// clone
dout(20) << __func__ << " " << soid
<< " snapset " << obc->ssc->snapset
<< dendl;
snapid_t first, last;
/*
obc->ssc->snapset.clone_snaps的定义:map<snapid_t, vector<snapid_t>> clone_snaps,
map中的key列表是SnapSet中的vector clones列表,map的value代表哪些snapId落在这个clone对象上。
假设一个待读的snap_id1对应clone_id1.
那么obc->ssc->snapset.clone_snaps[clone_id]得到的列表包含了snap_id1,那么对象存在
如果没有包含,那么对象就不存在。
*/
auto p = obc->ssc->snapset.clone_snaps.find(soid.snap);
ceph_assert(p != obc->ssc->snapset.clone_snaps.end());
if (p->second.empty())
{
dout(1) << __func__ << " " << soid << " empty snapset -- DNE" << dendl;
ceph_assert(!cct->_conf->osd_debug_verify_snaps);
return -ENOENT;
}
first = p->second.back();
last = p->second.front();
if (first <= oid.snap)
{
dout(20) << __func__ << " " << soid << " [" << first << "," << last
<< "] contains " << oid.snap << " -- HIT " << obc->obs << dendl;
*pobc = obc;
return 0;
}
else
{
dout(20) << __func__ << " " << soid << " [" << first << "," << last
<< "] does not contain " << oid.snap << " -- DNE" << dendl;
return -ENOENT;
}
}
find_object_context是获取一个对象的上下文,关键的流程在代码中已经进行了解释。
在文章《rados对象属性查看》中,可以看出header对象有“snapset”和“_”两种属性,而clone对象只有”_“属性。
-
在操作header对象的时候分为两种场景:
- 读场景:通过get_object_context,读”_“属性后,尽管也去获取了snapset属性,但是snapset内容其实是空的,然后返回。
- 写场景:通过get_object_context,读”_“属性后,如果对象不存在,那么需要在内存里面先创建object_context和snap_context,其中snap_context内容为空,不是null;如果对象存在,获取”_“是有值的,获取成功了以后,再去获取“snapset”,然后组装成一个object_context,然后返回。
-
clone对象只读,读clone对象先读"snapset"属性,然后在snapset的clones里面去找可能对应的clone对象,如果没有找到直接返回noentry,如果找到了,然后用刚刚找到的clone对象再去clone_snaps去进一步确认,没有找到返回noentry,找到了就组装出clone对象的上下文返回。