Browse Source

[1206] initial experiment with dlopened sqlite3 ds

Jelte Jansen 13 years ago
parent
commit
07b6398dbd

+ 5 - 2
src/lib/datasrc/Makefile.am

@@ -9,7 +9,7 @@ AM_CXXFLAGS = $(B10_CXXFLAGS)
 
 
 CLEANFILES = *.gcno *.gcda datasrc_messages.h datasrc_messages.cc
 CLEANFILES = *.gcno *.gcda datasrc_messages.h datasrc_messages.cc
 
 
-lib_LTLIBRARIES = libdatasrc.la
+lib_LTLIBRARIES = libdatasrc.la sqlite3_ds.la
 libdatasrc_la_SOURCES = data_source.h data_source.cc
 libdatasrc_la_SOURCES = data_source.h data_source.cc
 libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
 libdatasrc_la_SOURCES += static_datasrc.h static_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
 libdatasrc_la_SOURCES += sqlite3_datasrc.h sqlite3_datasrc.cc
@@ -23,10 +23,13 @@ libdatasrc_la_SOURCES += result.h
 libdatasrc_la_SOURCES += logger.h logger.cc
 libdatasrc_la_SOURCES += logger.h logger.cc
 libdatasrc_la_SOURCES += client.h iterator.h
 libdatasrc_la_SOURCES += client.h iterator.h
 libdatasrc_la_SOURCES += database.h database.cc
 libdatasrc_la_SOURCES += database.h database.cc
-libdatasrc_la_SOURCES += sqlite3_accessor.h sqlite3_accessor.cc
+#libdatasrc_la_SOURCES += sqlite3_accessor.h sqlite3_accessor.cc
 libdatasrc_la_SOURCES += factory.h factory.cc
 libdatasrc_la_SOURCES += factory.h factory.cc
 nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 nodist_libdatasrc_la_SOURCES = datasrc_messages.h datasrc_messages.cc
 
 
+sqlite3_ds_la_SOURCES = sqlite3_accessor.h sqlite3_accessor.cc
+sqlite3_ds_la_LDFLAGS = -module
+
 libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 libdatasrc_la_LIBADD = $(top_builddir)/src/lib/exceptions/libexceptions.la
 libdatasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
 libdatasrc_la_LIBADD += $(top_builddir)/src/lib/dns/libdns++.la
 libdatasrc_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la
 libdatasrc_la_LIBADD += $(top_builddir)/src/lib/log/liblog.la

+ 15 - 1
src/lib/datasrc/factory.cc

@@ -19,6 +19,8 @@
 #include "sqlite3_accessor.h"
 #include "sqlite3_accessor.h"
 #include "memory_datasrc.h"
 #include "memory_datasrc.h"
 
 
+#include <dlfcn.h>
+
 using namespace isc::data;
 using namespace isc::data;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
 
 
@@ -116,7 +118,19 @@ createDataSourceClient(const std::string& type,
     // For now, mapping hardcoded
     // For now, mapping hardcoded
     // config is assumed to be ok
     // config is assumed to be ok
     if (type == "sqlite3") {
     if (type == "sqlite3") {
-        return (sqlite3CreateInstance(config));
+        void *ds_lib = dlopen("sqlite3_ds.so", RTLD_LAZY);
+        if (ds_lib == NULL) {
+            isc_throw(DataSourceError, "Unable to load " << type <<
+                      ": " << dlerror());
+        }
+        dlerror();
+        ds_creator* ds_create = (ds_creator*)dlsym(ds_lib, "createInstance");
+        const char* dlsym_error = dlerror();
+        if (dlsym_error != NULL) {
+            isc_throw(DataSourceError, "Error in library " << type <<
+                      ": " << dlsym_error);
+        }
+        return (ds_create(config));
     } else if (type == "memory") {
     } else if (type == "memory") {
         return (memoryCreateInstance(config));
         return (memoryCreateInstance(config));
     } else {
     } else {

+ 2 - 0
src/lib/datasrc/factory.h

@@ -58,6 +58,8 @@ DataSourceClient*
 createDataSourceClient(const std::string& type,
 createDataSourceClient(const std::string& type,
                        isc::data::ConstElementPtr config);
                        isc::data::ConstElementPtr config);
 
 
+typedef DataSourceClient* ds_creator(isc::data::ConstElementPtr config);
+typedef void ds_destructor();
 }
 }
 }
 }
 #endif  // DATA_SOURCE_FACTORY_H
 #endif  // DATA_SOURCE_FACTORY_H

+ 71 - 0
src/lib/datasrc/sqlite3_accessor.cc

@@ -22,9 +22,11 @@
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/sqlite3_accessor.h>
 #include <datasrc/logger.h>
 #include <datasrc/logger.h>
 #include <datasrc/data_source.h>
 #include <datasrc/data_source.h>
+#include <datasrc/factory.h>
 #include <util/filename.h>
 #include <util/filename.h>
 
 
 using namespace std;
 using namespace std;
+using namespace isc::data;
 
 
 #define SQLITE_SCHEMA_VERSION 1
 #define SQLITE_SCHEMA_VERSION 1
 
 
@@ -658,5 +660,74 @@ SQLite3Accessor::deleteRecordInZone(const string (&params)[DEL_PARAM_COUNT]) {
         *dbparameters_, DEL_RECORD, params, "delete record from zone");
         *dbparameters_, DEL_RECORD, params, "delete record from zone");
 }
 }
 
 
+namespace {
+void
+addError(ElementPtr errors, const std::string& error) {
+    if (errors != ElementPtr() && errors->getType() == Element::list) {
+        errors->add(Element::create(error));
+    }
+}
+} // end anonymous namespace
+
+bool
+checkConfig(ConstElementPtr config, ElementPtr errors) {
+    bool result = true;
+    if (!config || config->getType() != Element::map) {
+        addError(errors, "Base config for SQlite3 backend must be a map");
+        result = false;
+    } else {
+        if (!config->contains("file")) {
+            addError(errors,
+                     "Config for SQlite3 backend does not contain a 'file' value");
+            result = false;
+        } else if (!config->get("file") ||
+                   config->get("file")->getType() != Element::string) {
+            addError(errors, "file value in SQLite3 backend is not a string");
+            result = false;
+        } else if (config->get("file")->stringValue() == "") {
+            addError(errors, "file value in SQLite3 backend is empty");
+            result = false;
+        }
+
+        if (!config->contains("class")) {
+            addError(errors, "Config for SQlite3 backend does not contain a 'class' value");
+            result = false;
+        } else if (!config->get("class") ||
+                   config->get("class")->getType() != Element::string) {
+            addError(errors, "class value in SQLite3 backend is not a string");
+            result = false;
+        } else {
+            try {
+                isc::dns::RRClass rrclass(config->get("class")->stringValue());
+            } catch (const isc::dns::InvalidRRClass& ivrc) {
+                addError(errors, ivrc.what());
+                result = false;
+            } catch (const isc::dns::IncompleteRRClass& icrc) {
+                addError(errors, icrc.what());
+                result = false;
+            }
+        }
+    }
+
+    return (result);
+}
+
+DataSourceClient *
+createInstance(isc::data::ConstElementPtr config) {
+    ElementPtr errors(Element::createList());
+    if (!checkConfig(config, errors)) {
+        isc_throw(DataSourceConfigError, errors->str());
+    }
+    isc::dns::RRClass rrclass(config->get("class")->stringValue());
+    std::string dbfile = config->get("file")->stringValue();
+    boost::shared_ptr<DatabaseAccessor> sqlite3_accessor(
+        new SQLite3Accessor(dbfile, rrclass));
+    return (new DatabaseClient(rrclass, sqlite3_accessor));
+}
+
+void destroyInstance(DataSourceClient* instance) {
+    delete instance;
+}
+
 }
 }
 }
 }

+ 6 - 0
src/lib/datasrc/sqlite3_accessor.h

@@ -24,6 +24,8 @@
 #include <boost/scoped_ptr.hpp>
 #include <boost/scoped_ptr.hpp>
 #include <string>
 #include <string>
 
 
+#include <cc/data.h>
+
 namespace isc {
 namespace isc {
 namespace dns {
 namespace dns {
 class RRClass;
 class RRClass;
@@ -187,6 +189,10 @@ private:
     const std::string database_name_;
     const std::string database_name_;
 };
 };
 
 
+extern "C" DataSourceClient* createInstance(isc::data::ConstElementPtr config);
+
+extern "C" void destroyInstance(DataSourceClient* instance);
+
 }
 }
 }
 }
 
 

+ 3 - 0
src/lib/datasrc/tests/Makefile.am

@@ -36,6 +36,9 @@ run_unittests_SOURCES += database_unittest.cc
 run_unittests_SOURCES += client_unittest.cc
 run_unittests_SOURCES += client_unittest.cc
 run_unittests_SOURCES += sqlite3_accessor_unittest.cc
 run_unittests_SOURCES += sqlite3_accessor_unittest.cc
 run_unittests_SOURCES += factory_unittest.cc
 run_unittests_SOURCES += factory_unittest.cc
+# for the dlopened types we have tests for, we also need to include the
+# sources
+run_unittests_SOURCES += $(top_srcdir)/src/lib/datasrc/sqlite3_accessor.cc
 
 
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_CPPFLAGS = $(AM_CPPFLAGS) $(GTEST_INCLUDES)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)
 run_unittests_LDFLAGS  = $(AM_LDFLAGS)  $(GTEST_LDFLAGS)