博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
ceph 对动态加载类的管理
阅读量:4215 次
发布时间:2019-05-26

本文共 6227 字,大约阅读时间需要 20 分钟。

ceph提供了一个ClassHandler来管理动态链接库使用ClassHandler 之前必要要先注册ClassHandler::ClassData *ClassHandler::register_class(const char *cname){  assert(mutex.is_locked());  #根据name得到要使用的class  ClassData *cls = _get_class(cname, false);  ldout(cct, 10) << "register_class " << cname << " status " << cls->status << dendl;  #如果class的status不是CLASS_INITIALIZING,说明这里动态链接库并没有被加载进来,这里直接返回NULL  if (cls->status != ClassData::CLASS_INITIALIZING) {    ldout(cct, 0) << "class " << cname << " isn't loaded; is the class registering under the wrong name?" << dendl;    return NULL;  }  return cls;}继续看_get_classClassHandler::ClassData *ClassHandler::_get_class(const string& cname,    bool check_allowed){  ClassData *cls;  #通过map的find函数根据这个class的name找到对应clasdata  map
::iterator iter = classes.find(cname); #如果不等于classes.end说明找到这个class了,这里通过iter->second就可以得到ClassData,随意不能重复注册 if (iter != classes.end()) { cls = &iter->second; } else { if (check_allowed && !in_class_list(cname, cct->_conf->osd_class_load_list)) { ldout(cct, 0) << "_get_class not permitted to load " << cname << dendl; return NULL; } #正常情况下应该走下面这段code 会新建一个ClassData. cls = &classes[cname]; ldout(cct, 10) << "_get_class adding new class name " << cname << " " << cls << dendl; cls->name = cname; cls->handler = this; cls->whitelisted = in_class_list(cname, cct->_conf->osd_class_default_list); } return cls;}注册类后要为这个类注册方法ClassHandler::ClassMethod *ClassHandler::ClassData::register_method(const char *mname, int flags, cls_method_call_t func){ /* no need for locking, called under the class_init mutex */ if (!flags) { lderr(handler->cct) << "register_method " << name << "." << mname << " flags " << flags << " " << (void*)func << " FAILED -- flags must be non-zero" << dendl; return NULL; } ldout(handler->cct, 10) << "register_method " << name << "." << mname << " flags " << flags << " " << (void*)func << dendl; ClassMethod& method = methods_map[mname]; method.func = func; method.name = mname; method.flags = flags; method.cls = this; return &method;}可以看到基本是为method赋值当使用的时候要调用open_class来dlopen动态链接库int ClassHandler::open_class(const string& cname, ClassData **pcls){ Mutex::Locker lock(mutex); #通过调用_get_class来根据name得到class,不过在这次正确情况下可以找到class ClassData *cls = _get_class(cname, true); if (!cls) return -EPERM; #如果这个类没有open的话,则调用_load_class来dlopen if (cls->status != ClassData::CLASS_OPEN) { int r = _load_class(cls); if (r) return r; } *pcls = cls; return 0;}int ClassHandler::_load_class(ClassData *cls){ // already open #不能重复打开 if (cls->status == ClassData::CLASS_OPEN) return 0; if (cls->status == ClassData::CLASS_UNKNOWN || cls->status == ClassData::CLASS_MISSING) { char fname[PATH_MAX]; snprintf(fname, sizeof(fname), "%s/" CLS_PREFIX "%s" CLS_SUFFIX, cct->_conf->osd_class_dir.c_str(), cls->name.c_str()); ldout(cct, 10) << "_load_class " << cls->name << " from " << fname << dendl; #这里很清楚的看到是调用dlopen来打开这个class cls->handle = dlopen(fname, RTLD_NOW); if (!cls->handle) { struct stat st; int r = ::stat(fname, &st); if (r < 0) { r = -errno; ldout(cct, 0) << __func__ << " could not stat class " << fname << ": " << cpp_strerror(r) << dendl; } else { ldout(cct, 0) << "_load_class could not open class " << fname << " (dlopen failed): " << dlerror() << dendl; r = -EIO; } cls->status = ClassData::CLASS_MISSING; return r; } #如果这个class 依赖其他class,则统计这些依赖类 cls_deps_t *(*cls_deps)(); cls_deps = (cls_deps_t *(*)())dlsym(cls->handle, "class_deps"); if (cls_deps) { cls_deps_t *deps = cls_deps(); while (deps) { if (!deps->name) break; #将这里依赖类保存到dependencies 中 ClassData *cls_dep = _get_class(deps->name, false); cls->dependencies.insert(cls_dep); if (cls_dep->status != ClassData::CLASS_OPEN) cls->missing_dependencies.insert(cls_dep); deps++; } } } // resolve dependencies #统一load这些依赖类 set
::iterator p = cls->missing_dependencies.begin(); while (p != cls->missing_dependencies.end()) { ClassData *dc = *p; int r = _load_class(dc); if (r < 0) { cls->status = ClassData::CLASS_MISSING_DEPS; return r; } ldout(cct, 10) << "_load_class " << cls->name << " satisfied dependency " << dc->name << dendl; cls->missing_dependencies.erase(p++); } 打开这个类后就可以调用exec 来执行这个类的方法 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; #这里的func 在register_method中赋值 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;}下来看一个编写helloworld的例子static int say_hello(cls_method_context_t hctx, bufferlist *in, bufferlist *out){ // see if the input data from the client matches what this method // expects to receive. your class can fill this buffer with what it // wants. if (in->length() > 100) return -EINVAL; // we generate our reply out->append("Hello, "); if (in->length() == 0) out->append("world"); else out->append(*in); out->append("!"); // this return value will be returned back to the librados caller return 0;}/** * initialize class * * We do two things here: we register the new class, and then register * all of the class's methods. */CLS_INIT(hello){ // this log message, at level 0, will always appear in the ceph-osd // log file. CLS_LOG(0, "loading cls_hello"); cls_handle_t h_class; cls_method_handle_t h_say_hello; #注册类 cls_register("hello", &h_class); #为这个类注册方法 cls_register_cxx_method(h_class, "say_hello", CLS_METHOD_RD, say_hello, &h_say_hello); }ceph为了方便大家提供了一个套更简答的api,例如本例中的cls_registerint cls_register(const char *name, cls_handle_t *handle){ #可见还是调用上面讲到的register_class来进行 ClassHandler::ClassData *cls = ch->register_class(name); *handle = (cls_handle_t)cls; return (cls != NULL);}

转载地址:http://djnmi.baihongyu.com/

你可能感兴趣的文章
CSS之浮动(一)
查看>>
CSS之浮动(二)
查看>>
AtomicInteger源码解析
查看>>
CopyOnWriteArraySet源码学习
查看>>
Openfiler 配置 NFS 示例
查看>>
Oracle 11.2.0.1 RAC GRID 无法启动 : Oracle High Availability Services startup failed
查看>>
Oracle 18c 单实例安装手册 详细截图版
查看>>
Oracle Linux 6.1 + Oracle 11.2.0.1 RAC + RAW 安装文档
查看>>
Oracle 11g 新特性 -- Online Patching (Hot Patching 热补丁)说明
查看>>
Oracle 11g 新特性 -- ASM 增强 说明
查看>>
Oracle 11g 新特性 -- Database Replay (重演) 说明
查看>>
Oracle 11g 新特性 -- 自动诊断资料档案库(ADR) 说明
查看>>
Oracle 11g 新特性 -- RMAN Data Recovery Advisor(DRA) 说明
查看>>
CSDN博客之星 投票说明
查看>>
Oracle wallet 配置 说明
查看>>
Oracle smon_scn_time 表 说明
查看>>
VBox fdisk 不显示 添加的硬盘 解决方法
查看>>
Secure CRT 自动记录日志 配置 小记
查看>>
RMAN RAC 到 单实例 duplicate 自动分配通道 触发 ORA-19505 错误
查看>>
mysql 随机分页的优化
查看>>