ceph osd find_object_context 代码解读

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对象只有”_“属性。

  1. 在操作header对象的时候分为两种场景:

    • 读场景:通过get_object_context,读”_“属性后,尽管也去获取了snapset属性,但是snapset内容其实是空的,然后返回。
    • 写场景:通过get_object_context,读”_“属性后,如果对象不存在,那么需要在内存里面先创建object_context和snap_context,其中snap_context内容为空,不是null;如果对象存在,获取”_“是有值的,获取成功了以后,再去获取“snapset”,然后组装成一个object_context,然后返回。
  2. clone对象只读,读clone对象先读"snapset"属性,然后在snapset的clones里面去找可能对应的clone对象,如果没有找到直接返回noentry,如果找到了,然后用刚刚找到的clone对象再去clone_snaps去进一步确认,没有找到返回noentry,找到了就组装出clone对象的上下文返回。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值