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

本文详细剖析了Ceph中ObjectContex、MOSDOp、OSDOp等数据结构,特别是对于读写操作中的关键元素如soid、oid的关系,以及SnapSetContext在对象上下文中的作用。通过分析ReplicatedPG的get_object_context、get_snapset_context和find_object_context等函数,阐述了如何根据snap_seq找到正确的对象上下文。
摘要由CSDN通过智能技术生成

继续分析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 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 *attrs)

soid 要获取的对象

bool can_create 是否需要创建,如果是写操作,就设置

*attrs 对象的属性

首先从object_contexts的lru cache里获取,如果获取成功,就之间返回

如果lru cache里没有查找到:

如果attrs 输入参数里没有给出,就调用pgbackend->objects_get_attr(soid, OI_ATTR, &bv)

decode后获取object_info_t

调用get_snapset_context获取SnapSetContext

设置obc相关的参数,并返回obc

ReplicatedPG::get_snapset_context

获取snapset_context

这个函数和get_object_context类似

从snapset_contexts 获取snapset_context,如果成功,直接返回结果

如果不存在,并且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 列表中。

首先如果是head对象,就调用函数get_object_context获取ObjectContext对象,如果失败,设置pmissing对象

其次检查如果是snapdir对象,先获取head对象的object_context,如果失败,在获取snapdir的object_context

如果!map_snapid_to_clone 并且该snap 已经标记删除了,就直接返回

调用函数获取 get_snapset_context

如果是map_snapid_to_clone

如果oid.snap > ssc->snapset.seq ,说明该snap是最新做的快照,首次相关的操作,osd端还没有相关的信息更新。直接返回head对象object_context

否则,直接检查SnapSet的 clones 列表, 如果没有,就之间返回-ENOENT

如果找到,检查对象是否missing,如果没有,就获取该clone对象的object_context

如果不是 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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值