Browse Source

[2853] Add Python wrapper for getCachedZoneWriter()

Mukund Sivaraman 12 years ago
parent
commit
f26eae2533

+ 1 - 2
src/lib/datasrc/client_list.h

@@ -379,10 +379,9 @@ public:
          memory::ZoneTableSegment::MemorySegmentOpenMode mode,
          memory::ZoneTableSegment::MemorySegmentOpenMode mode,
          isc::data::ConstElementPtr config_params);
          isc::data::ConstElementPtr config_params);
 
 
-private:
     /// \brief Convenience type shortcut
     /// \brief Convenience type shortcut
     typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
     typedef boost::shared_ptr<memory::ZoneWriter> ZoneWriterPtr;
-public:
+
     /// \brief Codes indicating in-memory cache status for a given zone name.
     /// \brief Codes indicating in-memory cache status for a given zone name.
     ///
     ///
     /// This is used as a result of the getCachedZoneWriter() method.
     /// This is used as a result of the getCachedZoneWriter() method.

+ 78 - 4
src/lib/python/isc/datasrc/configurableclientlist_python.cc

@@ -35,12 +35,14 @@
 #include "datasrc.h"
 #include "datasrc.h"
 #include "finder_python.h"
 #include "finder_python.h"
 #include "client_python.h"
 #include "client_python.h"
+#include "zonewriter_python.h"
 
 
 using namespace std;
 using namespace std;
 using namespace isc::util::python;
 using namespace isc::util::python;
 using namespace isc::datasrc;
 using namespace isc::datasrc;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::python;
 using namespace isc::datasrc::python;
+using namespace isc::datasrc::memory::python;
 using namespace isc::dns::python;
 using namespace isc::dns::python;
 
 
 //
 //
@@ -153,6 +155,47 @@ ConfigurableClientList_resetMemorySegment(PyObject* po_self, PyObject* args) {
 }
 }
 
 
 PyObject*
 PyObject*
+ConfigurableClientList_getCachedZoneWriter(PyObject* po_self, PyObject* args) {
+    s_ConfigurableClientList* self =
+        static_cast<s_ConfigurableClientList*>(po_self);
+    try {
+        PyObject* name_obj;
+        const char* datasrc_name_p = "";
+        if (PyArg_ParseTuple(args, "O!|s", &isc::dns::python::name_type,
+                             &name_obj, &datasrc_name_p)) {
+            const isc::dns::Name
+                name(isc::dns::python::PyName_ToName(name_obj));
+            const std::string datasrc_name(datasrc_name_p);
+
+            const ConfigurableClientList::ZoneWriterPair result =
+                self->cppobj->getCachedZoneWriter(name, datasrc_name);
+
+            PyObjectContainer writer;
+            if (!result.second) {
+                // Use the Py_BuildValue, as it takes care of the
+                // reference counts correctly.
+                writer.reset(Py_BuildValue(""));
+            } else {
+                // Make sure it keeps the writer alive.
+                writer.reset(createZoneWriterObject(result.second,
+                                                    writer.get()));
+            }
+
+            return (Py_BuildValue("IO", result.first, writer.get()));
+        } else {
+            return (NULL);
+        }
+    } catch (const std::exception& exc) {
+        PyErr_SetString(getDataSourceException("Error"), exc.what());
+        return (NULL);
+    } catch (...) {
+        PyErr_SetString(getDataSourceException("Error"),
+                        "Unknown C++ exception");
+        return (NULL);
+    }
+}
+
+PyObject*
 ConfigurableClientList_find(PyObject* po_self, PyObject* args) {
 ConfigurableClientList_find(PyObject* po_self, PyObject* args) {
     s_ConfigurableClientList* self =
     s_ConfigurableClientList* self =
         static_cast<s_ConfigurableClientList*>(po_self);
         static_cast<s_ConfigurableClientList*>(po_self);
@@ -241,6 +284,17 @@ Parameters:\n\
   datasrc_name      The name of the data source whose segment to reset.\
   datasrc_name      The name of the data source whose segment to reset.\
   mode              The open mode for the new memory segment.\
   mode              The open mode for the new memory segment.\
   config_params     The configuration for the new memory segment, as a JSON encoded string." },
   config_params     The configuration for the new memory segment, as a JSON encoded string." },
+    { "get_cached_zone_writer", ConfigurableClientList_getCachedZoneWriter,
+      METH_VARARGS,
+        "get_cached_zone_writer(zone, datasrc_name) -> status, zone_writer\n\
+\n\
+Wrapper around C++ ConfigurableClientList::getCachedZoneWriter\n\
+\n\
+This returns a ZoneWriter that can be used to (re)load a zone.\n\
+\n\
+Parameters:\n\
+  zone              The name of the zone to (re)load.\
+  datasrc_name      The name of the data source where the zone is to be loaded." },
     { "find", ConfigurableClientList_find, METH_VARARGS,
     { "find", ConfigurableClientList_find, METH_VARARGS,
 "find(zone, want_exact_match=False, want_finder=True) -> datasrc_client,\
 "find(zone, want_exact_match=False, want_finder=True) -> datasrc_client,\
 zone_finder, exact_match\n\
 zone_finder, exact_match\n\
@@ -350,11 +404,31 @@ initModulePart_ConfigurableClientList(PyObject* mod) {
     }
     }
     Py_INCREF(&configurableclientlist_type);
     Py_INCREF(&configurableclientlist_type);
 
 
-    // FIXME: These should eventually be moved to the ZoneTableSegment
-    // class when we add Python bindings for the memory data source
-    // specific bits. But for now, we add these enums here to support
-    // reloading a zone table segment.
     try {
     try {
+        // ConfigurableClientList::CacheStatus enum
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_CACHE_DISABLED",
+                             Py_BuildValue("I", ConfigurableClientList::CACHE_DISABLED));
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_ZONE_NOT_CACHED",
+                             Py_BuildValue("I", ConfigurableClientList::ZONE_NOT_CACHED));
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_ZONE_NOT_FOUND",
+                             Py_BuildValue("I", ConfigurableClientList::ZONE_NOT_FOUND));
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_CACHE_NOT_WRITABLE",
+                             Py_BuildValue("I", ConfigurableClientList::CACHE_NOT_WRITABLE));
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_DATASRC_NOT_FOUND",
+                             Py_BuildValue("I", ConfigurableClientList::DATASRC_NOT_FOUND));
+        installClassVariable(configurableclientlist_type,
+                             "CACHE_STATUS_ZONE_SUCCESS",
+                             Py_BuildValue("I", ConfigurableClientList::ZONE_SUCCESS));
+
+        // FIXME: These should eventually be moved to the
+        // ZoneTableSegment class when we add Python bindings for the
+        // memory data source specific bits. But for now, we add these
+        // enums here to support reloading a zone table segment.
         installClassVariable(configurableclientlist_type, "CREATE",
         installClassVariable(configurableclientlist_type, "CREATE",
                              Py_BuildValue("I", ZoneTableSegment::CREATE));
                              Py_BuildValue("I", ZoneTableSegment::CREATE));
         installClassVariable(configurableclientlist_type, "READ_WRITE",
         installClassVariable(configurableclientlist_type, "READ_WRITE",

+ 40 - 6
src/lib/python/isc/datasrc/zonewriter_python.cc

@@ -31,6 +31,7 @@
 
 
 using namespace std;
 using namespace std;
 using namespace isc::util::python;
 using namespace isc::util::python;
+using namespace isc::datasrc;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory;
 using namespace isc::datasrc::memory::python;
 using namespace isc::datasrc::memory::python;
 
 
@@ -38,12 +39,25 @@ using namespace isc::datasrc::memory::python;
 // ZoneWriter
 // ZoneWriter
 //
 //
 
 
-// Trivial constructor.
-s_ZoneWriter::s_ZoneWriter() : cppobj(NULL) {
-}
-
 namespace {
 namespace {
 
 
+// The s_* Class simply covers one instantiation of the object
+class s_ZoneWriter : public PyObject {
+public:
+    s_ZoneWriter() :
+        cppobj(ConfigurableClientList::ZoneWriterPtr()),
+        base_obj(NULL)
+    {}
+
+    ConfigurableClientList::ZoneWriterPtr cppobj;
+    // This is a reference to a base object; if the object of this class
+    // depends on another object to be in scope during its lifetime,
+    // we use INCREF the base object upon creation, and DECREF it at
+    // the end of the destructor
+    // This is an optional argument to createXXX(). If NULL, it is ignored.
+    PyObject* base_obj;
+};
+
 int
 int
 ZoneWriter_init(PyObject*, PyObject*, PyObject*) {
 ZoneWriter_init(PyObject*, PyObject*, PyObject*) {
     // can't be called directly
     // can't be called directly
@@ -56,8 +70,12 @@ ZoneWriter_init(PyObject*, PyObject*, PyObject*) {
 void
 void
 ZoneWriter_destroy(PyObject* po_self) {
 ZoneWriter_destroy(PyObject* po_self) {
     s_ZoneWriter* self = static_cast<s_ZoneWriter*>(po_self);
     s_ZoneWriter* self = static_cast<s_ZoneWriter*>(po_self);
-    delete self->cppobj;
-    self->cppobj = NULL;
+    // cppobj is a shared ptr, but to make sure things are not destroyed in
+    // the wrong order, we reset it here.
+    self->cppobj.reset();
+    if (self->base_obj != NULL) {
+        Py_DECREF(self->base_obj);
+    }
     Py_TYPE(self)->tp_free(self);
     Py_TYPE(self)->tp_free(self);
 }
 }
 
 
@@ -156,6 +174,22 @@ initModulePart_ZoneWriter(PyObject* mod) {
     return (true);
     return (true);
 }
 }
 
 
+PyObject*
+createZoneWriterObject(ConfigurableClientList::ZoneWriterPtr source,
+                       PyObject* base_obj)
+{
+    s_ZoneWriter* py_zf = static_cast<s_ZoneWriter*>(
+        zonewriter_type.tp_alloc(&zonewriter_type, 0));
+    if (py_zf != NULL) {
+        py_zf->cppobj = source;
+        py_zf->base_obj = base_obj;
+        if (base_obj != NULL) {
+            Py_INCREF(base_obj);
+        }
+    }
+    return (py_zf);
+}
+
 } // namespace python
 } // namespace python
 } // namespace memory
 } // namespace memory
 } // namespace datasrc
 } // namespace datasrc

+ 13 - 9
src/lib/python/isc/datasrc/zonewriter_python.h

@@ -16,29 +16,33 @@
 #define PYTHON_ZONEWRITER_H 1
 #define PYTHON_ZONEWRITER_H 1
 
 
 #include <Python.h>
 #include <Python.h>
+#include <datasrc/client_list.h>
 
 
 namespace isc {
 namespace isc {
 namespace datasrc {
 namespace datasrc {
 namespace memory {
 namespace memory {
-class ZoneWriter;
-
 namespace python {
 namespace python {
 
 
-// The s_* Class simply covers one instantiation of the object
-class s_ZoneWriter : public PyObject {
-public:
-    s_ZoneWriter();
-    ZoneWriter* cppobj;
-};
-
 extern PyTypeObject zonewriter_type;
 extern PyTypeObject zonewriter_type;
 
 
 bool initModulePart_ZoneWriter(PyObject* mod);
 bool initModulePart_ZoneWriter(PyObject* mod);
 
 
+/// \brief Create a ZoneWriter python object
+///
+/// \param source The zone writer pointer to wrap
+/// \param base_obj An optional PyObject that this ZoneWriter depends on
+///                 Its refcount is increased, and will be decreased when
+///                 this zone iterator is destroyed, making sure that the
+///                 base object is never destroyed before this ZoneWriter.
+PyObject* createZoneWriterObject(
+    isc::datasrc::ConfigurableClientList::ZoneWriterPtr source,
+    PyObject* base_obj = NULL);
+
 } // namespace python
 } // namespace python
 } // namespace memory
 } // namespace memory
 } // namespace datasrc
 } // namespace datasrc
 } // namespace isc
 } // namespace isc
+
 #endif // PYTHON_ZONEWRITER_H
 #endif // PYTHON_ZONEWRITER_H
 
 
 // Local Variables:
 // Local Variables: