ceph 通过自定义操作的方式来提供丰富的业务逻辑, 例如radosgw的业务逻辑
首先先通过下面方法注册到OSD中
72/* class registration api */
73extern int cls_register(const char *name, cls_handle_t *handle);
74extern int cls_unregister(cls_handle_t);
75
76-extern int cls_register_method(cls_handle_t hclass, const char *method, int flags,
77 cls_method_call_t class_call, cls_method_handle_t *handle);
78extern int cls_unregister_method(cls_method_handle_t handle);
79extern void cls_unregister_filter(cls_filter_handle_t handle);
...
137-extern int cls_register_cxx_method(cls_handle_t hclass, const char *method, int flags,
138 cls_method_cxx_call_t class_call, cls_method_handle_t *handle);
显然一个是用来注册c++ 方法的, 一个是注册c方法的
其中
hclass 是方法组
method 是方法名
flags 是这个方法会请求的锁类型
class_call 是定义的处理函数
handle 作为返回的句柄
客户端需要调用这些方法时
通过调用ObjectOperation::exec 输入方法组,方法名,参数
288 -class CEPH_RADOS_API ObjectOperation
289 {
290 public:
291 ObjectOperation();
292 virtual ~ObjectOperation();
293
294 size_t size();
295 void set_op_flags(ObjectOperationFlags flags) __attribute__((deprecated));
296 //flag mean ObjectOperationFlags
297 void set_op_flags2(int flags);
298
299 void cmpxattr(const char *name, uint8_t op, const bufferlist& val);
300 void cmpxattr(const char *name, uint8_t op, uint64_t v);
301 void src_cmpxattr(const std::string& src_oid,
302 const char *name, int op, const bufferlist& val);
303 void src_cmpxattr(const std::string& src_oid,
304 const char *name, int op, uint64_t v);
305 void exec(const char *cls, const char *method, bufferlist& inbl);
306 void exec(const char *cls, const char *method, bufferlist& inbl, bufferlist *obl, int *prval);
307 void exec(const char *cls, const char *method, bufferlist& inbl, ObjectOperationCompletion *completion);
具体的实现为
55-int cls_register_method(cls_handle_t hclass, const char *method,
56 int flags,
57 cls_method_call_t class_call, cls_method_handle_t *handle)
58{
59 if (!(flags & (CLS_METHOD_RD | CLS_METHOD_WR)))
60 return -EINVAL;
61 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass;
62=>cls_method_handle_t hmethod =(cls_method_handle_t)cls->register_method(method, flags, class_call);
63 if (handle)
64 *handle = hmethod;
65 return (hmethod != NULL);
66}
...
68-int cls_register_cxx_method(cls_handle_t hclass, const char *method,
69 int flags,
70 cls_method_cxx_call_t class_call, cls_method_handle_t *handle)
71{
72 ClassHandler::ClassData *cls = (ClassHandler::ClassData *)hclass;
73 cls_method_handle_t hmethod = (cls_method_handle_t)cls->register_cxx_method(method, flags, class_call);
74 if (handle)
75 *handle = hmethod;
76 return (hmethod != NULL);
77}
osd 在线程中根据消息的类型通过名字取出处理函数,例如
4099-int ReplicatedPG::do_osd_ops(OpContext *ctx, vector<OSDOp>& ops)
4100{
4101 int result = 0;
4102 SnapSetContext *ssc = ctx->obc->ssc;
4103 ObjectState& obs = ctx->new_obs;
4104 object_info_t& oi = obs.oi;
4105 const hobject_t& soid = oi.soid;
4106
4107 bool first_read = true;
4108
4109 PGBackend::PGTransaction* t = ctx->op_t.get();
...
4407 case CEPH_OSD_OP_CALL:
4408 {
...
4430 ClassHandler::ClassMethod *method = cls->get_method(mname.c_str());
...
}
这样只需要注册相关的操作函数,和方法名字,在客户端通过ObjectOperation::exec 取调用即可
这里值得注意的还有一点就是注册方法时的flags这里有
28#define CLS_METHOD_RD 0x1 /// method executes read operations
29#define CLS_METHOD_WR 0x2 /// method executes write operations
30#define CLS_METHOD_PUBLIC 0x4 /// unused
31=>efine CLS_METHOD_PROMOTE 0x8 /// method cannot be proxied to base tier
有这几种 其中
CLS_METHOD_RD 代表读锁
CLS_METHOD_WR 代表写锁
在确定了操作对象后会调用下面函数来申请对象的锁, 这个锁用于处理对象操作的互斥性
791=>-bool get_rw_locks(bool write_ordered, OpContext *ctx) {
792 /* If snapset_obc, !obc->obs->exists and we will always take the
793 * snapdir lock *before* the head lock. Since all callers will do
794 * this (read or write) if we get the first we will be guaranteed
795 * to get the second.
796 */
797 if (write_ordered && ctx->op->may_read()) {
798 ctx->lock_type = ObjectContext::RWState::RWEXCL;
799 } else if (write_ordered) {
800 ctx->lock_type = ObjectContext::RWState::RWWRITE;
801 } else {
802 assert(ctx->op->may_read());
803 ctx->lock_type = ObjectContext::RWState::RWREAD;
804 }
... 非快照的话 会在下面获取对应的锁
817 if (ctx->lock_manager.get_lock_type(
818 ctx->lock_type,
819 ctx->obc->obs.oi.soid,
820 ctx->obc,
821 ctx->op)) {
822 return true;
锁对象为
ObjectContext::RWState 实现了一种特殊的行为
可以多读, 可以多写但是读写互斥
当多读 多写时只会增加count 计数, 如果此时来了相异的请求类型时会在waiters 中加1,此时非贪婪的锁请求将不能获取锁
3525 -bool get_read_lock() {
3526 // don't starve anybody!
3527 if (!waiters.empty()) {
3528 return false;
3529 }
or
3557 if (!greedy) {
3558 // don't starve anybody!
3559 if (!waiters.empty() ||
3560 recovery_read_marker) {
3561 return false;
3562 }
3563 }
这样可以避免饥饿的现象,不过当大量读请求时 如果当中含有一个写请求时下一个读请求将要等待前面的读请求完成,在等待写请求完成才能获得对象锁
同时如果是请求读写类型的锁时是每次互斥的,我想对单一对象的大量此类操作会出现较长等待时间
以上就是关于ceph的自定义操作的基本流程, ceph 大多业务实现是在此基础上构建的 例如radosgw等
7487



被折叠的 条评论
为什么被折叠?



