]> git.apps.os.sepia.ceph.com Git - ceph.git/commitdiff
class: dependent classes are loaded automatically
authorYehuda Sadeh <yehuda@hq.newdream.net>
Wed, 27 May 2009 22:53:49 +0000 (15:53 -0700)
committerYehuda Sadeh <yehuda@hq.newdream.net>
Wed, 27 May 2009 22:54:42 +0000 (15:54 -0700)
src/Makefile.am
src/barclass.cc [new file with mode: 0644]
src/common/ClassHandler.cc
src/common/ClassHandler.h
src/fooclass.cc [new file with mode: 0644]
src/objclass/objclass.h
src/testclass.cc

index 6adf2aceff7b09651506934ad6b0cb006f8cb8c1..f99f68a340aa761df03f9904e7689548a0ec99b5 100644 (file)
@@ -122,7 +122,11 @@ testradospp_LDADD = librados.la libcrush.la
 
 libtestclass.so: testclass.cc
        ${CXX} -fPIC -shared -g -o libtestclass.so testclass.cc
-BUILT_SOURCES += libtestclass.so
+libbarclass.so: barclass.cc
+       ${CXX} -fPIC -shared -g -o libbarclass.so barclass.cc
+libfooclass.so: fooclass.cc
+       ${CXX} -fPIC -shared -g -o libfooclass.so fooclass.cc
+BUILT_SOURCES += libtestclass.so libfooclass.so libbarclass.so
 
 
 
diff --git a/src/barclass.cc b/src/barclass.cc
new file mode 100644 (file)
index 0000000..f5354f1
--- /dev/null
@@ -0,0 +1,48 @@
+
+
+
+#include <iostream>
+#include <string.h>
+#include <stdlib.h>
+
+#include "objclass/objclass.h"
+
+CLS_VER(1,0)
+CLS_NAME(bar)
+
+cls_handle_t h_class;
+
+cls_method_handle_t h_foo;
+
+int foo_method(cls_method_context_t ctx, char *indata, int datalen,
+                                char **outdata, int *outdatalen)
+{
+   int i;
+
+   cls_log("hello world, this is bar");
+   cls_log("indata=%s", indata);
+
+   *outdata = (char *)malloc(128);
+   for (i=0; i<strlen(indata) + 1; i++) {
+     if (indata[i] == '0') {
+       (*outdata)[i] = '*';
+     } else {
+       (*outdata)[i] = indata[i];
+     }
+   }
+   *outdatalen = strlen(*outdata) + 1;
+   cls_log("outdata=%s", *outdata);
+
+   return 0;
+}
+
+void class_init()
+{
+   cls_log("Loaded bar class!");
+
+   cls_register("bar", &h_class);
+   cls_register_method(h_class, "bar", foo_method, &h_foo);
+
+   return;
+}
+
index 0cbce6f64c776f1eb67b37364d348a8b4fb79ebe..6396ccb232000681827a34ba2785603543c6c431 100644 (file)
@@ -4,6 +4,7 @@
 #include "osd/OSD.h"
 #include "messages/MClass.h"
 #include "ClassHandler.h"
+#include "common/arch.h"
 
 #include <dlfcn.h>
 
@@ -20,29 +21,53 @@ void ClassHandler::load_class(const nstring& cname)
 {
   dout(10) << "load_class " << cname << dendl;
 
-  ClassData& data = classes[cname];
+  ClassData& cls = get_obj(cname);
   char *fname=strdup("/tmp/class-XXXXXX");
   int fd = mkstemp(fname);
 
-  for (list<bufferptr>::const_iterator it = data.impl.binary.buffers().begin();
-       it != data.impl.binary.buffers().end(); it++)
+  for (list<bufferptr>::const_iterator it = cls.impl.binary.buffers().begin();
+       it != cls.impl.binary.buffers().end(); it++)
     write(fd, it->c_str(), it->length());
 
   close(fd);
 
-  data.handle = dlopen(fname, RTLD_LAZY);
-  void (*cls_init)() = (void (*)())dlsym(data.handle, "class_init");
-  if (cls_init)
-    cls_init();
-
+  cls.handle = dlopen(fname, RTLD_LAZY);
+  cls_deps_t *(*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;
+      cls.add_dependency(deps);
+      deps++;
+    }
+  }
+  cls.load();
   unlink(fname);
   free(fname);
+
+  return;
 }
 
 
+ClassHandler::ClassData& ClassHandler::get_obj(const nstring& cname)
+{
+  map<nstring, ClassData>::iterator iter = classes.find(cname);
+  if (iter == classes.end()) {
+    ClassData& cls = classes[cname];
+    dout(0) << "get_obj: adding new class name=" << cname << " ptr=" << &cls << dendl;
+    cls.name = cname;
+    cls.osd = osd;
+    cls.handler = this;
+    return cls;
+  }
+
+  return iter->second;
+}
+
 ClassHandler::ClassData *ClassHandler::get_class(const nstring& cname, ClassVersion& version)
 {
-  ClassData *class_data = &classes[cname];
+  ClassData *class_data = &get_obj(cname);
 
   switch (class_data->status) {
   case ClassData::CLASS_LOADED:
@@ -78,7 +103,8 @@ void ClassHandler::handle_class(MClass *m)
   for (info_iter = m->info.begin(), add_iter = m->add.begin(), impl_iter = m->impl.begin();
        info_iter != m->info.end();
        ++info_iter, ++add_iter) {
-    ClassData& data = classes[info_iter->name];
+    ClassData& data = get_obj(info_iter->name);
+    dout(0) << "handle_class " << info_iter->name << dendl;
     
     if (*add_iter) {
       
@@ -86,12 +112,24 @@ void ClassHandler::handle_class(MClass *m)
        dout(10) << "added class '" << info_iter->name << "'" << dendl;
        data.impl = *impl_iter;
        ++impl_iter;
-       data.status = ClassData::CLASS_LOADED;
-       
        load_class(info_iter->name);
-       osd->got_class(info_iter->name);
+#if 0
+        switch (data.status) {
+        case ClassData::CLASS:
+            osd->got_class(info_iter->name);
+            break;
+        case ClassData::CLASS_LOADED:
+           osd->got_class(info_iter->name);
+            break;
+         default:
+           /* we're still waiting on some other classees */
+        }
+#endif
+      } else {
+        dout(0) << "class status=" << data.status << dendl;
       }
     } else {
+       dout(10) << "response of an invalid class '" << info_iter->name << "'" << dendl;
         data.status = ClassData::CLASS_INVALID;
         osd->got_class(info_iter->name);
     }
@@ -109,7 +147,9 @@ void ClassHandler::resend_class_requests()
 
 ClassHandler::ClassData *ClassHandler::register_class(const char *cname)
 {
-  ClassData& class_data = classes[cname];
+  ClassData& class_data = get_obj(cname);
+
+  dout(0) << "&class_data=" << (void *)&class_data << " status=" << class_data.status << dendl;
 
   if (class_data.status != ClassData::CLASS_LOADED) {
     dout(0) << "class " << cname << " can't be loaded" << dendl;
@@ -130,6 +170,89 @@ void ClassHandler::unregister_class(ClassHandler::ClassData *cls)
   /* FIXME: do we really need this one? */
 }
 
+
+void ClassHandler::ClassData::load()
+{
+  if (status == CLASS_INVALID) {
+    /* if we're invalid, we should just notify osd */
+    osd->got_class(name);
+    return;
+  }
+
+  if (!has_missing_deps()) {
+    status = CLASS_LOADED;
+    dout(0) << "setting class " << name << " status to CLASS_LOADED" << dendl;
+    init();
+    osd->got_class(name);
+  }
+
+  list<ClassData *>::iterator iter;
+  for (iter = dependents.begin(); iter != dependents.end(); ++iter) {
+    ClassData *cls = *iter;
+    cls->satisfy_dependency(this);
+  }
+}
+
+void ClassHandler::ClassData::init()
+{
+  void (*cls_init)() = (void (*)())dlsym(handle, "class_init");
+  if (cls_init)
+    cls_init();
+}
+
+bool ClassHandler::ClassData::add_dependency(cls_deps_t *dep)
+{
+  if (!dep->name)
+    return false;
+
+  ClassData& cls_dep = handler->get_obj(dep->name);
+  map<nstring, ClassData *>::iterator iter = missing_dependencies.find(dep->name);
+  dependencies[dep->name] = &cls_dep;
+  dout(0) << "adding dependency " << dep->name << dendl;
+
+  if (cls_dep.status != CLASS_LOADED) {
+    missing_dependencies[dep->name] = &cls_dep;
+
+    if(cls_dep.status == CLASS_UNKNOWN) {
+      ClassVersion version;
+      version.set_arch(get_arch());
+      handler->get_class(dep->name, version);
+    }
+    dout(0) << "adding missing dependency " << dep->name << dendl;
+  }
+  cls_dep.add_dependent(*this);
+
+  if (cls_dep.status == CLASS_INVALID) {
+    dout(0) << "ouch! depending on invalid class" << dendl;
+    status = CLASS_INVALID; /* we have an invalid dependency, we're invalid */
+  }
+
+  return true;
+}
+
+void ClassHandler::ClassData::satisfy_dependency(ClassData *cls)
+{
+  map<nstring, ClassData *>::iterator iter = missing_dependencies.find(cls->name);
+
+  if (iter != missing_dependencies.end()) {
+    dout(0) << "satisfied dependency name=" << name << " dep=" << cls->name << dendl;
+    missing_dependencies.erase(iter);
+    if (missing_dependencies.size() == 0) {
+      dout(0) << "all dependencies are satisfied! initializing, notifying osd" << dendl;
+      status = CLASS_LOADED;
+  dout(0) << "this=" << (void *)this << " status=" << status << dendl;
+      init();
+      osd->got_class(name);
+    }
+  }
+}
+
+void ClassHandler::ClassData::add_dependent(ClassData& dependent)
+{
+  dout(0) << "class " << name << " has dependet: " << dependent.name << dendl;
+  dependents.push_back(&dependent);
+}
+
 ClassHandler::ClassMethod *ClassHandler::ClassData::register_method(const char *mname, cls_method_call_t func)
 {
   ClassMethod& method = methods_map[mname];
@@ -142,7 +265,7 @@ ClassHandler::ClassMethod *ClassHandler::ClassData::register_method(const char *
 
 ClassHandler::ClassMethod *ClassHandler::ClassData::get_method(const char *mname)
 {
-   map<string, ClassHandler::ClassMethod>::iterator iter = methods_map.find(mname);
+   map<nstring, ClassHandler::ClassMethod>::iterator iter = methods_map.find(mname);
 
   if (iter == methods_map.end())
     return NULL;
@@ -152,7 +275,7 @@ ClassHandler::ClassMethod *ClassHandler::ClassData::get_method(const char *mname
 
 void ClassHandler::ClassData::unregister_method(ClassHandler::ClassMethod *method)
 {
-   map<string, ClassMethod>::iterator iter;
+   map<nstring, ClassMethod>::iterator iter;
 
    iter = methods_map.find(method->name);
    if (iter == methods_map.end())
index aed49018de7f611b456d16b16736bbaae9e98ac1..fc82017c2b6f73793bb47d999c37bfdb7dac7306 100644 (file)
@@ -31,30 +31,47 @@ public:
   };
 
   struct ClassData {
+    bool add_dependency(cls_deps_t *dep);
+    void add_dependent(ClassData& dependent);
+
+    void satisfy_dependency(ClassData *cls);
+
     enum { 
       CLASS_UNKNOWN, 
       CLASS_INVALID, 
-      //CLASS_UNLOADED, 
       CLASS_LOADED, 
       CLASS_REQUESTED, 
-      //CLASS_ERROR
     } status;
     ClassVersion version;
     ClassImpl impl;
+    nstring name;
+    OSD *osd;
+    ClassHandler *handler;
     void *handle;
     bool registered;
-    map<string, ClassMethod> methods_map;
+    map<nstring, ClassMethod> methods_map;
+
+    map<nstring, ClassData *> dependencies; /* our dependencies */
+    map<nstring, ClassData *> missing_dependencies; /* only missing dependencies */
+    list<ClassData *> dependents;          /* classes that depend on us */
 
-    ClassData() : status(CLASS_UNKNOWN), version(), handle(NULL), registered(false) {}
+    bool has_missing_deps() { return (missing_dependencies.size() > 0); }
+
+    ClassData() : status(CLASS_UNKNOWN), version(), handle(NULL), registered(false)  {}
     ~ClassData() { }
 
     ClassMethod *register_method(const char *mname,
                           cls_method_call_t func);
     ClassMethod *get_method(const char *mname);
     void unregister_method(ClassMethod *method);
+
+    void load();
+    void init();
   };
   map<nstring, ClassData> classes;
 
+  ClassData& get_obj(const nstring& cname);
+
   void load_class(const nstring& cname);
 
   ClassHandler(OSD *_osd) : osd(_osd) {}
diff --git a/src/fooclass.cc b/src/fooclass.cc
new file mode 100644 (file)
index 0000000..5a6a024
--- /dev/null
@@ -0,0 +1,48 @@
+
+
+
+#include <iostream>
+#include <string.h>
+#include <stdlib.h>
+
+#include "objclass/objclass.h"
+
+CLS_VER(1,0)
+CLS_NAME(foo)
+
+cls_handle_t h_class;
+
+cls_method_handle_t h_foo;
+
+int foo_method(cls_method_context_t ctx, char *indata, int datalen,
+                                char **outdata, int *outdatalen)
+{
+   int i;
+
+   cls_log("hello world, this is foo");
+   cls_log("indata=%s", indata);
+
+   *outdata = (char *)malloc(128);
+   for (i=0; i<strlen(indata) + 1; i++) {
+     if (indata[i] == '0') {
+       (*outdata)[i] = 'x';
+     } else {
+       (*outdata)[i] = indata[i];
+     }
+   }
+   *outdatalen = strlen(*outdata) + 1;
+   cls_log("outdata=%s", *outdata);
+
+   return 0;
+}
+
+void class_init()
+{
+   cls_log("Loaded foo class!");
+
+   cls_register("foo", &h_class);
+   cls_register_method(h_class, "foo", foo_method, &h_foo);
+
+   return;
+}
+
index 90c6037bc5cb6bd5f98e276f65f92afbc92f7a89..c87591332ef0bcae1e5746f3d1c73b16924bbb74 100644 (file)
@@ -5,6 +5,12 @@
 extern "C" {
 #endif
 
+#define CLS_VER(maj,min) \
+int __cls_ver__## maj ## _ ##min = 0;
+
+#define CLS_NAME(name) \
+int __cls_name__## name = 0;
+
 typedef void *cls_handle_t;
 typedef void *cls_method_handle_t;
 typedef void *cls_method_context_t;
@@ -12,6 +18,11 @@ typedef int (*cls_method_call_t)(cls_method_context_t ctx,
                                 char *indata, int datalen,
                                 char **outdata, int *outdatalen);
 
+typedef struct {
+       const char *name;
+       const char *ver;
+} cls_deps_t;
+
 /* class utils */
 extern int cls_log(const char *format, ...);
 extern void *cls_alloc(size_t size);
index 22b771201472824fc559e26dc4d4d6357160bce9..c6e6b2b0562ff35485e238d9ea0fe6d5fcb1a0f7 100644 (file)
@@ -7,6 +7,9 @@
 
 #include "objclass/objclass.h"
 
+CLS_VER(1,0)
+CLS_NAME(test)
+
 cls_handle_t h_class;
 
 cls_method_handle_t h_foo;
@@ -33,9 +36,16 @@ int foo_method(cls_method_context_t ctx, char *indata, int datalen,
    return 0;
 }
 
+static cls_deps_t depend[] = {{"foo", "1.0"}, {"bar", "1.0"}, {NULL, NULL}};
+
+extern "C" cls_deps_t *class_deps()
+{
+   return depend;
+};
+
 void class_init()
 {
-   cls_log("Loaded class!");
+   cls_log("Loaded class test!");
 
    cls_register("test", &h_class);
    cls_register_method(h_class, "foo", foo_method, &h_foo);