]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph.git/commitdiff
common: PluginRegistry
authorSage Weil <sage@redhat.com>
Sat, 11 Apr 2015 14:45:07 +0000 (07:45 -0700)
committerVed-vampir <akiselyova@mirantis.com>
Wed, 2 Dec 2015 11:00:52 +0000 (14:00 +0300)
Generic plugin loader.  Based on the ErasureCodePlugin.

Signed-off-by: Sage Weil <sage@redhat.com>
Conflicts:
src/common/Makefile.am
src/common/ceph_context.cc
src/common/ceph_context.h

missing files

src/common/Makefile.am
src/common/PluginRegistry.cc [new file with mode: 0644]
src/common/PluginRegistry.h [new file with mode: 0644]
src/common/ceph_context.cc
src/common/ceph_context.h
src/common/config_opts.h

index 83b64985d78b842fca2aaebdfb9f761723a22c4d..2dfcd46d025b1cc58aca4a0f41340ed8a405ea65 100644 (file)
@@ -68,7 +68,8 @@ libcommon_internal_la_SOURCES = \
        common/Readahead.cc \
        common/Cycles.cc \
        common/ContextCompletion.cc \
-       common/TracepointProvider.cc
+       common/TracepointProvider.cc \
+       common/PluginRegistry.cc
 
 if ENABLE_SERVER
 libcommon_internal_la_SOURCES += \
@@ -260,7 +261,7 @@ noinst_HEADERS += \
        common/SubProcess.h \
        common/valgrind.h \
        common/TracepointProvider.h \
-       common/event_socket.h
+       common/PluginRegistry.h
 
 if ENABLE_XIO
 noinst_HEADERS += \
diff --git a/src/common/PluginRegistry.cc b/src/common/PluginRegistry.cc
new file mode 100644 (file)
index 0000000..dbf20fa
--- /dev/null
@@ -0,0 +1,208 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
+ * Copyright (C) 2014 Red Hat <contact@redhat.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ */
+
+#include <errno.h>
+#include <dlfcn.h>
+
+#include "PluginRegistry.h"
+#include "ceph_ver.h"
+#include "common/ceph_context.h"
+#include "common/errno.h"
+#include "include/str_list.h"
+
+#include "common/debug.h"
+
+#define PLUGIN_PREFIX "libceph_"
+#define PLUGIN_SUFFIX ".so"
+#define PLUGIN_INIT_FUNCTION "__ceph_plugin_init"
+#define PLUGIN_VERSION_FUNCTION "__ceph_version"
+
+#define dout_subsys ceph_subsys_context
+
+PluginRegistry::PluginRegistry(CephContext *cct) :
+  cct(cct),
+  lock("PluginRegistry::lock"),
+  loading(false),
+  disable_dlclose(false)
+{
+}
+
+PluginRegistry::~PluginRegistry()
+{
+  if (disable_dlclose)
+    return;
+
+  for (std::map<std::string,std::map<std::string, Plugin*> >::iterator i =
+        plugins.begin();
+       i != plugins.end();
+       ++i) {
+    for (std::map<std::string,Plugin*>::iterator j = i->second.begin();
+        j != i->second.end(); ++j) {
+      void *library = j->second->library;
+      delete j->second;
+      dlclose(library);
+    }
+  }
+}
+
+int PluginRegistry::remove(const std::string& type, const std::string& name)
+{
+  assert(lock.is_locked());
+
+  std::map<std::string,std::map<std::string,Plugin*> >::iterator i =
+    plugins.find(type);
+  if (i == plugins.end())
+    return -ENOENT;
+  std::map<std::string,Plugin*>::iterator j = i->second.find(type);
+  if (j == i->second.end())
+    return -ENOENT;
+
+  ldout(cct, 1) << __func__ << " " << type << " " << name << dendl;
+  void *library = j->second->library;
+  delete j->second;
+  dlclose(library);
+  i->second.erase(j);
+  if (i->second.empty())
+    plugins.erase(i);
+
+  return 0;
+}
+
+int PluginRegistry::add(const std::string& type,
+                       const std::string& name,
+                       Plugin* plugin)
+{
+  assert(lock.is_locked());
+  if (plugins.count(type) &&
+      plugins[type].count(name)) {
+    return -EEXIST;
+  }
+  ldout(cct, 1) << __func__ << " " << type << " " << name
+               << " " << plugin << dendl;
+  plugins[type][name] = plugin;
+  return 0;
+}
+
+Plugin *PluginRegistry::get(const std::string& type,
+                           const std::string& name)
+{
+  assert(lock.is_locked());
+  Plugin *ret = 0;
+
+  std::map<std::string,Plugin*>::iterator j;
+  std::map<std::string,map<std::string,Plugin*> >::iterator i =
+    plugins.find(type);
+  if (i == plugins.end())
+    goto out;
+  j = i->second.find(type);
+  if (j == i->second.end())
+    goto out;
+  ret = j->second;
+
+ out:
+  ldout(cct, 1) << __func__ << " " << type << " " << name
+               << " = " << ret << dendl;
+  return ret;
+}
+
+int PluginRegistry::load(const std::string &type,
+                        const std::string &name)
+{
+  assert(lock.is_locked());
+  ldout(cct, 10) << __func__ << " " << type << " " << name << dendl;
+
+  std::string fname = cct->_conf->plugin_dir + "/" + type + "/" PLUGIN_PREFIX
+    + name + PLUGIN_SUFFIX;
+  void *library = dlopen(fname.c_str(), RTLD_NOW);
+  if (!library) {
+    lderr(cct) << __func__ << " failed dlopen(" << fname << "): "
+              << dlerror() << dendl;
+    return -EIO;
+  }
+
+  const char * (*code_version)() =
+    (const char *(*)())dlsym(library, PLUGIN_VERSION_FUNCTION);
+  if (code_version == NULL) {
+    return -EXDEV;
+  }
+  if (code_version() != string(CEPH_GIT_NICE_VER)) {
+    lderr(cct) << __func__ << " plugin " << fname << " version "
+              << code_version() << " != expected "
+              << CEPH_GIT_NICE_VER << dendl;
+    dlclose(library);
+    return -EXDEV;
+  }
+
+  int (*code_init)(CephContext *,
+                  const std::string& type,
+                  const std::string& name) =
+    (int (*)(CephContext *,
+            const std::string& type,
+            const std::string& name))dlsym(library, PLUGIN_INIT_FUNCTION);
+  if (code_init) {
+    int r = code_init(cct, type, name);
+    if (r != 0) {
+      lderr(cct) << __func__ << " " << fname << " "
+                << PLUGIN_INIT_FUNCTION << "(" << cct
+                << "," << type << "," << name << "): " << cpp_strerror(r)
+                << dendl;
+      dlclose(library);
+      return r;
+    }
+  } else {
+    lderr(cct) << __func__ << " " << fname << " dlsym(" << PLUGIN_INIT_FUNCTION
+              << "): " << dlerror() << dendl;
+    dlclose(library);
+    return -ENOENT;
+  }
+
+  Plugin *plugin = get(type, name);
+  if (plugin == 0) {
+    lderr(cct) << __func__ << " " << fname << " "
+              << PLUGIN_INIT_FUNCTION << "()"
+              << "did not register plugin type " << type << " name " << name
+              << dendl;
+    dlclose(library);
+    return -EBADF;
+  }
+
+  plugin->library = library;
+
+  ldout(cct, 1) << __func__ << ": " << type << " " << name
+               << " loaded and registered" << dendl;
+  return 0;
+}
+
+/*
+int ErasureCodePluginRegistry::preload(const std::string &plugins,
+                                      const std::string &directory,
+                                      ostream &ss)
+{
+  Mutex::Locker l(lock);
+  list<string> plugins_list;
+  get_str_list(plugins, plugins_list);
+  for (list<string>::iterator i = plugins_list.begin();
+       i != plugins_list.end();
+       ++i) {
+    ErasureCodePlugin *plugin;
+    int r = load(*i, directory, &plugin, ss);
+    if (r)
+      return r;
+  }
+  return 0;
+}
+*/
diff --git a/src/common/PluginRegistry.h b/src/common/PluginRegistry.h
new file mode 100644 (file)
index 0000000..b54fc6d
--- /dev/null
@@ -0,0 +1,69 @@
+// -*- mode:C++; tab-width:8; c-basic-offset:2; indent-tabs-mode:t -*- 
+// vim: ts=8 sw=2 smarttab
+/*
+ * Ceph distributed storage system
+ *
+ * Copyright (C) 2013,2014 Cloudwatt <libre.licensing@cloudwatt.com>
+ * Copyright (C) 2014 Red Hat <contact@redhat.com>
+ *
+ * Author: Loic Dachary <loic@dachary.org>
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ * 
+ */
+
+#ifndef CEPH_COMMON_PLUGINREGISTRY_H
+#define CEPH_COMMON_PLUGINREGISTERY_H
+
+#include <string>
+#include <map>
+
+#include "common/Mutex.h"
+
+class CephContext;
+
+extern "C" {
+  const char *__ceph_plugin_version();
+  int __ceph_plugin_init(CephContext *cct,
+                        const std::string& type,
+                        const std::string& name);
+}
+
+namespace ceph {
+
+  class Plugin {
+  public:
+    void *library;
+    CephContext *cct;
+
+    Plugin(CephContext *cct) : cct(cct) {}
+    virtual ~Plugin() {}
+  };
+
+  class PluginRegistry {
+  public:
+    CephContext *cct;
+    Mutex lock;
+    bool loading;
+    bool disable_dlclose;
+    std::map<std::string,std::map<std::string,Plugin*> > plugins;
+
+    PluginRegistry(CephContext *cct);
+    ~PluginRegistry();
+
+    int add(const std::string& type, const std::string& name,
+           Plugin *factory);
+    int remove(const std::string& type, const std::string& name);
+    Plugin *get(const std::string& type, const std::string& name);
+
+    int load(const std::string& type,
+            const std::string& name);
+    int preload();
+    int preload(const std::string& type);
+  };
+}
+
+#endif
index 6e60cf7a21658facfd5385c8aafa448141e920f4..71a00eca674f7b79fee29f7f14d444f6bc6bfa99 100644 (file)
@@ -32,6 +32,7 @@
 #include "include/str_list.h"
 #include "common/Mutex.h"
 #include "common/Cond.h"
+#include "common/PluginRegistry.h"
 
 #include <iostream>
 #include <pthread.h>
@@ -414,7 +415,8 @@ CephContext::CephContext(uint32_t module_type_, int init_flags_)
     _crypto_none(NULL),
     _crypto_aes(NULL),
     _lockdep_obs(NULL),
-    _cct_perf(NULL)
+    _cct_perf(NULL),
+       plugin_registry(NULL)
 {
   ceph_spin_init(&_service_thread_lock);
   ceph_spin_init(&_associated_objs_lock);
@@ -438,6 +440,8 @@ CephContext::CephContext(uint32_t module_type_, int init_flags_)
   _admin_socket = new AdminSocket(this);
   _heartbeat_map = new HeartbeatMap(this);
 
+  _plugin_registry = new PluginRegistry(this);
+
   _admin_hook = new CephContextHook(this);
   _admin_socket->register_command("perfcounters_dump", "perfcounters_dump", _admin_hook, "");
   _admin_socket->register_command("1", "1", _admin_hook, "");
@@ -474,6 +478,8 @@ CephContext::~CephContext()
     _cct_perf = NULL;
   }
 
+  delete _plugin_registry;
+
   _admin_socket->unregister_command("perfcounters_dump");
   _admin_socket->unregister_command("perf dump");
   _admin_socket->unregister_command("1");
@@ -587,11 +593,6 @@ uint32_t CephContext::get_module_type() const
   return _module_type;
 }
 
-int CephContext::get_init_flags() const
-{
-  return _init_flags;
-}
-
 PerfCountersCollection *CephContext::get_perfcounters_collection()
 {
   return _perf_counters_collection;
index 3820a2355ead4264c2404e6534a8599cff6ba668..cc029b4a1f850dd8c806d0463bacd18f304e4bf4 100644 (file)
@@ -38,6 +38,7 @@ class CephContextObs;
 class CryptoHandler;
 
 namespace ceph {
+  class PluginRegistry;
   class HeartbeatMap;
   namespace log {
     class Log;
@@ -151,6 +152,10 @@ public:
   bool check_experimental_feature_enabled(const std::string& feature,
                                          std::ostream *message);
 
+  PluginRegistry *get_plugin_registry() {
+    return _plugin_registry;
+  }
+
 private:
   struct SingletonWrapper : boost::noncopyable {
     virtual ~SingletonWrapper() {}
@@ -213,6 +218,8 @@ private:
   ceph_spinlock_t _feature_lock;
   std::set<std::string> _experimental_features;
 
+  PluginRegistry *_plugin_registry;
+
   md_config_obs_t *_lockdep_obs;
 
   enum {
index a19cc5d8ff78f3255a5c91f49223d8a8cedf5163..8092f385c6770504a516a1c2dab36567f8b19f00 100644 (file)
@@ -69,6 +69,8 @@ OPTION(mon_cluster_log_file_level, OPT_STR, "info")
 
 OPTION(enable_experimental_unrecoverable_data_corrupting_features, OPT_STR, "")
 
+OPTION(plugin_dir, OPT_STR, CEPH_PKGLIBDIR)
+
 OPTION(xio_trace_mempool, OPT_BOOL, false) // mempool allocation counters
 OPTION(xio_trace_msgcnt, OPT_BOOL, false) // incoming/outgoing msg counters
 OPTION(xio_trace_xcon, OPT_BOOL, false) // Xio message encode/decode trace