1 /*
2    Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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 <ndb_global.h>
26 #ifndef NDB_MGMAPI
27 
28 #include <NdbTCP.h>
29 #include "ConfigInfo.hpp"
30 #include <mgmapi_config_parameters.h>
31 #include <ndb_limits.h>
32 #include "InitConfigFileParser.hpp"
33 #include <m_string.h>
34 #include <Bitmask.hpp>
35 #include <ndb_opts.h>
36 #include <ndb_version.h>
37 
38 #else
39 #include "ConfigInfo.hpp"
40 #include <mgmapi_config_parameters.h>
41 #include <ndb_version.h>
42 #endif /* NDB_MGMAPI */
43 
44 #define KEY_INTERNAL 0
45 #define MAX_INT_RNIL 0xfffffeff
46 #define MAX_INT32 0xffffffff
47 #define MAX_PORT_NO 65535
48 
49 #define _STR_VALUE(x) #x
50 #define STR_VALUE(x) _STR_VALUE(x)
51 
52 /****************************************************************************
53  * Section names
54  ****************************************************************************/
55 
56 #define DB_TOKEN_PRINT  "ndbd(DB)"
57 #define MGM_TOKEN_PRINT "ndb_mgmd(MGM)"
58 #define API_TOKEN_PRINT "mysqld(API)"
59 
60 #define DB_TOKEN "DB"
61 #define MGM_TOKEN "MGM"
62 #define API_TOKEN "API"
63 
64 #ifndef NDB_MGMAPI
65 const ConfigInfo::AliasPair
66 ConfigInfo::m_sectionNameAliases[]={
67   {API_TOKEN, "MYSQLD"},
68   {DB_TOKEN,  "NDBD"},
69   {MGM_TOKEN, "NDB_MGMD"},
70   {0, 0}
71 };
72 
73 const char*
74 ConfigInfo::m_sectionNames[]={
75   "SYSTEM",
76   "COMPUTER",
77 
78   DB_TOKEN,
79   MGM_TOKEN,
80   API_TOKEN,
81 
82   "TCP",
83   "SCI",
84   "SHM"
85 };
86 const int ConfigInfo::m_noOfSectionNames =
87 sizeof(m_sectionNames)/sizeof(char*);
88 
89 /****************************************************************************
90  * Section Rules declarations
91  ****************************************************************************/
92 static bool transformComputer(InitConfigFileParser::Context & ctx, const char *);
93 static bool transformSystem(InitConfigFileParser::Context & ctx, const char *);
94 static bool transformNode(InitConfigFileParser::Context & ctx, const char *);
95 static bool checkConnectionSupport(InitConfigFileParser::Context & ctx, const char *);
96 static bool transformConnection(InitConfigFileParser::Context & ctx, const char *);
97 static bool uniqueConnection(InitConfigFileParser::Context & ctx, const char *);
98 static bool applyDefaultValues(InitConfigFileParser::Context & ctx, const char *);
99 static bool checkMandatory(InitConfigFileParser::Context & ctx, const char *);
100 static bool fixPortNumber(InitConfigFileParser::Context & ctx, const char *);
101 static bool fixShmKey(InitConfigFileParser::Context & ctx, const char *);
102 static bool checkDbConstraints(InitConfigFileParser::Context & ctx, const char *);
103 static bool checkConnectionConstraints(InitConfigFileParser::Context &, const char *);
104 static bool checkTCPConstraints(InitConfigFileParser::Context &, const char *);
105 static bool fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data);
106 static bool fixHostname(InitConfigFileParser::Context & ctx, const char * data);
107 static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data);
108 static bool fixDeprecated(InitConfigFileParser::Context & ctx, const char *);
109 static bool fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data);
110 static bool fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data);
111 static bool fixShmUniqueId(InitConfigFileParser::Context & ctx, const char * data);
112 static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const char * data);
113 static bool checkThreadPrioSpec(InitConfigFileParser::Context & ctx, const char * data);
114 static bool checkThreadConfig(InitConfigFileParser::Context & ctx, const char * data);
115 
116 const ConfigInfo::SectionRule
117 ConfigInfo::m_SectionRules[] = {
118   { "SYSTEM", transformSystem, 0 },
119   { "COMPUTER", transformComputer, 0 },
120 
121   { DB_TOKEN,   transformNode, 0 },
122   { API_TOKEN,  transformNode, 0 },
123   { MGM_TOKEN,  transformNode, 0 },
124 
125   { MGM_TOKEN,  fixShmUniqueId, 0 },
126 
127   { "TCP",  checkConnectionSupport, 0 },
128   { "SHM",  checkConnectionSupport, 0 },
129   { "SCI",  checkConnectionSupport, 0 },
130 
131   { "TCP",  transformConnection, 0 },
132   { "SHM",  transformConnection, 0 },
133   { "SCI",  transformConnection, 0 },
134 
135   { DB_TOKEN,   fixNodeHostname, 0 },
136   { API_TOKEN,  fixNodeHostname, 0 },
137   { MGM_TOKEN,  fixNodeHostname, 0 },
138 
139   { "TCP",  fixNodeId, "NodeId1" },
140   { "TCP",  fixNodeId, "NodeId2" },
141   { "SHM",  fixNodeId, "NodeId1" },
142   { "SHM",  fixNodeId, "NodeId2" },
143   { "SCI",  fixNodeId, "NodeId1" },
144   { "SCI",  fixNodeId, "NodeId2" },
145 
146   { "TCP",  uniqueConnection, "TCP" },
147   { "SHM",  uniqueConnection, "SHM" },
148   { "SCI",  uniqueConnection, "SCI" },
149 
150   { "TCP",  fixHostname, "HostName1" },
151   { "TCP",  fixHostname, "HostName2" },
152   { "SHM",  fixHostname, "HostName1" },
153   { "SHM",  fixHostname, "HostName2" },
154   { "SCI",  fixHostname, "HostName1" },
155   { "SCI",  fixHostname, "HostName2" },
156   { "SHM",  fixHostname, "HostName1" },
157   { "SHM",  fixHostname, "HostName2" },
158 
159   { "TCP",  fixPortNumber, 0 }, // has to come after fixHostName
160   { "SHM",  fixPortNumber, 0 }, // has to come after fixHostName
161   { "SCI",  fixPortNumber, 0 }, // has to come after fixHostName
162 
163   { "*",    applyDefaultValues, "user" },
164   { "*",    fixDeprecated, 0 },
165   { "*",    applyDefaultValues, "system" },
166 
167   { "SHM",  fixShmKey, 0 }, // has to come after apply default values
168 
169   { DB_TOKEN,   checkLocalhostHostnameMix, 0 },
170   { API_TOKEN,  checkLocalhostHostnameMix, 0 },
171   { MGM_TOKEN,  checkLocalhostHostnameMix, 0 },
172 
173   { DB_TOKEN,   fixFileSystemPath, 0 },
174   { DB_TOKEN,   fixBackupDataDir, 0 },
175 
176   { DB_TOKEN,   checkDbConstraints, 0 },
177   { DB_TOKEN,   checkThreadConfig, 0 },
178 
179   { API_TOKEN, checkThreadPrioSpec, 0 },
180   { MGM_TOKEN, checkThreadPrioSpec, 0 },
181 
182   { "TCP",  checkConnectionConstraints, 0 },
183   { "SHM",  checkConnectionConstraints, 0 },
184   { "SCI",  checkConnectionConstraints, 0 },
185 
186   { "TCP",  checkTCPConstraints, "HostName1" },
187   { "TCP",  checkTCPConstraints, "HostName2" },
188   { "SCI",  checkTCPConstraints, "HostName1" },
189   { "SCI",  checkTCPConstraints, "HostName2" },
190   { "SHM",  checkTCPConstraints, "HostName1" },
191   { "SHM",  checkTCPConstraints, "HostName2" },
192 
193   { "*",    checkMandatory, 0 }
194 };
195 const int ConfigInfo::m_NoOfRules = sizeof(m_SectionRules)/sizeof(SectionRule);
196 
197 /****************************************************************************
198  * Config Rules declarations
199  ****************************************************************************/
200 static bool add_system_section(Vector<ConfigInfo::ConfigRuleSection>&sections,
201                                struct InitConfigFileParser::Context &ctx,
202                                const char * rule_data);
203 static bool sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections,
204 			  struct InitConfigFileParser::Context &ctx,
205 			  const char * rule_data);
206 static bool add_node_connections(Vector<ConfigInfo::ConfigRuleSection>&sections,
207 				 struct InitConfigFileParser::Context &ctx,
208 				 const char * rule_data);
209 static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>&sections,
210 				 struct InitConfigFileParser::Context &ctx,
211 				 const char * rule_data);
212 static bool check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>&sections,
213 			    struct InitConfigFileParser::Context &ctx,
214 			    const char * rule_data);
215 static bool check_mutually_exclusive(Vector<ConfigInfo::ConfigRuleSection>&sections,
216                                      struct InitConfigFileParser::Context &ctx,
217                                      const char * rule_data);
218 
219 
220 static bool saveSectionsInConfigValues(Vector<ConfigInfo::ConfigRuleSection>&,
221                                        struct InitConfigFileParser::Context &,
222                                        const char * rule_data);
223 
224 const ConfigInfo::ConfigRule
225 ConfigInfo::m_ConfigRules[] = {
226   { add_system_section, 0 },
227   { sanity_checks, 0 },
228   { add_node_connections, 0 },
229   { set_connection_priorities, 0 },
230   { check_node_vs_replicas, 0 },
231   { check_mutually_exclusive, 0 },
232   { saveSectionsInConfigValues, "SYSTEM,Node,Connection" },
233   { 0, 0 }
234 };
235 
236 struct DeprecationTransform {
237   const char * m_section;
238   const char * m_oldName;
239   const char * m_newName;
240   double m_add;
241   double m_mul;
242 };
243 
244 static
245 const DeprecationTransform f_deprecation[] = {
246   { DB_TOKEN, "Discless", "Diskless", 0, 1 },
247   { DB_TOKEN, "Id", "NodeId", 0, 1 },
248   { API_TOKEN, "Id", "NodeId", 0, 1 },
249   { MGM_TOKEN, "Id", "NodeId", 0, 1 },
250   { 0, 0, 0, 0, 0}
251 };
252 #endif /* NDB_MGMAPI */
253 
254 static
255 const ConfigInfo::Typelib arbit_method_typelib[] = {
256   { "Disabled", ARBIT_METHOD_DISABLED },
257   { "Default", ARBIT_METHOD_DEFAULT },
258   { "WaitExternal", ARBIT_METHOD_WAITEXTERNAL },
259   { 0, 0 }
260 };
261 
262 static
263 const ConfigInfo::Typelib default_operation_redo_problem_action_typelib [] = {
264   { "abort", OPERATION_REDO_PROBLEM_ACTION_ABORT },
265   { "queue", OPERATION_REDO_PROBLEM_ACTION_QUEUE },
266   { 0, 0 }
267 };
268 
269 /**
270  * The default constructors create objects with suitable values for the
271  * configuration parameters.
272  *
273  * Some are however given the value MANDATORY which means that the value
274  * must be specified in the configuration file.
275  *
276  * Min and max values are also given for some parameters.
277  * - Attr1:  Name in file (initial config file)
278  * - Attr2:  Name in prop (properties object)
279  * - Attr3:  Name of Section (in init config file)
280  * - Attr4:  Updateable
281  * - Attr5:  Type of parameter (INT or BOOL)
282  * - Attr6:  Default Value (number only)
283  * - Attr7:  Min value
284  * - Attr8:  Max value
285  *
286  * Parameter constraints are coded in file Config.cpp.
287  *
288  * *******************************************************************
289  * Parameters used under development should be marked "NOTIMPLEMENTED"
290  * *******************************************************************
291  */
292 
293 const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
294 
295   /****************************************************************************
296    * COMPUTER
297    ***************************************************************************/
298   {
299     KEY_INTERNAL,
300     "COMPUTER",
301     "COMPUTER",
302     "Computer section",
303     ConfigInfo::CI_INTERNAL,
304     false,
305     ConfigInfo::CI_SECTION,
306     0,
307     0, 0 },
308 
309   {
310     KEY_INTERNAL,
311     "Id",
312     "COMPUTER",
313     "Name of computer",
314     ConfigInfo::CI_USED,
315     false,
316     ConfigInfo::CI_STRING,
317     MANDATORY,
318     0, 0 },
319 
320   {
321     KEY_INTERNAL,
322     "HostName",
323     "COMPUTER",
324     "Hostname of computer (e.g. mysql.com)",
325     ConfigInfo::CI_USED,
326     false,
327     ConfigInfo::CI_STRING,
328     MANDATORY,
329     0, 0 },
330 
331   {
332     KEY_INTERNAL,
333     "ByteOrder",
334     "COMPUTER",
335     0, // No new parameter to use instead of deprecated
336     ConfigInfo::CI_DEPRECATED,
337     false,
338     ConfigInfo::CI_STRING,
339     0,
340     0,
341     0 },
342 
343   /****************************************************************************
344    * SYSTEM
345    ***************************************************************************/
346   {
347     CFG_SECTION_SYSTEM,
348     "SYSTEM",
349     "SYSTEM",
350     "System section",
351     ConfigInfo::CI_USED,
352     false,
353     ConfigInfo::CI_SECTION,
354     (const char *)CFG_SECTION_SYSTEM,
355     0, 0 },
356 
357   {
358     CFG_SYS_NAME,
359     "Name",
360     "SYSTEM",
361     "Name of system (NDB Cluster)",
362     ConfigInfo::CI_USED,
363     false,
364     ConfigInfo::CI_STRING,
365     MANDATORY,
366     0, 0 },
367 
368   {
369     CFG_SYS_PRIMARY_MGM_NODE,
370     "PrimaryMGMNode",
371     "SYSTEM",
372     "Node id of Primary "MGM_TOKEN_PRINT" node",
373     ConfigInfo::CI_USED,
374     false,
375     ConfigInfo::CI_INT,
376     "0",
377     "0",
378     STR_VALUE(MAX_INT_RNIL) },
379 
380   /***************************************************************************
381    * DB
382    ***************************************************************************/
383 
384   {
385     CFG_SYS_CONFIG_GENERATION,
386     "ConfigGenerationNumber",
387     "SYSTEM",
388     "Configuration generation number",
389     ConfigInfo::CI_USED,
390     false,
391     ConfigInfo::CI_INT,
392     "0",
393     "0",
394     STR_VALUE(MAX_INT_RNIL) },
395 
396   /***************************************************************************
397    * DB
398    ***************************************************************************/
399   {
400     CFG_SECTION_NODE,
401     DB_TOKEN,
402     DB_TOKEN,
403     "[DB] section",
404     ConfigInfo::CI_USED,
405     false,
406     ConfigInfo::CI_SECTION,
407     (const char *)NODE_TYPE_DB,
408     0, 0
409   },
410 
411   {
412     CFG_DB_SUBSCRIPTIONS,
413     "MaxNoOfSubscriptions",
414     DB_TOKEN,
415     "Max no of subscriptions (default 0 == MaxNoOfTables)",
416     ConfigInfo::CI_USED,
417     false,
418     ConfigInfo::CI_INT,
419     "0",
420     "0",
421     STR_VALUE(MAX_INT_RNIL) },
422 
423   {
424     CFG_DB_SUBSCRIBERS,
425     "MaxNoOfSubscribers",
426     DB_TOKEN,
427     "Max no of subscribers (default 0 == 2 * MaxNoOfTables)",
428     ConfigInfo::CI_USED,
429     false,
430     ConfigInfo::CI_INT,
431     "0",
432     "0",
433     STR_VALUE(MAX_INT_RNIL) },
434 
435   {
436     CFG_DB_SUB_OPERATIONS,
437     "MaxNoOfConcurrentSubOperations",
438     DB_TOKEN,
439     "Max no of concurrent subscriber operations",
440     ConfigInfo::CI_USED,
441     false,
442     ConfigInfo::CI_INT,
443     "256",
444     "0",
445     STR_VALUE(MAX_INT_RNIL) },
446 
447   {
448     KEY_INTERNAL,
449     "TcpBind_INADDR_ANY",
450     DB_TOKEN,
451     "Bind IP_ADDR_ANY so that connections can be made from anywhere (for autogenerated connections)",
452     ConfigInfo::CI_USED,
453     false,
454     ConfigInfo::CI_BOOL,
455     "false",
456     "false",
457     "true"},
458 
459   {
460     CFG_NODE_HOST,
461     "HostName",
462     DB_TOKEN,
463     "Name of computer for this node",
464     ConfigInfo::CI_USED,
465     false,
466     ConfigInfo::CI_STRING,
467     "localhost",
468     0, 0 },
469 
470   {
471     CFG_NODE_SYSTEM,
472     "System",
473     DB_TOKEN,
474     "Name of system for this node",
475     ConfigInfo::CI_INTERNAL,
476     false,
477     ConfigInfo::CI_STRING,
478     0,
479     0, 0 },
480 
481   {
482     KEY_INTERNAL,
483     "Id",
484     DB_TOKEN,
485     "NodeId", // Name of new parameter to use instead of deprecated
486     ConfigInfo::CI_DEPRECATED,
487     false,
488     ConfigInfo::CI_INT,
489     MANDATORY,
490     "1",
491     STR_VALUE(MAX_DATA_NODE_ID) },
492 
493   {
494     CFG_NODE_ID,
495     "NodeId",
496     DB_TOKEN,
497     "Number identifying the database node ("DB_TOKEN_PRINT")",
498     ConfigInfo::CI_USED,
499     false,
500     ConfigInfo::CI_INT,
501     MANDATORY,
502     "1",
503     STR_VALUE(MAX_DATA_NODE_ID) },
504 
505   {
506     KEY_INTERNAL,
507     "ServerPort",
508     DB_TOKEN,
509     "Port used to setup transporter for incoming connections from API nodes",
510     ConfigInfo::CI_USED,
511     false,
512     ConfigInfo::CI_INT,
513     0,
514     "1",
515     STR_VALUE(MAX_PORT_NO) },
516 
517   {
518     CFG_DB_NO_REPLICAS,
519     "NoOfReplicas",
520     DB_TOKEN,
521     "Number of copies of all data in the database (1-4)",
522     ConfigInfo::CI_USED,
523     CI_RESTART_SYSTEM | CI_RESTART_INITIAL,
524     ConfigInfo::CI_INT,
525     "2",
526     "1",
527     "4" },
528 
529   {
530     CFG_DB_NO_ATTRIBUTES,
531     "MaxNoOfAttributes",
532     DB_TOKEN,
533     "Total number of attributes stored in database. I.e. sum over all tables",
534     ConfigInfo::CI_USED,
535     false,
536     ConfigInfo::CI_INT,
537     "1000",
538     "32",
539     STR_VALUE(MAX_INT_RNIL) },
540 
541   {
542     CFG_DB_NO_TABLES,
543     "MaxNoOfTables",
544     DB_TOKEN,
545     "Total number of tables stored in the database",
546     ConfigInfo::CI_USED,
547     false,
548     ConfigInfo::CI_INT,
549     "128",
550     "8",
551     STR_VALUE(NDB_MAX_TABLES) },
552 
553   {
554     CFG_DB_NO_ORDERED_INDEXES,
555     "MaxNoOfOrderedIndexes",
556     DB_TOKEN,
557     "Total number of ordered indexes that can be defined in the system",
558     ConfigInfo::CI_USED,
559     false,
560     ConfigInfo::CI_INT,
561     "128",
562     "0",
563     STR_VALUE(MAX_INT_RNIL) },
564 
565   {
566     CFG_DB_NO_UNIQUE_HASH_INDEXES,
567     "MaxNoOfUniqueHashIndexes",
568     DB_TOKEN,
569     "Total number of unique hash indexes that can be defined in the system",
570     ConfigInfo::CI_USED,
571     false,
572     ConfigInfo::CI_INT,
573     "64",
574     "0",
575     STR_VALUE(MAX_INT_RNIL) },
576 
577   {
578     CFG_DB_NO_INDEXES,
579     "MaxNoOfIndexes",
580     DB_TOKEN,
581     // The name of new parameter to use instead of deprecated
582     "MaxNoOfOrderedIndexes or MaxNoOfUniqueHashIndexes",
583     ConfigInfo::CI_DEPRECATED,
584     false,
585     ConfigInfo::CI_INT,
586     "128",
587     "0",
588     STR_VALUE(MAX_INT_RNIL) },
589 
590   {
591     CFG_DB_NO_INDEX_OPS,
592     "MaxNoOfConcurrentIndexOperations",
593     DB_TOKEN,
594     "Total number of index operations that can execute simultaneously on one "DB_TOKEN_PRINT" node",
595     ConfigInfo::CI_USED,
596     false,
597     ConfigInfo::CI_INT,
598     "8K",
599     "0",
600     STR_VALUE(MAX_INT_RNIL)
601    },
602 
603   {
604     CFG_DB_NO_TRIGGERS,
605     "MaxNoOfTriggers",
606     DB_TOKEN,
607     "Total number of triggers that can be defined in the system",
608     ConfigInfo::CI_USED,
609     false,
610     ConfigInfo::CI_INT,
611     "768",
612     "0",
613     STR_VALUE(MAX_INT_RNIL) },
614 
615   {
616     CFG_DB_NO_TRIGGER_OPS,
617     "MaxNoOfFiredTriggers",
618     DB_TOKEN,
619     "Total number of triggers that can fire simultaneously in one "DB_TOKEN_PRINT" node",
620     ConfigInfo::CI_USED,
621     false,
622     ConfigInfo::CI_INT,
623     "4000",
624     "0",
625     STR_VALUE(MAX_INT_RNIL) },
626 
627   {
628     KEY_INTERNAL,
629     "ExecuteOnComputer",
630     DB_TOKEN,
631     "String referencing an earlier defined COMPUTER",
632     ConfigInfo::CI_USED,
633     false,
634     ConfigInfo::CI_STRING,
635     0,
636     0, 0 },
637 
638   {
639     CFG_DB_NO_SAVE_MSGS,
640     "MaxNoOfSavedMessages",
641     DB_TOKEN,
642     "Max number of error messages in error log and max number of trace files",
643     ConfigInfo::CI_USED,
644     0,
645     ConfigInfo::CI_INT,
646     "25",
647     "0",
648     STR_VALUE(MAX_INT_RNIL) },
649 
650   {
651     CFG_DB_EXECUTE_LOCK_CPU,
652     "LockExecuteThreadToCPU",
653     DB_TOKEN,
654     "CPU list indicating which CPU will run the execution thread(s)",
655     ConfigInfo::CI_USED,
656     0,
657     ConfigInfo::CI_BITMASK,
658     0,
659     0,
660     "65535"
661   },
662 
663   {
664     CFG_DB_MAINT_LOCK_CPU,
665     "LockMaintThreadsToCPU",
666     DB_TOKEN,
667     "CPU ID indicating which CPU will run the maintenance threads",
668     ConfigInfo::CI_USED,
669     0,
670     ConfigInfo::CI_INT,
671     0,
672     "0",
673     "65535" },
674 
675   {
676     CFG_DB_REALTIME_SCHEDULER,
677     "RealtimeScheduler",
678     DB_TOKEN,
679     "If yes, then NDB Cluster threads will be scheduled as real-time threads",
680     ConfigInfo::CI_USED,
681     0,
682     ConfigInfo::CI_BOOL,
683     "false",
684     "false",
685     "true" },
686 
687   {
688     CFG_DB_MEMLOCK,
689     "LockPagesInMainMemory",
690     DB_TOKEN,
691     "If set to yes, then NDB Cluster data will not be swapped out to disk",
692     ConfigInfo::CI_USED,
693     0,
694     ConfigInfo::CI_INT,
695     "0",
696     "0",
697     "2" },
698 
699   {
700     CFG_DB_WATCHDOG_INTERVAL,
701     "TimeBetweenWatchDogCheck",
702     DB_TOKEN,
703     "Time between execution checks inside a database node",
704     ConfigInfo::CI_USED,
705     0,
706     ConfigInfo::CI_INT,
707     "6000",
708     "70",
709     STR_VALUE(MAX_INT_RNIL) },
710 
711   {
712     CFG_DB_SCHED_EXEC_TIME,
713     "SchedulerExecutionTimer",
714     DB_TOKEN,
715     "Number of microseconds to execute in scheduler before sending",
716     ConfigInfo::CI_USED,
717     false,
718     ConfigInfo::CI_INT,
719     "50",
720     "0",
721     "11000" },
722 
723   {
724     CFG_DB_SCHED_SPIN_TIME,
725     "SchedulerSpinTimer",
726     DB_TOKEN,
727     "Number of microseconds to execute in scheduler before sleeping",
728     ConfigInfo::CI_USED,
729     false,
730     ConfigInfo::CI_INT,
731     "0",
732     "0",
733     "500" },
734 
735   {
736     CFG_DB_WATCHDOG_INTERVAL_INITIAL,
737     "TimeBetweenWatchDogCheckInitial",
738     DB_TOKEN,
739     "Time between execution checks inside a database node in the early start phases when memory is allocated",
740     ConfigInfo::CI_USED,
741     0,
742     ConfigInfo::CI_INT,
743     "6000",
744     "70",
745     STR_VALUE(MAX_INT_RNIL) },
746 
747   {
748     CFG_DB_STOP_ON_ERROR,
749     "StopOnError",
750     DB_TOKEN,
751     "If set to N, "DB_TOKEN_PRINT" automatically restarts/recovers in case of node failure",
752     ConfigInfo::CI_USED,
753     0,
754     ConfigInfo::CI_BOOL,
755     "true",
756     "false",
757     "true" },
758 
759   {
760     CFG_DB_STOP_ON_ERROR_INSERT,
761     "RestartOnErrorInsert",
762     DB_TOKEN,
763     "See src/kernel/vm/Emulator.hpp NdbRestartType for details",
764     ConfigInfo::CI_INTERNAL,
765     0,
766     ConfigInfo::CI_INT,
767     "2",
768     "0",
769     "4" },
770 
771   {
772     CFG_DB_NO_OPS,
773     "MaxNoOfConcurrentOperations",
774     DB_TOKEN,
775     "Max number of operation records in transaction coordinator",
776     ConfigInfo::CI_USED,
777     false,
778     ConfigInfo::CI_INT,
779     "32k",
780     "32",
781     STR_VALUE(MAX_INT_RNIL) },
782 
783   {
784     CFG_DB_MAX_DML_OPERATIONS_PER_TRANSACTION,
785     "MaxDMLOperationsPerTransaction",
786     DB_TOKEN,
787     "Max DML-operations in one transaction (0 == no limit)",
788     ConfigInfo::CI_USED,
789     false,
790     ConfigInfo::CI_INT,
791     STR_VALUE(MAX_INT32),
792     "32",
793     STR_VALUE(MAX_INT32)
794   },
795 
796   {
797     CFG_DB_NO_LOCAL_OPS,
798     "MaxNoOfLocalOperations",
799     DB_TOKEN,
800     "Max number of operation records defined in the local storage node",
801     ConfigInfo::CI_USED,
802     false,
803     ConfigInfo::CI_INT,
804     0,
805     "32",
806     STR_VALUE(MAX_INT_RNIL) },
807 
808   {
809     CFG_DB_NO_LOCAL_SCANS,
810     "MaxNoOfLocalScans",
811     DB_TOKEN,
812     "Max number of fragment scans in parallel in the local storage node",
813     ConfigInfo::CI_USED,
814     false,
815     ConfigInfo::CI_INT,
816     0,
817     "32",
818     STR_VALUE(MAX_INT_RNIL) },
819 
820   {
821     CFG_DB_BATCH_SIZE,
822     "BatchSizePerLocalScan",
823     DB_TOKEN,
824     "Used to calculate the number of lock records for scan with hold lock",
825     ConfigInfo::CI_USED,
826     false,
827     ConfigInfo::CI_INT,
828     STR_VALUE(DEF_BATCH_SIZE),
829     "1",
830     STR_VALUE(MAX_PARALLEL_OP_PER_SCAN) },
831 
832   {
833     CFG_DB_NO_TRANSACTIONS,
834     "MaxNoOfConcurrentTransactions",
835     DB_TOKEN,
836     "Max number of transaction executing concurrently on the "DB_TOKEN_PRINT" node",
837     ConfigInfo::CI_USED,
838     false,
839     ConfigInfo::CI_INT,
840     "4096",
841     "32",
842     STR_VALUE(MAX_INT_RNIL) },
843 
844   {
845     CFG_DB_NO_SCANS,
846     "MaxNoOfConcurrentScans",
847     DB_TOKEN,
848     "Max number of scans executing concurrently on the "DB_TOKEN_PRINT" node",
849     ConfigInfo::CI_USED,
850     false,
851     ConfigInfo::CI_INT,
852     "256",
853     "2",
854     "500" },
855 
856   {
857     CFG_DB_TRANS_BUFFER_MEM,
858     "TransactionBufferMemory",
859     DB_TOKEN,
860     "Dynamic buffer space (in bytes) for key and attribute data allocated for each "DB_TOKEN_PRINT" node",
861     ConfigInfo::CI_USED,
862     false,
863     ConfigInfo::CI_INT,
864     "1M",
865     "1K",
866     STR_VALUE(MAX_INT_RNIL) },
867 
868   {
869     CFG_DB_INDEX_MEM,
870     "IndexMemory",
871     DB_TOKEN,
872     "Number bytes on each "DB_TOKEN_PRINT" node allocated for storing indexes",
873     ConfigInfo::CI_USED,
874     false,
875     ConfigInfo::CI_INT64,
876     "18M",
877     "1M",
878     "1024G" },
879 
880   {
881     CFG_DB_DATA_MEM,
882     "DataMemory",
883     DB_TOKEN,
884     "Number bytes on each "DB_TOKEN_PRINT" node allocated for storing data",
885     ConfigInfo::CI_USED,
886     false,
887     ConfigInfo::CI_INT64,
888     "80M",
889     "1M",
890     "1024G" },
891 
892   {
893     CFG_DB_UNDO_INDEX_BUFFER,
894     "UndoIndexBuffer",
895     DB_TOKEN,
896     "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing UNDO logs for index part",
897     ConfigInfo::CI_USED,
898     false,
899     ConfigInfo::CI_INT,
900     "2M",
901     "1M",
902     STR_VALUE(MAX_INT_RNIL)},
903 
904   {
905     CFG_DB_UNDO_DATA_BUFFER,
906     "UndoDataBuffer",
907     DB_TOKEN,
908     "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing UNDO logs for data part",
909     ConfigInfo::CI_USED,
910     false,
911     ConfigInfo::CI_INT,
912     "16M",
913     "1M",
914     STR_VALUE(MAX_INT_RNIL)},
915 
916   {
917     CFG_DB_REDO_BUFFER,
918     "RedoBuffer",
919     DB_TOKEN,
920     "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing REDO logs",
921     ConfigInfo::CI_USED,
922     false,
923     ConfigInfo::CI_INT,
924     "32M",
925     "1M",
926     STR_VALUE(MAX_INT_RNIL)},
927 
928   {
929     CFG_DB_LONG_SIGNAL_BUFFER,
930     "LongMessageBuffer",
931     DB_TOKEN,
932     "Number bytes on each "DB_TOKEN_PRINT" node allocated for internal long messages",
933     ConfigInfo::CI_USED,
934     false,
935     ConfigInfo::CI_INT,
936     "4M",
937     "512k",
938     STR_VALUE(MAX_INT_RNIL)},
939 
940   {
941     CFG_DB_DISK_PAGE_BUFFER_MEMORY,
942     "DiskPageBufferMemory",
943     DB_TOKEN,
944     "Number bytes on each "DB_TOKEN_PRINT" node allocated for disk page buffer cache",
945     ConfigInfo::CI_USED,
946     false,
947     ConfigInfo::CI_INT64,
948     "64M",
949     "4M",
950     "1024G" },
951 
952   {
953     CFG_DB_SGA,
954     "SharedGlobalMemory",
955     DB_TOKEN,
956     "Total number bytes on each "DB_TOKEN_PRINT" node allocated for any use",
957     ConfigInfo::CI_USED,
958     false,
959     ConfigInfo::CI_INT64,
960 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
961     "20M",
962 #else
963     "128M",
964 #endif
965     "0",
966     "65536G" }, // 32k pages * 32-bit i value
967 
968   {
969     CFG_DB_START_PARTIAL_TIMEOUT,
970     "StartPartialTimeout",
971     DB_TOKEN,
972     "Time to wait before trying to start wo/ all nodes. 0=Wait forever",
973     ConfigInfo::CI_USED,
974     0,
975     ConfigInfo::CI_INT,
976     "30000",
977     "0",
978     STR_VALUE(MAX_INT_RNIL) },
979 
980   {
981     CFG_DB_START_PARTITION_TIMEOUT,
982     "StartPartitionedTimeout",
983     DB_TOKEN,
984     "Time to wait before trying to start partitioned. 0=Wait forever",
985     ConfigInfo::CI_USED,
986     0,
987     ConfigInfo::CI_INT,
988     "60000",
989     "0",
990     STR_VALUE(MAX_INT_RNIL) },
991 
992   {
993     CFG_DB_START_FAILURE_TIMEOUT,
994     "StartFailureTimeout",
995     DB_TOKEN,
996     "Time to wait before terminating. 0=Wait forever",
997     ConfigInfo::CI_USED,
998     0,
999     ConfigInfo::CI_INT,
1000     "0",
1001     "0",
1002     STR_VALUE(MAX_INT_RNIL) },
1003 
1004   {
1005     CFG_DB_START_NO_NODEGROUP_TIMEOUT,
1006     "StartNoNodegroupTimeout",
1007     DB_TOKEN,
1008     "Time to wait for nodes wo/ nodegroup before trying to start (0=forever)",
1009     ConfigInfo::CI_USED,
1010     0,
1011     ConfigInfo::CI_INT,
1012     "15000",
1013     "0",
1014     STR_VALUE(MAX_INT_RNIL) },
1015 
1016   {
1017     CFG_DB_HEARTBEAT_INTERVAL,
1018     "HeartbeatIntervalDbDb",
1019     DB_TOKEN,
1020     "Time between "DB_TOKEN_PRINT"-"DB_TOKEN_PRINT" heartbeats. "DB_TOKEN_PRINT" considered dead after 3 missed HBs",
1021     ConfigInfo::CI_USED,
1022     0,
1023     ConfigInfo::CI_INT,
1024 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
1025     "1500",
1026 #else
1027     "5000",
1028 #endif
1029     "10",
1030     STR_VALUE(MAX_INT_RNIL) },
1031 
1032   {
1033     CFG_DB_CONNECT_CHECK_DELAY,
1034     "ConnectCheckIntervalDelay",
1035     DB_TOKEN,
1036     "Time between "DB_TOKEN_PRINT" connectivity check stages.  "DB_TOKEN_PRINT" considered suspect after 1 and dead after 2 intervals.",
1037     ConfigInfo::CI_USED,
1038     0,
1039     ConfigInfo::CI_INT,
1040     "0",
1041     "0",
1042     STR_VALUE(MAX_INT_RNIL) },
1043 
1044   {
1045     CFG_DB_API_HEARTBEAT_INTERVAL,
1046     "HeartbeatIntervalDbApi",
1047     DB_TOKEN,
1048     "Time between "API_TOKEN_PRINT"-"DB_TOKEN_PRINT" heartbeats. "API_TOKEN_PRINT" connection closed after 3 missed HBs",
1049     ConfigInfo::CI_USED,
1050     0,
1051     ConfigInfo::CI_INT,
1052     "1500",
1053     "100",
1054     STR_VALUE(MAX_INT_RNIL) },
1055 
1056   {
1057     CFG_DB_LCP_INTERVAL,
1058     "TimeBetweenLocalCheckpoints",
1059     DB_TOKEN,
1060     "Time between taking snapshots of the database (expressed in 2log of bytes)",
1061     ConfigInfo::CI_USED,
1062     0,
1063     ConfigInfo::CI_INT,
1064     "20",
1065     "0",
1066     "31" },
1067 
1068   {
1069     CFG_DB_GCP_INTERVAL,
1070     "TimeBetweenGlobalCheckpoints",
1071     DB_TOKEN,
1072     "Time between doing group commit of transactions to disk",
1073     ConfigInfo::CI_USED,
1074     0,
1075     ConfigInfo::CI_INT,
1076     "2000",
1077     "20",
1078     "32000" },
1079 
1080   {
1081     CFG_DB_MICRO_GCP_INTERVAL,
1082     "TimeBetweenEpochs",
1083     DB_TOKEN,
1084     "Time between epochs (syncronization used e.g for replication)",
1085     ConfigInfo::CI_USED,
1086     0,
1087     ConfigInfo::CI_INT,
1088     "100",
1089     "0",
1090     "32000" },
1091 
1092   {
1093     CFG_DB_MICRO_GCP_TIMEOUT,
1094     "TimeBetweenEpochsTimeout",
1095     DB_TOKEN,
1096     "Timeout for time between epochs.  Exceeding will cause node shutdown.",
1097     ConfigInfo::CI_USED,
1098     0,
1099     ConfigInfo::CI_INT,
1100 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
1101     "4000",
1102 #else
1103     "0",
1104 #endif
1105     "0",
1106     "256000" },
1107 
1108   {
1109     CFG_DB_MAX_BUFFERED_EPOCHS,
1110     "MaxBufferedEpochs",
1111     DB_TOKEN,
1112     "Allowed numbered of epochs that a subscribing node can lag behind (unprocessed epochs).  Exceeding will cause lagging subscribers to be disconnected.",
1113     ConfigInfo::CI_USED,
1114     0,
1115     ConfigInfo::CI_INT,
1116     "100",
1117     "0",
1118     "100000" },
1119 
1120   {
1121     CFG_DB_NO_REDOLOG_FILES,
1122     "NoOfFragmentLogFiles",
1123     DB_TOKEN,
1124     "No of 16 Mbyte Redo log files in each of 4 file sets belonging to "DB_TOKEN_PRINT" node",
1125     ConfigInfo::CI_USED,
1126     CI_RESTART_INITIAL,
1127     ConfigInfo::CI_INT,
1128     "16",
1129     "3",
1130     STR_VALUE(MAX_INT_RNIL) },
1131 
1132   {
1133     CFG_DB_REDOLOG_FILE_SIZE,
1134     "FragmentLogFileSize",
1135     DB_TOKEN,
1136     "Size of each Redo log file",
1137     ConfigInfo::CI_USED,
1138     CI_RESTART_INITIAL,
1139     ConfigInfo::CI_INT,
1140     "16M",
1141     "4M",
1142     "1G" },
1143 
1144   {
1145     CFG_DB_INIT_REDO,
1146     "InitFragmentLogFiles",
1147     DB_TOKEN,
1148     "Initialize fragment logfiles (sparse/full)",
1149     ConfigInfo::CI_USED,
1150     CI_RESTART_INITIAL,
1151     ConfigInfo::CI_STRING,
1152     0,
1153     0, 0 },
1154 
1155   {
1156     CFG_DB_THREAD_POOL,
1157     "DiskIOThreadPool",
1158     DB_TOKEN,
1159     "No of unbound threads for file access (currently only for DD)",
1160     ConfigInfo::CI_USED,
1161     false,
1162     ConfigInfo::CI_INT,
1163     "2",
1164     "0",
1165     STR_VALUE(MAX_INT_RNIL) },
1166 
1167   {
1168     CFG_DB_MAX_OPEN_FILES,
1169     "MaxNoOfOpenFiles",
1170     DB_TOKEN,
1171     "Max number of files open per "DB_TOKEN_PRINT" node.(One thread is created per file)",
1172     ConfigInfo::CI_USED,
1173     false,
1174     ConfigInfo::CI_INT,
1175     0,
1176     "20",
1177     STR_VALUE(MAX_INT_RNIL) },
1178 
1179   {
1180     CFG_DB_INITIAL_OPEN_FILES,
1181     "InitialNoOfOpenFiles",
1182     DB_TOKEN,
1183     "Initial number of files open per "DB_TOKEN_PRINT" node.(One thread is created per file)",
1184     ConfigInfo::CI_USED,
1185     false,
1186     ConfigInfo::CI_INT,
1187     "27",
1188     "20",
1189     STR_VALUE(MAX_INT_RNIL) },
1190 
1191   {
1192     CFG_DB_TRANSACTION_CHECK_INTERVAL,
1193     "TimeBetweenInactiveTransactionAbortCheck",
1194     DB_TOKEN,
1195     "Time between inactive transaction checks",
1196     ConfigInfo::CI_USED,
1197     0,
1198     ConfigInfo::CI_INT,
1199     "1000",
1200     "1000",
1201     STR_VALUE(MAX_INT_RNIL) },
1202 
1203   {
1204     CFG_DB_TRANSACTION_INACTIVE_TIMEOUT,
1205     "TransactionInactiveTimeout",
1206     DB_TOKEN,
1207     "Time application can wait before executing another transaction part (ms).\n"
1208     "This is the time the transaction coordinator waits for the application\n"
1209     "to execute or send another part (query, statement) of the transaction.\n"
1210     "If the application takes too long time, the transaction gets aborted.\n"
1211     "Timeout set to 0 means that we don't timeout at all on application wait.",
1212     ConfigInfo::CI_USED,
1213     0,
1214     ConfigInfo::CI_INT,
1215     STR_VALUE(MAX_INT_RNIL),
1216     "0",
1217     STR_VALUE(MAX_INT_RNIL) },
1218 
1219   {
1220     CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT,
1221     "TransactionDeadlockDetectionTimeout",
1222     DB_TOKEN,
1223     "Time transaction can be executing in a DB node (ms).\n"
1224     "This is the time the transaction coordinator waits for each database node\n"
1225     "of the transaction to execute a request. If the database node takes too\n"
1226     "long time, the transaction gets aborted.",
1227     ConfigInfo::CI_USED,
1228     0,
1229     ConfigInfo::CI_INT,
1230     "1200",
1231     "50",
1232     STR_VALUE(MAX_INT_RNIL) },
1233 
1234   {
1235     CFG_DB_LCP_DISC_PAGES_TUP_SR,
1236     "NoOfDiskPagesToDiskDuringRestartTUP",
1237     DB_TOKEN,
1238     "DiskCheckpointSpeedSr", // The new parameter name to use
1239     ConfigInfo::CI_DEPRECATED,
1240     0,
1241     ConfigInfo::CI_INT,
1242     "40",
1243     "1",
1244     STR_VALUE(MAX_INT_RNIL) },
1245 
1246   {
1247     CFG_DB_LCP_DISC_PAGES_TUP,
1248     "NoOfDiskPagesToDiskAfterRestartTUP",
1249     DB_TOKEN,
1250     "DiskCheckpointSpeed", // The new parameter name to use
1251     ConfigInfo::CI_DEPRECATED,
1252     0,
1253     ConfigInfo::CI_INT,
1254     "40",
1255     "1",
1256     STR_VALUE(MAX_INT_RNIL) },
1257 
1258   {
1259     CFG_DB_LCP_DISC_PAGES_ACC_SR,
1260     "NoOfDiskPagesToDiskDuringRestartACC",
1261     DB_TOKEN,
1262     "DiskCheckpointSpeedSr", // The new parameter name to use
1263     ConfigInfo::CI_DEPRECATED,
1264     0,
1265     ConfigInfo::CI_INT,
1266     "20",
1267     "1",
1268     STR_VALUE(MAX_INT_RNIL) },
1269 
1270   {
1271     CFG_DB_LCP_DISC_PAGES_ACC,
1272     "NoOfDiskPagesToDiskAfterRestartACC",
1273     DB_TOKEN,
1274     "DiskCheckpointSpeed",
1275     ConfigInfo::CI_DEPRECATED, // The new parameter name to use
1276     0,
1277     ConfigInfo::CI_INT,
1278     "20",
1279     "1",
1280     STR_VALUE(MAX_INT_RNIL) },
1281 
1282 
1283   {
1284     CFG_DB_DISCLESS,
1285     "Diskless",
1286     DB_TOKEN,
1287     "Run wo/ disk",
1288     ConfigInfo::CI_USED,
1289     CI_RESTART_INITIAL | CI_RESTART_SYSTEM,
1290     ConfigInfo::CI_BOOL,
1291     "false",
1292     "false",
1293     "true"},
1294 
1295   {
1296     KEY_INTERNAL,
1297     "Discless",
1298     DB_TOKEN,
1299     "Diskless", // The new parameter name to use
1300     ConfigInfo::CI_DEPRECATED,
1301     CI_RESTART_INITIAL | CI_RESTART_SYSTEM,
1302     ConfigInfo::CI_BOOL,
1303     "false",
1304     "false",
1305     "true"},
1306 
1307 
1308 
1309   {
1310     CFG_DB_ARBIT_TIMEOUT,
1311     "ArbitrationTimeout",
1312     DB_TOKEN,
1313     "Max time (milliseconds) database partion waits for arbitration signal",
1314     ConfigInfo::CI_USED,
1315     false,
1316     ConfigInfo::CI_INT,
1317 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
1318     "3000",
1319 #else
1320     "7500",
1321 #endif
1322     "10",
1323     STR_VALUE(MAX_INT_RNIL) },
1324 
1325   {
1326     CFG_DB_ARBIT_METHOD,
1327     "Arbitration",
1328     DB_TOKEN,
1329     "How to perform arbitration to avoid split-brain issue when node(s) fail",
1330     ConfigInfo::CI_USED,
1331     false,
1332     ConfigInfo::CI_ENUM,
1333     "Default", /* Default value */
1334     (const char*)arbit_method_typelib,
1335     0
1336   },
1337 
1338   {
1339     CFG_NODE_DATADIR,
1340     "DataDir",
1341     DB_TOKEN,
1342     "Data directory for this node",
1343     ConfigInfo::CI_USED,
1344     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1345     ConfigInfo::CI_STRING,
1346     ".",
1347     0, 0 },
1348 
1349   {
1350     CFG_DB_FILESYSTEM_PATH,
1351     "FileSystemPath",
1352     DB_TOKEN,
1353     "Path to directory where the "DB_TOKEN_PRINT" node stores its data (directory must exist)",
1354     ConfigInfo::CI_USED,
1355     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1356     ConfigInfo::CI_STRING,
1357     0,
1358     0, 0 },
1359 
1360   {
1361     CFG_LOGLEVEL_STARTUP,
1362     "LogLevelStartup",
1363     DB_TOKEN,
1364     "Node startup info printed on stdout",
1365     ConfigInfo::CI_USED,
1366     false,
1367     ConfigInfo::CI_INT,
1368     "1",
1369     "0",
1370     "15" },
1371 
1372   {
1373     CFG_LOGLEVEL_SHUTDOWN,
1374     "LogLevelShutdown",
1375     DB_TOKEN,
1376     "Node shutdown info printed on stdout",
1377     ConfigInfo::CI_USED,
1378     false,
1379     ConfigInfo::CI_INT,
1380     "0",
1381     "0",
1382     "15" },
1383 
1384   {
1385     CFG_LOGLEVEL_STATISTICS,
1386     "LogLevelStatistic",
1387     DB_TOKEN,
1388     "Transaction, operation, transporter info printed on stdout",
1389     ConfigInfo::CI_USED,
1390     false,
1391     ConfigInfo::CI_INT,
1392     "0",
1393     "0",
1394     "15" },
1395 
1396   {
1397     CFG_LOGLEVEL_CHECKPOINT,
1398     "LogLevelCheckpoint",
1399     DB_TOKEN,
1400     "Local and Global checkpoint info printed on stdout",
1401     ConfigInfo::CI_USED,
1402     false,
1403     ConfigInfo::CI_INT,
1404     "0",
1405     "0",
1406     "15" },
1407 
1408   {
1409     CFG_LOGLEVEL_NODERESTART,
1410     "LogLevelNodeRestart",
1411     DB_TOKEN,
1412     "Node restart, node failure info printed on stdout",
1413     ConfigInfo::CI_USED,
1414     false,
1415     ConfigInfo::CI_INT,
1416     "0",
1417     "0",
1418     "15" },
1419 
1420   {
1421     CFG_LOGLEVEL_CONNECTION,
1422     "LogLevelConnection",
1423     DB_TOKEN,
1424     "Node connect/disconnect info printed on stdout",
1425     ConfigInfo::CI_USED,
1426     false,
1427     ConfigInfo::CI_INT,
1428     "0",
1429     "0",
1430     "15" },
1431 
1432   {
1433     CFG_LOGLEVEL_CONGESTION,
1434     "LogLevelCongestion",
1435     DB_TOKEN,
1436     "Congestion info printed on stdout",
1437     ConfigInfo::CI_USED,
1438     false,
1439     ConfigInfo::CI_INT,
1440     "0",
1441     "0",
1442     "15" },
1443 
1444   {
1445     CFG_LOGLEVEL_ERROR,
1446     "LogLevelError",
1447     DB_TOKEN,
1448     "Transporter, heartbeat errors printed on stdout",
1449     ConfigInfo::CI_USED,
1450     false,
1451     ConfigInfo::CI_INT,
1452     "0",
1453     "0",
1454     "15" },
1455 
1456   {
1457     CFG_LOGLEVEL_INFO,
1458     "LogLevelInfo",
1459     DB_TOKEN,
1460     "Heartbeat and log info printed on stdout",
1461     ConfigInfo::CI_USED,
1462     false,
1463     ConfigInfo::CI_INT,
1464     "0",
1465     "0",
1466     "15" },
1467 
1468   /**
1469    * Backup
1470    */
1471   {
1472     CFG_DB_PARALLEL_BACKUPS,
1473     "ParallelBackups",
1474     DB_TOKEN,
1475     "Maximum number of parallel backups",
1476     ConfigInfo::CI_NOTIMPLEMENTED,
1477     false,
1478     ConfigInfo::CI_INT,
1479     "1",
1480     "1",
1481     "1" },
1482 
1483   {
1484     CFG_DB_BACKUP_DATADIR,
1485     "BackupDataDir",
1486     DB_TOKEN,
1487     "Path to where to store backups",
1488     ConfigInfo::CI_USED,
1489     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1490     ConfigInfo::CI_STRING,
1491     0,
1492     0, 0 },
1493 
1494   {
1495     CFG_DB_DISK_SYNCH_SIZE,
1496     "DiskSyncSize",
1497     DB_TOKEN,
1498     "Data written to a file before a synch is forced",
1499     ConfigInfo::CI_USED,
1500     false,
1501     ConfigInfo::CI_INT,
1502     "4M",
1503     "32k",
1504     STR_VALUE(MAX_INT_RNIL) },
1505 
1506   {
1507     CFG_DB_CHECKPOINT_SPEED,
1508     "DiskCheckpointSpeed",
1509     DB_TOKEN,
1510     "Bytes per second allowed to be written by checkpoint",
1511     ConfigInfo::CI_USED,
1512     false,
1513     ConfigInfo::CI_INT,
1514     "10M",
1515     "1M",
1516     STR_VALUE(MAX_INT_RNIL) },
1517 
1518   {
1519     CFG_DB_CHECKPOINT_SPEED_SR,
1520     "DiskCheckpointSpeedInRestart",
1521     DB_TOKEN,
1522     "Bytes per second allowed to be written by checkpoint during restart",
1523     ConfigInfo::CI_USED,
1524     false,
1525     ConfigInfo::CI_INT,
1526     "100M",
1527     "1M",
1528     STR_VALUE(MAX_INT_RNIL) },
1529 
1530   {
1531     CFG_DB_BACKUP_MEM,
1532     "BackupMemory",
1533     DB_TOKEN,
1534     "Total memory allocated for backups per node (in bytes)",
1535     ConfigInfo::CI_USED,
1536     false,
1537     ConfigInfo::CI_INT,
1538     "32M", // sum of BackupDataBufferSize and BackupLogBufferSize
1539     "0",
1540     STR_VALUE(MAX_INT_RNIL) },
1541 
1542   {
1543     CFG_DB_BACKUP_DATA_BUFFER_MEM,
1544     "BackupDataBufferSize",
1545     DB_TOKEN,
1546     "Default size of databuffer for a backup (in bytes)",
1547     ConfigInfo::CI_USED,
1548     false,
1549     ConfigInfo::CI_INT,
1550     "16M", // remember to change BackupMemory
1551     "0",
1552     STR_VALUE(MAX_INT_RNIL) },
1553 
1554   {
1555     CFG_DB_BACKUP_LOG_BUFFER_MEM,
1556     "BackupLogBufferSize",
1557     DB_TOKEN,
1558     "Default size of logbuffer for a backup (in bytes)",
1559     ConfigInfo::CI_USED,
1560     false,
1561     ConfigInfo::CI_INT,
1562     "16M", // remember to change BackupMemory
1563     "0",
1564     STR_VALUE(MAX_INT_RNIL) },
1565 
1566   {
1567     CFG_DB_BACKUP_WRITE_SIZE,
1568     "BackupWriteSize",
1569     DB_TOKEN,
1570     "Default size of filesystem writes made by backup (in bytes)",
1571     ConfigInfo::CI_USED,
1572     false,
1573     ConfigInfo::CI_INT,
1574     "256K",
1575     "2K",
1576     STR_VALUE(MAX_INT_RNIL) },
1577 
1578   {
1579     CFG_DB_BACKUP_MAX_WRITE_SIZE,
1580     "BackupMaxWriteSize",
1581     DB_TOKEN,
1582     "Max size of filesystem writes made by backup (in bytes)",
1583     ConfigInfo::CI_USED,
1584     false,
1585     ConfigInfo::CI_INT,
1586     "1M",
1587     "2K",
1588     STR_VALUE(MAX_INT_RNIL) },
1589 
1590   {
1591     CFG_DB_STRING_MEMORY,
1592     "StringMemory",
1593     DB_TOKEN,
1594     "Default size of string memory (1-100 -> %of max, >100 -> actual bytes)",
1595     ConfigInfo::CI_USED,
1596     false,
1597     ConfigInfo::CI_INT,
1598     "25",
1599     "0",
1600     STR_VALUE(MAX_INT_RNIL) },
1601 
1602   {
1603     CFG_DB_MAX_ALLOCATE,
1604     "MaxAllocate",
1605     DB_TOKEN,
1606     "Maximum size of allocation to use when allocating memory for tables",
1607     ConfigInfo::CI_USED,
1608     false,
1609     ConfigInfo::CI_INT,
1610     "32M",
1611     "1M",
1612     "1G" },
1613 
1614   {
1615     CFG_DB_MEMREPORT_FREQUENCY,
1616     "MemReportFrequency",
1617     DB_TOKEN,
1618     "Frequency of mem reports in seconds, 0 = only when passing %-limits",
1619     ConfigInfo::CI_USED,
1620     false,
1621     ConfigInfo::CI_INT,
1622     "0",
1623     "0",
1624     STR_VALUE(MAX_INT_RNIL) },
1625 
1626   {
1627     CFG_DB_BACKUP_REPORT_FREQUENCY,
1628     "BackupReportFrequency",
1629     DB_TOKEN,
1630     "Frequency of backup status reports during backup in seconds",
1631     ConfigInfo::CI_USED,
1632     false,
1633     ConfigInfo::CI_INT,
1634     "0",
1635     "0",
1636     STR_VALUE(MAX_INT_RNIL) },
1637 
1638    {
1639     CFG_DB_STARTUP_REPORT_FREQUENCY,
1640     "StartupStatusReportFrequency",
1641     DB_TOKEN,
1642     "Frequency of various status reports during startup in seconds",
1643     ConfigInfo::CI_USED,
1644     false,
1645     ConfigInfo::CI_INT,
1646     "0",
1647     "0",
1648     STR_VALUE(MAX_INT_RNIL) },
1649 
1650   {
1651     CFG_DB_O_DIRECT,
1652     "ODirect",
1653     DB_TOKEN,
1654     "Use O_DIRECT file write/read when possible",
1655     ConfigInfo::CI_USED,
1656     false,
1657     ConfigInfo::CI_BOOL,
1658     "false",
1659     "false",
1660     "true"},
1661   {
1662     CFG_DB_COMPRESSED_BACKUP,
1663     "CompressedBackup",
1664     DB_TOKEN,
1665     "Use zlib to compress BACKUPs as they are written",
1666     ConfigInfo::CI_USED,
1667     0,
1668     ConfigInfo::CI_BOOL,
1669     "false",
1670     "false",
1671     "true"},
1672   {
1673     CFG_DB_COMPRESSED_LCP,
1674     "CompressedLCP",
1675     DB_TOKEN,
1676     "Write compressed LCPs using zlib",
1677     ConfigInfo::CI_USED,
1678     CI_RESTART_INITIAL,
1679     ConfigInfo::CI_BOOL,
1680     "false",
1681     "false",
1682     "true"},
1683 
1684   {
1685     CFG_TOTAL_SEND_BUFFER_MEMORY,
1686     "TotalSendBufferMemory",
1687     DB_TOKEN,
1688     "Total memory to use for send buffers in all transporters",
1689     ConfigInfo::CI_USED,
1690     false,
1691     ConfigInfo::CI_INT,
1692     "0",
1693     "256K",
1694     STR_VALUE(MAX_INT_RNIL)
1695   },
1696 
1697   {
1698     CFG_RESERVED_SEND_BUFFER_MEMORY,
1699     "ReservedSendBufferMemory",
1700     DB_TOKEN,
1701     "Amount of bytes (out of TotalSendBufferMemory) to reserve for connection\n"
1702     "between data nodes. This memory will not be available for connections to\n"
1703     "management server or API nodes.",
1704     ConfigInfo::CI_USED,
1705     false,
1706     ConfigInfo::CI_INT,
1707     "0",
1708     "256K",
1709     STR_VALUE(MAX_INT_RNIL)
1710   },
1711 
1712   {
1713     CFG_DB_NODEGROUP,
1714     "Nodegroup",
1715     DB_TOKEN,
1716     "Nodegroup for node, only used during initial cluster start",
1717     ConfigInfo::CI_USED,
1718     false,
1719     ConfigInfo::CI_INT,
1720     0,
1721     "0",
1722     STR_VALUE(NDB_NO_NODEGROUP)
1723   },
1724 
1725   {
1726     CFG_DB_MT_THREADS,
1727     "MaxNoOfExecutionThreads",
1728     DB_TOKEN,
1729     "For ndbmtd, specify max no of execution threads",
1730     ConfigInfo::CI_USED,
1731     false,
1732     ConfigInfo::CI_INT,
1733     "0",
1734     "2",
1735     "8"
1736   },
1737 
1738   {
1739     CFG_NDBMT_LQH_WORKERS,
1740     "__ndbmt_lqh_workers",
1741     DB_TOKEN,
1742     "For ndbmtd specify no of lqh workers",
1743     ConfigInfo::CI_USED,
1744     false,
1745     ConfigInfo::CI_INT,
1746     0,
1747     "1",
1748     "4"
1749   },
1750 
1751   {
1752     CFG_NDBMT_LQH_THREADS,
1753     "__ndbmt_lqh_threads",
1754     DB_TOKEN,
1755     "For ndbmtd specify no of lqh threads",
1756     ConfigInfo::CI_USED,
1757     false,
1758     ConfigInfo::CI_INT,
1759     0,
1760     "1",
1761     "4"
1762   },
1763 
1764   {
1765     CFG_NDBMT_CLASSIC,
1766     "__ndbmt_classic",
1767     DB_TOKEN,
1768     "For ndbmtd use mt-classic",
1769     ConfigInfo::CI_USED,
1770     false,
1771     ConfigInfo::CI_BOOL,
1772     0,
1773     "false",
1774     "true"
1775   },
1776 
1777   {
1778     CFG_DB_MT_THREAD_CONFIG,
1779     "ThreadConfig",
1780     DB_TOKEN,
1781     "Thread configuration",
1782     ConfigInfo::CI_USED,
1783     false,
1784     ConfigInfo::CI_STRING,
1785     0,
1786     0,
1787     0
1788   },
1789 
1790   {
1791     CFG_DB_DD_FILESYSTEM_PATH,
1792     "FileSystemPathDD",
1793     DB_TOKEN,
1794     "Path to directory where the "DB_TOKEN_PRINT" node stores its disk-data/undo-files",
1795     ConfigInfo::CI_USED,
1796     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1797     ConfigInfo::CI_STRING,
1798     0,
1799     0, 0 },
1800 
1801   {
1802     CFG_DB_DD_DATAFILE_PATH,
1803     "FileSystemPathDataFiles",
1804     DB_TOKEN,
1805     "Path to directory where the "DB_TOKEN_PRINT" node stores its disk-data-files",
1806     ConfigInfo::CI_USED,
1807     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1808     ConfigInfo::CI_STRING,
1809     0,
1810     0, 0 },
1811 
1812   {
1813     CFG_DB_DD_UNDOFILE_PATH,
1814     "FileSystemPathUndoFiles",
1815     DB_TOKEN,
1816     "Path to directory where the "DB_TOKEN_PRINT" node stores its disk-undo-files",
1817     ConfigInfo::CI_USED,
1818     CI_CHECK_WRITABLE | CI_RESTART_INITIAL,
1819     ConfigInfo::CI_STRING,
1820     0,
1821     0, 0 },
1822 
1823   {
1824     CFG_DB_DD_LOGFILEGROUP_SPEC,
1825     "InitialLogfileGroup",
1826     DB_TOKEN,
1827     "Logfile group that will be created during initial start",
1828     ConfigInfo::CI_USED,
1829     CI_RESTART_SYSTEM | CI_RESTART_INITIAL,
1830     ConfigInfo::CI_STRING,
1831     0,
1832     0, 0 },
1833 
1834   {
1835     CFG_DB_DD_TABLEPACE_SPEC,
1836     "InitialTablespace",
1837     DB_TOKEN,
1838     "Tablespace that will be created during initial start",
1839     ConfigInfo::CI_USED,
1840     CI_RESTART_SYSTEM | CI_RESTART_INITIAL,
1841     ConfigInfo::CI_STRING,
1842     0,
1843     0, 0 },
1844 
1845   {
1846     CFG_DB_LCP_TRY_LOCK_TIMEOUT,
1847     "MaxLCPStartDelay",
1848     DB_TOKEN,
1849     "Time in seconds that LCP will poll for checkpoint mutex, before putting it self in lock-queue",
1850     ConfigInfo::CI_USED,
1851     false,
1852     ConfigInfo::CI_INT,
1853     "0",
1854     "0",
1855     "600" },
1856 
1857 // 7.0 NodeGroup -> initial, system
1858 
1859   {
1860     CFG_DB_MT_BUILD_INDEX,
1861     "BuildIndexThreads",
1862     DB_TOKEN,
1863     "No of threads to use for building ordered indexes during system/node restart",
1864     ConfigInfo::CI_USED,
1865     false,
1866     ConfigInfo::CI_INT,
1867     "0",
1868     "0",
1869     "128" },
1870 
1871   {
1872     CFG_DB_HB_ORDER,
1873     "HeartbeatOrder",
1874     DB_TOKEN,
1875     "Heartbeat circle is ordered by the given values "
1876     "which must be non-zero and distinct",
1877     ConfigInfo::CI_USED,
1878     false,
1879     ConfigInfo::CI_INT,
1880     "0",
1881     "0",
1882     "65535" },
1883 
1884   {
1885     CFG_DB_DICT_TRACE,
1886     "DictTrace",
1887     DB_TOKEN,
1888     "Tracelevel for ndbd's dictionary",
1889     ConfigInfo::CI_USED,
1890     false,
1891     ConfigInfo::CI_INT,
1892     0,
1893     "0",
1894     "100" },
1895 
1896   {
1897     CFG_DB_MAX_START_FAIL,
1898     "MaxStartFailRetries",
1899     DB_TOKEN,
1900     "Maximum retries when Ndbd fails in startup, requires StopOnError=0.  "
1901     "0 is infinite.",
1902     ConfigInfo::CI_USED,
1903     false,
1904     ConfigInfo::CI_INT,
1905     "3",                      /* Default */
1906     "0",                      /* Min */
1907     STR_VALUE(MAX_INT_RNIL)   /* Max */
1908   },
1909 
1910   {
1911     CFG_DB_START_FAIL_DELAY_SECS,
1912     "StartFailRetryDelay",
1913     DB_TOKEN,
1914     "Delay in seconds after start failure prior to retry.  "
1915     "Requires StopOnError= 0",
1916     ConfigInfo::CI_USED,
1917     false,
1918     ConfigInfo::CI_INT,
1919     "0",                     /* Default */
1920     "0",                     /* Min */
1921     STR_VALUE(MAX_INT_RNIL)  /* Max */
1922   },
1923 
1924   {
1925     CFG_DB_EVENTLOG_BUFFER_SIZE,
1926     "EventLogBufferSize",
1927     DB_TOKEN,
1928     "Size of circular buffer of ndb_logevent (inside datanodes)",
1929     ConfigInfo::CI_USED,
1930     false,
1931     ConfigInfo::CI_INT,
1932     "4096",                  /* Default */
1933     "0",                     /* Min */
1934     "64k"                    /* Max : There is no flow control...so set limit*/
1935   },
1936 
1937   {
1938     CFG_DB_NUMA,
1939     "Numa",
1940     DB_TOKEN,
1941     "Enable/disable numa support (currently linux only)",
1942     ConfigInfo::CI_USED,
1943     false,
1944     ConfigInfo::CI_INT,
1945     "1",                     /* Interleave on all numa nodes */
1946     "0",                     /* Min (no numa action at all)  */
1947     "1"                      /* Max */
1948   },
1949 
1950   {
1951     CFG_DB_REDO_OVERCOMMIT_LIMIT,
1952     "RedoOverCommitLimit",
1953     DB_TOKEN,
1954     "Limit for how long it will take to flush current "
1955     "RedoBuffer before action is taken (in seconds)",
1956     ConfigInfo::CI_USED,
1957     false,
1958     ConfigInfo::CI_INT,
1959     "20",                    /* Default */
1960     "0",                     /* Min */
1961     STR_VALUE(MAX_INT_RNIL)  /* Max */
1962   },
1963 
1964   {
1965     CFG_DB_REDO_OVERCOMMIT_COUNTER,
1966     "RedoOverCommitCounter",
1967     DB_TOKEN,
1968     "If RedoOverCommitLimit has been reached RedoOverCommitCounter"
1969     " in a row times, transactions will be aborted",
1970     ConfigInfo::CI_USED,
1971     false,
1972     ConfigInfo::CI_INT,
1973     "3",                     /* Default */
1974     "0",                     /* Min */
1975     STR_VALUE(MAX_INT_RNIL)  /* Max */
1976   },
1977 
1978   {
1979     CFG_DB_LATE_ALLOC,
1980     "LateAlloc",
1981     DB_TOKEN,
1982     "Allocate memory after connection to ndb_mgmd has been established",
1983     ConfigInfo::CI_USED,
1984     false,
1985     ConfigInfo::CI_INT,
1986     "1",
1987     "0",                     /* Min */
1988     "1"                      /* Max */
1989   },
1990 
1991 
1992   {
1993     CFG_DB_2PASS_INR,
1994     "TwoPassInitialNodeRestartCopy",
1995     DB_TOKEN,
1996     "Copy data in 2 passes for initial node restart, "
1997     "this enables multi-threaded-ordered index build for initial node restart",
1998     ConfigInfo::CI_USED,
1999     false,
2000     ConfigInfo::CI_BOOL,
2001     "false",
2002     "false",                     /* Min */
2003     "true"                       /* Max */
2004   },
2005 
2006   {
2007     CFG_DB_PARALLEL_SCANS_PER_FRAG,
2008     "MaxParallelScansPerFragment",
2009     DB_TOKEN,
2010     "Max parallel scans per fragment (tup or tux). If this limit is reached "
2011     " scans will be serialized using a queue.",
2012     ConfigInfo::CI_USED,
2013     false,
2014     ConfigInfo::CI_INT,
2015 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
2016     "32",
2017 #else
2018     "256",
2019 #endif
2020     "1",                         /* Min */
2021     STR_VALUE(MAX_INT_RNIL)      /* Max */
2022   },
2023 
2024   /* ordered index stats */
2025 
2026   {
2027     CFG_DB_INDEX_STAT_AUTO_CREATE,
2028     "IndexStatAutoCreate",
2029     DB_TOKEN,
2030     "Make create index also create initial index stats",
2031     ConfigInfo::CI_USED,
2032     0,
2033     ConfigInfo::CI_INT,
2034     "0",
2035     "0",
2036     "1"
2037   },
2038 
2039   {
2040     CFG_DB_INDEX_STAT_AUTO_UPDATE,
2041     "IndexStatAutoUpdate",
2042     DB_TOKEN,
2043     "Monitor each index for changes and trigger automatic stats updates."
2044     " See IndexStatTrigger options",
2045     ConfigInfo::CI_USED,
2046     0,
2047     ConfigInfo::CI_INT,
2048     "0",
2049     "0",
2050     "1"
2051   },
2052 
2053   {
2054     CFG_DB_INDEX_STAT_SAVE_SIZE,
2055     "IndexStatSaveSize",
2056     DB_TOKEN,
2057     "Maximum bytes allowed for the saved stats of one index."
2058     " At least 1 sample is produced regardless of size limit."
2059     " The size is scaled up by a factor from IndexStatSaveScale."
2060     " The value affects size of stats saved in NDB system tables"
2061     " and in mysqld memory cache",
2062     ConfigInfo::CI_USED,
2063     0,
2064     ConfigInfo::CI_INT,
2065     "32768",
2066     "0",
2067     STR_VALUE(MAX_INT_RNIL)
2068   },
2069 
2070   {
2071     CFG_DB_INDEX_STAT_SAVE_SCALE,
2072     "IndexStatSaveScale",
2073     DB_TOKEN,
2074     "Factor to scale up IndexStatSaveSize for a large index."
2075     " Given in units of 0.01."
2076     " Multiplied by a logarithmic index size."
2077     " Value 0 disables scaling",
2078     ConfigInfo::CI_USED,
2079     0,
2080     ConfigInfo::CI_INT,
2081     "100",
2082     "0",
2083     STR_VALUE(MAX_INT_RNIL)
2084   },
2085 
2086   {
2087     CFG_DB_INDEX_STAT_TRIGGER_PCT,
2088     "IndexStatTriggerPct",
2089     DB_TOKEN,
2090     "Percent change (in DML ops) to schedule index stats update."
2091     " The value is scaled down by a factor from IndexStatTriggerScale."
2092     " Value 0 disables the trigger",
2093     ConfigInfo::CI_USED,
2094     0,
2095     ConfigInfo::CI_INT,
2096     "100",
2097     "0",
2098     STR_VALUE(MAX_INT_RNIL)
2099   },
2100 
2101   {
2102     CFG_DB_INDEX_STAT_TRIGGER_SCALE,
2103     "IndexStatTriggerScale",
2104     DB_TOKEN,
2105     "Factor to scale down IndexStatTriggerPct for a large index."
2106     " Given in units of 0.01."
2107     " Multiplied by a logarithmic index size."
2108     " Value 0 disables scaling",
2109     ConfigInfo::CI_USED,
2110     0,
2111     ConfigInfo::CI_INT,
2112     "100",
2113     "0",
2114     STR_VALUE(MAX_INT_RNIL)
2115   },
2116 
2117   {
2118     CFG_DB_INDEX_STAT_UPDATE_DELAY,
2119     "IndexStatUpdateDelay",
2120     DB_TOKEN,
2121     "Minimum delay in seconds between automatic index stats updates"
2122     " for a given index."
2123     " Value 0 means no delay",
2124     ConfigInfo::CI_USED,
2125     0,
2126     ConfigInfo::CI_INT,
2127     "60",
2128     "0",
2129     STR_VALUE(MAX_INT_RNIL)
2130   },
2131 
2132   /***************************************************************************
2133    * API
2134    ***************************************************************************/
2135   {
2136     CFG_SECTION_NODE,
2137     API_TOKEN,
2138     API_TOKEN,
2139     "Node section",
2140     ConfigInfo::CI_USED,
2141     false,
2142     ConfigInfo::CI_SECTION,
2143     (const char *)NODE_TYPE_API,
2144     0, 0
2145   },
2146 
2147   {
2148     KEY_INTERNAL,
2149     "wan",
2150     API_TOKEN,
2151     "Use WAN TCP setting as default",
2152     ConfigInfo::CI_USED,
2153     false,
2154     ConfigInfo::CI_BOOL,
2155     "false",
2156     "false",
2157     "true"
2158   },
2159 
2160   {
2161     CFG_NODE_HOST,
2162     "HostName",
2163     API_TOKEN,
2164     "Name of computer for this node",
2165     ConfigInfo::CI_USED,
2166     false,
2167     ConfigInfo::CI_STRING,
2168     "",
2169     0, 0 },
2170 
2171   {
2172     CFG_NODE_SYSTEM,
2173     "System",
2174     API_TOKEN,
2175     "Name of system for this node",
2176     ConfigInfo::CI_INTERNAL,
2177     false,
2178     ConfigInfo::CI_STRING,
2179     0,
2180     0, 0 },
2181 
2182   {
2183     KEY_INTERNAL,
2184     "Id",
2185     API_TOKEN,
2186     "NodeId", // Name of new parameter to use instead of deprecated
2187     ConfigInfo::CI_DEPRECATED,
2188     false,
2189     ConfigInfo::CI_INT,
2190     MANDATORY,
2191     "1",
2192     STR_VALUE(MAX_NODES_ID) },
2193 
2194   {
2195     CFG_NODE_ID,
2196     "NodeId",
2197     API_TOKEN,
2198     "Number identifying application node ("API_TOKEN_PRINT")",
2199     ConfigInfo::CI_USED,
2200     false,
2201     ConfigInfo::CI_INT,
2202     MANDATORY,
2203     "1",
2204     STR_VALUE(MAX_NODES_ID) },
2205 
2206   {
2207     KEY_INTERNAL,
2208     "ExecuteOnComputer",
2209     API_TOKEN,
2210     "String referencing an earlier defined COMPUTER",
2211     ConfigInfo::CI_USED,
2212     false,
2213     ConfigInfo::CI_STRING,
2214     0,
2215     0, 0 },
2216 
2217   {
2218     CFG_NODE_ARBIT_RANK,
2219     "ArbitrationRank",
2220     API_TOKEN,
2221     "If 0, then "API_TOKEN_PRINT" is not arbitrator. Kernel selects arbitrators in order 1, 2",
2222     ConfigInfo::CI_USED,
2223     false,
2224     ConfigInfo::CI_INT,
2225     "0",
2226     "0",
2227     "2" },
2228 
2229   {
2230     CFG_NODE_ARBIT_DELAY,
2231     "ArbitrationDelay",
2232     API_TOKEN,
2233     "When asked to arbitrate, arbitrator waits this long before voting (msec)",
2234     ConfigInfo::CI_USED,
2235     0,
2236     ConfigInfo::CI_INT,
2237     "0",
2238     "0",
2239     STR_VALUE(MAX_INT_RNIL) },
2240 
2241   {
2242     CFG_MAX_SCAN_BATCH_SIZE,
2243     "MaxScanBatchSize",
2244     "API",
2245     "The maximum collective batch size for one scan",
2246     ConfigInfo::CI_USED,
2247     false,
2248     ConfigInfo::CI_INT,
2249     STR_VALUE(MAX_SCAN_BATCH_SIZE),
2250     "32k",
2251     "16M" },
2252 
2253   {
2254     CFG_BATCH_BYTE_SIZE,
2255     "BatchByteSize",
2256     "API",
2257     "The default batch size in bytes",
2258     ConfigInfo::CI_USED,
2259     false,
2260     ConfigInfo::CI_INT,
2261     STR_VALUE(SCAN_BATCH_SIZE),
2262     "1k",
2263     "1M" },
2264 
2265   {
2266     CFG_BATCH_SIZE,
2267     "BatchSize",
2268     "API",
2269     "The default batch size in number of records",
2270     ConfigInfo::CI_USED,
2271     false,
2272     ConfigInfo::CI_INT,
2273     STR_VALUE(DEF_BATCH_SIZE),
2274     "1",
2275     STR_VALUE(MAX_PARALLEL_OP_PER_SCAN) },
2276 
2277   {
2278     KEY_INTERNAL,
2279     "ConnectionMap",
2280     "API",
2281     "Specifies which DB nodes to connect",
2282     ConfigInfo::CI_USED,
2283     false,
2284     ConfigInfo::CI_STRING,
2285     0,
2286     0,
2287     0
2288   },
2289 
2290   {
2291     CFG_TOTAL_SEND_BUFFER_MEMORY,
2292     "TotalSendBufferMemory",
2293     "API",
2294     "Total memory to use for send buffers in all transporters",
2295     ConfigInfo::CI_USED,
2296     false,
2297     ConfigInfo::CI_INT,
2298     "0",
2299     "256K",
2300     STR_VALUE(MAX_INT_RNIL)
2301   },
2302 
2303   {
2304     CFG_AUTO_RECONNECT,
2305     "AutoReconnect",
2306     "API",
2307     "Specifies if an api node should reconnect when fully disconnected from cluster",
2308     ConfigInfo::CI_USED,
2309     false,
2310     ConfigInfo::CI_BOOL,
2311     "true",
2312     "false",
2313     "true"
2314   },
2315 
2316   {
2317     CFG_HB_THREAD_PRIO,
2318     "HeartbeatThreadPriority",
2319     API_TOKEN,
2320     "Specify thread properties of heartbeat thread",
2321     ConfigInfo::CI_USED,
2322     0,
2323     ConfigInfo::CI_STRING,
2324     0, 0, 0 },
2325 
2326   {
2327     CFG_DEFAULT_OPERATION_REDO_PROBLEM_ACTION,
2328     "DefaultOperationRedoProblemAction",
2329     API_TOKEN,
2330     "If Redo-log is having problem, should operation default "
2331     "(unless overridden on transaction/operation level) abort "
2332     "or be put on queue",
2333     ConfigInfo::CI_USED,
2334     false,
2335     ConfigInfo::CI_ENUM,
2336 #if NDB_VERSION_D < NDB_MAKE_VERSION(7,2,0)
2337     "abort", /* Default value */
2338 #else
2339     "queue", /* Default value */
2340 #endif
2341     (const char*)default_operation_redo_problem_action_typelib,
2342     0
2343   },
2344 
2345   /****************************************************************************
2346    * MGM
2347    ***************************************************************************/
2348   {
2349     CFG_SECTION_NODE,
2350     MGM_TOKEN,
2351     MGM_TOKEN,
2352     "Node section",
2353     ConfigInfo::CI_USED,
2354     false,
2355     ConfigInfo::CI_SECTION,
2356     (const char *)NODE_TYPE_MGM,
2357     0, 0
2358   },
2359 
2360   {
2361     KEY_INTERNAL,
2362     "wan",
2363     MGM_TOKEN,
2364     "Use WAN TCP setting as default",
2365     ConfigInfo::CI_USED,
2366     false,
2367     ConfigInfo::CI_BOOL,
2368     "false",
2369     "false",
2370     "true"
2371   },
2372 
2373   {
2374     CFG_NODE_HOST,
2375     "HostName",
2376     MGM_TOKEN,
2377     "Name of computer for this node",
2378     ConfigInfo::CI_USED,
2379     false,
2380     ConfigInfo::CI_STRING,
2381     "",
2382     0, 0 },
2383 
2384   {
2385     CFG_NODE_DATADIR,
2386     "DataDir",
2387     MGM_TOKEN,
2388     "Data directory for this node",
2389     ConfigInfo::CI_USED,
2390     CI_CHECK_WRITABLE,
2391     ConfigInfo::CI_STRING,
2392     "",
2393     0, 0 },
2394 
2395   {
2396     CFG_NODE_SYSTEM,
2397     "System",
2398     MGM_TOKEN,
2399     "Name of system for this node",
2400     ConfigInfo::CI_INTERNAL,
2401     false,
2402     ConfigInfo::CI_STRING,
2403     0,
2404     0, 0 },
2405 
2406   {
2407     KEY_INTERNAL,
2408     "Id",
2409     MGM_TOKEN,
2410     "NodeId", // Name of new parameter to use instead of deprecated
2411     ConfigInfo::CI_DEPRECATED,
2412     false,
2413     ConfigInfo::CI_INT,
2414     MANDATORY,
2415     "1",
2416     STR_VALUE(MAX_NODES_ID) },
2417 
2418   {
2419     CFG_NODE_ID,
2420     "NodeId",
2421     MGM_TOKEN,
2422     "Number identifying the management server node ("MGM_TOKEN_PRINT")",
2423     ConfigInfo::CI_USED,
2424     false,
2425     ConfigInfo::CI_INT,
2426     MANDATORY,
2427     "1",
2428     STR_VALUE(MAX_NODES_ID) },
2429 
2430   {
2431     CFG_LOG_DESTINATION,
2432     "LogDestination",
2433     MGM_TOKEN,
2434     "String describing where logmessages are sent",
2435     ConfigInfo::CI_USED,
2436     false,
2437     ConfigInfo::CI_STRING,
2438     0,
2439     0, 0 },
2440 
2441   {
2442     KEY_INTERNAL,
2443     "ExecuteOnComputer",
2444     MGM_TOKEN,
2445     "String referencing an earlier defined COMPUTER",
2446     ConfigInfo::CI_USED,
2447     false,
2448     ConfigInfo::CI_STRING,
2449     0,
2450     0, 0 },
2451 
2452   {
2453     KEY_INTERNAL,
2454     "MaxNoOfSavedEvents",
2455     MGM_TOKEN,
2456     "",
2457     ConfigInfo::CI_USED,
2458     false,
2459     ConfigInfo::CI_INT,
2460     "100",
2461     "0",
2462     STR_VALUE(MAX_INT_RNIL) },
2463 
2464   {
2465     CFG_MGM_PORT,
2466     "PortNumber",
2467     MGM_TOKEN,
2468     "Port number to give commands to/fetch configurations from management server",
2469     ConfigInfo::CI_USED,
2470     false,
2471     ConfigInfo::CI_INT,
2472     STR_VALUE(NDB_PORT),
2473     "0",
2474     STR_VALUE(MAX_PORT_NO) },
2475 
2476   {
2477     KEY_INTERNAL,
2478     "PortNumberStats",
2479     MGM_TOKEN,
2480     "Port number used to get statistical information from a management server",
2481     ConfigInfo::CI_USED,
2482     false,
2483     ConfigInfo::CI_INT,
2484     0,
2485     "0",
2486     STR_VALUE(MAX_PORT_NO) },
2487 
2488   {
2489     CFG_NODE_ARBIT_RANK,
2490     "ArbitrationRank",
2491     MGM_TOKEN,
2492     "If 0, then "MGM_TOKEN_PRINT" is not arbitrator. Kernel selects arbitrators in order 1, 2",
2493     ConfigInfo::CI_USED,
2494     false,
2495     ConfigInfo::CI_INT,
2496     "1",
2497     "0",
2498     "2" },
2499 
2500   {
2501     CFG_NODE_ARBIT_DELAY,
2502     "ArbitrationDelay",
2503     MGM_TOKEN,
2504     "",
2505     ConfigInfo::CI_USED,
2506     false,
2507     ConfigInfo::CI_INT,
2508     "0",
2509     "0",
2510     STR_VALUE(MAX_INT_RNIL) },
2511 
2512   {
2513     CFG_TOTAL_SEND_BUFFER_MEMORY,
2514     "TotalSendBufferMemory",
2515     MGM_TOKEN,
2516     "Total memory to use for send buffers in all transporters",
2517     ConfigInfo::CI_USED,
2518     false,
2519     ConfigInfo::CI_INT,
2520     "0",
2521     "256K",
2522     STR_VALUE(MAX_INT_RNIL)
2523   },
2524 
2525   {
2526     CFG_HB_THREAD_PRIO,
2527     "HeartbeatThreadPriority",
2528     MGM_TOKEN,
2529     "Specify thread properties of heartbeat thread",
2530     ConfigInfo::CI_USED,
2531     0,
2532     ConfigInfo::CI_STRING,
2533     0, 0, 0
2534   },
2535 
2536   /****************************************************************************
2537    * TCP
2538    ***************************************************************************/
2539   {
2540     CFG_SECTION_CONNECTION,
2541     "TCP",
2542     "TCP",
2543     "Connection section",
2544     ConfigInfo::CI_USED,
2545     false,
2546     ConfigInfo::CI_SECTION,
2547     (const char *)CONNECTION_TYPE_TCP,
2548     0, 0
2549   },
2550 
2551   {
2552     CFG_CONNECTION_HOSTNAME_1,
2553     "HostName1",
2554     "TCP",
2555     "Name/IP of computer on one side of the connection",
2556     ConfigInfo::CI_USED,
2557     false,
2558     ConfigInfo::CI_STRING,
2559     0,
2560     0, 0 },
2561 
2562   {
2563     CFG_CONNECTION_HOSTNAME_2,
2564     "HostName2",
2565     "TCP",
2566     "Name/IP of computer on one side of the connection",
2567     ConfigInfo::CI_USED,
2568     false,
2569     ConfigInfo::CI_STRING,
2570     0,
2571     0, 0 },
2572 
2573   {
2574     CFG_CONNECTION_NODE_1,
2575     "NodeId1",
2576     "TCP",
2577     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2578     ConfigInfo::CI_USED,
2579     false,
2580     ConfigInfo::CI_STRING,
2581     MANDATORY,
2582     0, 0 },
2583 
2584   {
2585     CFG_CONNECTION_NODE_2,
2586     "NodeId2",
2587     "TCP",
2588     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2589     ConfigInfo::CI_USED,
2590     false,
2591     ConfigInfo::CI_STRING,
2592     MANDATORY,
2593     0, 0 },
2594 
2595   {
2596     CFG_CONNECTION_GROUP,
2597     "Group",
2598     "TCP",
2599     "",
2600     ConfigInfo::CI_USED,
2601     false,
2602     ConfigInfo::CI_INT,
2603     "55",
2604     "0", "200" },
2605 
2606   {
2607     CFG_CONNECTION_NODE_ID_SERVER,
2608     "NodeIdServer",
2609     "TCP",
2610     "",
2611     ConfigInfo::CI_USED,
2612     false,
2613     ConfigInfo::CI_INT,
2614     MANDATORY,
2615     "1", "63" },
2616 
2617   {
2618     CFG_CONNECTION_SEND_SIGNAL_ID,
2619     "SendSignalId",
2620     "TCP",
2621     "Sends id in each signal.  Used in trace files.",
2622     ConfigInfo::CI_USED,
2623     false,
2624     ConfigInfo::CI_BOOL,
2625     "true",
2626     "false",
2627     "true" },
2628 
2629 
2630   {
2631     CFG_CONNECTION_CHECKSUM,
2632     "Checksum",
2633     "TCP",
2634     "If checksum is enabled, all signals between nodes are checked for errors",
2635     ConfigInfo::CI_USED,
2636     false,
2637     ConfigInfo::CI_BOOL,
2638     "false",
2639     "false",
2640     "true" },
2641 
2642   {
2643     CFG_CONNECTION_SERVER_PORT,
2644     "PortNumber",
2645     "TCP",
2646     0, // No new parameter to use instead of deprecated
2647     ConfigInfo::CI_DEPRECATED,
2648     false,
2649     ConfigInfo::CI_INT,
2650     MANDATORY,
2651     "0",
2652     STR_VALUE(MAX_PORT_NO) },
2653 
2654   {
2655     CFG_TCP_SEND_BUFFER_SIZE,
2656     "SendBufferMemory",
2657     "TCP",
2658     "Bytes of buffer for signals sent from this node",
2659     ConfigInfo::CI_USED,
2660     false,
2661     ConfigInfo::CI_INT,
2662     "2M",
2663     "64K",
2664     STR_VALUE(MAX_INT_RNIL) },
2665 
2666   {
2667     CFG_TCP_RECEIVE_BUFFER_SIZE,
2668     "ReceiveBufferMemory",
2669     "TCP",
2670     "Bytes of buffer for signals received by this node",
2671     ConfigInfo::CI_USED,
2672     false,
2673     ConfigInfo::CI_INT,
2674     "2M",
2675     "16K",
2676     STR_VALUE(MAX_INT_RNIL) },
2677 
2678   {
2679     CFG_TCP_PROXY,
2680     "Proxy",
2681     "TCP",
2682     "",
2683     ConfigInfo::CI_USED,
2684     false,
2685     ConfigInfo::CI_STRING,
2686     0,
2687     0, 0 },
2688 
2689   {
2690     CFG_CONNECTION_NODE_1_SYSTEM,
2691     "NodeId1_System",
2692     "TCP",
2693     "System for node 1 in connection",
2694     ConfigInfo::CI_INTERNAL,
2695     false,
2696     ConfigInfo::CI_STRING,
2697     0,
2698     0, 0 },
2699 
2700   {
2701     CFG_CONNECTION_NODE_2_SYSTEM,
2702     "NodeId2_System",
2703     "TCP",
2704     "System for node 2 in connection",
2705     ConfigInfo::CI_INTERNAL,
2706     false,
2707     ConfigInfo::CI_STRING,
2708     0,
2709     0, 0 },
2710 
2711   {
2712     CFG_TCP_SND_BUF_SIZE,
2713     "TCP_SND_BUF_SIZE",
2714     "TCP",
2715     "Value used for SO_SNDBUF",
2716     ConfigInfo::CI_USED,
2717     false,
2718     ConfigInfo::CI_INT,
2719     "71540",
2720     "1",
2721     "2G"
2722   },
2723 
2724   {
2725     CFG_TCP_RCV_BUF_SIZE,
2726     "TCP_RCV_BUF_SIZE",
2727     "TCP",
2728     "Value used for SO_RCVBUF",
2729     ConfigInfo::CI_USED,
2730     false,
2731     ConfigInfo::CI_INT,
2732     "70080",
2733     "1",
2734     "2G"
2735   },
2736 
2737   {
2738     CFG_TCP_MAXSEG_SIZE,
2739     "TCP_MAXSEG_SIZE",
2740     "TCP",
2741     "Value used for TCP_MAXSEG",
2742     ConfigInfo::CI_USED,
2743     false,
2744     ConfigInfo::CI_INT,
2745     "0",
2746     "0",
2747     "2G"
2748   },
2749 
2750   {
2751     CFG_TCP_BIND_INADDR_ANY,
2752     "TcpBind_INADDR_ANY",
2753     "TCP",
2754     "Bind InAddrAny instead of hostname for server part of connection",
2755     ConfigInfo::CI_USED,
2756     false,
2757     ConfigInfo::CI_BOOL,
2758     "false",
2759     "false", "true" },
2760 
2761   {
2762     CFG_CONNECTION_OVERLOAD,
2763     "OverloadLimit",
2764     "TCP",
2765     "Number of unsent bytes that must be in the send buffer before the\n"
2766     "connection is considered overloaded",
2767     ConfigInfo::CI_USED,
2768     false,
2769     ConfigInfo::CI_INT,
2770     "0",
2771     "0",
2772     STR_VALUE(MAX_INT_RNIL)
2773   },
2774 
2775   /****************************************************************************
2776    * SHM
2777    ***************************************************************************/
2778   {
2779     CFG_SECTION_CONNECTION,
2780     "SHM",
2781     "SHM",
2782     "Connection section",
2783     ConfigInfo::CI_EXPERIMENTAL,
2784     false,
2785     ConfigInfo::CI_SECTION,
2786     (const char *)CONNECTION_TYPE_SHM,
2787     0, 0 },
2788 
2789   {
2790     CFG_CONNECTION_HOSTNAME_1,
2791     "HostName1",
2792     "SHM",
2793     "Name/IP of computer on one side of the connection",
2794     ConfigInfo::CI_USED,
2795     false,
2796     ConfigInfo::CI_STRING,
2797     0,
2798     0, 0 },
2799 
2800   {
2801     CFG_CONNECTION_HOSTNAME_2,
2802     "HostName2",
2803     "SHM",
2804     "Name/IP of computer on one side of the connection",
2805     ConfigInfo::CI_USED,
2806     false,
2807     ConfigInfo::CI_STRING,
2808     0,
2809     0, 0 },
2810 
2811   {
2812     CFG_CONNECTION_SERVER_PORT,
2813     "PortNumber",
2814     "SHM",
2815     0, // No new parameter to use instead of deprecated
2816     ConfigInfo::CI_DEPRECATED,
2817     false,
2818     ConfigInfo::CI_INT,
2819     MANDATORY,
2820     "0",
2821     STR_VALUE(MAX_PORT_NO) },
2822 
2823   {
2824     CFG_SHM_SIGNUM,
2825     "Signum",
2826     "SHM",
2827     "Signum to be used for signalling",
2828     ConfigInfo::CI_EXPERIMENTAL,
2829     false,
2830     ConfigInfo::CI_INT,
2831     0,
2832     "0",
2833     STR_VALUE(MAX_INT_RNIL) },
2834 
2835   {
2836     CFG_CONNECTION_NODE_1,
2837     "NodeId1",
2838     "SHM",
2839     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2840     ConfigInfo::CI_EXPERIMENTAL,
2841     false,
2842     ConfigInfo::CI_STRING,
2843     MANDATORY,
2844     0, 0 },
2845 
2846   {
2847     CFG_CONNECTION_NODE_2,
2848     "NodeId2",
2849     "SHM",
2850     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2851     ConfigInfo::CI_EXPERIMENTAL,
2852     false,
2853     ConfigInfo::CI_STRING,
2854     MANDATORY,
2855     0, 0 },
2856 
2857   {
2858     CFG_CONNECTION_GROUP,
2859     "Group",
2860     "SHM",
2861     "",
2862     ConfigInfo::CI_EXPERIMENTAL,
2863     false,
2864     ConfigInfo::CI_INT,
2865     "35",
2866     "0", "200" },
2867 
2868   {
2869     CFG_CONNECTION_NODE_ID_SERVER,
2870     "NodeIdServer",
2871     "SHM",
2872     "",
2873     ConfigInfo::CI_EXPERIMENTAL,
2874     false,
2875     ConfigInfo::CI_INT,
2876     MANDATORY,
2877     "1", "63" },
2878 
2879   {
2880     CFG_CONNECTION_SEND_SIGNAL_ID,
2881     "SendSignalId",
2882     "SHM",
2883     "Sends id in each signal.  Used in trace files.",
2884     ConfigInfo::CI_EXPERIMENTAL,
2885     false,
2886     ConfigInfo::CI_BOOL,
2887     "false",
2888     "false",
2889     "true" },
2890 
2891 
2892   {
2893     CFG_CONNECTION_CHECKSUM,
2894     "Checksum",
2895     "SHM",
2896     "If checksum is enabled, all signals between nodes are checked for errors",
2897     ConfigInfo::CI_EXPERIMENTAL,
2898     false,
2899     ConfigInfo::CI_BOOL,
2900     "true",
2901     "false",
2902     "true" },
2903 
2904   {
2905     CFG_SHM_KEY,
2906     "ShmKey",
2907     "SHM",
2908     "A shared memory key",
2909     ConfigInfo::CI_EXPERIMENTAL,
2910     false,
2911     ConfigInfo::CI_INT,
2912     0,
2913     "0",
2914     STR_VALUE(MAX_INT_RNIL) },
2915 
2916   {
2917     CFG_SHM_BUFFER_MEM,
2918     "ShmSize",
2919     "SHM",
2920     "Size of shared memory segment",
2921     ConfigInfo::CI_EXPERIMENTAL,
2922     false,
2923     ConfigInfo::CI_INT,
2924     "1M",
2925     "64K",
2926     STR_VALUE(MAX_INT_RNIL) },
2927 
2928   {
2929     CFG_CONNECTION_NODE_1_SYSTEM,
2930     "NodeId1_System",
2931     "SHM",
2932     "System for node 1 in connection",
2933     ConfigInfo::CI_INTERNAL,
2934     false,
2935     ConfigInfo::CI_STRING,
2936     0,
2937     0, 0 },
2938 
2939   {
2940     CFG_CONNECTION_NODE_2_SYSTEM,
2941     "NodeId2_System",
2942     "SHM",
2943     "System for node 2 in connection",
2944     ConfigInfo::CI_INTERNAL,
2945     false,
2946     ConfigInfo::CI_STRING,
2947     0,
2948     0, 0 },
2949 
2950   {
2951     CFG_CONNECTION_OVERLOAD,
2952     "OverloadLimit",
2953     "SHM",
2954     "Number of unsent bytes that must be in the send buffer before the\n"
2955     "connection is considered overloaded",
2956     ConfigInfo::CI_USED,
2957     false,
2958     ConfigInfo::CI_INT,
2959     "0",
2960     "0",
2961     STR_VALUE(MAX_INT_RNIL)
2962   },
2963 
2964   /****************************************************************************
2965    * SCI
2966    ***************************************************************************/
2967   {
2968     CFG_SECTION_CONNECTION,
2969     "SCI",
2970     "SCI",
2971     "Connection section",
2972     ConfigInfo::CI_EXPERIMENTAL,
2973     false,
2974     ConfigInfo::CI_SECTION,
2975     (const char *)CONNECTION_TYPE_SCI,
2976     0, 0
2977   },
2978 
2979   {
2980     CFG_CONNECTION_NODE_1,
2981     "NodeId1",
2982     "SCI",
2983     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2984     ConfigInfo::CI_EXPERIMENTAL,
2985     false,
2986     ConfigInfo::CI_STRING,
2987     MANDATORY,
2988     0, 0 },
2989 
2990   {
2991     CFG_CONNECTION_NODE_2,
2992     "NodeId2",
2993     "SCI",
2994     "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
2995     ConfigInfo::CI_EXPERIMENTAL,
2996     false,
2997     ConfigInfo::CI_STRING,
2998     MANDATORY,
2999     0, 0 },
3000 
3001   {
3002     CFG_CONNECTION_GROUP,
3003     "Group",
3004     "SCI",
3005     "",
3006     ConfigInfo::CI_EXPERIMENTAL,
3007     false,
3008     ConfigInfo::CI_INT,
3009     "15",
3010     "0", "200" },
3011 
3012   {
3013     CFG_CONNECTION_NODE_ID_SERVER,
3014     "NodeIdServer",
3015     "SCI",
3016     "",
3017     ConfigInfo::CI_EXPERIMENTAL,
3018     false,
3019     ConfigInfo::CI_INT,
3020     MANDATORY,
3021     "1", "63" },
3022 
3023   {
3024     CFG_CONNECTION_HOSTNAME_1,
3025     "HostName1",
3026     "SCI",
3027     "Name/IP of computer on one side of the connection",
3028     ConfigInfo::CI_USED,
3029     false,
3030     ConfigInfo::CI_STRING,
3031     0,
3032     0, 0 },
3033 
3034   {
3035     CFG_CONNECTION_HOSTNAME_2,
3036     "HostName2",
3037     "SCI",
3038     "Name/IP of computer on one side of the connection",
3039     ConfigInfo::CI_USED,
3040     false,
3041     ConfigInfo::CI_STRING,
3042     0,
3043     0, 0 },
3044 
3045   {
3046     CFG_CONNECTION_SERVER_PORT,
3047     "PortNumber",
3048     "SCI",
3049     0, // No new parameter to use instead of deprecated
3050     ConfigInfo::CI_DEPRECATED,
3051     false,
3052     ConfigInfo::CI_INT,
3053     MANDATORY,
3054     "0",
3055     STR_VALUE(MAX_PORT_NO) },
3056 
3057   {
3058     CFG_SCI_HOST1_ID_0,
3059     "Host1SciId0",
3060     "SCI",
3061     "SCI-node id for adapter 0 on Host1 (a computer can have two adapters)",
3062     ConfigInfo::CI_EXPERIMENTAL,
3063     false,
3064     ConfigInfo::CI_INT,
3065     MANDATORY,
3066     "0",
3067     STR_VALUE(MAX_INT_RNIL) },
3068 
3069   {
3070     CFG_SCI_HOST1_ID_1,
3071     "Host1SciId1",
3072     "SCI",
3073     "SCI-node id for adapter 1 on Host1 (a computer can have two adapters)",
3074     ConfigInfo::CI_EXPERIMENTAL,
3075     false,
3076     ConfigInfo::CI_INT,
3077     "0",
3078     "0",
3079     STR_VALUE(MAX_INT_RNIL) },
3080 
3081   {
3082     CFG_SCI_HOST2_ID_0,
3083     "Host2SciId0",
3084     "SCI",
3085     "SCI-node id for adapter 0 on Host2 (a computer can have two adapters)",
3086     ConfigInfo::CI_EXPERIMENTAL,
3087     false,
3088     ConfigInfo::CI_INT,
3089     MANDATORY,
3090     "0",
3091     STR_VALUE(MAX_INT_RNIL) },
3092 
3093   {
3094     CFG_SCI_HOST2_ID_1,
3095     "Host2SciId1",
3096     "SCI",
3097     "SCI-node id for adapter 1 on Host2 (a computer can have two adapters)",
3098     ConfigInfo::CI_EXPERIMENTAL,
3099     false,
3100     ConfigInfo::CI_INT,
3101     "0",
3102     "0",
3103     STR_VALUE(MAX_INT_RNIL) },
3104 
3105   {
3106     CFG_CONNECTION_SEND_SIGNAL_ID,
3107     "SendSignalId",
3108     "SCI",
3109     "Sends id in each signal.  Used in trace files.",
3110     ConfigInfo::CI_EXPERIMENTAL,
3111     false,
3112     ConfigInfo::CI_BOOL,
3113     "true",
3114     "false",
3115     "true" },
3116 
3117   {
3118     CFG_CONNECTION_CHECKSUM,
3119     "Checksum",
3120     "SCI",
3121     "If checksum is enabled, all signals between nodes are checked for errors",
3122     ConfigInfo::CI_EXPERIMENTAL,
3123     false,
3124     ConfigInfo::CI_BOOL,
3125     "false",
3126     "false",
3127     "true" },
3128 
3129   {
3130     CFG_SCI_SEND_LIMIT,
3131     "SendLimit",
3132     "SCI",
3133     "Transporter send buffer contents are sent when this no of bytes is buffered",
3134     ConfigInfo::CI_EXPERIMENTAL,
3135     false,
3136     ConfigInfo::CI_INT,
3137     "8K",
3138     "128",
3139     "32K" },
3140 
3141   {
3142     CFG_SCI_BUFFER_MEM,
3143     "SharedBufferSize",
3144     "SCI",
3145     "Size of shared memory segment",
3146     ConfigInfo::CI_EXPERIMENTAL,
3147     false,
3148     ConfigInfo::CI_INT,
3149     "1M",
3150     "64K",
3151     STR_VALUE(MAX_INT_RNIL) },
3152 
3153   {
3154     CFG_CONNECTION_NODE_1_SYSTEM,
3155     "NodeId1_System",
3156     "SCI",
3157     "System for node 1 in connection",
3158     ConfigInfo::CI_INTERNAL,
3159     false,
3160     ConfigInfo::CI_STRING,
3161     0,
3162     0, 0 },
3163 
3164   {
3165     CFG_CONNECTION_NODE_2_SYSTEM,
3166     "NodeId2_System",
3167     "SCI",
3168     "System for node 2 in connection",
3169     ConfigInfo::CI_INTERNAL,
3170     false,
3171     ConfigInfo::CI_STRING,
3172     0,
3173     0, 0 },
3174 
3175   {
3176     CFG_CONNECTION_OVERLOAD,
3177     "OverloadLimit",
3178     "SCI",
3179     "Number of unsent bytes that must be in the send buffer before the\n"
3180     "connection is considered overloaded",
3181     ConfigInfo::CI_EXPERIMENTAL,
3182     false,
3183     ConfigInfo::CI_INT,
3184     "0",
3185     "0",
3186     STR_VALUE(MAX_INT_RNIL)
3187   }
3188 
3189 };
3190 
3191 const int ConfigInfo::m_NoOfParams = sizeof(m_ParamInfo) / sizeof(ParamInfo);
3192 
3193 #ifndef NDB_MGMAPI
3194 /****************************************************************************
3195  * Ctor
3196  ****************************************************************************/
3197 #undef require
3198 #define require(x) require_exit_or_core(x, -1)
3199 
ConfigInfo()3200 ConfigInfo::ConfigInfo()
3201   : m_info(true), m_systemDefaults(true)
3202 {
3203   int i;
3204   Properties *section;
3205   const Properties *oldpinfo;
3206 
3207   for (i=0; i<m_NoOfParams; i++) {
3208     const ParamInfo & param = m_ParamInfo[i];
3209     Uint64 default_uint64;
3210     bool   default_bool;
3211 
3212     // Create new section if it did not exist
3213     if (!m_info.getCopy(param._section, &section)) {
3214       Properties newsection(true);
3215       m_info.put(param._section, &newsection);
3216 
3217       // Get copy of section
3218       m_info.getCopy(param._section, &section);
3219     }
3220 
3221     // Create pinfo (parameter info) entry
3222     Properties pinfo(true);
3223     pinfo.put("Id",          param._paramId);
3224     pinfo.put("Fname",       param._fname);
3225     pinfo.put("Description", param._description);
3226 
3227     /*
3228       Check that flags are set according to current rules
3229     */
3230     const Uint32 flags = param._flags;
3231     const Uint32 allowed_flags = (CI_ONLINE_UPDATEABLE | CI_CHECK_WRITABLE |
3232                                   CI_RESTART_SYSTEM | CI_RESTART_INITIAL);
3233     // Check that no other flags then the defined are set
3234     require((flags & ~allowed_flags) == 0);
3235 
3236     if (flags & CI_ONLINE_UPDATEABLE)
3237     {
3238       // Check that online updateable parameter does
3239       // not have any CI_RESTART_* flag(s)
3240       require((flags & CI_RESTART_INITIAL) == 0 &&
3241               (flags & CI_RESTART_SYSTEM) == 0);
3242 
3243       // Currently no online updatable parameters have been implemented
3244       require(false);
3245     }
3246 
3247     // only DB nodes should have CI_RESTART_*
3248     if ((flags & CI_RESTART_INITIAL) || (flags & CI_RESTART_SYSTEM))
3249       require(strcmp(param._section, DB_TOKEN) == 0);
3250 
3251     pinfo.put("Flags", flags);
3252 
3253     pinfo.put("Type",        param._type);
3254 
3255     const Status status = param._status;
3256     require(status == CI_USED ||
3257             status == CI_EXPERIMENTAL ||
3258             status == CI_DEPRECATED ||
3259             status == CI_NOTIMPLEMENTED ||
3260             status == CI_INTERNAL);
3261     pinfo.put("Status", status);
3262 
3263     switch (param._type) {
3264       case CI_BOOL:
3265       {
3266 	bool tmp_bool;
3267 	require(InitConfigFileParser::convertStringToBool(param._min, tmp_bool));
3268 	pinfo.put64("Min", tmp_bool);
3269 	require(InitConfigFileParser::convertStringToBool(param._max, tmp_bool));
3270 	pinfo.put64("Max", tmp_bool);
3271 
3272         if(param._default == MANDATORY)
3273           pinfo.put("Mandatory", (Uint32)1);
3274         else if(param._default)
3275         {
3276           require(InitConfigFileParser::convertStringToBool(param._default,
3277                                                             tmp_bool));
3278           pinfo.put("Default", tmp_bool);
3279         }
3280 
3281 	break;
3282       }
3283       case CI_INT:
3284       case CI_INT64:
3285       {
3286 	Uint64 tmp_uint64;
3287 	require(InitConfigFileParser::convertStringToUint64(param._min, tmp_uint64));
3288 	pinfo.put64("Min", tmp_uint64);
3289 	require(InitConfigFileParser::convertStringToUint64(param._max, tmp_uint64));
3290 	pinfo.put64("Max", tmp_uint64);
3291 
3292         if(param._default == MANDATORY)
3293           pinfo.put("Mandatory", (Uint32)1);
3294         else if(param._default)
3295         {
3296           require(InitConfigFileParser::convertStringToUint64(param._default,
3297                                                               tmp_uint64));
3298           pinfo.put64("Default", tmp_uint64);
3299         }
3300 	break;
3301       }
3302       case CI_SECTION:
3303 	pinfo.put("SectionType", (Uint32)UintPtr(param._default));
3304 	break;
3305       case CI_ENUM:
3306       {
3307        assert(param._min); // Enums typelib pointer is stored in _min
3308        assert(param._max == 0); // Enums can't have max
3309 
3310         Properties values(true); // case insensitive
3311         // Put the list of allowed enum values in pinfo
3312         for (const Typelib* entry = ConfigInfo::getTypelibPtr(param);
3313              entry->name != 0; entry++)
3314           values.put(entry->name, entry->value);
3315         require(pinfo.put("values", &values));
3316 
3317         if(param._default == MANDATORY)
3318           pinfo.put("Mandatory", (Uint32)1);
3319         else if(param._default)
3320         {
3321           /*
3322             Map default value of enum from string to int since
3323             enum is stored as int internally
3324           */
3325           Uint32 default_value;
3326           require(values.get(param._default, &default_value));
3327           require(pinfo.put("Default", default_value));
3328 
3329           /* Also store the default as string */
3330           require(pinfo.put("DefaultString", param._default));
3331         }
3332         break;
3333       }
3334       case CI_STRING:
3335         assert(param._min == 0); // String can't have min value
3336         assert(param._max == 0); // String can't have max value
3337 
3338         if(param._default == MANDATORY)
3339           pinfo.put("Mandatory", (Uint32)1);
3340         else if(param._default)
3341           pinfo.put("Default", param._default);
3342 	break;
3343 
3344       case CI_BITMASK:
3345         assert(param._min == 0); // Bitmask can't have min value
3346 
3347 	Uint64 tmp_uint64;
3348 	require(InitConfigFileParser::convertStringToUint64(param._max,
3349                                                             tmp_uint64));
3350 	pinfo.put64("Max", tmp_uint64);
3351 
3352         if(param._default == MANDATORY)
3353           pinfo.put("Mandatory", (Uint32)1);
3354         else if(param._default)
3355           pinfo.put("Default", param._default);
3356         break;
3357     }
3358 
3359     // Check that pinfo is really new
3360     if (section->get(param._fname, &oldpinfo)) {
3361       ndbout << "Error: Parameter " << param._fname
3362 	     << " defined twice in section " << param._section
3363 	     << "." << endl;
3364       require(false);
3365     }
3366 
3367     // Add new pinfo to section
3368     section->put(param._fname, &pinfo);
3369 
3370     // Replace section with modified section
3371     m_info.put(param._section, section, true);
3372     delete section;
3373 
3374     if(param._type != ConfigInfo::CI_SECTION){
3375       Properties * p;
3376       if(!m_systemDefaults.getCopy(param._section, &p)){
3377 	p = new Properties(true);
3378       }
3379       if(param._default &&
3380 	 param._default != MANDATORY){
3381 	switch (param._type)
3382         {
3383 	  case CI_SECTION:
3384 	    break;
3385 	  case CI_STRING:
3386           case CI_BITMASK:
3387 	    require(p->put(param._fname, param._default));
3388 	    break;
3389 	  case CI_BOOL:
3390 	    {
3391 	      require(InitConfigFileParser::convertStringToBool(param._default, default_bool));
3392 	      require(p->put(param._fname, default_bool));
3393 
3394 	      break;
3395 	    }
3396 	  case CI_INT:
3397 	  case CI_INT64:
3398 	    {
3399 	      require(InitConfigFileParser::convertStringToUint64(param._default, default_uint64));
3400 	      require(p->put64(param._fname, Uint64(default_uint64)));
3401 	      break;
3402 	    }
3403           case CI_ENUM:
3404           {
3405             /*
3406               Map default value of enum from string to int since
3407               enum is stored as int internally
3408             */
3409             Uint32 default_value;
3410             require(verify_enum(getInfo(param._section),
3411                                 param._fname, param._default,
3412                                 default_value));
3413             require(p->put(param._fname, default_value));
3414             break;
3415           }
3416 
3417 	}
3418       }
3419       require(m_systemDefaults.put(param._section, p, true));
3420       delete p;
3421     }
3422   }
3423 
3424   for (i=0; i<m_NoOfParams; i++) {
3425     if(m_ParamInfo[i]._section == NULL){
3426       ndbout << "Check that each entry has a section failed." << endl;
3427       ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl;
3428       ndbout << "Edit file " << __FILE__ << "." << endl;
3429       require(false);
3430     }
3431 
3432     if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION)
3433       continue;
3434 
3435     const Properties * p = getInfo(m_ParamInfo[i]._section);
3436     if (!p || !p->contains(m_ParamInfo[i]._fname)) {
3437       ndbout << "Check that each pname has an fname failed." << endl;
3438       ndbout << "Parameter \"" << m_ParamInfo[i]._fname
3439 	     << "\" does not exist in section \""
3440 	     << m_ParamInfo[i]._section << "\"." << endl;
3441       ndbout << "Edit file " << __FILE__ << "." << endl;
3442       require(false);
3443     }
3444    }
3445 
3446 }
3447 
3448 /****************************************************************************
3449  * Getters
3450  ****************************************************************************/
warning(const char * src,const char * arg)3451 inline void warning(const char * src, const char * arg){
3452   ndbout << "Illegal call to ConfigInfo::" << src << "() - " << arg << endl;
3453   require(false);
3454 }
3455 
3456 const Properties *
getInfo(const char * section) const3457 ConfigInfo::getInfo(const char * section) const {
3458   const Properties * p;
3459   if(!m_info.get(section, &p)){
3460     return 0;
3461     //    warning("getInfo", section);
3462   }
3463   return p;
3464 }
3465 
3466 const Properties *
getDefaults(const char * section) const3467 ConfigInfo::getDefaults(const char * section) const {
3468   const Properties * p;
3469   if(!m_systemDefaults.get(section, &p)){
3470     return 0;
3471     //warning("getDefaults", section);
3472   }
3473   return p;
3474 }
3475 
3476 static
3477 Uint64
getInfoInt(const Properties * section,const char * fname,const char * type)3478 getInfoInt(const Properties * section,
3479 	   const char* fname, const char * type){
3480   Uint32 val32;
3481   const Properties * p;
3482   if (section->get(fname, &p) && p->get(type, &val32)) {
3483     return val32;
3484   }
3485 
3486   Uint64 val64;
3487   if(p && p->get(type, &val64)){
3488     return val64;
3489   }
3490 
3491   section->print();
3492   if(section->get(fname, &p)){
3493     p->print();
3494   }
3495 
3496   warning(type, fname);
3497   return 0;
3498 }
3499 
3500 static
3501 const char *
getInfoString(const Properties * section,const char * fname,const char * type)3502 getInfoString(const Properties * section,
3503 	      const char* fname, const char * type){
3504   const char* val;
3505   const Properties * p;
3506   if (section->get(fname, &p) && p->get(type, &val)) {
3507     return val;
3508   }
3509   warning(type, fname);
3510   return val;
3511 }
3512 
3513 Uint64
getMax(const Properties * section,const char * fname) const3514 ConfigInfo::getMax(const Properties * section, const char* fname) const {
3515   return getInfoInt(section, fname, "Max");
3516 }
3517 
3518 Uint64
getMin(const Properties * section,const char * fname) const3519 ConfigInfo::getMin(const Properties * section, const char* fname) const {
3520   return getInfoInt(section, fname, "Min");
3521 }
3522 
3523 Uint64
getDefault(const Properties * section,const char * fname) const3524 ConfigInfo::getDefault(const Properties * section, const char* fname) const {
3525   return getInfoInt(section, fname, "Default");
3526 }
3527 
3528 const char*
getDefaultString(const Properties * section,const char * fname) const3529 ConfigInfo::getDefaultString(const Properties * section,
3530                              const char* fname) const
3531 {
3532   switch (getType(section, fname))
3533   {
3534   case ConfigInfo::CI_BITMASK:
3535   case ConfigInfo::CI_STRING:
3536     return getInfoString(section, fname, "Default");
3537 
3538   case ConfigInfo::CI_ENUM:
3539   {
3540     /*
3541       Default value for enum are stored as int internally
3542       but also stores the orignal string, use different
3543       key to get at the default value as string
3544      */
3545     return getInfoString(section, fname, "DefaultString");
3546   }
3547 
3548   default:
3549     require(false);
3550   }
3551 
3552   return NULL;
3553 }
3554 
3555 bool
hasDefault(const Properties * section,const char * fname) const3556 ConfigInfo::hasDefault(const Properties * section, const char* fname) const {
3557   const Properties * p;
3558   require(section->get(fname, &p));
3559   return p->contains("Default");
3560 }
3561 
3562 bool
getMandatory(const Properties * section,const char * fname) const3563 ConfigInfo::getMandatory(const Properties * section, const char* fname) const {
3564   const Properties * p;
3565   require(section->get(fname, &p));
3566   return p->contains("Mandatory");
3567 }
3568 
3569 const char*
getDescription(const Properties * section,const char * fname) const3570 ConfigInfo::getDescription(const Properties * section,
3571                            const char* fname) const {
3572   return getInfoString(section, fname, "Description");
3573 }
3574 
3575 bool
isSection(const char * section) const3576 ConfigInfo::isSection(const char * section) const {
3577   for (int i = 0; i<m_noOfSectionNames; i++) {
3578     if(!strcasecmp(section, m_sectionNames[i])) return true;
3579   }
3580   return false;
3581 }
3582 
3583 const char*
nameToAlias(const char * name)3584 ConfigInfo::nameToAlias(const char * name) {
3585   for (int i = 0; m_sectionNameAliases[i].name != 0; i++)
3586     if(!strcasecmp(name, m_sectionNameAliases[i].name))
3587       return m_sectionNameAliases[i].alias;
3588   return 0;
3589 }
3590 
3591 const char*
getAlias(const char * section)3592 ConfigInfo::getAlias(const char * section) {
3593   for (int i = 0; m_sectionNameAliases[i].name != 0; i++)
3594     if(!strcasecmp(section, m_sectionNameAliases[i].alias))
3595       return m_sectionNameAliases[i].name;
3596   return 0;
3597 }
3598 
3599 const char*
sectionName(Uint32 section_type,Uint32 type) const3600 ConfigInfo::sectionName(Uint32 section_type, Uint32 type) const {
3601 
3602   switch (section_type){
3603   case CFG_SECTION_SYSTEM:
3604     return "SYSTEM";
3605     break;
3606 
3607   case CFG_SECTION_NODE:
3608     switch(type){
3609     case NODE_TYPE_DB:
3610       return DB_TOKEN_PRINT;
3611       break;
3612     case NODE_TYPE_MGM:
3613       return MGM_TOKEN_PRINT;
3614       break;
3615     case NODE_TYPE_API:
3616       return API_TOKEN_PRINT;
3617       break;
3618     default:
3619       assert(false);
3620       break;
3621     }
3622     break;
3623 
3624   case CFG_SECTION_CONNECTION:
3625     switch(type){
3626     case CONNECTION_TYPE_TCP:
3627       return "TCP";
3628       break;
3629     case CONNECTION_TYPE_SHM:
3630       return "SHM";
3631       break;
3632     case CONNECTION_TYPE_SCI:
3633       return "SCI";
3634       break;
3635     default:
3636       assert(false);
3637       break;
3638     }
3639     break;
3640 
3641   default:
3642     assert(false);
3643     break;
3644   }
3645 
3646   return "<unknown section>";
3647 }
3648 
3649 const ConfigInfo::AliasPair
3650 section2PrimaryKeys[]={
3651   {API_TOKEN, "NodeId"},
3652   {DB_TOKEN,  "NodeId"},
3653   {MGM_TOKEN, "NodeId"},
3654   {"TCP", "NodeId1,NodeId2"},
3655   {"SCI", "NodeId1,NodeId2"},
3656   {"SHM", "NodeId1,NodeId2"},
3657   {0, 0}
3658 };
3659 
3660 static const char*
sectionPrimaryKeys(const char * name)3661 sectionPrimaryKeys(const char * name) {
3662   for (int i = 0; section2PrimaryKeys[i].name != 0; i++)
3663     if(!strcasecmp(name, section2PrimaryKeys[i].name))
3664       return section2PrimaryKeys[i].alias;
3665   return 0;
3666 }
3667 
3668 bool
verify(const Properties * section,const char * fname,Uint64 value) const3669 ConfigInfo::verify(const Properties * section, const char* fname,
3670 		   Uint64 value) const {
3671   Uint64 min, max;
3672 
3673   min = getInfoInt(section, fname, "Min");
3674   max = getInfoInt(section, fname, "Max");
3675   if(min > max){
3676     warning("verify", fname);
3677   }
3678   if (value >= min && value <= max)
3679     return true;
3680   else
3681     return false;
3682 }
3683 
3684 
3685 bool
verify_enum(const Properties * section,const char * fname,const char * value,Uint32 & value_int) const3686 ConfigInfo::verify_enum(const Properties * section, const char* fname,
3687                         const char* value, Uint32& value_int) const {
3688   const Properties * p;
3689   const Properties * values;
3690   require(section->get(fname, &p));
3691   require(p->get("values", &values));
3692 
3693   if (values->get(value, &value_int))
3694     return true;
3695   return false;
3696 }
3697 
3698 
3699 void
get_enum_values(const Properties * section,const char * fname,BaseString & list) const3700 ConfigInfo::get_enum_values(const Properties * section, const char* fname,
3701                       BaseString& list) const {
3702   const Properties * p;
3703   const Properties * values;
3704   require(section->get(fname, &p));
3705   require(p->get("values", &values));
3706 
3707   const char* separator = "";
3708   Properties::Iterator it(values);
3709   for (const char* name = it.first(); name != NULL; name = it.next())
3710   {
3711     list.appfmt("%s%s", separator, name);
3712     separator = " ";
3713   }
3714 }
3715 
3716 
3717 ConfigInfo::Type
getType(const Properties * section,const char * fname) const3718 ConfigInfo::getType(const Properties * section, const char* fname) const {
3719   return (ConfigInfo::Type) getInfoInt(section, fname, "Type");
3720 }
3721 
3722 ConfigInfo::Status
getStatus(const Properties * section,const char * fname) const3723 ConfigInfo::getStatus(const Properties * section, const char* fname) const {
3724   return (ConfigInfo::Status) getInfoInt(section, fname, "Status");
3725 }
3726 
3727 Uint32
getFlags(const Properties * section,const char * fname) const3728 ConfigInfo::getFlags(const Properties* section, const char* fname) const {
3729   return (Uint32)getInfoInt(section, fname, "Flags");
3730 }
3731 
3732 /****************************************************************************
3733  * Printers
3734  ****************************************************************************/
3735 
3736 class ConfigPrinter {
3737 protected:
3738   FILE* m_out;
3739 public:
ConfigPrinter(FILE * out=stdout)3740   ConfigPrinter(FILE* out = stdout) :
3741     m_out(out)
3742     {}
~ConfigPrinter()3743   virtual ~ConfigPrinter() {};
3744 
start()3745   virtual void start() {}
end()3746   virtual void end() {}
3747 
section_start(const char * name,const char * alias,const char * primarykeys=NULL)3748   virtual void section_start(const char* name, const char* alias,
3749                              const char* primarykeys = NULL) {}
section_end(const char * name)3750   virtual void section_end(const char* name) {}
3751 
parameter(const char * section_name,const Properties * section,const char * param_name,const ConfigInfo & info)3752   virtual void parameter(const char* section_name,
3753                          const Properties* section,
3754                          const char* param_name,
3755                          const ConfigInfo& info){}
3756 };
3757 
3758 
3759 class PrettyPrinter : public ConfigPrinter {
3760 public:
PrettyPrinter(FILE * out=stdout)3761   PrettyPrinter(FILE* out = stdout) : ConfigPrinter(out) {}
~PrettyPrinter()3762   virtual ~PrettyPrinter() {}
3763 
section_start(const char * name,const char * alias,const char * primarykeys=NULL)3764   virtual void section_start(const char* name, const char* alias,
3765                              const char* primarykeys = NULL) {
3766     fprintf(m_out, "****** %s ******\n\n", name);
3767   }
3768 
parameter(const char * section_name,const Properties * section,const char * param_name,const ConfigInfo & info)3769   virtual void parameter(const char* section_name,
3770                          const Properties* section,
3771                          const char* param_name,
3772                          const ConfigInfo& info){
3773     switch (info.getType(section, param_name)) {
3774     case ConfigInfo::CI_BOOL:
3775       fprintf(m_out, "%s (Boolean value)\n", param_name);
3776       fprintf(m_out, "%s\n", info.getDescription(section, param_name));
3777 
3778       if (info.getMandatory(section, param_name))
3779         fprintf(m_out, "MANDATORY (Legal values: Y, N)\n");
3780       else if (info.hasDefault(section, param_name))
3781       {
3782         if (info.getDefault(section, param_name) == false)
3783           fprintf(m_out, "Default: N (Legal values: Y, N)\n");
3784         else if (info.getDefault(section, param_name) == true)
3785           fprintf(m_out, "Default: Y (Legal values: Y, N)\n");
3786         else
3787           fprintf(m_out, "UNKNOWN\n");
3788       }
3789       fprintf(m_out, "\n");
3790       break;
3791 
3792     case ConfigInfo::CI_INT:
3793     case ConfigInfo::CI_INT64:
3794       fprintf(m_out, "%s (Non-negative Integer)\n", param_name);
3795       fprintf(m_out, "%s\n", info.getDescription(section, param_name));
3796       if (info.getMandatory(section, param_name))
3797         fprintf(m_out, "MANDATORY (");
3798       else if (info.hasDefault(section, param_name))
3799         fprintf(m_out, "Default: %llu (",
3800                 info.getDefault(section, param_name));
3801       else
3802         fprintf(m_out, "(");
3803       fprintf(m_out, "Min: %llu, ", info.getMin(section, param_name));
3804       fprintf(m_out, "Max: %llu)\n", info.getMax(section, param_name));
3805       fprintf(m_out, "\n");
3806       break;
3807 
3808     case ConfigInfo::CI_BITMASK:
3809     case ConfigInfo::CI_ENUM:
3810     case ConfigInfo::CI_STRING:
3811       fprintf(m_out, "%s (String)\n", param_name);
3812       fprintf(m_out, "%s\n", info.getDescription(section, param_name));
3813       if (info.getMandatory(section, param_name))
3814         fprintf(m_out, "MANDATORY\n");
3815       else if (info.hasDefault(section, param_name))
3816         fprintf(m_out, "Default: %s\n",
3817               info.getDefaultString(section, param_name));
3818       fprintf(m_out, "\n");
3819       break;
3820     case ConfigInfo::CI_SECTION:
3821       break;
3822     }
3823   }
3824 };
3825 
3826 
3827 class XMLPrinter : public ConfigPrinter {
3828   int m_indent;
3829 
print_xml(const char * name,const Properties & pairs,bool close=true)3830   void print_xml(const char* name, const Properties& pairs,
3831                  bool close = true) {
3832     const char* value;
3833     Properties::Iterator it(&pairs);
3834     for (int i= 0; i < m_indent; i++)
3835       fprintf(m_out, "  ");
3836     fprintf(m_out, "<%s", name);
3837     for (const char* name = it.first(); name != NULL; name = it.next()) {
3838       require(pairs.get(name, &value));
3839       fprintf(m_out, " %s=\"%s\"", name, value);
3840     }
3841     if (close)
3842       fprintf(m_out, "/");
3843     fprintf(m_out, ">\n");
3844   }
3845 
3846 public:
XMLPrinter(FILE * out=stdout)3847   XMLPrinter(FILE* out = stdout) : ConfigPrinter(out), m_indent(0) {}
~XMLPrinter()3848   virtual ~XMLPrinter() {
3849     assert(m_indent == 0);
3850   }
3851 
start()3852   virtual void start() {
3853     BaseString buf;
3854     Properties pairs;
3855     pairs.put("protocolversion", "1");
3856     pairs.put("ndbversionstring", ndbGetOwnVersionString());
3857     Uint32 ndbversion = ndbGetOwnVersion();
3858     buf.assfmt("%u", ndbversion);
3859     pairs.put("ndbversion", buf.c_str());
3860     buf.assfmt("%u", ndbGetMajor(ndbversion));
3861     pairs.put("ndbversionmajor", buf.c_str());
3862     buf.assfmt("%u", ndbGetMinor(ndbversion));
3863     pairs.put("ndbversionminor", buf.c_str());
3864     buf.assfmt("%u", ndbGetBuild(ndbversion));
3865     pairs.put("ndbversionbuild", buf.c_str());
3866 
3867     print_xml("configvariables", pairs, false);
3868     m_indent++;
3869   }
end()3870   virtual void end() {
3871     m_indent--;
3872     Properties pairs;
3873     print_xml("/configvariables", pairs, false);
3874   }
3875 
section_start(const char * name,const char * alias,const char * primarykeys=NULL)3876   virtual void section_start(const char* name, const char* alias,
3877                              const char* primarykeys = NULL) {
3878     Properties pairs;
3879     pairs.put("name", alias ? alias : name);
3880     if (primarykeys)
3881       pairs.put("primarykeys", primarykeys);
3882     print_xml("section", pairs, false);
3883     m_indent++;
3884   }
section_end(const char * name)3885   virtual void section_end(const char* name) {
3886     m_indent--;
3887     Properties pairs;
3888     print_xml("/section", pairs, false);
3889   }
3890 
parameter(const char * section_name,const Properties * section,const char * param_name,const ConfigInfo & info)3891   virtual void parameter(const char* section_name,
3892                          const Properties* section,
3893                          const char* param_name,
3894                          const ConfigInfo& info){
3895     BaseString buf;
3896     Properties pairs;
3897     pairs.put("name", param_name);
3898     pairs.put("comment", info.getDescription(section, param_name));
3899 
3900     switch (info.getType(section, param_name)) {
3901     case ConfigInfo::CI_BOOL:
3902       pairs.put("type", "bool");
3903 
3904       if (info.getMandatory(section, param_name))
3905         pairs.put("mandatory", "true");
3906       else if (info.hasDefault(section, param_name))
3907       {
3908         if (info.getDefault(section, param_name) == false)
3909           pairs.put("default", "false");
3910         else if (info.getDefault(section, param_name) == true)
3911           pairs.put("default", "true");
3912       }
3913       break;
3914 
3915     case ConfigInfo::CI_INT:
3916     case ConfigInfo::CI_INT64:
3917       pairs.put("type", "unsigned");
3918 
3919       if (info.getMandatory(section, param_name))
3920         pairs.put("mandatory", "true");
3921       else if (info.hasDefault(section, param_name))
3922       {
3923         buf.assfmt("%llu", info.getDefault(section, param_name));
3924         pairs.put("default", buf.c_str());
3925       }
3926       buf.assfmt("%llu", info.getMin(section, param_name));
3927       pairs.put("min", buf.c_str());
3928       buf.assfmt("%llu", info.getMax(section, param_name));
3929       pairs.put("max", buf.c_str());
3930     break;
3931 
3932     case ConfigInfo::CI_BITMASK:
3933     case ConfigInfo::CI_ENUM:
3934     case ConfigInfo::CI_STRING:
3935       pairs.put("type", "string");
3936 
3937       if (info.getMandatory(section, param_name))
3938         pairs.put("mandatory", "true");
3939       else if (info.hasDefault(section, param_name))
3940         pairs.put("default", info.getDefaultString(section, param_name));
3941       break;
3942 
3943     case ConfigInfo::CI_SECTION:
3944       return; // Don't print anything for the section itself
3945     }
3946 
3947     // Get "check" flag(s)
3948     Uint32 flags = info.getFlags(section, param_name);
3949     buf.clear();
3950     if (flags & ConfigInfo::CI_CHECK_WRITABLE)
3951       buf.append("writable");
3952 
3953     if (buf.length())
3954       pairs.put("check", buf.c_str());
3955 
3956     // Get "restart" flag
3957     if (flags & ConfigInfo::CI_RESTART_SYSTEM)
3958       pairs.put("restart", "system");
3959 
3960     // Get "initial" flag
3961     if (flags & ConfigInfo::CI_RESTART_INITIAL)
3962       pairs.put("initial", "true");
3963 
3964     // Get "supported" flag
3965     Uint32 status = info.getStatus(section, param_name);
3966     buf.clear();
3967     if (status & ConfigInfo::CI_EXPERIMENTAL)
3968       buf.append("experimental");
3969 
3970     if (buf.length())
3971       pairs.put("supported", buf.c_str());
3972 
3973     print_xml("param", pairs);
3974   }
3975 };
3976 
print(const char * section) const3977 void ConfigInfo::print(const char* section) const {
3978   PrettyPrinter pretty_printer;
3979   print_impl(section, pretty_printer);
3980 }
3981 
print_xml(const char * section) const3982 void ConfigInfo::print_xml(const char* section) const {
3983   XMLPrinter xml_printer;
3984   print_impl(section, xml_printer);
3985 }
3986 
3987 
3988 bool
is_internal_section(const Properties * sec) const3989 ConfigInfo::is_internal_section(const Properties* sec) const
3990 {
3991   /* Check if the section is marked as internal */
3992   Properties::Iterator it(sec);
3993   for (const char* n = it.first(); n != NULL; n = it.next()) {
3994     if (getStatus(sec, n) == ConfigInfo::CI_INTERNAL &&
3995         getType(sec, n) == ConfigInfo:: CI_SECTION)
3996       return true;
3997   }
3998   return false;
3999 }
4000 
4001 
print_impl(const char * section_filter,ConfigPrinter & printer) const4002 void ConfigInfo::print_impl(const char* section_filter,
4003                             ConfigPrinter& printer) const {
4004   printer.start();
4005   /* Iterate through all sections */
4006   Properties::Iterator it(&m_info);
4007   for (const char* s = it.first(); s != NULL; s = it.next()) {
4008     if (section_filter && strcmp(section_filter, s))
4009       continue; // Skip this section
4010 
4011     const Properties * sec = getInfo(s);
4012 
4013     if (is_internal_section(sec))
4014       continue; // Skip whole section
4015 
4016     const char* section_alias = nameToAlias(s);
4017     printer.section_start(s, section_alias, sectionPrimaryKeys(s));
4018 
4019     /* Iterate through all parameters in section */
4020     Properties::Iterator it(sec);
4021     for (const char* n = it.first(); n != NULL; n = it.next()) {
4022       // Skip entries with different F- and P-names
4023       if (getStatus(sec, n) == ConfigInfo::CI_INTERNAL) continue;
4024       if (getStatus(sec, n) == ConfigInfo::CI_DEPRECATED) continue;
4025       if (getStatus(sec, n) == ConfigInfo::CI_NOTIMPLEMENTED) continue;
4026       printer.parameter(s, sec, n, *this);
4027     }
4028     printer.section_end(s);
4029 
4030     // Print [<section> DEFAULT] for all sections but SYSTEM
4031     if (strcmp(s, "SYSTEM") == 0)
4032       continue; // Skip SYSTEM section
4033 
4034     BaseString default_section_name;
4035     default_section_name.assfmt("%s %s",
4036                                 section_alias ? section_alias : s,
4037                                 "DEFAULT");
4038     printer.section_start(s, default_section_name.c_str());
4039 
4040     /* Iterate through all parameters in section */
4041     for (const char* n = it.first(); n != NULL; n = it.next()) {
4042       // Skip entries with different F- and P-names
4043       if (getStatus(sec, n) == ConfigInfo::CI_INTERNAL) continue;
4044       if (getStatus(sec, n) == ConfigInfo::CI_DEPRECATED) continue;
4045       if (getStatus(sec, n) == ConfigInfo::CI_NOTIMPLEMENTED) continue;
4046       printer.parameter(s, sec, n, *this);
4047     }
4048     printer.section_end(s);
4049 
4050   }
4051   printer.end();
4052 }
4053 
4054 
4055 
4056 /****************************************************************************
4057  * Section Rules
4058  ****************************************************************************/
4059 
4060 /**
4061  * Node rule: Add "Type" and update "NoOfNodes"
4062  */
4063 bool
transformNode(InitConfigFileParser::Context & ctx,const char * data)4064 transformNode(InitConfigFileParser::Context & ctx, const char * data){
4065 
4066   Uint32 id, line;
4067   if(!ctx.m_currentSection->get("NodeId", &id) && !ctx.m_currentSection->get("Id", &id)){
4068     Uint32 nextNodeId= 1;
4069     ctx.m_userProperties.get("NextNodeId", &nextNodeId);
4070     id= nextNodeId;
4071     while (ctx.m_userProperties.get("AllocatedNodeId_", id, &line))
4072       id++;
4073     if (id != nextNodeId)
4074     {
4075       fprintf(stderr,"Cluster configuration warning line %d: "
4076 	       "Could not use next node id %d for section [%s], "
4077 	       "using next unused node id %d.\n",
4078 	       ctx.m_sectionLineno, nextNodeId, ctx.fname, id);
4079     }
4080     ctx.m_currentSection->put("NodeId", id);
4081   } else if(ctx.m_userProperties.get("AllocatedNodeId_", id, &line)) {
4082     ctx.reportError("Duplicate nodeid in section "
4083 		    "[%s] starting at line: %d. Previously used on line %d.",
4084 		    ctx.fname, ctx.m_sectionLineno, line);
4085     return false;
4086   }
4087 
4088   if(id >= MAX_NODES)
4089   {
4090     ctx.reportError("too many nodes configured, only up to %d nodes supported.",
4091             MAX_NODES);
4092     return false;
4093   }
4094 
4095   // next node id _always_ next numbers after last used id
4096   ctx.m_userProperties.put("NextNodeId", id+1, true);
4097 
4098   ctx.m_userProperties.put("AllocatedNodeId_", id, ctx.m_sectionLineno);
4099   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id);
4100 
4101   ctx.m_currentSection->put("Type", ctx.fname);
4102 
4103   Uint32 nodes = 0;
4104   ctx.m_userProperties.get("NoOfNodes", &nodes);
4105   ctx.m_userProperties.put("NoOfNodes", ++nodes, true);
4106 
4107   /**
4108    * Update count (per type)
4109    */
4110   nodes = 0;
4111   ctx.m_userProperties.get(ctx.fname, &nodes);
4112   ctx.m_userProperties.put(ctx.fname, ++nodes, true);
4113 
4114   return true;
4115 }
4116 
checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx,const char * data)4117 static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const char * data)
4118 {
4119   DBUG_ENTER("checkLocalhostHostnameMix");
4120   const char * hostname= 0;
4121   ctx.m_currentSection->get("HostName", &hostname);
4122   if (hostname == 0 || hostname[0] == 0)
4123     DBUG_RETURN(true);
4124 
4125   Uint32 localhost_used= 0;
4126   if(!strcmp(hostname, "localhost") || !strcmp(hostname, "127.0.0.1")){
4127     localhost_used= 1;
4128     ctx.m_userProperties.put("$computer-localhost-used", localhost_used);
4129     if(!ctx.m_userProperties.get("$computer-localhost", &hostname))
4130       DBUG_RETURN(true);
4131   } else {
4132     ctx.m_userProperties.get("$computer-localhost-used", &localhost_used);
4133     ctx.m_userProperties.put("$computer-localhost", hostname);
4134   }
4135 
4136   if (localhost_used) {
4137     ctx.reportError("Mixing of localhost (default for [NDBD]HostName) with other hostname(%s) is illegal",
4138 		    hostname);
4139     DBUG_RETURN(false);
4140   }
4141 
4142   DBUG_RETURN(true);
4143 }
4144 
4145 bool
fixNodeHostname(InitConfigFileParser::Context & ctx,const char * data)4146 fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data)
4147 {
4148   const char * hostname;
4149   DBUG_ENTER("fixNodeHostname");
4150 
4151   if (ctx.m_currentSection->get("HostName", &hostname))
4152     DBUG_RETURN(checkLocalhostHostnameMix(ctx,0));
4153 
4154   const char * compId;
4155   if(!ctx.m_currentSection->get("ExecuteOnComputer", &compId))
4156     DBUG_RETURN(true);
4157 
4158   const Properties * computer;
4159   char tmp[255];
4160   BaseString::snprintf(tmp, sizeof(tmp), "Computer_%s", compId);
4161   if(!ctx.m_config->get(tmp, &computer)){
4162     ctx.reportError("Computer \"%s\" not declared"
4163 		    "- [%s] starting at line: %d",
4164 		    compId, ctx.fname, ctx.m_sectionLineno);
4165     DBUG_RETURN(false);
4166   }
4167 
4168   if(!computer->get("HostName", &hostname)){
4169     ctx.reportError("HostName missing in [COMPUTER] (Id: %s) "
4170 		    " - [%s] starting at line: %d",
4171 		    compId, ctx.fname, ctx.m_sectionLineno);
4172     DBUG_RETURN(false);
4173   }
4174 
4175   require(ctx.m_currentSection->put("HostName", hostname));
4176   DBUG_RETURN(checkLocalhostHostnameMix(ctx,0));
4177 }
4178 
4179 bool
fixFileSystemPath(InitConfigFileParser::Context & ctx,const char * data)4180 fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data){
4181   DBUG_ENTER("fixFileSystemPath");
4182 
4183   const char * path;
4184   if (ctx.m_currentSection->get("FileSystemPath", &path))
4185     DBUG_RETURN(true);
4186 
4187   if (ctx.m_currentSection->get("DataDir", &path)) {
4188     require(ctx.m_currentSection->put("FileSystemPath", path));
4189     DBUG_RETURN(true);
4190   }
4191 
4192   require(false);
4193   DBUG_RETURN(false);
4194 }
4195 
4196 bool
fixBackupDataDir(InitConfigFileParser::Context & ctx,const char * data)4197 fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data){
4198 
4199   const char * path;
4200   if (ctx.m_currentSection->get("BackupDataDir", &path))
4201     return true;
4202 
4203   if (ctx.m_currentSection->get("FileSystemPath", &path)) {
4204     require(ctx.m_currentSection->put("BackupDataDir", path));
4205     return true;
4206   }
4207 
4208   require(false);
4209   return false;
4210 }
4211 
4212 /**
4213  * Connection rule: Check support of connection
4214  */
4215 bool
checkConnectionSupport(InitConfigFileParser::Context & ctx,const char * data)4216 checkConnectionSupport(InitConfigFileParser::Context & ctx, const char * data)
4217 {
4218   int error= 0;
4219   if (strcasecmp("TCP",ctx.fname) == 0)
4220   {
4221     // always enabled
4222   }
4223   else if (strcasecmp("SHM",ctx.fname) == 0)
4224   {
4225 #ifndef NDB_SHM_TRANSPORTER
4226     error= 1;
4227 #endif
4228   }
4229   else if (strcasecmp("SCI",ctx.fname) == 0)
4230   {
4231 #ifndef NDB_SCI_TRANSPORTER
4232     error= 1;
4233 #endif
4234   }
4235 
4236   if (error)
4237   {
4238     ctx.reportError("Binary not compiled with this connection support, "
4239 		    "[%s] starting at line: %d",
4240 		    ctx.fname, ctx.m_sectionLineno);
4241     return false;
4242   }
4243   return true;
4244 }
4245 
4246 /**
4247  * Connection rule: Update "NoOfConnections"
4248  */
4249 bool
transformConnection(InitConfigFileParser::Context & ctx,const char * data)4250 transformConnection(InitConfigFileParser::Context & ctx, const char * data)
4251 {
4252   Uint32 connections = 0;
4253   ctx.m_userProperties.get("NoOfConnections", &connections);
4254   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Connection_%d", connections);
4255   ctx.m_userProperties.put("NoOfConnections", ++connections, true);
4256 
4257   ctx.m_currentSection->put("Type", ctx.fname);
4258   return true;
4259 }
4260 
4261 /**
4262  * System rule: Just add it
4263  */
4264 bool
transformSystem(InitConfigFileParser::Context & ctx,const char * data)4265 transformSystem(InitConfigFileParser::Context & ctx, const char * data){
4266 
4267   const char * name;
4268   if(!ctx.m_currentSection->get("Name", &name)){
4269     ctx.reportError("Mandatory parameter Name missing from section "
4270 		    "[%s] starting at line: %d",
4271 		    ctx.fname, ctx.m_sectionLineno);
4272     return false;
4273   }
4274 
4275   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name);
4276 
4277   ctx.m_currentSection->put("Type", ctx.fname);
4278 
4279   return true;
4280 }
4281 
4282 /**
4283  * Computer rule: Update "NoOfComputers", add "Type"
4284  */
4285 bool
transformComputer(InitConfigFileParser::Context & ctx,const char * data)4286 transformComputer(InitConfigFileParser::Context & ctx, const char * data){
4287   const char * id;
4288   if(!ctx.m_currentSection->get("Id", &id)){
4289     ctx.reportError("Mandatory parameter Id missing from section "
4290 		    "[%s] starting at line: %d",
4291 		    ctx.fname, ctx.m_sectionLineno);
4292     return false;
4293   }
4294   BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Computer_%s", id);
4295 
4296   Uint32 computers = 0;
4297   ctx.m_userProperties.get("NoOfComputers", &computers);
4298   ctx.m_userProperties.put("NoOfComputers", ++computers, true);
4299 
4300   const char * hostname = 0;
4301   ctx.m_currentSection->get("HostName", &hostname);
4302   if(!hostname){
4303     return true;
4304   }
4305 
4306   return checkLocalhostHostnameMix(ctx,0);
4307 }
4308 
4309 /**
4310  * Apply default values
4311  */
4312 void
applyDefaultValues(InitConfigFileParser::Context & ctx,const Properties * defaults)4313 applyDefaultValues(InitConfigFileParser::Context & ctx,
4314 		   const Properties * defaults)
4315 {
4316   DBUG_ENTER("applyDefaultValues");
4317   if(defaults != NULL){
4318     Properties::Iterator it(defaults);
4319 
4320     for(const char * name = it.first(); name != NULL; name = it.next()){
4321       (void) ctx.m_info->getStatus(ctx.m_currentInfo, name);
4322       if(!ctx.m_currentSection->contains(name)){
4323 	switch (ctx.m_info->getType(ctx.m_currentInfo, name)){
4324 	case ConfigInfo::CI_ENUM:
4325 	case ConfigInfo::CI_INT:
4326 	case ConfigInfo::CI_BOOL:{
4327 	  Uint32 val = 0;
4328 	  require(defaults->get(name, &val));
4329 	  ctx.m_currentSection->put(name, val);
4330           DBUG_PRINT("info",("%s=%d #default",name,val));
4331 	  break;
4332 	}
4333 	case ConfigInfo::CI_INT64:{
4334 	  Uint64 val = 0;
4335 	  require(defaults->get(name, &val));
4336 	  ctx.m_currentSection->put64(name, val);
4337           DBUG_PRINT("info",("%s=%lld #default",name,val));
4338 	  break;
4339 	}
4340         case ConfigInfo::CI_BITMASK:
4341 	case ConfigInfo::CI_STRING:{
4342 	  const char * val;
4343 	  require(defaults->get(name, &val));
4344 	  ctx.m_currentSection->put(name, val);
4345           DBUG_PRINT("info",("%s=%s #default",name,val));
4346 	  break;
4347 	}
4348 	case ConfigInfo::CI_SECTION:
4349 	  break;
4350         }
4351       }
4352 #ifndef DBUG_OFF
4353       else
4354       {
4355         switch (ctx.m_info->getType(ctx.m_currentInfo, name)){
4356         case ConfigInfo::CI_ENUM:
4357         case ConfigInfo::CI_INT:
4358         case ConfigInfo::CI_BOOL:{
4359           Uint32 val = 0;
4360           require(ctx.m_currentSection->get(name, &val));
4361           DBUG_PRINT("info",("%s=%d",name,val));
4362           break;
4363         }
4364         case ConfigInfo::CI_INT64:{
4365           Uint64 val = 0;
4366           require(ctx.m_currentSection->get(name, &val));
4367           DBUG_PRINT("info",("%s=%lld",name,val));
4368           break;
4369         }
4370         case ConfigInfo::CI_BITMASK:
4371         case ConfigInfo::CI_STRING:{
4372           const char * val;
4373           require(ctx.m_currentSection->get(name, &val));
4374           DBUG_PRINT("info",("%s=%s",name,val));
4375           break;
4376         }
4377         case ConfigInfo::CI_SECTION:
4378           break;
4379         }
4380       }
4381 #endif
4382     }
4383   }
4384   DBUG_VOID_RETURN;
4385 }
4386 
4387 bool
applyDefaultValues(InitConfigFileParser::Context & ctx,const char * data)4388 applyDefaultValues(InitConfigFileParser::Context & ctx, const char * data){
4389 
4390   if(strcmp(data, "user") == 0)
4391     applyDefaultValues(ctx, ctx.m_userDefaults);
4392   else if (strcmp(data, "system") == 0)
4393     applyDefaultValues(ctx, ctx.m_systemDefaults);
4394   else
4395     return false;
4396 
4397   return true;
4398 }
4399 
4400 /**
4401  * Check that a section contains all MANDATORY parameters
4402  */
4403 bool
checkMandatory(InitConfigFileParser::Context & ctx,const char * data)4404 checkMandatory(InitConfigFileParser::Context & ctx, const char * data){
4405 
4406   Properties::Iterator it(ctx.m_currentInfo);
4407   for(const char * name = it.first(); name != NULL; name = it.next()){
4408     const Properties * info = NULL;
4409     require(ctx.m_currentInfo->get(name, &info));
4410     Uint32 val;
4411     if(info->get("Mandatory", &val)){
4412       const char * fname;
4413       require(info->get("Fname", &fname));
4414       if(!ctx.m_currentSection->contains(fname)){
4415 	ctx.reportError("Mandatory parameter %s missing from section "
4416 			"[%s] starting at line: %d",
4417 			fname, ctx.fname, ctx.m_sectionLineno);
4418 	return false;
4419       }
4420     }
4421   }
4422   return true;
4423 }
4424 
4425 /**
4426  * Connection rule: Fix node id
4427  *
4428  * Transform a string "NodeidX" (e.g. "uppsala.32")
4429  * into a Uint32 "NodeIdX" (e.g. 32) and a string "SystemX" (e.g. "uppsala").
4430  */
fixNodeId(InitConfigFileParser::Context & ctx,const char * data)4431 static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data)
4432 {
4433   char buf[] = "NodeIdX";  buf[6] = data[sizeof("NodeI")];
4434   char sysbuf[] = "SystemX";  sysbuf[6] = data[sizeof("NodeI")];
4435   const char* nodeId;
4436   if(!ctx.m_currentSection->get(buf, &nodeId))
4437   {
4438     ctx.reportError("Mandatory parameter %s missing from section"
4439                     "[%s] starting at line: %d",
4440                     buf, ctx.fname, ctx.m_sectionLineno);
4441     return false;
4442   }
4443 
4444   BaseString str(nodeId);
4445   Vector<BaseString> token_list;
4446   int tokens = str.split(token_list, ".", 2);
4447 
4448   Uint32 id;
4449 
4450   if (tokens == 0)
4451   {
4452     ctx.reportError("Value for mandatory parameter %s missing from section "
4453                     "[%s] starting at line: %d",
4454                     buf, ctx.fname, ctx.m_sectionLineno);
4455     return false;
4456   }
4457 
4458   const char* token1 = token_list[0].c_str();
4459   if (tokens == 1) {                // Only a number given
4460     errno = 0;
4461     char* p;
4462     id = strtol(token1, &p, 10);
4463     if (errno != 0 || id <= 0x0  || id > MAX_NODES)
4464     {
4465       ctx.reportError("Illegal value for mandatory parameter %s from section "
4466                     "[%s] starting at line: %d",
4467                     buf, ctx.fname, ctx.m_sectionLineno);
4468       return false;
4469     }
4470     require(ctx.m_currentSection->put(buf, id, true));
4471   } else {                             // A pair given (e.g. "uppsala.32")
4472     assert(tokens == 2 && token_list.size() == 2);
4473     const char* token2 = token_list[1].c_str();
4474 
4475     errno = 0;
4476     char* p;
4477     id = strtol(token2, &p, 10);
4478     if (errno != 0 || id <= 0x0  || id > MAX_NODES)
4479     {
4480       ctx.reportError("Illegal value for mandatory parameter %s from section "
4481                     "[%s] starting at line: %d",
4482                     buf, ctx.fname, ctx.m_sectionLineno);
4483       return false;
4484     }
4485     require(ctx.m_currentSection->put(buf, id, true));
4486     require(ctx.m_currentSection->put(sysbuf, token1));
4487   }
4488   return true;
4489 }
4490 
4491 /**
4492  * Connection rule: Fix hostname
4493  *
4494  * Unless Hostname is not already specified, do steps:
4495  * -# Via Connection's NodeId lookup Node
4496  * -# Via Node's ExecuteOnComputer lookup Hostname
4497  * -# Add HostName to Connection
4498  */
4499 static bool
fixHostname(InitConfigFileParser::Context & ctx,const char * data)4500 fixHostname(InitConfigFileParser::Context & ctx, const char * data){
4501 
4502   char buf[] = "NodeIdX"; buf[6] = data[sizeof("HostNam")];
4503   char sysbuf[] = "SystemX"; sysbuf[6] = data[sizeof("HostNam")];
4504 
4505   if(!ctx.m_currentSection->contains(data)){
4506     Uint32 id = 0;
4507     require(ctx.m_currentSection->get(buf, &id));
4508 
4509     const Properties * node;
4510     if(!ctx.m_config->get("Node", id, &node))
4511     {
4512       ctx.reportError("Unknown node: \"%d\" specified in connection "
4513 		      "[%s] starting at line: %d",
4514 		      id, ctx.fname, ctx.m_sectionLineno);
4515       return false;
4516     }
4517 
4518     const char * hostname;
4519     require(node->get("HostName", &hostname));
4520     require(ctx.m_currentSection->put(data, hostname));
4521   }
4522   return true;
4523 }
4524 
4525 /**
4526  * Connection rule: Fix port number (using a port number adder)
4527  */
4528 static bool
fixPortNumber(InitConfigFileParser::Context & ctx,const char * data)4529 fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){
4530 
4531   DBUG_ENTER("fixPortNumber");
4532 
4533   Uint32 id1, id2;
4534   const char *hostName1;
4535   const char *hostName2;
4536   require(ctx.m_currentSection->get("NodeId1", &id1));
4537   require(ctx.m_currentSection->get("NodeId2", &id2));
4538   require(ctx.m_currentSection->get("HostName1", &hostName1));
4539   require(ctx.m_currentSection->get("HostName2", &hostName2));
4540   DBUG_PRINT("info",("NodeId1=%d HostName1=\"%s\"",id1,hostName1));
4541   DBUG_PRINT("info",("NodeId2=%d HostName2=\"%s\"",id2,hostName2));
4542 
4543   const Properties *node1, *node2;
4544   require(ctx.m_config->get("Node", id1, &node1));
4545   require(ctx.m_config->get("Node", id2, &node2));
4546 
4547   const char *type1, *type2;
4548   require(node1->get("Type", &type1));
4549   require(node2->get("Type", &type2));
4550 
4551   /* add NodeIdServer info */
4552   {
4553     Uint32 nodeIdServer = id1 < id2 ? id1 : id2;
4554     if(strcmp(type1, API_TOKEN) == 0 || strcmp(type2, MGM_TOKEN) == 0)
4555       nodeIdServer = id2;
4556     else if(strcmp(type2, API_TOKEN) == 0 || strcmp(type1, MGM_TOKEN) == 0)
4557       nodeIdServer = id1;
4558     ctx.m_currentSection->put("NodeIdServer", nodeIdServer);
4559 
4560     if (id2 == nodeIdServer) {
4561       {
4562 	const char *tmp= hostName1;
4563 	hostName1= hostName2;
4564 	hostName2= tmp;
4565       }
4566       {
4567 	Uint32 tmp= id1;
4568 	id1= id2;
4569 	id2= tmp;
4570       }
4571       {
4572 	const Properties *tmp= node1;
4573 	node1= node2;
4574 	node2= tmp;
4575       }
4576       {
4577 	const char *tmp= type1;
4578 	type1= type2;
4579 	type2= tmp;
4580       }
4581     }
4582   }
4583 
4584   BaseString hostname(hostName1);
4585 
4586   if (hostname.c_str()[0] == 0) {
4587     ctx.reportError("Hostname required on nodeid %d since it will "
4588 		    "act as server.", id1);
4589     DBUG_RETURN(false);
4590   }
4591 
4592   Uint32 bindAnyAddr = 0;
4593   node1->get("TcpBind_INADDR_ANY", &bindAnyAddr);
4594   if (bindAnyAddr)
4595   {
4596     ctx.m_currentSection->put("TcpBind_INADDR_ANY", 1, true);
4597   }
4598 
4599   Uint32 port= 0;
4600   if(strcmp(type1, MGM_TOKEN)==0)
4601     node1->get("PortNumber",&port);
4602   else if(strcmp(type2, MGM_TOKEN)==0)
4603     node2->get("PortNumber",&port);
4604 
4605   if (!port &&
4606       !node1->get("ServerPort", &port) &&
4607       !ctx.m_userProperties.get("ServerPort_", id1, &port))
4608   {
4609     Uint32 base= 0;
4610     /*
4611      * If the connection doesn't involve an mgm server,
4612      * and a default port number has been set, behave the old
4613      * way of allocating port numbers for transporters.
4614      */
4615     if(ctx.m_userDefaults && ctx.m_userDefaults->get("PortNumber", &base))
4616     {
4617       Uint32 adder= 0;
4618       {
4619 	BaseString server_port_adder(hostname);
4620 	server_port_adder.append("_ServerPortAdder");
4621 	ctx.m_userProperties.get(server_port_adder.c_str(), &adder);
4622 	ctx.m_userProperties.put(server_port_adder.c_str(), adder+1, true);
4623       }
4624 
4625       port= base + adder;
4626       ctx.m_userProperties.put("ServerPort_", id1, port);
4627     }
4628   }
4629 
4630   if(ctx.m_currentSection->contains("PortNumber")) {
4631     ndbout << "PortNumber should no longer be specificied "
4632 	   << "per connection, please remove from config. "
4633 	   << "Will be changed to " << port << endl;
4634     ctx.m_currentSection->put("PortNumber", port, true);
4635   }
4636   else
4637   {
4638     ctx.m_currentSection->put("PortNumber", port);
4639   }
4640 
4641   DBUG_PRINT("info", ("connection %d-%d port %d host %s",
4642 		      id1, id2, port, hostname.c_str()));
4643 
4644   DBUG_RETURN(true);
4645 }
4646 
4647 static bool
fixShmUniqueId(InitConfigFileParser::Context & ctx,const char * data)4648 fixShmUniqueId(InitConfigFileParser::Context & ctx, const char * data)
4649 {
4650   DBUG_ENTER("fixShmUniqueId");
4651   Uint32 nodes= 0;
4652   ctx.m_userProperties.get(ctx.fname, &nodes);
4653   if (nodes == 1) // first management server
4654   {
4655     Uint32 portno= NDB_PORT;
4656     ctx.m_currentSection->get("PortNumber", &portno);
4657     ctx.m_userProperties.put("ShmUniqueId", portno);
4658   }
4659   DBUG_RETURN(true);
4660 }
4661 
4662 static
4663 bool
fixShmKey(InitConfigFileParser::Context & ctx,const char *)4664 fixShmKey(InitConfigFileParser::Context & ctx, const char *)
4665 {
4666   DBUG_ENTER("fixShmKey");
4667   {
4668     static int last_signum= -1;
4669     Uint32 signum = 0;
4670     if(!ctx.m_currentSection->get("Signum", &signum))
4671     {
4672       if (signum <= 0)
4673       {
4674 	  ctx.reportError("Unable to set default parameter for [SHM]Signum"
4675 			  " please specify [SHM DEFAULT]Signum");
4676 	  return false;
4677       }
4678       ctx.m_currentSection->put("Signum", signum);
4679       DBUG_PRINT("info",("Added Signum=%u", signum));
4680     }
4681     if ( last_signum != (int)signum && last_signum >= 0 )
4682     {
4683       ctx.reportError("All shared memory transporters must have same [SHM]Signum defined."
4684 		      " Use [SHM DEFAULT]Signum");
4685       return false;
4686     }
4687     last_signum= (int)signum;
4688   }
4689   {
4690     Uint32 id1= 0, id2= 0, key= 0;
4691     require(ctx.m_currentSection->get("NodeId1", &id1));
4692     require(ctx.m_currentSection->get("NodeId2", &id2));
4693     if(!ctx.m_currentSection->get("ShmKey", &key))
4694     {
4695       require(ctx.m_userProperties.get("ShmUniqueId", &key));
4696       key= key << 16 | (id1 > id2 ? id1 << 8 | id2 : id2 << 8 | id1);
4697       ctx.m_currentSection->put("ShmKey", key);
4698       DBUG_PRINT("info",("Added ShmKey=0x%x", key));
4699     }
4700   }
4701   DBUG_RETURN(true);
4702 }
4703 
4704 /**
4705  * DB Node rule: Check various constraints
4706  */
4707 static bool
checkDbConstraints(InitConfigFileParser::Context & ctx,const char *)4708 checkDbConstraints(InitConfigFileParser::Context & ctx, const char *){
4709 
4710   Uint32 t1 = 0, t2 = 0;
4711   ctx.m_currentSection->get("MaxNoOfConcurrentOperations", &t1);
4712   ctx.m_currentSection->get("MaxNoOfConcurrentTransactions", &t2);
4713 
4714   if (t1 < t2) {
4715     ctx.reportError("MaxNoOfConcurrentOperations must be greater than "
4716 		    "MaxNoOfConcurrentTransactions - [%s] starting at line: %d",
4717 		    ctx.fname, ctx.m_sectionLineno);
4718     return false;
4719   }
4720 
4721   Uint32 replicas = 0, otherReplicas;
4722   ctx.m_currentSection->get("NoOfReplicas", &replicas);
4723   if(ctx.m_userProperties.get("NoOfReplicas", &otherReplicas)){
4724     if(replicas != otherReplicas){
4725       ctx.reportError("NoOfReplicas defined differently on different nodes"
4726 		      " - [%s] starting at line: %d",
4727 		      ctx.fname, ctx.m_sectionLineno);
4728       return false;
4729     }
4730   } else {
4731     ctx.m_userProperties.put("NoOfReplicas", replicas);
4732   }
4733 
4734   /**
4735    * In kernel, will calculate the MaxNoOfMeataTables use the following sum:
4736    * Uint32 noOfMetaTables = noOfTables + noOfOrderedIndexes +
4737    *                         noOfUniqueHashIndexes + 2
4738    * 2 is the number of the SysTables.
4739    * So must check that the sum does't exceed the max value of Uint32.
4740    */
4741   Uint32 noOfTables = 0,
4742          noOfOrderedIndexes = 0,
4743          noOfUniqueHashIndexes = 0;
4744   ctx.m_currentSection->get("MaxNoOfTables", &noOfTables);
4745   ctx.m_currentSection->get("MaxNoOfOrderedIndexes", &noOfOrderedIndexes);
4746   ctx.m_currentSection->get("MaxNoOfUniqueHashIndexes", &noOfUniqueHashIndexes);
4747 
4748   Uint64 sum= (Uint64)noOfTables + noOfOrderedIndexes + noOfUniqueHashIndexes;
4749 
4750   if (sum > ((Uint32)~0 - 2)) {
4751     ctx.reportError("The sum of MaxNoOfTables, MaxNoOfOrderedIndexes and"
4752 		    " MaxNoOfUniqueHashIndexes must not exceed %u - [%s]"
4753                     " starting at line: %d",
4754 		    ((Uint32)~0 - 2), ctx.fname, ctx.m_sectionLineno);
4755     return false;
4756   }
4757 
4758   return true;
4759 }
4760 
4761 #include <NdbThread.h>
4762 
4763 static
4764 bool
checkThreadPrioSpec(InitConfigFileParser::Context & ctx,const char * unused)4765 checkThreadPrioSpec(InitConfigFileParser::Context & ctx, const char * unused)
4766 {
4767   (void)unused;
4768   const char * spec = 0;
4769   if (ctx.m_currentSection->get("HeartbeatThreadPriority", &spec))
4770   {
4771     int ret = NdbThread_SetHighPrioProperties(spec);
4772     NdbThread_SetHighPrioProperties(0); // reset
4773     if (ret)
4774     {
4775       ctx.reportError("Unable to parse HeartbeatThreadPriority: %s", spec);
4776       return false;
4777     }
4778     return true;
4779   }
4780   return true;
4781 }
4782 
4783 #include "../kernel/vm/mt_thr_config.hpp"
4784 
4785 static
4786 bool
checkThreadConfig(InitConfigFileParser::Context & ctx,const char * unused)4787 checkThreadConfig(InitConfigFileParser::Context & ctx, const char * unused)
4788 {
4789   (void)unused;
4790   Uint32 maxExecuteThreads = 0;
4791   Uint32 lqhThreads = 0;
4792   Uint32 classic = 0;
4793   const char * thrconfig = 0;
4794   const char * locktocpu = 0;
4795 
4796   THRConfig tmp;
4797   if (ctx.m_currentSection->get("LockExecuteThreadToCPU", &locktocpu))
4798   {
4799     tmp.setLockExecuteThreadToCPU(locktocpu);
4800   }
4801 
4802   ctx.m_currentSection->get("MaxNoOfExecutionThreads", &maxExecuteThreads);
4803   ctx.m_currentSection->get("__ndbmt_lqh_threads", &lqhThreads);
4804   ctx.m_currentSection->get("__ndbmt_classic", &classic);
4805 
4806   if (ctx.m_currentSection->get("ThreadConfig", &thrconfig))
4807   {
4808     int ret = tmp.do_parse(thrconfig);
4809     if (ret)
4810     {
4811       ctx.reportError("Unable to parse ThreadConfig: %s",
4812                       tmp.getErrorMessage());
4813       return false;
4814     }
4815 
4816     if (maxExecuteThreads)
4817     {
4818       ctx.reportWarning("ThreadConfig overrides MaxNoOfExecutionThreads");
4819     }
4820 
4821     if (lqhThreads)
4822     {
4823       ctx.reportWarning("ThreadConfig overrides __ndbmt_lqh_threads");
4824     }
4825 
4826     if (classic)
4827     {
4828       ctx.reportWarning("ThreadConfig overrides __ndbmt_classic");
4829     }
4830   }
4831   else if (maxExecuteThreads || lqhThreads || classic)
4832   {
4833     int ret = tmp.do_parse(maxExecuteThreads, lqhThreads, classic);
4834     if (ret)
4835     {
4836       ctx.reportError("Unable to set thread configuration: %s",
4837                       tmp.getErrorMessage());
4838       return false;
4839     }
4840   }
4841 
4842   if (tmp.getInfoMessage())
4843   {
4844     ctx.reportWarning("%s", tmp.getInfoMessage());
4845   }
4846 
4847   if (thrconfig == 0)
4848   {
4849     ctx.m_currentSection->put("ThreadConfig", tmp.getConfigString());
4850   }
4851 
4852   return true;
4853 }
4854 
4855 /**
4856  * Connection rule: Check varius constraints
4857  */
4858 static bool
checkConnectionConstraints(InitConfigFileParser::Context & ctx,const char *)4859 checkConnectionConstraints(InitConfigFileParser::Context & ctx, const char *){
4860 
4861   Uint32 id1 = 0, id2 = 0;
4862   ctx.m_currentSection->get("NodeId1", &id1);
4863   ctx.m_currentSection->get("NodeId2", &id2);
4864 
4865   if(id1 == id2){
4866     ctx.reportError("Illegal connection from node to itself"
4867 		    " - [%s] starting at line: %d",
4868 		    ctx.fname, ctx.m_sectionLineno);
4869     return false;
4870   }
4871 
4872   const Properties * node1;
4873   if(!ctx.m_config->get("Node", id1, &node1)){
4874     ctx.reportError("Connection refering to undefined node: %d"
4875 		    " - [%s] starting at line: %d",
4876 		    id1, ctx.fname, ctx.m_sectionLineno);
4877     return false;
4878   }
4879 
4880   const Properties * node2;
4881   if(!ctx.m_config->get("Node", id2, &node2)){
4882     ctx.reportError("Connection refering to undefined node: %d"
4883 		    " - [%s] starting at line: %d",
4884 		    id2, ctx.fname, ctx.m_sectionLineno);
4885     return false;
4886   }
4887 
4888   const char * type1;
4889   const char * type2;
4890   require(node1->get("Type", &type1));
4891   require(node2->get("Type", &type2));
4892 
4893   /**
4894    * Report error if the following are true
4895    * -# None of the nodes is of type DB
4896    * -# Not both of them are MGMs
4897    */
4898   if((strcmp(type1, DB_TOKEN) != 0 && strcmp(type2, DB_TOKEN) != 0) &&
4899      !(strcmp(type1, MGM_TOKEN) == 0 && strcmp(type2, MGM_TOKEN) == 0))
4900   {
4901     ctx.reportError("Invalid connection between node %d (%s) and node %d (%s)"
4902 		    " - [%s] starting at line: %d",
4903 		    id1, type1, id2, type2,
4904 		    ctx.fname, ctx.m_sectionLineno);
4905     return false;
4906   }
4907 
4908   return true;
4909 }
4910 
4911 /**
4912  * Connection rule: allow only one connection between each node pair.
4913  */
4914 static bool
uniqueConnection(InitConfigFileParser::Context & ctx,const char * data)4915 uniqueConnection(InitConfigFileParser::Context & ctx, const char * data)
4916 {
4917   Uint32 lo_node, hi_node;
4918   BaseString key;       /* Properties key to identify this link */
4919   BaseString defn;      /* Value stored at key (used in error msgs) */
4920 
4921   /* This rule runs *after* fixNodeId, so it is guaranteed that the
4922    NodeId1 and NodeId2 properties exist and contain integers */
4923   require(ctx.m_currentSection->get("NodeId1", &lo_node) == true);
4924   require(ctx.m_currentSection->get("NodeId2", &hi_node) == true);
4925 
4926   if(lo_node > hi_node) /* sort the node ids, low-node-first */
4927   {
4928     const Uint32 tmp_node = hi_node;
4929     hi_node = lo_node;
4930     lo_node = tmp_node;
4931   }
4932 
4933   key.assfmt("Link_%d_%d", lo_node, hi_node);
4934 
4935   /* The property must not already exist */
4936   if(ctx.m_userProperties.contains(key.c_str()))
4937   {
4938     const char * old_defn;
4939     if(ctx.m_userProperties.get(key.c_str(), &old_defn))
4940       ctx.reportError("%s connection is a duplicate of the existing %s",
4941                       data, old_defn);
4942     return false;
4943   }
4944 
4945   /* Set the unique link identifier property */
4946   defn.assfmt("%s link from line %d", data, ctx.m_sectionLineno);
4947   ctx.m_userProperties.put(key.c_str(), defn.c_str());
4948 
4949   return true;
4950 }
4951 
4952 static bool
checkTCPConstraints(InitConfigFileParser::Context & ctx,const char * data)4953 checkTCPConstraints(InitConfigFileParser::Context & ctx, const char * data){
4954 
4955   const char * host;
4956   struct in_addr addr;
4957   if(ctx.m_currentSection->get(data, &host) && strlen(host) &&
4958      Ndb_getInAddr(&addr, host)){
4959     ctx.reportError("Unable to lookup/illegal hostname %s"
4960 		    " - [%s] starting at line: %d",
4961 		    host, ctx.fname, ctx.m_sectionLineno);
4962     return false;
4963   }
4964   return true;
4965 }
4966 
4967 static
4968 bool
transform(InitConfigFileParser::Context & ctx,Properties & dst,const char * oldName,const char * newName,double add,double mul)4969 transform(InitConfigFileParser::Context & ctx,
4970 	  Properties & dst,
4971 	  const char * oldName,
4972 	  const char * newName,
4973 	  double add, double mul){
4974 
4975   if(ctx.m_currentSection->contains(newName)){
4976     ctx.reportError("Both %s and %s specified"
4977 		    " - [%s] starting at line: %d",
4978 		    oldName, newName,
4979 		    ctx.fname, ctx.m_sectionLineno);
4980     return false;
4981   }
4982 
4983   PropertiesType oldType;
4984   require(ctx.m_currentSection->getTypeOf(oldName, &oldType));
4985   ConfigInfo::Type newType = ctx.m_info->getType(ctx.m_currentInfo, newName);
4986 
4987   if(!((oldType == PropertiesType_Uint32 || oldType == PropertiesType_Uint64)
4988        && (newType == ConfigInfo::CI_INT || newType == ConfigInfo::CI_INT64 || newType == ConfigInfo::CI_BOOL))){
4989     ndbout << "oldType: " << (int)oldType << ", newType: " << (int)newType << endl;
4990     ctx.reportError("Unable to handle type conversion w.r.t deprecation %s %s"
4991 		    "- [%s] starting at line: %d",
4992 		    oldName, newName,
4993 		    ctx.fname, ctx.m_sectionLineno);
4994     return false;
4995   }
4996   Uint64 oldVal;
4997   require(ctx.m_currentSection->get(oldName, &oldVal));
4998 
4999   Uint64 newVal = (Uint64)((Int64)oldVal * mul + add);
5000   if(!ctx.m_info->verify(ctx.m_currentInfo, newName, newVal)){
5001     ctx.reportError("Unable to handle deprecation, new value not within bounds"
5002 		    "%s %s - [%s] starting at line: %d",
5003 		    oldName, newName,
5004 		    ctx.fname, ctx.m_sectionLineno);
5005     return false;
5006   }
5007 
5008   if(newType == ConfigInfo::CI_INT || newType == ConfigInfo::CI_BOOL){
5009     require(dst.put(newName, (Uint32)newVal));
5010   } else if(newType == ConfigInfo::CI_INT64) {
5011     require(dst.put64(newName, newVal));
5012   }
5013   return true;
5014 }
5015 
5016 static bool
fixDeprecated(InitConfigFileParser::Context & ctx,const char * data)5017 fixDeprecated(InitConfigFileParser::Context & ctx, const char * data){
5018   const char * name;
5019   /**
5020    * Transform old values to new values
5021    * Transform new values to old values (backward compatible)
5022    */
5023   Properties tmp(true);
5024   Properties::Iterator it(ctx.m_currentSection);
5025   for (name = it.first(); name != NULL; name = it.next()) {
5026     const DeprecationTransform * p = &f_deprecation[0];
5027     while(p->m_section != 0){
5028       if(strcmp(p->m_section, ctx.fname) == 0){
5029 	double mul = p->m_mul;
5030 	double add = p->m_add;
5031 	if(strcasecmp(name, p->m_oldName) == 0){
5032 	  if(!transform(ctx, tmp, name, p->m_newName, add, mul)){
5033 	    return false;
5034 	  }
5035 	} else if(strcasecmp(name, p->m_newName) == 0) {
5036 	  if(!transform(ctx, tmp, name, p->m_oldName, -add/mul,1.0/mul)){
5037 	    return false;
5038 	  }
5039 	}
5040       }
5041       p++;
5042     }
5043   }
5044 
5045   Properties::Iterator it2(&tmp);
5046   for (name = it2.first(); name != NULL; name = it2.next()) {
5047     PropertiesType type;
5048     require(tmp.getTypeOf(name, &type));
5049     switch(type){
5050     case PropertiesType_Uint32:{
5051       Uint32 val;
5052       require(tmp.get(name, &val));
5053       require(ctx.m_currentSection->put(name, val));
5054       break;
5055     }
5056     case PropertiesType_char:{
5057       const char * val;
5058       require(tmp.get(name, &val));
5059       require(ctx.m_currentSection->put(name, val));
5060       break;
5061     }
5062     case PropertiesType_Uint64:{
5063       Uint64 val;
5064       require(tmp.get(name, &val));
5065       require(ctx.m_currentSection->put64(name, val));
5066       break;
5067     }
5068     case PropertiesType_Properties:
5069     default:
5070       require(false);
5071     }
5072   }
5073   return true;
5074 }
5075 
5076 static bool
saveInConfigValues(InitConfigFileParser::Context & ctx,const char * data)5077 saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){
5078   const Properties * sec;
5079   if(!ctx.m_currentInfo->get(ctx.fname, &sec)){
5080     require(false);
5081     return false;
5082   }
5083 
5084   do {
5085     const char *secName;
5086     Uint32 id, status, typeVal;
5087     require(sec->get("Fname", &secName));
5088     require(sec->get("Id", &id));
5089     require(sec->get("Status", &status));
5090     require(sec->get("SectionType", &typeVal));
5091 
5092     if(id == KEY_INTERNAL || status == ConfigInfo::CI_INTERNAL){
5093       ndbout_c("skipping section %s", ctx.fname);
5094       break;
5095     }
5096 
5097     Uint32 no = 0;
5098     ctx.m_userProperties.get("$Section", id, &no);
5099     ctx.m_userProperties.put("$Section", id, no+1, true);
5100 
5101     ctx.m_configValues.openSection(id, no);
5102     ctx.m_configValues.put(CFG_TYPE_OF_SECTION, typeVal);
5103 
5104     Properties::Iterator it(ctx.m_currentSection);
5105     for (const char* n = it.first(); n != NULL; n = it.next()) {
5106       const Properties * info;
5107       if(!ctx.m_currentInfo->get(n, &info))
5108 	continue;
5109 
5110       id = 0;
5111       info->get("Id", &id);
5112 
5113       if(id == KEY_INTERNAL)
5114 	continue;
5115 
5116       bool ok = true;
5117       PropertiesType type;
5118       require(ctx.m_currentSection->getTypeOf(n, &type));
5119       switch(type){
5120       case PropertiesType_Uint32:{
5121 	Uint32 val;
5122 	require(ctx.m_currentSection->get(n, &val));
5123 	ok = ctx.m_configValues.put(id, val);
5124 	break;
5125       }
5126       case PropertiesType_Uint64:{
5127 	Uint64 val;
5128 	require(ctx.m_currentSection->get(n, &val));
5129 	ok = ctx.m_configValues.put64(id, val);
5130 	break;
5131       }
5132       case PropertiesType_char:{
5133 	const char * val;
5134 	require(ctx.m_currentSection->get(n, &val));
5135 	ok = ctx.m_configValues.put(id, val);
5136 	break;
5137       }
5138       default:
5139 	require(false);
5140       }
5141       require(ok);
5142     }
5143     ctx.m_configValues.closeSection();
5144   } while(0);
5145   return true;
5146 }
5147 
5148 
5149 static bool
add_system_section(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5150 add_system_section(Vector<ConfigInfo::ConfigRuleSection>&sections,
5151                    struct InitConfigFileParser::Context &ctx,
5152                    const char * rule_data)
5153 {
5154   if (!ctx.m_userProperties.contains("SYSTEM")) {
5155     ConfigInfo::ConfigRuleSection s;
5156 
5157     // Generate a unique name for this new cluster
5158     time_t now = ::time((time_t*)NULL);
5159     struct tm* tm_now = ::localtime(&now);
5160 
5161     char name_buf[18];
5162     BaseString::snprintf(name_buf, sizeof(name_buf),
5163                          "MC_%d%.2d%.2d%.2d%.2d%.2d",
5164                          tm_now->tm_year + 1900,
5165                          tm_now->tm_mon + 1,
5166                          tm_now->tm_mday,
5167                          tm_now->tm_hour,
5168                          tm_now->tm_min,
5169                          tm_now->tm_sec);
5170 
5171     s.m_sectionType = BaseString("SYSTEM");
5172     s.m_sectionData = new Properties(true);
5173     s.m_sectionData->put("Name", name_buf);
5174     s.m_sectionData->put("Type", "SYSTEM");
5175 
5176     // ndbout_c("Generated new SYSTEM section with name '%s'", name_buf);
5177 
5178     sections.push_back(s);
5179   }
5180   return true;
5181 }
5182 
5183 
5184 static bool
sanity_checks(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5185 sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections,
5186 	      struct InitConfigFileParser::Context &ctx,
5187 	      const char * rule_data)
5188 {
5189   Uint32 db_nodes = 0;
5190   Uint32 mgm_nodes = 0;
5191   Uint32 api_nodes = 0;
5192   if (!ctx.m_userProperties.get("DB", &db_nodes)) {
5193     ctx.reportError("At least one database node (ndbd) should be defined in config file");
5194     return false;
5195   }
5196   if (!ctx.m_userProperties.get("MGM", &mgm_nodes)) {
5197     ctx.reportError("At least one management server node (ndb_mgmd) should be defined in config file");
5198     return false;
5199   }
5200   if (!ctx.m_userProperties.get("API", &api_nodes)) {
5201     ctx.reportError("At least one application node (for the mysqld) should be defined in config file");
5202     return false;
5203   }
5204   return true;
5205 }
5206 
5207 static
5208 int
check_connection(struct InitConfigFileParser::Context & ctx,const char * map,Uint32 nodeId1,const char * hostname,Uint32 nodeId2)5209 check_connection(struct InitConfigFileParser::Context &ctx,
5210 		 const char * map,
5211 		 Uint32 nodeId1, const char * hostname,
5212 		 Uint32 nodeId2)
5213 {
5214   Bitmask<(MAX_NODES+31)/32> bitmap;
5215 
5216   BaseString str(map);
5217   Vector<BaseString> arr;
5218   str.split(arr, ",");
5219   for (Uint32 i = 0; i<arr.size(); i++)
5220   {
5221     char *endptr = 0;
5222     long val = strtol(arr[i].c_str(), &endptr, 10);
5223     if (*endptr)
5224     {
5225       ctx.reportError("Unable to parse ConnectionMap(\"%s\" for "
5226 		      "node: %d, hostname: %s",
5227 		      map, nodeId1, hostname);
5228       return -1;
5229     }
5230     if (! (val > 0 && val < MAX_NDB_NODES))
5231     {
5232       ctx.reportError("Invalid node in in ConnectionMap(\"%s\" for "
5233 		      "node: %d, hostname: %s",
5234 		      map, nodeId1, hostname);
5235       return -1;
5236     }
5237     bitmap.set(val);
5238   }
5239   return bitmap.get(nodeId2);
5240 }
5241 
5242 static
5243 bool
add_a_connection(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,Uint32 nodeId1,Uint32 nodeId2,bool use_shm)5244 add_a_connection(Vector<ConfigInfo::ConfigRuleSection>&sections,
5245 		 struct InitConfigFileParser::Context &ctx,
5246 		 Uint32 nodeId1, Uint32 nodeId2, bool use_shm)
5247 {
5248   int ret;
5249   ConfigInfo::ConfigRuleSection s;
5250   const char * map = 0;
5251   const char *hostname1= 0, *hostname2= 0;
5252   const Properties *tmp;
5253 
5254   Uint32 wan = 0;
5255   require(ctx.m_config->get("Node", nodeId1, &tmp));
5256   tmp->get("HostName", &hostname1);
5257   if (!wan)
5258   {
5259     tmp->get("wan", &wan);
5260   }
5261 
5262   if (tmp->get("ConnectionMap", &map))
5263 {
5264     if ((ret = check_connection(ctx, map, nodeId1, hostname1, nodeId2)) != 1)
5265     {
5266       return ret == 0 ? true : false;
5267     }
5268   }
5269 
5270   require(ctx.m_config->get("Node", nodeId2, &tmp));
5271   tmp->get("HostName", &hostname2);
5272   if (!wan)
5273   {
5274     tmp->get("wan", &wan);
5275   }
5276 
5277   if (tmp->get("ConnectionMap", &map))
5278   {
5279     if ((ret = check_connection(ctx, map, nodeId2, hostname2, nodeId1)) != 1)
5280     {
5281       return ret == 0 ? true : false;
5282     }
5283   }
5284 
5285   char buf[16];
5286   s.m_sectionData= new Properties(true);
5287   BaseString::snprintf(buf, sizeof(buf), "%u", nodeId1);
5288   s.m_sectionData->put("NodeId1", buf);
5289   BaseString::snprintf(buf, sizeof(buf), "%u", nodeId2);
5290   s.m_sectionData->put("NodeId2", buf);
5291 
5292   if (use_shm &&
5293       hostname1 && hostname1[0] &&
5294       hostname2 && hostname2[0] &&
5295       strcmp(hostname1,hostname2) == 0)
5296   {
5297     s.m_sectionType= BaseString("SHM");
5298     DBUG_PRINT("info",("adding SHM connection %d %d",nodeId1,nodeId2));
5299   }
5300   else
5301   {
5302     s.m_sectionType= BaseString("TCP");
5303     DBUG_PRINT("info",("adding TCP connection %d %d",nodeId1,nodeId2));
5304 
5305     if (wan)
5306     {
5307       s.m_sectionData->put("TCP_RCV_BUF_SIZE", 4194304);
5308       s.m_sectionData->put("TCP_SND_BUF_SIZE", 4194304);
5309       s.m_sectionData->put("TCP_MAXSEG_SIZE", 61440);
5310     }
5311   }
5312 
5313   sections.push_back(s);
5314   return true;
5315 }
5316 
5317 static bool
add_node_connections(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5318 add_node_connections(Vector<ConfigInfo::ConfigRuleSection>&sections,
5319   struct InitConfigFileParser::Context &ctx,
5320   const char * rule_data)
5321 {
5322   DBUG_ENTER("add_node_connections");
5323   Uint32 i;
5324   Properties * props= ctx.m_config;
5325   Properties p_connections(true);
5326   Properties p_connections2(true);
5327 
5328   for (i = 0;; i++){
5329     const Properties * tmp;
5330     Uint32 nodeId1, nodeId2;
5331 
5332     if(!props->get("Connection", i, &tmp)) break;
5333 
5334     if(!tmp->get("NodeId1", &nodeId1)) continue;
5335     p_connections.put("", nodeId1, nodeId1);
5336     if(!tmp->get("NodeId2", &nodeId2)) continue;
5337     p_connections.put("", nodeId2, nodeId2);
5338 
5339     p_connections2.put("", nodeId1 + (nodeId2<<16), nodeId1);
5340     p_connections2.put("", nodeId2 + (nodeId1<<16), nodeId2);
5341   }
5342 
5343   Uint32 nNodes;
5344   ctx.m_userProperties.get("NoOfNodes", &nNodes);
5345 
5346   Properties p_db_nodes(true);
5347   Properties p_api_nodes(true);
5348   Properties p_mgm_nodes(true);
5349 
5350   Uint32 i_db= 0, i_api= 0, i_mgm= 0, n;
5351   for (i= 0, n= 0; n < nNodes; i++){
5352     const Properties * tmp;
5353     if(!props->get("Node", i, &tmp)) continue;
5354     n++;
5355 
5356     const char * type;
5357     if(!tmp->get("Type", &type)) continue;
5358 
5359     if (strcmp(type,DB_TOKEN) == 0)
5360       p_db_nodes.put("", i_db++, i);
5361     else if (strcmp(type,API_TOKEN) == 0)
5362       p_api_nodes.put("", i_api++, i);
5363     else if (strcmp(type,MGM_TOKEN) == 0)
5364       p_mgm_nodes.put("", i_mgm++, i);
5365   }
5366 
5367   Uint32 nodeId1, nodeId2, dummy;
5368 
5369   // DB -> DB
5370   for (i= 0; p_db_nodes.get("", i, &nodeId1); i++){
5371     for (Uint32 j= i+1;; j++){
5372       if(!p_db_nodes.get("", j, &nodeId2)) break;
5373       if(!p_connections2.get("", nodeId1+(nodeId2<<16), &dummy))
5374       {
5375 	if (!add_a_connection(sections,ctx,nodeId1,nodeId2,false))
5376 	  goto err;
5377       }
5378     }
5379   }
5380 
5381   // API -> DB
5382   for (i= 0; p_api_nodes.get("", i, &nodeId1); i++){
5383     if(!p_connections.get("", nodeId1, &dummy)) {
5384       for (Uint32 j= 0;; j++){
5385 	if(!p_db_nodes.get("", j, &nodeId2)) break;
5386 	if (!add_a_connection(sections,ctx,nodeId1,nodeId2,false))
5387 	  goto err;
5388       }
5389     }
5390   }
5391 
5392   // MGM -> DB
5393   for (i= 0; p_mgm_nodes.get("", i, &nodeId1); i++){
5394     if(!p_connections.get("", nodeId1, &dummy)) {
5395       for (Uint32 j= 0;; j++){
5396 	if(!p_db_nodes.get("", j, &nodeId2)) break;
5397 	if (!add_a_connection(sections,ctx,nodeId1,nodeId2,0))
5398 	  goto err;
5399       }
5400     }
5401   }
5402 
5403   // MGM -> MGM
5404   for (i= 0; p_mgm_nodes.get("", i, &nodeId1); i++){
5405     for (Uint32 j= i+1;; j++){
5406       if(!p_mgm_nodes.get("", j, &nodeId2)) break;
5407       if(!p_connections2.get("", nodeId1+(nodeId2<<16), &dummy))
5408       {
5409 	if (!add_a_connection(sections,ctx,nodeId1,nodeId2,0))
5410 	  goto err;
5411      }
5412     }
5413   }
5414 
5415   DBUG_RETURN(true);
5416 err:
5417   DBUG_RETURN(false);
5418 }
5419 
set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5420 static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>&sections,
5421 				 struct InitConfigFileParser::Context &ctx,
5422 				 const char * rule_data)
5423 {
5424   DBUG_ENTER("set_connection_priorities");
5425   DBUG_RETURN(true);
5426 }
5427 
5428 static bool
check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5429 check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>&sections,
5430 		       struct InitConfigFileParser::Context &ctx,
5431 		       const char * rule_data)
5432 {
5433   Uint32 i, n;
5434   Uint32 n_nodes;
5435   Uint32 replicas= 0;
5436   Uint32 db_host_count= 0;
5437   bool  with_arbitration_rank= false;
5438   ctx.m_userProperties.get("NoOfNodes", &n_nodes);
5439   ctx.m_userProperties.get("NoOfReplicas", &replicas);
5440 
5441   /**
5442    * Register user supplied values
5443    */
5444   Uint8 ng_cnt[MAX_NDB_NODES];
5445   Bitmask<(MAX_NDB_NODES+31)/32> nodes_wo_ng;
5446   bzero(ng_cnt, sizeof(ng_cnt));
5447 
5448   for (i= 0, n= 0; n < n_nodes; i++)
5449   {
5450     const Properties * tmp;
5451     if(!ctx.m_config->get("Node", i, &tmp)) continue;
5452     n++;
5453 
5454     const char * type;
5455     if(!tmp->get("Type", &type)) continue;
5456 
5457     if (strcmp(type,DB_TOKEN) == 0)
5458     {
5459       Uint32 id;
5460       tmp->get("NodeId", &id);
5461 
5462       Uint32 ng;
5463       if (tmp->get("Nodegroup", &ng))
5464       {
5465         if (ng == NDB_NO_NODEGROUP)
5466         {
5467           break;
5468         }
5469         else if (ng >= MAX_NDB_NODES)
5470         {
5471           ctx.reportError("Invalid nodegroup %u for node %u",
5472                           ng, id);
5473           return false;
5474         }
5475         ng_cnt[ng]++;
5476       }
5477       else
5478       {
5479         nodes_wo_ng.set(i);
5480       }
5481     }
5482   }
5483 
5484   /**
5485    * Auto-assign nodegroups if user didnt
5486    */
5487   Uint32 next_ng = 0;
5488   for (;ng_cnt[next_ng] >= replicas; next_ng++);
5489   for (i = nodes_wo_ng.find(0); i!=BitmaskImpl::NotFound;
5490        i = nodes_wo_ng.find(i + 1))
5491   {
5492     Properties* tmp = 0;
5493     ctx.m_config->getCopy("Node", i, &tmp);
5494 
5495     tmp->put("Nodegroup", next_ng, true);
5496     ctx.m_config->put("Node", i, tmp, true);
5497     ng_cnt[next_ng]++;
5498 
5499     Uint32 id;
5500     tmp->get("NodeId", &id);
5501 
5502     for (;ng_cnt[next_ng] >= replicas; next_ng++);
5503 
5504     delete tmp;
5505   }
5506 
5507   /**
5508    * Check node vs replicas
5509    */
5510   for (i = 0; i<MAX_NDB_NODES; i++)
5511   {
5512     if (ng_cnt[i] != 0 && ng_cnt[i] != (Uint8)replicas)
5513     {
5514       ctx.reportError("Nodegroup %u has %u members, NoOfReplicas=%u",
5515                       i, ng_cnt[i], replicas);
5516       return false;
5517     }
5518   }
5519 
5520   // check that node groups and arbitrators are ok
5521   // just issue warning if not
5522   if(replicas > 1){
5523     Properties p_db_hosts(true); // store hosts which db nodes run on
5524     Properties p_arbitrators(true); // store hosts which arbitrators run on
5525     // arbitrator should not run together with db node on same host
5526     Uint32 group= 0, i_group= 0;
5527     BaseString node_group_warning, arbitration_warning;
5528     const char *arbit_warn_fmt=
5529       "\n  arbitrator with id %d and db node with id %d on same host %s";
5530     const char *arbit_warn_fmt2=
5531       "\n  arbitrator with id %d has no hostname specified";
5532 
5533     ctx.m_userProperties.get("NoOfNodes", &n_nodes);
5534     for (i= 0, n= 0; n < n_nodes; i++){
5535       const Properties * tmp;
5536       if(!ctx.m_config->get("Node", i, &tmp)) continue;
5537       n++;
5538 
5539       const char * type;
5540       if(!tmp->get("Type", &type)) continue;
5541 
5542       const char* host= 0;
5543       tmp->get("HostName", &host);
5544 
5545       if (strcmp(type,DB_TOKEN) == 0)
5546       {
5547         {
5548           Uint32 ii;
5549           if (!p_db_hosts.get(host,&ii))
5550             db_host_count++;
5551           p_db_hosts.put(host,i);
5552           if (p_arbitrators.get(host,&ii))
5553           {
5554             arbitration_warning.appfmt(arbit_warn_fmt, ii, i, host);
5555             p_arbitrators.remove(host); // only one warning per db node
5556           }
5557         }
5558         {
5559           unsigned j;
5560           BaseString str, str2;
5561           str.assfmt("#group%d_",group);
5562           p_db_hosts.put(str.c_str(),i_group,host);
5563           str2.assfmt("##group%d_",group);
5564           p_db_hosts.put(str2.c_str(),i_group,i);
5565           for (j= 0; j < i_group; j++)
5566           {
5567             const char *other_host;
5568             p_db_hosts.get(str.c_str(),j,&other_host);
5569             if (strcmp(host,other_host) == 0) {
5570               unsigned int other_i, c= 0;
5571               p_db_hosts.get(str2.c_str(),j,&other_i);
5572               p_db_hosts.get(str.c_str(),&c);
5573               if (c == 0) // first warning in this node group
5574                 node_group_warning.appfmt("  Node group %d", group);
5575               c|= 1 << j;
5576               p_db_hosts.put(str.c_str(),c);
5577               node_group_warning.appfmt(",\n    db node with id %d and id %d "
5578               "on same host %s", other_i, i, host);
5579             }
5580           }
5581           i_group++;
5582           DBUG_ASSERT(i_group <= replicas);
5583           if (i_group == replicas)
5584           {
5585             unsigned c= 0;
5586             p_db_hosts.get(str.c_str(),&c);
5587             if (c+1 == (1u << (replicas-1))) // all nodes on same machine
5588               node_group_warning.append(".\n    Host failure will "
5589               "cause complete cluster shutdown.");
5590             else if (c > 0)
5591               node_group_warning.append(".\n    Host failure may "
5592               "cause complete cluster shutdown.");
5593             group++;
5594             i_group= 0;
5595           }
5596         }
5597       }
5598       else if (strcmp(type,API_TOKEN) == 0 ||
5599 	       strcmp(type,MGM_TOKEN) == 0)
5600       {
5601         Uint32 rank;
5602         if(tmp->get("ArbitrationRank", &rank) && rank > 0)
5603         {
5604           with_arbitration_rank = true;  //check whether MGM or API node configured with rank >0
5605           if(host && host[0] != 0)
5606           {
5607             Uint32 ii;
5608             p_arbitrators.put(host,i);
5609             if (p_db_hosts.get(host,&ii))
5610             {
5611               arbitration_warning.appfmt(arbit_warn_fmt, i, ii, host);
5612             }
5613           }
5614           else
5615           {
5616             arbitration_warning.appfmt(arbit_warn_fmt2, i);
5617           }
5618         }
5619       }
5620     }
5621     if (db_host_count > 1 && node_group_warning.length() > 0)
5622       ctx.reportWarning("Cluster configuration warning:\n%s",node_group_warning.c_str());
5623     if (!with_arbitration_rank)
5624     {
5625       ctx.reportWarning("Cluster configuration warning:"
5626          "\n  Neither %s nor %s nodes are configured with arbitrator,"
5627          "\n  may cause complete cluster shutdown in case of host failure.",
5628          MGM_TOKEN, API_TOKEN);
5629     }
5630     if (db_host_count > 1 && arbitration_warning.length() > 0)
5631       ctx.reportWarning("Cluster configuration warning:%s%s",arbitration_warning.c_str(),
5632 	       "\n  Running arbitrator on the same host as a database node may"
5633 	       "\n  cause complete cluster shutdown in case of host failure.");
5634   }
5635   return true;
5636 }
5637 
5638 static bool
check_mutually_exclusive(Vector<ConfigInfo::ConfigRuleSection> & sections,struct InitConfigFileParser::Context & ctx,const char * rule_data)5639 check_mutually_exclusive(Vector<ConfigInfo::ConfigRuleSection>&sections,
5640                          struct InitConfigFileParser::Context &ctx,
5641                          const char * rule_data)
5642 {
5643   /* This rule checks for configuration settings that are
5644    * mutually exclusive and rejects them
5645    */
5646 
5647   //ctx.m_userProperties.print(stderr);
5648 
5649   Uint32 numNodes, n;
5650   ctx.m_userProperties.get("NoOfNodes", &numNodes);
5651 
5652   for (n=0; n < numNodes; n++)
5653   {
5654     const Properties* nodeProperties;
5655     if (!ctx.m_config->get("Node", n, &nodeProperties)) continue;
5656 
5657     //nodeProperties->print(stderr);
5658 
5659     const char* nodeType;
5660     if (unlikely(!nodeProperties->get("Type", &nodeType)))
5661     {
5662       ctx.reportError("Missing nodeType for node %u", n);
5663       return false;
5664     }
5665 
5666     if (strcmp(nodeType,DB_TOKEN) == 0)
5667     {
5668       {
5669         /* StopOnError related cross-checks */
5670         Uint32 stopOnError;
5671         Uint32 maxStartFailRetries;
5672         Uint32 startFailRetryDelay;
5673 
5674         if (unlikely(!nodeProperties->get("StopOnError", &stopOnError)))
5675         {
5676           ctx.reportError("Missing StopOnError setting for node %u", n);
5677           return false;
5678         }
5679 
5680         if (unlikely(!nodeProperties->get("MaxStartFailRetries", &maxStartFailRetries)))
5681         {
5682           ctx.reportError("Missing MaxStartFailRetries setting");
5683           return false;
5684         }
5685 
5686         if (unlikely(!nodeProperties->get("StartFailRetryDelay", &startFailRetryDelay)))
5687         {
5688           ctx.reportError("Missing StartFailRetryDelay setting");
5689           return false;
5690         }
5691 
5692         if (unlikely(((stopOnError != 0) &&
5693                       ((maxStartFailRetries != 3) ||
5694                        (startFailRetryDelay != 0)))))
5695         {
5696           ctx.reportError("Non default settings for MaxStartFailRetries "
5697                           "or StartFailRetryDelay with StopOnError != 0");
5698           return false;
5699         }
5700       }
5701     } /* DB_TOKEN */
5702   } /* for nodes */
5703 
5704   return true;
5705 }
5706 
5707 
ParamInfoIter(const ConfigInfo & info,Uint32 section,Uint32 section_type)5708 ConfigInfo::ParamInfoIter::ParamInfoIter(const ConfigInfo& info,
5709                                          Uint32 section,
5710                                          Uint32 section_type) :
5711   m_info(info),
5712   m_section_name(NULL),
5713   m_curr_param(0)
5714 {
5715   /* Find the section's name */
5716   for (int j=0; j<info.m_NoOfParams; j++) {
5717     const ConfigInfo::ParamInfo & param = info.m_ParamInfo[j];
5718     if (param._type == ConfigInfo::CI_SECTION &&
5719         param._paramId == section &&
5720         (section_type == ~(Uint32)0 ||
5721          ConfigInfo::getSectionType(param) == section_type))
5722     {
5723       m_section_name= param._section;
5724       return;
5725     }
5726   }
5727   abort();
5728 }
5729 
5730 
5731 const ConfigInfo::ParamInfo*
next(void)5732 ConfigInfo::ParamInfoIter::next(void) {
5733   assert(m_curr_param < m_info.m_NoOfParams);
5734   do {
5735     /*  Loop through the parameter and return a pointer to the next found */
5736     const ConfigInfo::ParamInfo* param = &m_info.m_ParamInfo[m_curr_param++];
5737     if (strcmp(param->_section, m_section_name) == 0 &&
5738         param->_type != ConfigInfo::CI_SECTION)
5739       return param;
5740   }
5741   while (m_curr_param<m_info.m_NoOfParams);
5742 
5743   return NULL;
5744 }
5745 
5746 
5747 static bool
is_name_in_list(const char * name,Vector<BaseString> & list)5748 is_name_in_list(const char* name, Vector<BaseString>& list)
5749 {
5750   for (Uint32 i = 0; i<list.size(); i++)
5751   {
5752     if (strstr(name, list[i].c_str()))
5753       return true;
5754   }
5755   return false;
5756 }
5757 
5758 
5759 static
5760 bool
saveSectionsInConfigValues(Vector<ConfigInfo::ConfigRuleSection> & notused,struct InitConfigFileParser::Context & ctx,const char * rule_data)5761 saveSectionsInConfigValues(Vector<ConfigInfo::ConfigRuleSection>& notused,
5762                            struct InitConfigFileParser::Context &ctx,
5763                            const char * rule_data)
5764 {
5765   if (rule_data == 0)
5766     return true;
5767 
5768   BaseString sections(rule_data);
5769   Vector<BaseString> list;
5770   sections.split(list, ",");
5771 
5772   Properties::Iterator it(ctx.m_config);
5773 
5774   {
5775     // Estimate size of Properties when saved as ConfigValues
5776     // and expand ConfigValues to that size in order to avoid
5777     // the need of allocating memory and copying from new to old
5778     Uint32 keys = 0;
5779     Uint64 data_sz = 0;
5780     for (const char * name = it.first(); name != 0; name = it.next())
5781     {
5782       PropertiesType pt;
5783       if (is_name_in_list(name, list) &&
5784           ctx.m_config->getTypeOf(name, &pt) &&
5785           pt == PropertiesType_Properties)
5786       {
5787         const Properties* tmp;
5788         require(ctx.m_config->get(name, &tmp) != 0);
5789 
5790         keys += 2; // openSection(key + no)
5791         keys += 1; // CFG_TYPE_OF_SECTION
5792 
5793         Properties::Iterator it2(tmp);
5794         for (const char * name2 = it2.first(); name2 != 0; name2 = it2.next())
5795         {
5796           keys++;
5797           require(tmp->getTypeOf(name2, &pt) != 0);
5798           switch(pt){
5799           case PropertiesType_char:
5800             const char* value;
5801             require(tmp->get(name2, &value) != 0);
5802             data_sz += 1 + ((strlen(value) + 3) / 4);
5803             break;
5804 
5805           case PropertiesType_Uint32:
5806             data_sz += 1;
5807             break;
5808 
5809           case PropertiesType_Uint64:
5810             data_sz += 2;
5811             break;
5812 
5813           case PropertiesType_Properties:
5814           default:
5815             require(false);
5816             break;
5817           }
5818         }
5819       }
5820     }
5821 
5822     assert(data_sz >> 32 == 0);
5823     ctx.m_configValues.expand(keys, Uint32(data_sz));
5824   }
5825 
5826   for (const char * name = it.first(); name != 0; name = it.next())
5827   {
5828     PropertiesType pt;
5829     if (is_name_in_list(name, list) &&
5830         ctx.m_config->getTypeOf(name, &pt) &&
5831         pt == PropertiesType_Properties)
5832     {
5833       const char * type;
5834       const Properties* tmp;
5835       require(ctx.m_config->get(name, &tmp) != 0);
5836       require(tmp->get("Type", &type) != 0);
5837       require((ctx.m_currentInfo = ctx.m_info->getInfo(type)) != 0);
5838       ctx.m_currentSection = const_cast<Properties*>(tmp);
5839       BaseString::snprintf(ctx.fname, sizeof(ctx.fname), "%s", type);
5840       saveInConfigValues(ctx, 0);
5841     }
5842   }
5843 
5844   return true;
5845 }
5846 
5847 
5848 template class Vector<ConfigInfo::ConfigRuleSection>;
5849 #endif /* NDB_MGMAPI */
5850