BIND 10 master, updated. c4df99eac2910af079f19b0bdacc95d7cd88192f [master] Merge branch 'trac2438'

BIND 10 source code commits bind10-changes at lists.isc.org
Mon Jan 21 16:23:32 UTC 2013


The branch, master has been updated
       via  c4df99eac2910af079f19b0bdacc95d7cd88192f (commit)
       via  39a3150a0fe822b177c53379b2c93ad6f24585b9 (commit)
       via  610f3ecc55290ff4c2d3453f0f90c222b00a6f38 (commit)
       via  003f49d97927cc4dd85c4a631611152e7e10bd1c (commit)
       via  fd29a774079b86f2b62c857d13ef450f0da29a00 (commit)
       via  e149d57f779c6597a6ed1d497c40a9641ac6651c (commit)
       via  ce19e77d9f6b9715502b5636511421dc09148f86 (commit)
       via  88ff44432d5fed287aa8a91d620692f4a715ae1c (commit)
       via  738540ce3a7b5d06707d5b298a6223629ab66050 (commit)
       via  3b37e9c152b05606bb5401c16c5b9f6d37155539 (commit)
       via  81ed5b0185f7b37aafada49c52880ba87b03785f (commit)
       via  37a8e164d7e3267b42ad438f49ae2505bd5b952b (commit)
       via  e3bde86b2e51188e37fab58965709fe2f22f9610 (commit)
       via  1ba7dea264623db66cbf62fed95db34cde362cf5 (commit)
       via  b927f6e09523bcadf613b4e409a0039e5bfbb03c (commit)
       via  0cce212fefe299518426d10812c74ce14d547782 (commit)
       via  878a31b83ab5df9441804a67a2f9a16ad615ae84 (commit)
       via  c846c5417c22b4a3b02122860ce9a6977a6ffa44 (commit)
       via  ae4e532f39b85f619ff99d8feb91898d8ee741a9 (commit)
       via  ba27028c44e71d0fa19077209b412538be635c81 (commit)
       via  9a7261d103fb09bf87b1f827a733aca3cb87d46c (commit)
       via  ff502308eef747bad13e1e4c763ca7fc2d820a99 (commit)
       via  0e9831ebbe7ff8c719605c36f3c3292db31d28c8 (commit)
       via  d33133715b3f211459678061e0f2d3c40738c07f (commit)
       via  a6e58431e3582cc73e5c3e2aa20ee09c5da199a4 (commit)
       via  f2fa03f0b6156c8a64376d1524fe822e3a74cb16 (commit)
       via  869ad53a069b3fe4836d818fe820160e914a017c (commit)
       via  e601cb8dbb5dae21aa90061d2dbf0e23223186c0 (commit)
       via  76b963dc31b5df73631b3689868b991759414ba9 (commit)
       via  5fa3d0e12c20cd9d07fc83c98dbd32c64eadca3e (commit)
       via  cd894167c8d367f7367b790d60c3dd23f740ffdf (commit)
       via  add399ede802585b4606e6b07d60fe831aa8ec7a (commit)
       via  7773035d231a2a55664dbe04baa4744da4ada7a7 (commit)
       via  8d160f47d4cd2b6bf265580331215fa9d48a9571 (commit)
       via  f0779391ff33e44afac4fc7911400d9b3f345446 (commit)
       via  a2e1d3f2d9f4bd9680932a46cf2b00c1cd2a1a64 (commit)
       via  09a0594ddec459ff3d7bf1e0f0814847d5904883 (commit)
       via  a25a5fca02c5aca0a29113ca293581b1b48bcfdd (commit)
       via  8e118d8e64ff03678c4dd4bdbc6e8e8c64737ac6 (commit)
       via  13b8d3383b390dfb30ba39d9f7c69d1c0a7fd572 (commit)
       via  7eaf1f34a92aef6e6e82b59e1a8200c858820b77 (commit)
       via  45b538d01cc68a759ed8eb1d9e069def986e2ae9 (commit)
      from  99a6e8470907e678cd8c208eeef2810b4bd0bacb (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
commit c4df99eac2910af079f19b0bdacc95d7cd88192f
Merge: 99a6e84 39a3150
Author: JINMEI Tatuya <jinmei at isc.org>
Date:   Mon Jan 21 08:23:23 2013 -0800

    [master] Merge branch 'trac2438'
    
    resolved Conflicts:
    	src/lib/dns/python/Makefile.am
    	src/lib/dns/python/rrset_collection_python.cc
    	src/lib/dns/python/rrset_collection_python.h
    	src/lib/dns/python/rrset_collection_python_inc.cc

-----------------------------------------------------------------------

Summary of changes:
 configure.ac                                      |    5 +-
 src/bin/bindctl/run_bindctl.sh.in                 |    5 +-
 src/bin/dbutil/run_dbutil.sh.in                   |    5 +-
 src/bin/sysinfo/run_sysinfo.sh.in                 |    9 +-
 src/lib/dns/python/rrset_collection_python.cc     |   73 +++++++---
 src/lib/dns/python/rrset_collection_python.h      |   10 +-
 src/lib/dns/python/rrset_collection_python_inc.cc |   12 +-
 src/lib/dns/rrset_collection_base.h               |    2 +
 src/lib/python/isc/datasrc/datasrc.cc             |   17 ---
 src/lib/python/isc/datasrc/tests/datasrc_test.py  |   35 +++++
 src/lib/python/isc/datasrc/updater_inc.cc         |   36 +++++
 src/lib/python/isc/datasrc/updater_python.cc      |  154 +++++++++++++++++++++
 src/lib/python/isc/datasrc/updater_python.h       |    2 +-
 tests/system/ifconfig.sh                          |    4 +-
 14 files changed, 311 insertions(+), 58 deletions(-)

-----------------------------------------------------------------------
diff --git a/configure.ac b/configure.ac
index 9ae7a30..d8bbef5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -282,7 +282,10 @@ AC_SUBST(PYTHON_LOGMSGPKG_DIR)
 
 # This is python package paths commonly used in python tests.  See
 # README of log_messages for why it's included.
-COMMON_PYTHON_PATH="\$(abs_top_builddir)/src/lib/python/isc/log_messages:\$(abs_top_srcdir)/src/lib/python:\$(abs_top_builddir)/src/lib/python"
+# lib/dns/python/.libs is necessary because __init__.py of isc package
+# automatically imports isc.datasrc, which then requires the DNS loadable
+# module.  #2145 should eliminate the need for it.
+COMMON_PYTHON_PATH="\$(abs_top_builddir)/src/lib/python/isc/log_messages:\$(abs_top_srcdir)/src/lib/python:\$(abs_top_builddir)/src/lib/python:\$(abs_top_builddir)/src/lib/dns/python/.libs"
 AC_SUBST(COMMON_PYTHON_PATH)
 
 # Check for python development environments
diff --git a/src/bin/bindctl/run_bindctl.sh.in b/src/bin/bindctl/run_bindctl.sh.in
index f4cc40c..999d7ee 100755
--- a/src/bin/bindctl/run_bindctl.sh.in
+++ b/src/bin/bindctl/run_bindctl.sh.in
@@ -20,7 +20,10 @@ export PYTHON_EXEC
 
 BINDCTL_PATH=@abs_top_builddir@/src/bin/bindctl
 
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
+# Note: lib/dns/python/.libs is necessary because __init__.py of isc package
+# automatically imports isc.datasrc, which then requires the DNS loadable
+# module.  #2145 should eliminate the need for it.
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/dbutil/run_dbutil.sh.in b/src/bin/dbutil/run_dbutil.sh.in
index fea7482..f0c6dbd 100755
--- a/src/bin/dbutil/run_dbutil.sh.in
+++ b/src/bin/dbutil/run_dbutil.sh.in
@@ -20,7 +20,10 @@ export PYTHON_EXEC
 
 DBUTIL_PATH=@abs_top_builddir@/src/bin/dbutil
 
-PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python
+# Note: lib/dns/python/.libs is necessary because __init__.py of isc package
+# automatically imports isc.datasrc, which then requires the DNS loadable
+# module.  #2145 should eliminate the need for it.
+PYTHONPATH=@abs_top_srcdir@/src/bin:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/python:@abs_top_builddir@/src/bin:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # If necessary (rare cases), explicitly specify paths to dynamic libraries
diff --git a/src/bin/sysinfo/run_sysinfo.sh.in b/src/bin/sysinfo/run_sysinfo.sh.in
index 268b5a4..6459c2d 100755
--- a/src/bin/sysinfo/run_sysinfo.sh.in
+++ b/src/bin/sysinfo/run_sysinfo.sh.in
@@ -20,10 +20,11 @@ export PYTHON_EXEC
 
 SYSINFO_PATH=@abs_top_builddir@/src/bin/sysinfo
 
-# Note: we shouldn't need log_messages except for the seemingly necessary
-# dependency due to the automatic import in the isc package (its __init__.py
-# imports some other modules)
-PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python/isc/log_messages
+# Note: we shouldn't need log_messages and lib/dns except for the seemingly
+# necessary dependency due to the automatic import in the isc package (its
+# __init__.py imports some other modules)
+# #2145 should eliminate the need for them.
+PYTHONPATH=@abs_top_builddir@/src/lib/python:@abs_top_srcdir@/src/lib/python:@abs_top_builddir@/src/lib/python/isc/log_messages:@abs_top_builddir@/src/lib/dns/python/.libs
 export PYTHONPATH
 
 # Likewise, we need only because isc.log requires some loadable modules.
diff --git a/src/lib/dns/python/rrset_collection_python.cc b/src/lib/dns/python/rrset_collection_python.cc
index df313f7..cfdcdae 100644
--- a/src/lib/dns/python/rrset_collection_python.cc
+++ b/src/lib/dns/python/rrset_collection_python.cc
@@ -55,10 +55,23 @@ setTypeError(PyObject* pobj, const char* var_name, const char* type_name) {
 }
 }
 
+// RRsetCollectionBase: the base RRsetCollection class in Python.
 //
-// RRsetCollectionBase
-//
-
+// Any derived RRsetCollection class is supposed to be inherited from this
+// class:
+// - If the derived class is implemented via a C++ wrapper (associated with
+//   a C++ implementation of RRsetCollection), its PyTypeObject should
+//   specify rrset_collection_base_type for tp_base.  Its C/C++-representation
+//   of objects should be compatible with s_RRsetCollection, and the wrapper
+//   should set its cppobj member to point to the corresponding C++
+//   RRsetCollection object.  Normally it doesn't have to provide Python
+//   wrapper of find(); the Python interpreter will then call find() on
+//   the base class, which ensures that the corresponding C++ version of
+//   find() will be used.
+// - If the derived class is implemented purely in Python, it must implement
+//   find() in Python within the class.  As explained in the first bullet,
+//   the base class method is generally expected to be used only for C++
+//   wrapper of RRsetCollection derived class.
 namespace {
 int
 RRsetCollectionBase_init(PyObject*, PyObject*, PyObject*) {
@@ -70,8 +83,13 @@ RRsetCollectionBase_init(PyObject*, PyObject*, PyObject*) {
 void
 RRsetCollectionBase_destroy(PyObject* po_self) {
     s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
-    delete self->cppobj;
-    self->cppobj = NULL;
+
+    // Any C++-wrapper of derived RRsetCollection class should have its own
+    // destroy function (as it may manage cppobj in its own way);
+    // Python-only derived classes shouldn't set cppobj (which is
+    // 0-initialized).  So this assertion must hold.
+    assert(self->cppobj == NULL);
+
     Py_TYPE(self)->tp_free(self);
 }
 
@@ -79,6 +97,9 @@ PyObject*
 RRsetCollectionBase_find(PyObject* po_self, PyObject* args) {
     s_RRsetCollection* self = static_cast<s_RRsetCollection*>(po_self);
 
+    // If this function is called with cppobj being NULL, this means
+    // a pure-Python derived class skips implementing its own find().
+    // This is an error (see general description above).
     if (self->cppobj == NULL) {
         PyErr_Format(PyExc_TypeError, "find() is not implemented in the "
                      "derived RRsetCollection class");
@@ -108,6 +129,9 @@ RRsetCollectionBase_find(PyObject* po_self, PyObject* args) {
             }
             Py_RETURN_NONE;
         }
+    } catch (const RRsetCollectionError& ex) {
+        PyErr_SetString(po_RRsetCollectionError, ex.what());
+        return (NULL);
     } catch (const std::exception& ex) {
         const string ex_what = "Unexpected failure in "
             "RRsetCollectionBase.find: " + string(ex.what());
@@ -137,6 +161,9 @@ PyMethodDef RRsetCollectionBase_methods[] = {
 namespace isc {
 namespace dns {
 namespace python {
+// Definition of class specific exception(s)
+PyObject* po_RRsetCollectionError;
+
 // This defines the complete type for reflection in python and
 // parsing of PyObject* to s_RRsetCollection
 // Most of the functions are not actually implemented and NULL here.
@@ -193,18 +220,27 @@ PyTypeObject rrset_collection_base_type = {
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_RRsetCollectionBase(PyObject* mod) {
-    // We initialize the static description object with PyType_Ready(),
-    // then add it to the module. This is not just a check! (leaving
-    // this out results in segmentation faults)
-    if (PyType_Ready(&rrset_collection_base_type) < 0) {
+    if (!initClass(rrset_collection_base_type, "RRsetCollectionBase", mod)) {
         return (false);
     }
-    void* p = &rrset_collection_base_type;
-    if (PyModule_AddObject(mod, "RRsetCollectionBase",
-                           static_cast<PyObject*>(p)) < 0) {
+
+    try {
+        po_RRsetCollectionError =
+            PyErr_NewException("dns.RRsetCollectionError",
+                               po_IscException, NULL);
+        PyObjectContainer(po_RRsetCollectionError).installToModule(
+            mod, "RRsetCollectionError");
+    } catch (const std::exception& ex) {
+        const std::string ex_what =
+            "Unexpected failure in RRsetCollectionBase initialization: " +
+            std::string(ex.what());
+        PyErr_SetString(po_IscException, ex_what.c_str());
+        return (false);
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError, "Unexpected failure in "
+                        "RRsetCollectionBase initialization");
         return (false);
     }
-    Py_INCREF(&rrset_collection_base_type);
 
     return (true);
 }
@@ -405,18 +441,9 @@ PyTypeObject rrset_collection_type = {
 // Module Initialization, all statics are initialized here
 bool
 initModulePart_RRsetCollection(PyObject* mod) {
-    // We initialize the static description object with PyType_Ready(),
-    // then add it to the module. This is not just a check! (leaving
-    // this out results in segmentation faults)
-    if (PyType_Ready(&rrset_collection_type) < 0) {
-        return (false);
-    }
-    void* p = &rrset_collection_type;
-    if (PyModule_AddObject(mod, "RRsetCollection",
-                           static_cast<PyObject*>(p)) < 0) {
+    if (!initClass(rrset_collection_type, "RRsetCollection", mod)) {
         return (false);
     }
-    Py_INCREF(&rrset_collection_type);
 
     return (true);
 }
diff --git a/src/lib/dns/python/rrset_collection_python.h b/src/lib/dns/python/rrset_collection_python.h
index 98cb84b..ea442bb 100644
--- a/src/lib/dns/python/rrset_collection_python.h
+++ b/src/lib/dns/python/rrset_collection_python.h
@@ -23,10 +23,13 @@ class RRsetCollectionBase;
 
 namespace python {
 
-// The s_* Class simply covers one instantiation of the object
+// The s_* Class simply covers one instantiation of the object.
 // This structure will be commonly used for all derived classes of
 // RRsetCollectionBase.  cppobj will point to an instance of the specific
-// derived class.
+// derived class of (C++) RRsetCollectionBase.
+//
+// A C++ wrapper for Python version of RRsetCollection should set this
+// variable, and skip the implementation of C++ wrapper of find() method.
 class s_RRsetCollection : public PyObject {
 public:
     s_RRsetCollection() : cppobj(NULL) {}
@@ -39,6 +42,9 @@ extern PyTypeObject rrset_collection_base_type;
 // Python type information for dns.RRsetCollection
 extern PyTypeObject rrset_collection_type;
 
+// Class specific exceptions
+extern PyObject* po_RRsetCollectionError;
+
 bool initModulePart_RRsetCollectionBase(PyObject* mod);
 bool initModulePart_RRsetCollection(PyObject* mod);
 
diff --git a/src/lib/dns/python/rrset_collection_python_inc.cc b/src/lib/dns/python/rrset_collection_python_inc.cc
index 5c1e532..f6eb8a3 100644
--- a/src/lib/dns/python/rrset_collection_python_inc.cc
+++ b/src/lib/dns/python/rrset_collection_python_inc.cc
@@ -1,7 +1,7 @@
 namespace {
 // Modifications
 //   - libdns++ => isc.dns, libdatasrc => isc.datasrc
-//   - note about the constructor.
+//   - note about the direct construction.
 //   - add note about iteration
 const char* const RRsetCollectionBase_doc = "\
 Generic class to represent a set of RRsets.\n\
@@ -18,8 +18,8 @@ maybe class) and a way to iterate over all RRsets.\n\
 See RRsetCollection for a simple isc.dns implementation. Other modules\n\
 such as isc.datasrc will have another implementation.\n\
 \n\
-This base class cannot be directly instantiated, so no constructor is\n\
-defined.\n\
+This base class cannot be directly instantiated.  Such an attempt will\n\
+result in a TypeError exception.\n\
 \n\
 ";
 
@@ -79,18 +79,18 @@ RRsetCollection(filename, origin, rrclass)\n\
       origin     (isc.dns.Name) The zone origin.\n\
       rrclass    (isc.dns.RRClass) The zone class.\n\
 \n\
-RRsetCollection(input_stream, origin, rrclass)\n\
+RRsetCollection(input, origin, rrclass)\n\
 \n\
     Constructor.\n\
 \n\
     This constructor is similar to the previous one, but instead of\n\
-    taking a filename to load a zone from, it takes a byte object,\n\
+    taking a filename to load a zone from, it takes a bytes object,\n\
     representing the zone contents in text.\n\
     The constructor throws IscException if there is an error\n\
     during loading.\n\
 \n\
     Parameters:\n\
-      input      (byte) Textual representation of the zone.\n\
+      input      (bytes) Textual representation of the zone.\n\
       origin     (isc.dns.Name) The zone origin.\n\
       rrclass    (isc.dns.RRClass) The zone class.\n\
 \n\
diff --git a/src/lib/dns/rrset_collection_base.h b/src/lib/dns/rrset_collection_base.h
index 5ae172a..7ccf7b5 100644
--- a/src/lib/dns/rrset_collection_base.h
+++ b/src/lib/dns/rrset_collection_base.h
@@ -185,6 +185,8 @@ public:
     }
 };
 
+typedef boost::shared_ptr<RRsetCollectionBase> RRsetCollectionPtr;
+
 } // end of namespace dns
 } // end of namespace isc
 
diff --git a/src/lib/python/isc/datasrc/datasrc.cc b/src/lib/python/isc/datasrc/datasrc.cc
index cfacc64..c183af9 100644
--- a/src/lib/python/isc/datasrc/datasrc.cc
+++ b/src/lib/python/isc/datasrc/datasrc.cc
@@ -218,23 +218,6 @@ initModulePart_ZoneLoader(PyObject* mod) {
 }
 
 bool
-initModulePart_ZoneUpdater(PyObject* mod) {
-    // We initialize the static description object with PyType_Ready(),
-    // then add it to the module. This is not just a check! (leaving
-    // this out results in segmentation faults)
-    if (PyType_Ready(&zoneupdater_type) < 0) {
-        return (false);
-    }
-    void* zip = &zoneupdater_type;
-    if (PyModule_AddObject(mod, "ZoneUpdater", static_cast<PyObject*>(zip)) < 0) {
-        return (false);
-    }
-    Py_INCREF(&zoneupdater_type);
-
-    return (true);
-}
-
-bool
 initModulePart_ZoneJournalReader(PyObject* mod) {
     if (PyType_Ready(&journal_reader_type) < 0) {
         return (false);
diff --git a/src/lib/python/isc/datasrc/tests/datasrc_test.py b/src/lib/python/isc/datasrc/tests/datasrc_test.py
index 659e7a8..36cf951 100644
--- a/src/lib/python/isc/datasrc/tests/datasrc_test.py
+++ b/src/lib/python/isc/datasrc/tests/datasrc_test.py
@@ -528,6 +528,41 @@ class DataSrcUpdater(unittest.TestCase):
         self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
                          rrset.to_text())
 
+    def test_updater_rrset_collection(self):
+        dsc = isc.datasrc.DataSourceClient("sqlite3", WRITE_ZONE_DB_CONFIG)
+        updater = dsc.get_updater(isc.dns.Name("example.com"), False)
+        updater_refs = sys.getrefcount(updater)
+
+        # Get (internally create) updater's RRset collection
+        rrsets = updater.get_rrset_collection()
+
+        # From this point we cannot make further updates
+        rrset = RRset(isc.dns.Name('www.example.com'), isc.dns.RRClass.IN(),
+                      isc.dns.RRType.AAAA(), isc.dns.RRTTL(10))
+        rrset.add_rdata(isc.dns.Rdata(isc.dns.RRType.AAAA(),
+                                      isc.dns.RRClass.IN(), '2001:db8::1'))
+        self.assertRaises(isc.datasrc.Error, updater.add_rrset, rrset)
+
+        # Checks basic API
+        found = rrsets.find(isc.dns.Name("www.example.com"),
+                            isc.dns.RRClass.IN(), isc.dns.RRType.A())
+        self.assertEqual("www.example.com. 3600 IN A 192.0.2.1\n",
+                         found.to_text())
+        self.assertEqual(None, rrsets.find(isc.dns.Name("www.example.com"),
+                                           isc.dns.RRClass.IN(),
+                                           isc.dns.RRType.AAAA()))
+
+        # Once committed collection cannot be used any more.
+        updater.commit()
+        self.assertRaises(isc.dns.RRsetCollectionError,
+                          rrsets.find, isc.dns.Name("www.example.com"),
+                          isc.dns.RRClass.IN(), isc.dns.RRType.A())
+
+        # When we destroy the RRsetCollection it should release the refcount
+        # to the updater.
+        rrsets = None
+        self.assertEqual(updater_refs, sys.getrefcount(updater))
+
     def test_two_modules(self):
         # load two modules, and check if they don't interfere
         mem_cfg = { "type": "memory", "class": "IN", "zones": [] };
diff --git a/src/lib/python/isc/datasrc/updater_inc.cc b/src/lib/python/isc/datasrc/updater_inc.cc
index 32715ec..f040f85 100644
--- a/src/lib/python/isc/datasrc/updater_inc.cc
+++ b/src/lib/python/isc/datasrc/updater_inc.cc
@@ -76,6 +76,10 @@ This method must not be called once commit() is performed. If it calls\n\
 after commit() the implementation must throw a isc.datasrc.Error\n\
 exception.\n\
 \n\
+Implementations of ZoneUpdater may not allow adding or deleting RRsets\n\
+after get_rrset_collection() is called. In this case, implementations\n\
+throw an InvalidOperation exception.\n\
+\n\
 Todo As noted above we may have to revisit the design details as we\n\
 gain experiences:\n\
 \n\
@@ -133,6 +137,10 @@ This method must not be called once commit() is performed. If it calls\n\
 after commit() the implementation must throw a isc.datasrc.Error\n\
 exception.\n\
 \n\
+Implementations of ZoneUpdater may not allow adding or deleting RRsets\n\
+after get_rrset_collection() is called. In this case, implementations\n\
+throw an InvalidOperation exception.\n\
+\n\
 Todo: As noted above we may have to revisit the design details as we\n\
 gain experiences:\n\
 \n\
@@ -178,4 +186,32 @@ Exceptions:\n\
              error, or wrapper error\n\\n\
 \n\
 ";
+
+// Modifications
+// - isc.datasrc.RRsetCollectionBase => isc.dns.RRsetCollectionBase
+//   (in the Python wrapper, the former is completely invisible)
+// - remove other reference to isc.datasrc.RRsetCollectionBase
+const char* const ZoneUpdater_getRRsetCollection_doc = "\
+get_rrset_collection() -> isc.dns.RRsetCollectionBase \n\
+\n\
+Return an RRsetCollection for the updater.\n\
+\n\
+This method returns an RRsetCollection for the updater, implementing\n\
+the isc.dns.RRsetCollectionBase interface. Typically, the returned\n\
+RRsetCollection is a singleton for its ZoneUpdater. The returned\n\
+RRsetCollection object must not be used after its corresponding\n\
+ZoneUpdater has been destroyed. The returned RRsetCollection object\n\
+may be used to search RRsets from the ZoneUpdater. The actual\n\
+RRsetCollection returned has a behavior dependent on the ZoneUpdater\n\
+implementation.\n\
+\n\
+The behavior of the RRsetCollection is similar to the behavior of the\n\
+Zonefinder returned by get_finder(). Implementations of ZoneUpdater\n\
+may not allow adding or deleting RRsets after get_rrset_collection()\n\
+is called. Implementations of ZoneUpdater may disable a previously\n\
+returned RRsetCollection after commit() is called. If an\n\
+RRsetCollection is disabled, using methods such as find() and using\n\
+its iterator would cause an exception to be thrown.\n\
+\n\
+";
 } // unnamed namespace
diff --git a/src/lib/python/isc/datasrc/updater_python.cc b/src/lib/python/isc/datasrc/updater_python.cc
index 97ffa00..cb727c3 100644
--- a/src/lib/python/isc/datasrc/updater_python.cc
+++ b/src/lib/python/isc/datasrc/updater_python.cc
@@ -32,6 +32,7 @@
 #include <dns/python/rrset_python.h>
 #include <dns/python/rrclass_python.h>
 #include <dns/python/rrtype_python.h>
+#include <dns/python/rrset_collection_python.h>
 
 #include "datasrc.h"
 #include "updater_python.h"
@@ -195,6 +196,107 @@ ZoneUpdater_find_all(PyObject* po_self, PyObject* args) {
         &self->cppobj->getFinder(), args));
 }
 
+namespace {
+// Below we define Python RRsetCollection class generated by the updater.
+// It's never expected to be instantiated directly from Python code, so
+// everything is hidden here, and tp_init always fails.
+
+class s_UpdaterRRsetCollection : public s_RRsetCollection {
+public:
+    s_UpdaterRRsetCollection() : s_RRsetCollection() {}
+    PyObject* base_obj_;
+};
+
+int
+RRsetCollection_init(PyObject*, PyObject*, PyObject*) {
+    // can't be called directly; actually, the constructor shouldn't even be
+    // called, but we catch the case just in case.
+    PyErr_SetString(PyExc_TypeError,
+                    "datasrc.RRsetCollection cannot be constructed directly");
+
+    return (-1);
+}
+
+void
+RRsetCollection_destroy(PyObject* po_self) {
+    s_UpdaterRRsetCollection* const self =
+        static_cast<s_UpdaterRRsetCollection*>(po_self);
+
+    // We don't own the C++ collection object; we shouldn't delete it here.
+
+    // Note: we need to check if this is NULL; it remains NULL in case of
+    // direct instantiation (which fails).
+    if (self->base_obj_ != NULL) {
+        Py_DECREF(self->base_obj_);
+    }
+    Py_TYPE(self)->tp_free(self);
+}
+
+PyTypeObject updater_rrset_collection_type = {
+    PyVarObject_HEAD_INIT(NULL, 0)
+    "datasrc.UpdaterRRsetCollection",
+    sizeof(s_UpdaterRRsetCollection),   // tp_basicsize
+    0,                                  // tp_itemsize
+    RRsetCollection_destroy,            // tp_dealloc
+    NULL,                               // tp_print
+    NULL,                               // tp_getattr
+    NULL,                               // tp_setattr
+    NULL,                               // tp_reserved
+    NULL,                               // tp_repr
+    NULL,                               // tp_as_number
+    NULL,                               // tp_as_sequence
+    NULL,                               // tp_as_mapping
+    NULL,                               // tp_hash
+    NULL,                               // tp_call
+    NULL,                               // tp_str
+    NULL,                               // tp_getattro
+    NULL,                               // tp_setattro
+    NULL,                               // tp_as_buffer
+    Py_TPFLAGS_DEFAULT,                 // tp_flags
+    NULL,
+    NULL,                               // tp_traverse
+    NULL,                               // tp_clear
+    NULL,                               // tp_richcompare
+    0,                                  // tp_weaklistoffset
+    NULL,                               // tp_iter
+    NULL,                               // tp_iternext
+    NULL,                               // tp_methods
+    NULL,                               // tp_members
+    NULL,                               // tp_getset
+    NULL,   // tp_base (rrset_collection_base_type, set at run time)
+    NULL,                               // tp_dict
+    NULL,                               // tp_descr_get
+    NULL,                               // tp_descr_set
+    0,                                  // tp_dictoffset
+    RRsetCollection_init,               // tp_init
+    NULL,                               // tp_alloc
+    PyType_GenericNew,                  // tp_new
+    NULL,                               // tp_free
+    NULL,                               // tp_is_gc
+    NULL,                               // tp_bases
+    NULL,                               // tp_mro
+    NULL,                               // tp_cache
+    NULL,                               // tp_subclasses
+    NULL,                               // tp_weaklist
+    NULL,                               // tp_del
+    0                                   // tp_version_tag
+};
+} // unnamed namespace
+
+PyObject*
+ZoneUpdater_getRRsetCollection(PyObject* po_self, PyObject*) {
+    s_ZoneUpdater* const self = static_cast<s_ZoneUpdater*>(po_self);
+
+    s_UpdaterRRsetCollection* collection =
+        static_cast<s_UpdaterRRsetCollection*>(
+            PyObject_New(s_RRsetCollection, &updater_rrset_collection_type));
+    collection->cppobj = &self->cppobj->getRRsetCollection();
+    collection->base_obj_ = po_self;;
+    Py_INCREF(collection->base_obj_);
+
+    return (collection);
+}
+
 // This list contains the actual set of functions we have in
 // python. Each entry has
 // 1. Python method name
@@ -207,6 +309,8 @@ PyMethodDef ZoneUpdater_methods[] = {
     { "delete_rrset", ZoneUpdater_deleteRRset,
       METH_VARARGS, ZoneUpdater_deleteRRset_doc },
     { "commit", ZoneUpdater_commit, METH_NOARGS, ZoneUpdater_commit_doc },
+    { "get_rrset_collection", ZoneUpdater_getRRsetCollection,
+      METH_NOARGS, ZoneUpdater_getRRsetCollection_doc },
     // Instead of a getFinder, we implement the finder functionality directly
     // This is because ZoneFinder is non-copyable, and we should not create
     // a ZoneFinder object from a reference only (which is what is returned
@@ -292,6 +396,56 @@ createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source,
     return (py_zu);
 }
 
+bool
+initModulePart_ZoneUpdater(PyObject* mod) {
+    // We initialize the static description object with PyType_Ready(),
+    // then add it to the module. This is not just a check! (leaving
+    // this out results in segmentation faults)
+    if (PyType_Ready(&zoneupdater_type) < 0) {
+        return (false);
+    }
+    void* zip = &zoneupdater_type;
+    if (PyModule_AddObject(mod, "ZoneUpdater",
+                           static_cast<PyObject*>(zip)) < 0)
+    {
+        return (false);
+    }
+    Py_INCREF(&zoneupdater_type);
+
+    // get_rrset_collection() needs the base class type information.  Since
+    // it's defined in a separate loadable module, we retrieve its C object
+    // via the Python interpreter.  Directly referring to
+    // isc::dns::python::rrset_collection_base_type might work depending on
+    // the runtime environment (and in fact it does for some), but that would
+    // be less portable.
+    try {
+        if (updater_rrset_collection_type.tp_base == NULL) {
+            PyObjectContainer dns_module(PyImport_ImportModule("isc.dns"));
+            PyObjectContainer dns_dict(PyModule_GetDict(dns_module.get()));
+            // GetDict doesn't acquire a reference, so we need to get it to
+            // meet the container's requirement.
+            Py_INCREF(dns_dict.get());
+            PyObjectContainer base(
+                PyDict_GetItemString(dns_dict.get(), "RRsetCollectionBase"));
+            PyTypeObject* pt_rrset_collection_base =
+                static_cast<PyTypeObject*>(static_cast<void*>(base.get()));
+            updater_rrset_collection_type.tp_base = pt_rrset_collection_base;
+            if (PyType_Ready(&updater_rrset_collection_type) < 0) {
+                isc_throw(Unexpected, "failed to import isc.dns module");
+            }
+
+            // Make sure the base type won't suddenly disappear.  Note that we
+            // are effectively leaking it; it's intentional.
+            Py_INCREF(base.get());
+        }
+    } catch (...) {
+        PyErr_SetString(PyExc_SystemError,
+                        "Unexpected failure in ZoneUpdater initialization");
+        return (false);
+    }
+
+    return (true);
+}
 } // namespace python
 } // namespace datasrc
 } // namespace isc
diff --git a/src/lib/python/isc/datasrc/updater_python.h b/src/lib/python/isc/datasrc/updater_python.h
index b09c524..b7f1452 100644
--- a/src/lib/python/isc/datasrc/updater_python.h
+++ b/src/lib/python/isc/datasrc/updater_python.h
@@ -36,7 +36,7 @@ extern PyTypeObject zoneupdater_type;
 PyObject* createZoneUpdaterObject(isc::datasrc::ZoneUpdaterPtr source,
                                   PyObject* base_obj = NULL);
 
-
+bool initModulePart_ZoneUpdater(PyObject* mod);
 } // namespace python
 } // namespace datasrc
 } // namespace isc
diff --git a/tests/system/ifconfig.sh b/tests/system/ifconfig.sh
index c0c365a..7c695e2 100755
--- a/tests/system/ifconfig.sh
+++ b/tests/system/ifconfig.sh
@@ -63,7 +63,7 @@ esac
 case "$1" in
 
     start|up)
-	for ns in 1 2 3 4 5 6 7
+	for ns in 1 2 3 4 5 6 7 8
 	do
 		if test -n "$base"
 		then
@@ -145,7 +145,7 @@ case "$1" in
 	;;
 
     stop|down)
-	for ns in 7 6 5 4 3 2 1
+	for ns in 8 7 6 5 4 3 2 1
 	do
 		if test -n "$base"
 		then



More information about the bind10-changes mailing list