Browse Source

added isc::data::merge(element, element), that merges the values in the second mapelement into the first (copies the pointers that are present in the second element, and removes from a the values that are empty pointers in the second)

the ElementPtr passed to the module's config handler now only contains the data that has actually changed (settings that are the same as before are removed from what is passed to the config handler)


git-svn-id: svn://bind10.isc.org/svn/bind10/trunk@1041 e5f2f494-b856-4b98-b285-d166d9295462
Jelte Jansen 15 years ago
parent
commit
bb8fe6795f

+ 3 - 7
src/bin/auth/auth_srv.cc

@@ -128,10 +128,8 @@ AuthSrv::processMessage() {
 void
 AuthSrv::setDbFile(const std::string& db_file)
 {
-    if (_db_file != db_file) {
-        cout << "Change data source file, call our data source's function to now read " << db_file << endl;
-        _db_file = db_file;
-    }
+    cout << "Change data source file, call our data source's function to now read " << db_file << endl;
+    _db_file = db_file;
 }
 
 ElementPtr
@@ -140,9 +138,7 @@ AuthSrv::updateConfig(isc::data::ElementPtr new_config) {
         // the ModuleCCSession has already checked if we have
         // the correct ElementPtr type as specified in our .spec file
         if (new_config->contains("database_file")) {
-            // Since we also get this value if it hasn't changed,
-            // but is non-default, setDbFile here should only really
-            // do anything if it has actually changed
+            // We only get this if the value has actually changed.
             setDbFile(new_config->get("database_file")->stringValue());
         }
     }

+ 23 - 4
src/lib/cc/cpp/data.cc

@@ -1005,21 +1005,40 @@ isc::data::isNull(ElementPtr p)
 void
 isc::data::removeIdentical(ElementPtr a, const ElementPtr b)
 {
+    if (!b) {
+        return;
+    }
     if (a->getType() != Element::map || b->getType() != Element::map) {
         dns_throw(TypeError, "Non-map Elements passed to removeIdentical");
     }
-    std::cout<<"[XX] removeidentical from " << a << " and " << b << std::endl;
-    
+
     std::map<std::string, ElementPtr> m = a->mapValue();
     for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
          it != m.end() ; ++it) {
         if (b->contains((*it).first)) {
             if (a->get((*it).first)->equals(b->get((*it).first))) {
-                std::cout<<"[XX] remove " << (*it).first << std::endl;
                 a->remove((*it).first);
             }
         }
     }
-    std::cout<<"[XX] a now " << a << std::endl;
+}
 
+void
+isc::data::merge(ElementPtr element, const ElementPtr other)
+{
+    if (element->getType() != Element::map ||
+        other->getType() != Element::map) {
+        dns_throw(TypeError, "merge arguments not MapElements");
+    }
+    
+    std::map<std::string, ElementPtr> m = other->mapValue();
+    for (std::map<std::string, ElementPtr>::iterator it = m.begin() ;
+         it != m.end() ; ++it) {
+        if ((*it).second) {
+            element->set((*it).first, (*it).second);
+        } else if (element->contains((*it).first)) {
+            element->remove((*it).first);
+        }
+    }
 }
+

+ 11 - 1
src/lib/cc/cpp/data.h

@@ -455,13 +455,23 @@ bool isNull(ElementPtr p);
 
 ///
 /// \brief Remove all values from the first ElementPtr that are
-/// also present in the second. Both ElementPtrs MUST be MapElements
+/// equal in the second. Both ElementPtrs MUST be MapElements
 /// The use for this function is to end up with a MapElement that
 /// only contains new and changed values (for ModuleCCSession and
 /// configuration update handlers)
 /// Raises a TypeError if a or b are not MapElements
 void removeIdentical(ElementPtr a, const ElementPtr b);
 
+/// \brief Merges the data from other into element.
+/// (on the first level). Both elements must be
+/// MapElements.
+/// Every string,value pair in other is copied into element
+/// (the ElementPtr of value is copied, this is not a new object)
+/// Unless the value is an empty ElementPtr, in which case the
+/// whole key is removed from element.
+/// Raises a TypeError if either ElementPtr is not a MapElement
+void merge(ElementPtr element, const ElementPtr other);
+
 } }
 
 ///

+ 32 - 0
src/lib/cc/cpp/data_unittests.cc

@@ -380,3 +380,35 @@ TEST(Element, removeIdentical) {
     removeIdentical(a, b);
     EXPECT_TRUE(a == c);
 }
+
+TEST(Element, merge)
+{
+    ElementPtr a = Element::createFromString("{}");
+    ElementPtr b = Element::createFromString("{}");
+    ElementPtr c = Element::createFromString("{}");
+    merge(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("1");
+    b = Element::createFromString("{}");
+    EXPECT_THROW(merge(a, b), TypeError);
+
+    a = Element::createFromString("{}");
+    b = Element::createFromString("{ \"a\": 1 }");
+    c = Element::createFromString("{ \"a\": 1 }");
+    merge(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": 1 }");
+    b = Element::createFromString("{ \"a\": 2 }");
+    c = Element::createFromString("{ \"a\": 2 }");
+    merge(a, b);
+    EXPECT_TRUE(a == c);
+
+    a = Element::createFromString("{ \"a\": { \"b\": \"c\" } }");
+    b = Element::createFromString("{ \"a\": { \"b\": \"d\" } }");
+    c = Element::createFromString("{ \"a\": { \"b\": \"d\" } }");
+    merge(a, b);
+    EXPECT_TRUE(a == c);
+
+}

+ 6 - 3
src/lib/config/cpp/ccsession.cc

@@ -189,7 +189,8 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
     ElementPtr spec_msg = createCommand("module_spec", module_specification_.getFullSpec());
     session_.group_sendmsg(spec_msg, "ConfigManager");
     session_.group_recvmsg(env, answer, false);
-    
+
+    config_ = Element::createFromString("{}");
     // get any stored configuration from the manager
     if (config_handler_) {
         ElementPtr cmd = Element::createFromString("{ \"command\": [\"get_config\", {\"module_name\":\"" + module_name_ + "\"} ] }");
@@ -202,7 +203,7 @@ ModuleCCSession::ModuleCCSession(std::string spec_file_name,
 }
 
 /// Validates the new config values, if they are correct,
-/// call the config handler
+/// call the config handler with the values that have changed
 /// If that results in success, store the new config
 ElementPtr
 ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
@@ -220,13 +221,15 @@ ModuleCCSession::handleConfigUpdate(ElementPtr new_config)
         }
         answer = createAnswer(2, ss.str());
     } else {
+        // remove the values that have not changed
+        isc::data::removeIdentical(new_config, getConfig());
         // handle config update
         std::cout << "handleConfigUpdate " << new_config << std::endl;
         answer = config_handler_(new_config);
         int rcode;
         parseAnswer(rcode, answer);
         if (rcode == 0) {
-            config_ = new_config;
+            isc::data::merge(config_, new_config);
         }
     }
     std::cout << "end handleConfigUpdate " << new_config << std::endl;