继续分析Ceph 读写路径上的源代码,本文主要ObjectContex这个比较重要的数据结构。
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中。
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后的值
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;
......
}
函数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 对象的属性
获取snapset_context
这个函数和get_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 列表中。