ceph 读写路径源代码分析(2)

继续分析Ceph 读写路径上的源代码,本文主要ObjectContex这个比较重要的数据结构。

数据结构

MOSDOp

OSDOp

struct OSDOp {
  ceph_osd_op op; 
   //具体操作数据的封装
  sobject_t soid;
   //src oid, 并不是op操作的对象,而是源数据对象
   //例如rados_clone_range 需要 dest obj 和 src obj
  bufferlist indata, outdata;
  //操作的输入输出的data  
  int32_t rval;
  //操作返回值
  OSDOp() : rval(0) {
    memset(&op, 0, sizeof(ceph_osd_op));
  }
class MOSDOp : public Message {
  object_t oid;
  //操作的对象
  object_locator_t oloc;
  pg_t pgid; //pg
public:
  vector ops;
  //针对oid的多个操作集合
private:
  //快照相关
  snapid_t snapid;
  //snapid,如果是CEPH_NOSNAP,就是head对象,否则就是等于snap_seq
  snapid_t snap_seq;
  //如果是head对象,就是最新的 快照序号
  //如果是snap对象,就是snap对应的seq
  vector snaps;
  //所有的snap列表
  uint64_t features;

  osd_reqid_t reqid; // reqid explicitly set by sender

}

MOSDOp封装了一些基本的请求。在ops里分装了多个OSDOp操作。每个OSDOp操作里又有一个soid, 这个soid和 MOSDOp的 oid 之间是什么关系?

在这里,MOSDOp 封装的操作都是关于oid相关的操作,也就是说,一个MOSDOp只封装针对同一个oid 的操作。但是对于rados_clone_range这样的操作,有一个dest oid, 还有一个src oid,那么src oid 就保存在OSDOp的soid中。

object_info_t

struct object_info_t {
  hobject_t soid;
  eversion_t version, prior_version;
  version_t user_version;
  osd_reqid_t last_reqid;

  uint64_t size;
  utime_t mtime;
  utime_t local_mtime; // local mtime

  // note: these are currently encoded into a total 16 bits; see
  // encode()/decode() for the weirdness.
  typedef enum {
    FLAG_LOST     = 1<<0,
    FLAG_WHITEOUT = 1<<1,  // object logically does not exist
    FLAG_DIRTY    = 1<<2,  
    // object has been modified since last flushed or undirtied
    FLAG_OMAP     = 1 << 3,  // has (or may have) some/any omap data
    FLAG_DATA_DIGEST = 1 << 4,  // has data crc
    FLAG_OMAP_DIGEST = 1 << 5,  // has omap crc
    FLAG_CACHE_PIN = 1 << 6,    // pin the object in cache tier
    // ...
    FLAG_USES_TMAP = 1<<8,  // deprecated; no longer used.
  } flag_t;

  flag_t flags;

  ......

  vector snaps;  // [clone]

  uint64_t truncate_seq, truncate_size;

  map, watch_info_t> watchers;

  // opportunistic checksums; may or may not be present
  __u32 data_digest;  ///< data crc32c
  __u32 omap_digest;  ///< omap crc32c
}

object_info_t 做为 对象的属性,保存在xattr中,key为 OI_ATTR (”_”),value就是object_info_t 的decode后的值

ObjectState

struct ObjectState {
  object_info_t oi;
  bool exists;         
  //the stored object exists (i.e., we will remember the object_info_t)

  ObjectState() : exists(false) {}
  ObjectState(const object_info_t &oi_, bool exists_)
    : oi(oi_), exists(exists_) {}
};

SnapSetContext 保存了SnapSet的上下文信息。关于SnapSet的内容,可以参考相关的文章介绍。

struct SnapSetContext {
  hobject_t oid;  //对象
  int ref;   //本结构的引用计数
  bool registered; //是否在SnapSet Cache中记录
  SnapSet snapset; //SnapSet 对象快照相关的记录
  bool exists;  //snapset是否存在

  SnapSetContext(const hobject_t& o) :
    oid(o), ref(0), registered(false), exists(true) { }
};

对象ObjectContext保存了一个对象的上下文信息

struct ObjectContext {
  ObjectState obs;
  //obs,主要包括object_infot_t, 描述了对象的状态信息
  SnapSetContext *ssc;  // may be null
  //快照上下文信息
  Context *destructor_callback;

private:
  Mutex lock;
public:
  Cond cond;
  int unstable_writes, readers, writers_waiting, readers_waiting;
  //正在写操作的数目,正在读操作的数目
  //等待写操作的数目,等待读操作的数目


  // set if writes for this object are blocked 
  //on another objects recovery
  ObjectContextRef blocked_by;      // object blocking our writes
  set blocking;   // objects whose writes we block

  // any entity in obs.oi.watchers 
  //MUST be in either watchers or unconnected_watchers.
  map, WatchRef> watchers;

  // attr cache
  map<string, bufferlist> attr_cache;

  list waiters;  ///< ops waiting on state change
  int count;              ///< number of readers or writers

  State state:4;               ///< rw state
  /// if set, restart backfill when we can get a read lock
  bool recovery_read_marker:1;
  /// if set, requeue snaptrim on lock release
  bool snaptrimmer_write_marker:1;
  ......
  }

ReplicatedPG::get_object_context

函数get_object_context获取一个对象的object_context信息。输入参数为:

ObjectContextRef 
ReplicatedPG::get_object_context(const hobject_t& soid,
                      bool can_create,
                      map<string, bufferlist> *attrs)

soid 要获取的对象
bool can_create 是否需要创建,如果是写操作,就设置
*attrs 对象的属性

  1. 首先从object_contexts的lru cache里获取,如果获取成功,就之间返回
  2. 如果lru cache里没有查找到:
  3. 如果attrs 输入参数里没有给出,就调用pgbackend->objects_get_attr(soid, OI_ATTR, &bv)
  4. decode后获取object_info_t
  5. 调用get_snapset_context获取SnapSetContext
  6. 设置obc相关的参数,并返回obc

ReplicatedPG::get_snapset_context

获取snapset_context
这个函数和get_object_context类似

  1. 从snapset_contexts 获取snapset_context,如果成功,直接返回结果
  2. 如果不存在,并且can_create,就调用pgbackend->objects_get_attr(oid.get_head(), SS_ATTR, &bv)获取SS_ATTR属性。 只有head对象有ATTR属性,如果head对象不存在,就获取snapdir

ReplicatedPG::find_object_context

这个函数查找对象的object_context,这个要理解snapshot相关的知识。根据snap_seq 正确获取相应的clone对象,然后获取相应的object_context

int ReplicatedPG::find_object_context(
const hobject_t& oid,    要查找的对象
 ObjectContextRef *pobc,  输出对象的ObjectContext 
  bool can_create,     是否需要创建
  bool map_snapid_to_clone,  映射snapid到clone对象
  hobject_t *pmissing   如果对象不存在,返回缺失的对象
  }

参数map_snapid_to_clone, 指该snap是否可以直接对应一个clone对象,也就是snap对象的snap_id在SnapSet的 clones 列表中。

  1. 首先如果是head对象,就调用函数get_object_context获取ObjectContext对象,如果失败,设置pmissing对象
  2. 其次检查如果是snapdir对象,先获取head对象的object_context,如果失败,在获取snapdir的object_context
  3. 如果!map_snapid_to_clone 并且该snap 已经标记删除了,就直接返回
  4. 调用函数获取 get_snapset_context
  5. 如果是map_snapid_to_clone
    • 如果oid.snap > ssc->snapset.seq ,说明该snap是最新做的快照,首次相关的操作,osd端还没有相关的信息更新。直接返回head对象object_context
    • 否则,直接检查SnapSet的 clones 列表, 如果没有,就之间返回-ENOENT
    • 如果找到,检查对象是否missing,如果没有,就获取该clone对象的object_context
  6. 如果不是 map_snapid_to_clone, 就不能从snap_id直接获取clone对象,需要更加snaps和clones 列表,计算snap_id对应的clone对象
    • 如果oid.snap > ssc->snapset.seq,获取head对象
    • 计算oid.snap 首次大于 ssc->snapset.clones 列表中的clone对象,就是oid对应的clone对象
    • 构建soid对象
    • 检查该soid对象是否是 missing
    • 调用函数get_object_context 获取 object_context
    • 最后调用snapid_t first = obc->obs.oi.snaps[obc->obs.oi.snaps.size()-1];
      snapid_t last = obc->obs.oi.snaps[0];
      验证了first <= oid.snap

你可能感兴趣的:(ceph)