随着项目规模的扩大,最初提供的简单增删改查 API 虽然能够满足基本业务需求,但在特殊场景下可能需要额外的 API 接口。逐渐增加的业务需求导致业务逻辑变得更加复杂,因此提供的 API 数量也会不断增加,这可能会使得底层的 RADOS 层变得臃肿,从解耦方面来看,特定的业务逻辑应该与基础架构分离,这样即使业务逻辑发生变化,也不会影响到基础架构的稳定性,实现业务逻辑与底层的解耦。
#include<algorithm> #include<string> #include<sstream> #include<errno.h> #include"objclass/objclass.h" //cls 版本号 /* #define CLS_VER(maj,min) \ int __cls_ver__## maj ## _ ##min = 0; \ int __cls_ver_maj = maj; \ int __cls_ver_min = min; */ CLS_VER(1,0) //cls 名字 CLS_NAME(hello) /* #define CLS_NAME(name) \ int __cls_name__## name = 0; \ const char *__cls_name = #name; */ //要实现的函数 staticintsay_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { if (in->length() > 100) // 这里面函数是跑在 osd 上的 // 这不同于客户端,这是在存储集群进程osd直接访问 // this return value will be returned back to the librados caller return0; }
/* #define CLS_INIT(name) \ CEPH_CLS_API void __cls_init() */ // CLS_INIT 是必须的,加载 动态库后,会调用 init 函数,主要作用在于把cls中的函数指针持久到一个map中,为以后调用做准备 CLS_INIT(hello) { // this log message, at level 0, will always appear in the ceph-osd // log file. // cls的句柄,通过该句柄可以找到对应的库 cls_handle_t h_class; // 动态库里面的函数句柄 cls_method_handle_t h_say_hello; // 从系统 读到已加载的动态库 cls_register("hello", &h_class);
// There are two flags we specify for methods: // RD : whether this method (may) read prior object state // WR : whether this method (may) write or update the object // A method can be RD, WR, neither, or both. If a method does // neither, the data it returns to the caller is a function of the // request and not the object contents. //将 say_hello这个函数 注册到 h_say_hello cls_register_cxx_method(h_class, "say_hello", CLS_METHOD_RD, say_hello, &h_say_hello); }
intOSD::init(){ //..... class_handler = new ClassHandler(cct); cls_initialize(class_handler);
if (cct->_conf->osd_open_classes_on_start) { int r = class_handler->open_all_classes(); if (r) dout(1) << "warning: got an error loading one or more classes: " << cpp_strerror(r) << dendl; } //.... }
staticintsay_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out) { if (in->length() > 100) // 这里面函数是跑在 osd 上的 // 这不同于客户端,这是在存储集群进程osd直接访问 // this return value will be returned back to the librados caller return0; }
// There are two flags we specify for methods: // RD : whether this method (may) read prior object state // WR : whether this method (may) write or update the object // A method can be RD, WR, neither, or both. If a method does // neither, the data it returns to the caller is a function of the // request and not the object contents. //将 say_hello这个函数 注册到 h_say_hello cls_register_cxx_method(h_class, "say_hello", CLS_METHOD_RD, say_hello, &h_say_hello); }
cls_register_cxx_method
1
intcls_register_method(cls_handle_t hclass, constchar *method, int flags,cls_method_call_t class_call, cls_method_handle_t *handle);
int ClassHandler::ClassMethod::exec(cls_method_context_t ctx, bufferlist& indata, bufferlist& outdata) { int ret; if (cxx_func) { // C++ call version ret = cxx_func(ctx, &indata, &outdata); } else { // C version char *out = NULL; int olen = 0; ret = func(ctx, indata.c_str(), indata.length(), &out, &olen); if (out) { // assume *out was allocated via cls_alloc (which calls malloc!) buffer::ptr bp = buffer::claim_malloc(olen, out); outdata.push_back(bp); } } return ret; }