1 /*
2    Copyright (c) 2003, 2021, Oracle and/or its affiliates.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License, version 2.0,
6    as published by the Free Software Foundation.
7 
8    This program is also distributed with certain software (including
9    but not limited to OpenSSL) that is licensed under separate terms,
10    as designated in a particular file or component or in included license
11    documentation.  The authors of MySQL hereby grant you an additional
12    permission to link the program and your derivative works with the
13    separately licensed software that they have included with MySQL.
14 
15    This program is distributed in the hope that it will be useful,
16    but WITHOUT ANY WARRANTY; without even the implied warranty of
17    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18    GNU General Public License, version 2.0, for more details.
19 
20    You should have received a copy of the GNU General Public License
21    along with this program; if not, write to the Free Software
22    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
23 */
24 
25 #include "Config.hpp"
26 
27 #include <mgmapi.h>
28 #include <NdbOut.hpp>
29 #include "ConfigInfo.hpp"
30 
31 #include <HashMap.hpp>
32 
Config(struct ndb_mgm_configuration * config_values)33 Config::Config(struct ndb_mgm_configuration *config_values) :
34   m_configValues(config_values)
35 {
36 }
37 
38 
Config(ConfigValues * config_values)39 Config::Config(ConfigValues *config_values) :
40   m_configValues((struct ndb_mgm_configuration*)config_values)
41 {
42 }
43 
Config(const Config * conf)44 Config::Config(const Config* conf)
45 {
46   // TODO Magnus, improve copy constructor
47   // to not use pack/unpack
48   assert(conf);
49   UtilBuffer buf;
50   conf->pack(buf);
51   ConfigValuesFactory cvf;
52   cvf.unpack(buf);
53   m_configValues= (struct ndb_mgm_configuration*)cvf.getConfigValues();
54 }
55 
56 
~Config()57 Config::~Config() {
58   ndb_mgm_destroy_configuration(m_configValues);
59 }
60 
61 unsigned sections[]=
62 {
63   CFG_SECTION_SYSTEM,
64   CFG_SECTION_NODE,
65   CFG_SECTION_CONNECTION
66 };
67 const size_t num_sections= sizeof(sections)/sizeof(unsigned);
68 
69 static const ConfigInfo g_info;
70 
71 void
print(const char * section_filter,NodeId nodeid_filter,const char * param_filter,NdbOut & out) const72 Config::print(const char* section_filter, NodeId nodeid_filter,
73               const char* param_filter,
74               NdbOut& out) const {
75 
76   for(unsigned i= 0; i < num_sections; i++) {
77     unsigned section= sections[i];
78     ConfigIter it(this, section);
79 
80     if (it.first())
81       continue;
82 
83     for(;it.valid();it.next()) {
84 
85       Uint32 section_type;
86       if(it.get(CFG_TYPE_OF_SECTION, &section_type) != 0)
87         continue;
88 
89       const ConfigInfo::ParamInfo* pinfo= NULL;
90       ConfigInfo::ParamInfoIter param_iter(g_info,
91                                            section,
92                                            section_type);
93 
94       const char* section_name= g_info.sectionName(section, section_type);
95 
96       // Section name filter
97       if (section_filter &&                     // Filter is on
98           strcmp(section_filter, section_name)) // Value is different
99         continue;
100 
101       // NodeId filter
102       Uint32 nodeid = 0;
103       it.get(CFG_NODE_ID, &nodeid);
104       if (nodeid_filter &&                   // Filter is on
105           nodeid_filter != nodeid)           // Value is different
106         continue;
107 
108       /*  Loop through the section and print those values that exist */
109       Uint32 val;
110       Uint64 val64;
111       const char* val_str;
112       while((pinfo= param_iter.next())){
113 
114         // Param name filter
115         if (param_filter &&                      // Filter is on
116             strcmp(param_filter, pinfo->_fname)) // Value is different
117           continue;
118 
119         if (section_name) // Print section name only first time
120         {
121           out << "[" << section_name << "]" << endl;
122           section_name= NULL;
123         }
124 
125         if (!it.get(pinfo->_paramId, &val))
126           out << pinfo->_fname << "=" << val << endl;
127         else if (!it.get(pinfo->_paramId, &val64))
128           out << pinfo->_fname << "=" << val64 << endl;
129         else if (!it.get(pinfo->_paramId, &val_str))
130           out << pinfo->_fname << "=" << val_str << endl;
131       }
132     }
133   }
134 }
135 
136 
137 
138 Uint32
getGeneration() const139 Config::getGeneration() const
140 {
141   Uint32 generation;
142   ConfigIter iter(this, CFG_SECTION_SYSTEM);
143 
144   if (iter.get(CFG_SYS_CONFIG_GENERATION, &generation))
145     return 0;
146 
147   return generation;
148 }
149 
150 
151 Uint32
getPrimaryMgmNode() const152 Config::getPrimaryMgmNode() const
153 {
154   Uint32 primaryMgmNode;
155   ConfigIter iter(this, CFG_SECTION_SYSTEM);
156 
157   if (iter.get(CFG_SYS_PRIMARY_MGM_NODE, &primaryMgmNode))
158     return 0;
159 
160   return primaryMgmNode;
161 }
162 
163 
164 const char*
getName() const165 Config::getName() const
166 {
167   const char* name;
168   ConfigIter iter(this, CFG_SECTION_SYSTEM);
169 
170   if (iter.get(CFG_SYS_NAME, &name))
171     return 0;
172 
173   return name;
174 }
175 
176 
177 bool
setValue(Uint32 section,Uint32 section_no,Uint32 id,Uint32 new_val)178 Config::setValue(Uint32 section, Uint32 section_no,
179                  Uint32 id, Uint32 new_val)
180 {
181   ConfigValues::Iterator iter(m_configValues->m_config);
182   if (!iter.openSection(section, section_no))
183     return false;
184 
185   if (!iter.set(id, new_val))
186     return false;
187 
188   return true;
189 }
190 
191 
192 bool
setValue(Uint32 section,Uint32 section_no,Uint32 id,const char * new_val)193 Config::setValue(Uint32 section, Uint32 section_no,
194                  Uint32 id, const char* new_val)
195 {
196   ConfigValues::Iterator iter(m_configValues->m_config);
197   if (!iter.openSection(section, section_no))
198     return false;
199 
200   if (!iter.set(id, new_val))
201     return false;
202 
203   return true;
204 }
205 
206 
207 bool
setGeneration(Uint32 new_gen)208 Config::setGeneration(Uint32 new_gen)
209 {
210   return setValue(CFG_SECTION_SYSTEM, 0,
211                   CFG_SYS_CONFIG_GENERATION,
212                   new_gen);
213 }
214 
215 
216 bool
setPrimaryMgmNode(Uint32 new_primary)217 Config::setPrimaryMgmNode(Uint32 new_primary)
218 {
219   return setValue(CFG_SECTION_SYSTEM, 0,
220                   CFG_SYS_PRIMARY_MGM_NODE,
221                   new_primary);
222 }
223 
224 
225 bool
setName(const char * new_name)226 Config::setName(const char* new_name)
227 {
228   return setValue(CFG_SECTION_SYSTEM, 0,
229                   CFG_SYS_NAME,
230                   new_name);
231 }
232 
233 
234 Uint32
pack(UtilBuffer & buf) const235 Config::pack(UtilBuffer& buf) const
236 {
237   return m_configValues->m_config.pack(buf);
238 }
239 
240 
241 #include <ndb_base64.h>
242 
243 bool
pack64(BaseString & encoded) const244 Config::pack64(BaseString& encoded) const
245 {
246   UtilBuffer buf;
247   if (m_configValues->m_config.pack(buf) == 0)
248     return false;
249 
250   /*
251     Expand the string to correct length by filling with Z.
252     The base64 encoded data of UtilBuffer can be of max length (1024*1024)/3*4
253     hence using int to store the length.
254   */
255   encoded.assfmt("%*s",
256                  (int)base64_needed_encoded_length(buf.length()),
257                  "Z");
258 
259   if (base64_encode(buf.get_data(),
260                     buf.length(),
261                     (char*)encoded.c_str()))
262     return false;
263   return true;
264 }
265 
266 
267 enum diff_types {
268   DT_DIFF,            // Value differed
269   DT_MISSING_VALUE,   // Value didn't exist
270   DT_MISSING_SECTION, // Section missing
271   DT_ILLEGAL_CHANGE    // Illegal change detected
272 };
273 
274 
275 static void
add_diff(const char * name,const char * key,Properties & diff,const char * value_name,Properties * value)276 add_diff(const char* name, const char* key,
277          Properties& diff,
278          const char* value_name, Properties* value)
279 {
280   Properties *section;
281   // Create a new section if it did not exist
282   if (!diff.getCopy(key, &section)){
283     Properties new_section(true);
284     new_section.put("Key", key);
285     new_section.put("Name", name);
286 
287     require(diff.put(key, &new_section));
288 
289     // Get copy of section
290     require(diff.getCopy(key, &section));
291   }
292 
293   // Make sure type of diff has been set
294   Uint32 type;
295   require(value->get("Type", &type));
296 
297   require(value->put("Name", value_name));
298 
299   // Add the value to the section if not already added
300   // (a changed value will be detected twice)
301   if (!section->put(value_name, value))
302     require(section->getPropertiesErrno() ==
303             E_PROPERTIES_ELEMENT_ALREADY_EXISTS);
304 
305   // Put the updated section into the diff
306   require(diff.put(key, section, true));
307 
308   delete section;
309 }
310 
311 
312 static void
compare_value(const char * name,const char * key,const ConfigInfo::ParamInfo * pinfo,ConfigValues::ConstIterator & it,ConfigValues::ConstIterator & it2,Properties & diff)313 compare_value(const char* name, const char* key,
314               const ConfigInfo::ParamInfo* pinfo,
315               ConfigValues::ConstIterator& it,
316               ConfigValues::ConstIterator& it2,
317               Properties& diff)
318 {
319   Uint32 pid= pinfo->_paramId;
320   {
321     Uint32 val;
322     if (it.get(pid, &val) == true) {
323       Uint32 val2;
324       if (it2.get(pid, &val2) == true) {
325         if (val != val2){
326           Properties info(true);
327           info.put("Type", DT_DIFF);
328           info.put("New", val2);
329           info.put("Old", val);
330           add_diff(name, key,
331                    diff,
332                    pinfo->_fname, &info);
333         }
334       }
335       else
336       {
337         Properties info(true);
338         info.put("Type", DT_MISSING_VALUE);
339         info.put("Old", val);
340         add_diff(name, key,
341                  diff,
342                  pinfo->_fname, &info);
343       }
344       return;
345     }
346   }
347 
348   {
349     Uint64 val;
350     if (it.get(pid, &val) == true) {
351       Uint64 val2;
352       if (it2.get(pid, &val2) == true) {
353         if (val != val2) {
354           Properties info(true);
355           info.put("Type", DT_DIFF);
356           info.put64("New", Uint64(val2));
357           info.put64("Old", Uint64(val));
358           add_diff(name, key,
359                    diff,
360                    pinfo->_fname, &info);
361         }
362       }
363       else
364       {
365         Properties info(true);
366         info.put("Type", DT_MISSING_VALUE);
367         info.put64("Old", Uint64(val));
368         add_diff(name, key,
369                  diff,
370                  pinfo->_fname, &info);
371       }
372       return;
373     }
374   }
375 
376   {
377     const char* val;
378     if (it.get(pid, &val) == true) {
379       const char* val2;
380       if (it2.get(pid, &val2) == true) {
381         if (strcmp(val, val2)) {
382           Properties info(true);
383           info.put("Type", DT_DIFF);
384           info.put("New", val2);
385           info.put("Old", val);
386           add_diff(name, key,
387                    diff,
388                    pinfo->_fname, &info);
389         }
390       }
391       else
392       {
393         Properties info(true);
394         info.put("Type", DT_MISSING_VALUE);
395         info.put("Old", val);
396         add_diff(name, key,
397                  diff,
398                  pinfo->_fname, &info);
399       }
400       return;
401     }
402   }
403 }
404 
405 
406 static void
diff_system(const Config * a,const Config * b,Properties & diff)407 diff_system(const Config* a, const Config* b, Properties& diff)
408 {
409   ConfigIter itA(a, CFG_SECTION_SYSTEM);
410   ConfigIter itB(b, CFG_SECTION_SYSTEM);
411 
412   // Check each possible configuration value
413   const ConfigInfo::ParamInfo* pinfo= NULL;
414   ConfigInfo::ParamInfoIter param_iter(g_info,
415                                        CFG_SECTION_SYSTEM,
416                                        CFG_SECTION_SYSTEM);
417   while((pinfo= param_iter.next())) {
418     /*  Loop through the section and compare values */
419     compare_value("SYSTEM", "", pinfo, itA.m_config, itB.m_config, diff);
420   }
421 }
422 
423 
424 static void
diff_nodes(const Config * a,const Config * b,Properties & diff)425 diff_nodes(const Config* a, const Config* b, Properties& diff)
426 {
427   ConfigIter itA(a, CFG_SECTION_NODE);
428 
429   for(;itA.valid(); itA.next())
430   {
431 
432     /* Get typ of Node */
433     Uint32 nodeType;
434     require(itA.get(CFG_TYPE_OF_SECTION, &nodeType) == 0);
435 
436     BaseString name(g_info.sectionName(CFG_SECTION_NODE, nodeType));
437 
438     /* Get NodeId which is "primary key" */
439     Uint32 nodeId;
440     require(itA.get(CFG_NODE_ID, &nodeId) == 0);
441 
442     BaseString key;
443     key.assfmt("NodeId=%d", nodeId);
444 
445     /* Position itB in the section with same NodeId */
446     ConfigIter itB(b, CFG_SECTION_NODE);
447     if (itB.find(CFG_NODE_ID, nodeId) != 0)
448     {
449       // A whole node has been removed
450       Properties info(true);
451       info.put("Type", DT_MISSING_SECTION);
452       info.put("Why", "Node removed");
453       add_diff(name.c_str(), key.c_str(),
454                diff,
455                "Node removed", &info);
456 
457       continue;
458     }
459 
460     /* Make sure it has the same node type */
461     Uint32 nodeType2;
462     require(itB.get(CFG_TYPE_OF_SECTION, &nodeType2) == 0);
463     if ((nodeType == NODE_TYPE_DB || nodeType == NODE_TYPE_MGM) &&
464         nodeType != nodeType2)
465     {
466       // DB or MGM node has changed type -> not allowed change
467       Properties info(true);
468       info.put("Type", DT_ILLEGAL_CHANGE);
469       info.put("Why", "Node has changed type");
470       add_diff(name.c_str(), key.c_str(),
471                diff,
472                "Node type changed", &info);
473       continue;
474     }
475 
476     // Check each possible configuration value
477     const ConfigInfo::ParamInfo* pinfo= NULL;
478     ConfigInfo::ParamInfoIter param_iter(g_info, CFG_SECTION_NODE, nodeType);
479     while((pinfo= param_iter.next())) {
480       /*  Loop through the section and compare values */
481       compare_value(name.c_str(), key.c_str(), pinfo,
482                     itA.m_config, itB.m_config, diff);
483     }
484   }
485 }
486 
487 
488 struct NodePair {
489   Uint32 nodeId1;
490   Uint32 nodeId2;
NodePairNodePair491   NodePair(Uint32 n1, Uint32 n2) : nodeId1(n1), nodeId2(n2) {};
492 };
493 
494 static void
diff_connections(const Config * a,const Config * b,Properties & diff)495 diff_connections(const Config* a, const Config* b, Properties& diff)
496 {
497   // Build lookup table to make it a quick operation to check
498   // if a given connection(with "primary key" NodeId1+NodeId2)
499   // exists in other config, in such case return the section number
500   // so that the section can be retrieved quickly
501   HashMap<NodePair, Uint32> lookup;
502   {
503     Uint32 nodeId1, nodeId2;
504     ConfigIter itB(b, CFG_SECTION_CONNECTION);
505     for(; itB.valid(); itB.next())
506     {
507       require(itB.get(CFG_CONNECTION_NODE_1, &nodeId1) == 0);
508       require(itB.get(CFG_CONNECTION_NODE_2, &nodeId2) == 0);
509 
510       require(lookup.insert(NodePair(nodeId1, nodeId2), itB.m_sectionNo));
511     }
512   }
513 
514   ConfigIter itA(a, CFG_SECTION_CONNECTION);
515 
516   for(;itA.valid(); itA.next())
517   {
518     /* Get typ of connection */
519     Uint32 connectionType;
520     require(itA.get(CFG_TYPE_OF_SECTION, &connectionType) == 0);
521 
522     BaseString name(g_info.sectionName(CFG_SECTION_CONNECTION, connectionType));
523 
524     /* Get NodeId1 and NodeId2 which is "primary key" */
525     Uint32 nodeId1_A, nodeId2_A;
526     require(itA.get(CFG_CONNECTION_NODE_1, &nodeId1_A) == 0);
527     require(itA.get(CFG_CONNECTION_NODE_2, &nodeId2_A) == 0);
528 
529     BaseString key;
530     key.assfmt("NodeId1=%d;NodeId2=%d", nodeId1_A, nodeId2_A);
531 
532     /* Lookup connection and get section no if it exists */
533     Uint32 sectionNo;
534     if (!lookup.search(NodePair(nodeId1_A, nodeId2_A), sectionNo))
535     {
536       // A connection has been removed
537       Properties info(true);
538       info.put("Type", DT_MISSING_SECTION);
539       info.put("Why", "Connection removed");
540       add_diff(name.c_str(), key.c_str(),
541                diff,
542                "Connection removed", &info);
543 
544       continue;
545     }
546 
547     /* Open the connection section in other config */
548     ConfigValues::ConstIterator itB(b->m_configValues->m_config);
549     require(itB.openSection(CFG_SECTION_CONNECTION, sectionNo) == true);
550 
551     Uint32 nodeId1_B = 0; /* Silence compiler warning */
552     Uint32 nodeId2_B = 0; /* Silence compiler warning */
553     require(itB.get(CFG_CONNECTION_NODE_1, &nodeId1_B) == true);
554     require(itB.get(CFG_CONNECTION_NODE_2, &nodeId2_B) == true);
555     require(nodeId1_A == nodeId1_B && nodeId2_A == nodeId2_B);
556 
557     // Check each possible configuration value
558     const ConfigInfo::ParamInfo* pinfo= NULL;
559     ConfigInfo::ParamInfoIter param_iter(g_info,
560                                          CFG_SECTION_CONNECTION,
561                                          connectionType);
562     while((pinfo= param_iter.next())) {
563       /*  Loop through the section and compare values */
564       compare_value(name.c_str(), key.c_str(), pinfo, itA.m_config, itB, diff);
565     }
566   }
567 }
568 
569 
570 static bool
include_section(const unsigned * exclude,unsigned section)571 include_section(const unsigned* exclude, unsigned section){
572   if (exclude == NULL)
573     return true;
574 
575   while(*exclude){
576     if (*exclude == section)
577       return false;
578     exclude++;
579   }
580   return true;
581 }
582 
583 
584 /**
585   Generate a diff list
586 */
587 
diff(const Config * other,Properties & diff,const unsigned * exclude) const588 void Config::diff(const Config* other, Properties& diff,
589                   const unsigned* exclude) const {
590 
591   if (include_section(exclude, CFG_SECTION_SYSTEM)) {
592     diff_system(this, other, diff);
593     diff_system(other, this, diff);
594   }
595   if (include_section(exclude, CFG_SECTION_NODE)) {
596     diff_nodes(this, other, diff);
597     diff_nodes(other, this, diff);
598   }
599   if (include_section(exclude, CFG_SECTION_CONNECTION)) {
600     diff_connections(this, other, diff);
601     diff_connections(other, this, diff);
602   }
603 }
604 
605 
606 static const char*
p2s(const Properties * prop,const char * name,BaseString & buf)607 p2s(const Properties* prop, const char* name, BaseString& buf){
608   PropertiesType type;
609   require(prop->getTypeOf(name, &type));
610   switch(type){
611   case PropertiesType_Uint32:
612   {
613     Uint32 val;
614     require(prop->get(name, &val));
615     buf.assfmt("%u", val);
616     break;
617   }
618   case PropertiesType_Uint64:
619   {
620     Uint64 val;
621     require(prop->get(name, &val));
622     buf.assfmt("%llu", val);
623     break;
624   }
625   case PropertiesType_char:
626   {
627     require(prop->get(name, buf));
628     break;
629   }
630   default:
631     require(false);
632     break;
633   }
634   return buf.c_str();
635 }
636 
637 
638 const char*
diff2str(const Properties & diff_list,BaseString & str) const639 Config::diff2str(const Properties& diff_list, BaseString& str) const
640 {
641   const char* name;
642   Properties::Iterator prop_it(&diff_list);
643   while ((name= prop_it.next())){
644 
645     const Properties *node;
646     require(diff_list.get(name, &node));
647 
648     require(node->get("Name", &name));
649     str.appfmt("[%s]\n", name);
650 
651     BaseString key;
652     require(node->get("Key", key));
653     if (key.length() > 0){
654       Vector<BaseString> keys;
655       key.split(keys, ";");
656       for (unsigned i= 0; i < keys.size(); i++)
657         str.appfmt("%s\n", keys[i].c_str());
658     }
659 
660     BaseString buf;
661     Properties::Iterator prop_it2(node);
662     while ((name= prop_it2.next())){
663 
664       const Properties *what;
665       if (!node->get(name, &what))
666         continue;
667 
668       Uint32 type;
669       require(what->get("Type", &type));
670       require(what->get("Name", &name));
671       switch (type) {
672       case DT_DIFF:
673       {
674         str.appfmt("-%s=%s\n", name, p2s(what, "Old", buf));
675         str.appfmt("+%s=%s\n", name, p2s(what, "New", buf));
676         break;
677       }
678 
679       case DT_MISSING_VALUE:
680       {
681         str.appfmt("-%s=%s\n", name, p2s(what, "Old", buf));
682         break;
683       }
684 
685       case DT_MISSING_SECTION:
686       {
687         const char* why;
688         if (what->get("Why", &why))
689           str.appfmt("%s\n", why);
690         break;
691       }
692 
693       case DT_ILLEGAL_CHANGE:
694       {
695         const char* why;
696         str.appfmt("Illegal change\n");
697         if (what->get("Why", &why))
698           str.appfmt("%s\n", why);
699         break;
700       }
701 
702       default:
703         str.appfmt("Illegal 'type' found in diff_list\n");
704         require(false);
705         break;
706       }
707     }
708     str.appfmt("\n");
709   }
710   return str.c_str();
711 }
712 
713 
print_diff(const Config * other) const714 void Config::print_diff(const Config* other) const {
715   Properties diff_list;
716   diff(other, diff_list);
717   BaseString str;
718   ndbout_c("%s", diff2str(diff_list, str));
719 }
720 
721 
722 const char*
diff2str(const Config * other,BaseString & str,const unsigned * exclude) const723 Config::diff2str(const Config* other, BaseString& str, const unsigned * exclude) const {
724   Properties diff_list;
725   diff(other, diff_list, exclude);
726   return diff2str(diff_list, str);
727 }
728 
729 
equal(const Properties & diff_list) const730 bool Config::equal(const Properties& diff_list) const {
731   int count= 0;
732   Properties::Iterator prop_it(&diff_list);
733   while ((prop_it.next()))
734     count++;
735   return (count == 0);
736 }
737 
738 
equal(const Config * other,const unsigned * exclude) const739 bool Config::equal(const Config* other, const unsigned * exclude) const {
740   Properties diff_list;
741   diff(other, diff_list, exclude);
742   return equal(diff_list);
743 }
744 
745 
746 
illegal_change(const Properties & diff_list) const747 bool Config::illegal_change(const Properties& diff_list) const {
748   bool illegal= false;
749   const char* name;
750   Properties::Iterator prop_it(&diff_list);
751   while ((name= prop_it.next())){
752 
753     const Properties *node;
754     require(diff_list.get(name, &node));
755 
756     Properties::Iterator prop_it2(node);
757     while ((name= prop_it2.next())){
758 
759       const Properties *what;
760       if (!node->get(name, &what))
761         continue;
762 
763       Uint32 type;
764       require(what->get("Type", &type));
765       if (type == DT_ILLEGAL_CHANGE)
766       {
767         illegal= true;
768         break;
769       }
770     }
771   }
772   return illegal;
773 }
774 
775 
illegal_change(const Config * other) const776 bool Config::illegal_change(const Config* other) const {
777   Properties diff_list;
778   diff(other, diff_list);
779   return illegal_change(diff_list);
780 }
781 
782 
getConnectString(BaseString & connectstring,const BaseString & separator) const783 void Config::getConnectString(BaseString& connectstring,
784                               const BaseString& separator) const
785 {
786   bool first= true;
787   ConfigIter it(this, CFG_SECTION_NODE);
788 
789   for(;it.valid(); it.next())
790   {
791     /* Get type of Node */
792     Uint32 nodeType;
793     require(it.get(CFG_TYPE_OF_SECTION, &nodeType) == 0);
794 
795     if (nodeType != NODE_TYPE_MGM)
796       continue;
797 
798     Uint32 port;
799     const char* hostname;
800     require(it.get(CFG_NODE_HOST, &hostname) == 0);
801     require(it.get(CFG_MGM_PORT, &port) == 0);
802 
803     if (!first)
804       connectstring.append(separator);
805     first= false;
806 
807     connectstring.appfmt("%s:%d", hostname, port);
808 
809   }
810   ndbout << connectstring << endl;
811 }
812 
813 
814 void
get_nodemask(NodeBitmask & mask,ndb_mgm_node_type type) const815 Config::get_nodemask(NodeBitmask& mask,
816                      ndb_mgm_node_type type) const
817 {
818   mask.clear();
819   ConfigIter it(this, CFG_SECTION_NODE);
820   for (; it.valid(); it.next())
821   {
822     Uint32 node_type;
823     require(it.get(CFG_TYPE_OF_SECTION, &node_type) == 0);
824 
825     if (type == NDB_MGM_NODE_TYPE_UNKNOWN || // UNKOWN -> add all nodes to mask
826         type == (ndb_mgm_node_type)node_type)
827     {
828       Uint32 nodeid;
829       require(it.get(CFG_NODE_ID, &nodeid) == 0);
830       mask.set(nodeid);
831     }
832   }
833 }
834 
835 
836 Uint32
checksum(void) const837 Config::checksum(void) const {
838   Uint32 chk;
839 
840   UtilBuffer buf;
841   pack(buf);
842 
843   // Checksum is the last 4 bytes in buffer
844   const char* chk_ptr = (const char*)buf.get_data();
845   chk_ptr += buf.length() - sizeof(Uint32);
846   chk = *(Uint32*) chk_ptr;
847 
848   return chk;
849 }
850 
851