When replacing value of an attribute which has default-value tag with NULL
during runtime, NULL value will be replaced with its default value after
cluster is rebooted; in other words, that value is not persisted.

This patch makes some changes in immdump/immloader/imm om library/immnd
to handle such requirement.
---
 src/imm/README                   | 10 +---
 src/imm/agent/imma_om_api.cc     |  7 ++-
 src/imm/immloadd/imm_loader.cc   | 23 +++++---
 src/imm/immloadd/imm_pbe_load.cc | 16 ++++--
 src/imm/immnd/ImmModel.cc        |  9 ++-
 src/imm/tools/imm_xmlw_dump.cc   | 96 ++++++++++++++++++++------------
 6 files changed, 100 insertions(+), 61 deletions(-)

diff --git a/src/imm/README b/src/imm/README
index 7ace34741..132ee0ac0 100644
--- a/src/imm/README
+++ b/src/imm/README
@@ -351,14 +351,8 @@ as part of an attribute definition.
 (i) A default declaration is only allowed for single valued attributes (no
 concept of a multivalued default exists).
 
-(ii) Default values are assigned at object creation. Default values are NOT
-assigned if an attribute is set to the empty/null value by a modification.
-
-(iii) Default values are assigned at cluster restart for any attributes that
-are null/empty and that have a default. This is a special case of (i) because
-imm loading actually uses the regular imm API to recreate the imm contents.
-In particular, saImmOmCcbObjectCreate is used to recreate all objects from
-the file-system image.
+(ii) Default values are assigned at object creation, except the creation comes
+from IMM loader.
 
 Common missunderstandings about "system attributes" of an imm object.
 ---------------------------------------------------------------------
diff --git a/src/imm/agent/imma_om_api.cc b/src/imm/agent/imma_om_api.cc
index 7155799d9..0d24b2335 100644
--- a/src/imm/agent/imma_om_api.cc
+++ b/src/imm/agent/imma_om_api.cc
@@ -2037,7 +2037,7 @@ static SaAisErrorT ccb_object_create_common(
         TRACE_2("ERR_INVALID_PARAM: Not allowed to set attribute %s",
                 sysaImplName);
         goto mds_send_fail;
-      } else if (attr->attrValuesNumber == 0) {
+      } else if (attr->attrValuesNumber == 0 && !immOmIsLoader) {
         TRACE("CcbObjectCreate ignoring attribute %s with no values",
               attr->attrName);
         continue;
@@ -2065,7 +2065,9 @@ static SaAisErrorT ccb_object_create_common(
 
       const SaImmAttrValueT *avarr = attr->attrValues;
       /*alloc-5 */
-      imma_copyAttrValue(&(p->n.attrValue), attr->attrValueType, avarr[0]);
+      if (attr->attrValuesNumber > 0) {
+        imma_copyAttrValue(&(p->n.attrValue), attr->attrValueType, avarr[0]);
+      }
 
       if (attr->attrValuesNumber > 1) {
         unsigned int numAdded = attr->attrValuesNumber - 1;
@@ -2087,6 +2089,7 @@ static SaAisErrorT ccb_object_create_common(
     }
   }
 
+
   rc = imma_evt_fake_evs(cb, &evt, &out_evt, cl_node->syncr_timeout,
                          cl_node->handle, &locked, false);
   cl_node = NULL;
diff --git a/src/imm/immloadd/imm_loader.cc b/src/imm/immloadd/imm_loader.cc
index e9a985c22..3bd3e2b2e 100644
--- a/src/imm/immloadd/imm_loader.cc
+++ b/src/imm/immloadd/imm_loader.cc
@@ -117,6 +117,7 @@ typedef struct ParserStateStruct {
   SaImmAttrFlagsT attrFlags;
   SaUint32T attrNtfId;
   char *attrDefaultValueBuffer;
+  bool is_null_value;
 
   int attrValueTypeSet;
   int attrNtfIdSet;
@@ -925,6 +926,13 @@ static void startElementHandler(void *userData, const 
xmlChar *name,
     state->state[state->depth] = VALUE;
     state->valueContinue = 0;
     state->isBase64Encoded = isBase64Encoded(attrs);
+    state->is_null_value = false;
+    if (attrs) {
+      char* null_value = getAttributeValue("xsi:nil", attrs);
+      if (null_value && std::string{null_value} == "true") {
+        state->is_null_value = true;
+      }
+    }
     /* <category> */
   } else if (strcmp((const char *)name, "category") == 0) {
     state->state[state->depth] = CATEGORY;
@@ -982,7 +990,7 @@ static void endElementHandler(void *userData, const xmlChar 
*name) {
 
   /* </value> */
   if (strcmp((const char *)name, "value") == 0) {
-    if (state->attrValueBuffers.empty()) {
+    if (state->attrValueBuffers.empty() && !state->is_null_value) {
       char *str = (char *)malloc(1);
 
       str[0] = '\0';
@@ -1759,14 +1767,13 @@ void addObjectAttributeDefinition(
   SaImmAttrValuesT_2 attrValues;
   int i;
   size_t len;
+  bool null_value = attrValueBuffers->empty();
+
   TRACE_ENTER2("attrValueBuffers size:%u",
                (unsigned int)attrValueBuffers->size());
   /* The attrName must be set */
   assert(attrName);
 
-  /* The value array can not be empty */
-  assert(!attrValueBuffers->empty());
-
   /* The object class must be set */
   assert(objectClass);
 
@@ -1778,15 +1785,15 @@ void addObjectAttributeDefinition(
 
   /* For each value, convert from char* to SaImmAttrValuesT_2 and
      store an array pointing to all in attrValues */
-  attrValues.attrValuesNumber = attrValueBuffers->size();
-  attrValues.attrValues = (SaImmAttrValueT *)malloc(
+  attrValues.attrValuesNumber = null_value ? 0 : attrValueBuffers->size();
+  attrValues.attrValues = null_value ? nullptr : (SaImmAttrValueT *)malloc(
       sizeof(SaImmAttrValuesT_2) * attrValues.attrValuesNumber + 1);
 
-  attrValues.attrValues[attrValues.attrValuesNumber] = NULL;
+  if (!null_value) attrValues.attrValues[attrValues.attrValuesNumber] = NULL;
 
   it = attrValueBuffers->begin();
   i = 0;
-  while (it != attrValueBuffers->end()) {
+  while (!null_value && it != attrValueBuffers->end()) {
     charsToValueHelper(&attrValues.attrValues[i], attrValues.attrValueType,
                        *it);
     i++;
diff --git a/src/imm/immloadd/imm_pbe_load.cc b/src/imm/immloadd/imm_pbe_load.cc
index d9e1c4d83..72b926383 100644
--- a/src/imm/immloadd/imm_pbe_load.cc
+++ b/src/imm/immloadd/imm_pbe_load.cc
@@ -524,7 +524,8 @@ bool loadObjectFromPbe(void *pbeHandle, SaImmHandleT 
immHandle,
   const unsigned char *res;
   for (c = 0; c < ncols; ++c) {
     res = sqlite3_column_text(stmt, c);
-    if (res) {
+    bool is_null = false;
+    if (true) {
       SaImmValueTypeT attrType = (SaImmValueTypeT)0;
       const char *colname = sqlite3_column_name(stmt, c);
       assert(colname != NULL);
@@ -544,7 +545,7 @@ bool loadObjectFromPbe(void *pbeHandle, SaImmHandleT 
immHandle,
       assert(it != class_info->attrInfoVector.end());
 
       char *val;
-      if (attrType == SA_IMM_ATTR_SADOUBLET) {
+      if (res && attrType == SA_IMM_ATTR_SADOUBLET) {
         double dbl = sqlite3_column_double(stmt, c);
 
         val = (char *)malloc(30);
@@ -555,12 +556,16 @@ bool loadObjectFromPbe(void *pbeHandle, SaImmHandleT 
immHandle,
           snprintf(val, size, "%.17g", dbl);
         }
       } else {
-        val = strdup((const char *)res);
+        if (res) {
+          val = strdup((const char *)res);
+        }
       }
 
+      is_null = (res == nullptr);
       std::list<char *> attrValueBuffers;
-      attrValueBuffers.push_front(val);
-
+      if (!is_null) {
+        attrValueBuffers.push_front(val);
+      }
       addObjectAttributeDefinition((char *)class_info->className.c_str(),
                                    (SaImmAttrNameT)colname, &attrValueBuffers,
                                    attrType, &attrValuesList);
@@ -669,7 +674,6 @@ bool loadObjectFromPbe(void *pbeHandle, SaImmHandleT 
immHandle,
                                      (char *)(*it)->attrName.c_str(),
                                      &attrValueBuffers, (*it)->attrValueType,
                                      &attrValuesList);
-
       sqlite3_reset(stmt);
     } /*if(attr_is_multi && !attr_is_pure_rt)*/
     ++it;
diff --git a/src/imm/immnd/ImmModel.cc b/src/imm/immnd/ImmModel.cc
index 8e3f338dc..747b406c6 100644
--- a/src/imm/immnd/ImmModel.cc
+++ b/src/imm/immnd/ImmModel.cc
@@ -8393,8 +8393,13 @@ SaAisErrorT ImmModel::ccbObjectCreate(
 
       ImmAttrValue* attrValue = i6->second;
       IMMSV_OCTET_STRING tmpos;  // temporary octet string
-      eduAtValToOs(&tmpos, &(p->n.attrValue),
-                   (SaImmValueTypeT)p->n.attrValueType);
+      memset(&tmpos, 0, sizeof(tmpos));
+      // Attribute value will be assigned null value or <empty>
+      // if having `attrValuesNumber=0` goes with it.
+      if (p->n.attrValuesNumber) {
+        eduAtValToOs(&tmpos, &(p->n.attrValue),
+                     (SaImmValueTypeT)p->n.attrValueType);
+      }
       attrValue->setValue(tmpos);
       if (p->n.attrValuesNumber > 1) {
         /*
diff --git a/src/imm/tools/imm_xmlw_dump.cc b/src/imm/tools/imm_xmlw_dump.cc
index 2e7fcda86..e6fdd279f 100644
--- a/src/imm/tools/imm_xmlw_dump.cc
+++ b/src/imm/tools/imm_xmlw_dump.cc
@@ -419,11 +419,6 @@ void objectToXMLw(std::string objectNameString, 
SaImmAttrValuesT_2** attrs,
     exit(1);
   }
   for (SaImmAttrValuesT_2** p = attrs; *p != NULL; p++) {
-    /* Skip attributes with attrValues = NULL */
-    if ((*p)->attrValues == NULL) {
-      continue;
-    }
-
     if (classRDNMap.find(classNameString) != classRDNMap.end() &&
         classRDNMap[classNameString] == std::string((*p)->attrName)) {
       continue;
@@ -469,10 +464,6 @@ static void StoreObject(const std::string& objectName,
 
   /* Add attributes to list */
   for (SaImmAttrValuesT_2** p = attrs; *p != NULL; p++) {
-    /* Skip attributes with attrValues = NULL */
-    if ((*p)->attrValues == NULL) {
-      continue;
-    }
     /* Skip RDN */
     if (classRDNMap.find(obj.className) != classRDNMap.end() &&
         classRDNMap[obj.className] == std::string((*p)->attrName)) {
@@ -544,42 +535,62 @@ static void ObjectSetToXMLw(std::set<Object, ObjectComp>& 
objectSet,
       }
 
       /* Write attribute values */
-      for (std::list<std::string>::const_iterator value_it =
-               attr_it->second.begin();
-           value_it != attr_it->second.end(); ++value_it) {
+      std::list<std::string> values = attr_it->second;
+      if (values.empty()) {
         if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
           std::cout << "Error at xmlTextWriterStartElement (value)"
                     << std::endl;
           exit(1);
         }
-        if (osaf_is_valid_xml_utf8((*value_it).c_str())) {
-          if (xmlTextWriterWriteString(writer, (xmlChar*)(*value_it).c_str()) <
-              0) {
-            std::cout << "Error at xmlTextWriterWriteString (value)"
-                      << std::endl;
-            exit(1);
-          }
-        } else {
-          if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:type",
-                                          (xmlChar*)"xs:base64Binary") < 0) {
-            std::cout << "Error at xmlTextWriterWriteAttribute (value)"
-                      << std::endl;
-            exit(1);
-          }
-          if (xmlTextWriterWriteBase64(writer, (*value_it).c_str(), 0,
-                                       (*value_it).size()) < 0) {
-            std::cout << "Error at xmlTextWriterWriteBase64 (value)"
-                      << std::endl;
-            exit(1);
-          }
+        if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:nil",
+                                        (xmlChar*)"true") < 0) {
+          std::cout << "Error at xmlTextWriterWriteAttribute (value)"
+                    << std::endl;
+          exit(1);
         }
         if (xmlTextWriterEndElement(writer) < 0) {
           std::cout << "Error at xmlTextWriterWriteEndElement (value)"
                     << std::endl;
           exit(1);
         }
-      } /* Attribute values loop */
 
+      } else {
+        for (std::list<std::string>::const_iterator value_it =
+                 attr_it->second.begin();
+             value_it != attr_it->second.end(); ++value_it) {
+          if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
+            std::cout << "Error at xmlTextWriterStartElement (value)"
+                      << std::endl;
+            exit(1);
+          }
+          if (osaf_is_valid_xml_utf8((*value_it).c_str())) {
+            if (xmlTextWriterWriteString(writer, 
(xmlChar*)(*value_it).c_str()) <
+                0) {
+              std::cout << "Error at xmlTextWriterWriteString (value)"
+                        << std::endl;
+              exit(1);
+            }
+          } else {
+            if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:type",
+                                            (xmlChar*)"xs:base64Binary") < 0) {
+              std::cout << "Error at xmlTextWriterWriteAttribute (value)"
+                        << std::endl;
+              exit(1);
+            }
+            if (xmlTextWriterWriteBase64(writer, (*value_it).c_str(), 0,
+                                         (*value_it).size()) < 0) {
+              std::cout << "Error at xmlTextWriterWriteBase64 (value)"
+                        << std::endl;
+              exit(1);
+            }
+          }
+          if (xmlTextWriterEndElement(writer) < 0) {
+            std::cout << "Error at xmlTextWriterWriteEndElement (value)"
+                      << std::endl;
+            exit(1);
+          }
+        } /* Attribute values loop */
+      }
       if (xmlTextWriterEndElement(writer) < 0) {
         std::cout << "Error at xmlTextWriterEndElement (attr-object)"
                   << std::endl;
@@ -597,8 +608,23 @@ static void ObjectSetToXMLw(std::set<Object, ObjectComp>& 
objectSet,
 }
 
 void valuesToXMLw(SaImmAttrValuesT_2* p, xmlTextWriterPtr writer) {
-  if (!p->attrValues) {
-    // std::cout << "No values!" << std::endl;
+  if (p->attrValuesNumber == 0) {
+    if (xmlTextWriterStartElement(writer, (xmlChar*)"value") < 0) {
+      std::cout << "Error at xmlTextWriterStartElement (value)"
+                << std::endl;
+      exit(1);
+    }
+    if (xmlTextWriterWriteAttribute(writer, (xmlChar*)"xsi:nil",
+                                    (xmlChar*)"true") < 0) {
+      std::cout << "Error at xmlTextWriterWriteAttribute (value)"
+                << std::endl;
+      exit(1);
+    }
+    if (xmlTextWriterEndElement(writer) < 0) {
+      std::cout << "Error at xmlTextWriterWriteEndElement (value)"
+                << std::endl;
+      exit(1);
+    }
     return;
   }
 
-- 
2.19.2



_______________________________________________
Opensaf-devel mailing list
Opensaf-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/opensaf-devel

Reply via email to