ceph 对动态加载类的管理

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_class
ClassHandler::ClassData *ClassHandler::_get_class(const string& cname,
    bool check_allowed)
{
  ClassData *cls;
  #通过map的find函数根据这个class的name找到对应clasdata
  map<string, ClassData>::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<ClassData*>::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_register
int 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);
}

猜你喜欢

转载自blog.csdn.net/tiantao2012/article/details/80244322
今日推荐