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