summaryrefslogtreecommitdiff
path: root/storage/ndb/src/mgmsrv/ConfigInfo.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/mgmsrv/ConfigInfo.cpp')
-rw-r--r--storage/ndb/src/mgmsrv/ConfigInfo.cpp3876
1 files changed, 3876 insertions, 0 deletions
diff --git a/storage/ndb/src/mgmsrv/ConfigInfo.cpp b/storage/ndb/src/mgmsrv/ConfigInfo.cpp
new file mode 100644
index 00000000000..67bf09fab10
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp
@@ -0,0 +1,3876 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+#include <ndb_global.h>
+#include <ndb_opt_defaults.h>
+
+#include <NdbTCP.h>
+#include "ConfigInfo.hpp"
+#include <mgmapi_config_parameters.h>
+#include <ndb_limits.h>
+#include "InitConfigFileParser.hpp"
+#include <m_string.h>
+
+extern my_bool opt_ndb_shm;
+
+#define MAX_LINE_LENGTH 255
+#define KEY_INTERNAL 0
+#define MAX_INT_RNIL 0xfffffeff
+
+#define _STR_VALUE(x) #x
+#define STR_VALUE(x) _STR_VALUE(x)
+
+/****************************************************************************
+ * Section names
+ ****************************************************************************/
+
+#define DB_TOKEN_PRINT "ndbd(DB)"
+#define MGM_TOKEN_PRINT "ndb_mgmd(MGM)"
+#define API_TOKEN_PRINT "mysqld(API)"
+
+#define DB_TOKEN "DB"
+#define MGM_TOKEN "MGM"
+#define API_TOKEN "API"
+
+const ConfigInfo::AliasPair
+ConfigInfo::m_sectionNameAliases[]={
+ {API_TOKEN, "MYSQLD"},
+ {DB_TOKEN, "NDBD"},
+ {MGM_TOKEN, "NDB_MGMD"},
+ {0, 0}
+};
+
+const char*
+ConfigInfo::m_sectionNames[]={
+ "SYSTEM",
+ "EXTERNAL SYSTEM",
+ "COMPUTER",
+
+ DB_TOKEN,
+ MGM_TOKEN,
+ API_TOKEN,
+ "REP",
+ "EXTERNAL REP",
+
+ "TCP",
+ "SCI",
+ "SHM",
+ "OSE"
+};
+const int ConfigInfo::m_noOfSectionNames =
+sizeof(m_sectionNames)/sizeof(char*);
+
+
+/****************************************************************************
+ * Section Rules declarations
+ ****************************************************************************/
+static bool transformComputer(InitConfigFileParser::Context & ctx, const char *);
+static bool transformSystem(InitConfigFileParser::Context & ctx, const char *);
+static bool transformExternalSystem(InitConfigFileParser::Context & ctx, const char *);
+static bool transformNode(InitConfigFileParser::Context & ctx, const char *);
+static bool transformExtNode(InitConfigFileParser::Context & ctx, const char *);
+static bool checkConnectionSupport(InitConfigFileParser::Context & ctx, const char *);
+static bool transformConnection(InitConfigFileParser::Context & ctx, const char *);
+static bool applyDefaultValues(InitConfigFileParser::Context & ctx, const char *);
+static bool checkMandatory(InitConfigFileParser::Context & ctx, const char *);
+static bool fixPortNumber(InitConfigFileParser::Context & ctx, const char *);
+static bool fixShmKey(InitConfigFileParser::Context & ctx, const char *);
+static bool checkDbConstraints(InitConfigFileParser::Context & ctx, const char *);
+static bool checkConnectionConstraints(InitConfigFileParser::Context &, const char *);
+static bool checkTCPConstraints(InitConfigFileParser::Context &, const char *);
+static bool fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixHostname(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixExtConnection(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixDepricated(InitConfigFileParser::Context & ctx, const char *);
+static bool saveInConfigValues(InitConfigFileParser::Context & ctx, const char *);
+static bool fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data);
+static bool fixShmUniqueId(InitConfigFileParser::Context & ctx, const char * data);
+
+const ConfigInfo::SectionRule
+ConfigInfo::m_SectionRules[] = {
+ { "SYSTEM", transformSystem, 0 },
+ { "EXTERNAL SYSTEM", transformExternalSystem, 0 },
+ { "COMPUTER", transformComputer, 0 },
+
+ { DB_TOKEN, transformNode, 0 },
+ { API_TOKEN, transformNode, 0 },
+ { MGM_TOKEN, transformNode, 0 },
+ { "REP", transformNode, 0 },
+ { "EXTERNAL REP", transformExtNode, 0 },
+
+ { MGM_TOKEN, fixShmUniqueId, 0 },
+
+ { "TCP", checkConnectionSupport, 0 },
+ { "SHM", checkConnectionSupport, 0 },
+ { "SCI", checkConnectionSupport, 0 },
+ { "OSE", checkConnectionSupport, 0 },
+
+ { "TCP", transformConnection, 0 },
+ { "SHM", transformConnection, 0 },
+ { "SCI", transformConnection, 0 },
+ { "OSE", transformConnection, 0 },
+
+ { DB_TOKEN, fixNodeHostname, 0 },
+ { API_TOKEN, fixNodeHostname, 0 },
+ { MGM_TOKEN, fixNodeHostname, 0 },
+ { "REP", fixNodeHostname, 0 },
+ //{ "EXTERNAL REP", fixNodeHostname, 0 },
+
+ { "TCP", fixNodeId, "NodeId1" },
+ { "TCP", fixNodeId, "NodeId2" },
+ { "SHM", fixNodeId, "NodeId1" },
+ { "SHM", fixNodeId, "NodeId2" },
+ { "SCI", fixNodeId, "NodeId1" },
+ { "SCI", fixNodeId, "NodeId2" },
+ { "OSE", fixNodeId, "NodeId1" },
+ { "OSE", fixNodeId, "NodeId2" },
+
+ { "TCP", fixHostname, "HostName1" },
+ { "TCP", fixHostname, "HostName2" },
+ { "SHM", fixHostname, "HostName1" },
+ { "SHM", fixHostname, "HostName2" },
+ { "SCI", fixHostname, "HostName1" },
+ { "SCI", fixHostname, "HostName2" },
+ { "SHM", fixHostname, "HostName1" },
+ { "SHM", fixHostname, "HostName2" },
+ { "OSE", fixHostname, "HostName1" },
+ { "OSE", fixHostname, "HostName2" },
+
+ { "TCP", fixPortNumber, 0 }, // has to come after fixHostName
+ { "SHM", fixPortNumber, 0 }, // has to come after fixHostName
+ { "SCI", fixPortNumber, 0 }, // has to come after fixHostName
+ { "SHM", fixShmKey, 0 },
+
+ /**
+ * fixExtConnection must be after fixNodeId
+ */
+ { "TCP", fixExtConnection, 0 },
+ { "SHM", fixExtConnection, 0 },
+ { "SCI", fixExtConnection, 0 },
+ { "OSE", fixExtConnection, 0 },
+
+ { "*", applyDefaultValues, "user" },
+ { "*", fixDepricated, 0 },
+ { "*", applyDefaultValues, "system" },
+
+ { DB_TOKEN, fixFileSystemPath, 0 },
+ { DB_TOKEN, fixBackupDataDir, 0 },
+
+ { DB_TOKEN, checkDbConstraints, 0 },
+
+ /**
+ * checkConnectionConstraints must be after fixExtConnection
+ */
+ { "TCP", checkConnectionConstraints, 0 },
+ { "SHM", checkConnectionConstraints, 0 },
+ { "SCI", checkConnectionConstraints, 0 },
+ { "OSE", checkConnectionConstraints, 0 },
+
+ { "TCP", checkTCPConstraints, "HostName1" },
+ { "TCP", checkTCPConstraints, "HostName2" },
+ { "SCI", checkTCPConstraints, "HostName1" },
+ { "SCI", checkTCPConstraints, "HostName2" },
+ { "SHM", checkTCPConstraints, "HostName1" },
+ { "SHM", checkTCPConstraints, "HostName2" },
+
+ { "*", checkMandatory, 0 },
+
+ { DB_TOKEN, saveInConfigValues, 0 },
+ { API_TOKEN, saveInConfigValues, 0 },
+ { MGM_TOKEN, saveInConfigValues, 0 },
+ { "REP", saveInConfigValues, 0 },
+
+ { "TCP", saveInConfigValues, 0 },
+ { "SHM", saveInConfigValues, 0 },
+ { "SCI", saveInConfigValues, 0 },
+ { "OSE", saveInConfigValues, 0 }
+};
+const int ConfigInfo::m_NoOfRules = sizeof(m_SectionRules)/sizeof(SectionRule);
+
+/****************************************************************************
+ * Config Rules declarations
+ ****************************************************************************/
+static bool sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data);
+static bool add_node_connections(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data);
+static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data);
+static bool add_server_ports(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data);
+static bool check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data);
+
+const ConfigInfo::ConfigRule
+ConfigInfo::m_ConfigRules[] = {
+ { sanity_checks, 0 },
+ { add_node_connections, 0 },
+ { set_connection_priorities, 0 },
+ { add_server_ports, 0 },
+ { check_node_vs_replicas, 0 },
+ { 0, 0 }
+};
+
+struct DepricationTransform {
+ const char * m_section;
+ const char * m_oldName;
+ const char * m_newName;
+ double m_add;
+ double m_mul;
+};
+
+static
+const DepricationTransform f_deprication[] = {
+ { DB_TOKEN, "Discless", "Diskless", 0, 1 },
+ { 0, 0, 0, 0, 0}
+};
+
+/**
+ * The default constructors create objects with suitable values for the
+ * configuration parameters.
+ *
+ * Some are however given the value MANDATORY which means that the value
+ * must be specified in the configuration file.
+ *
+ * Min and max values are also given for some parameters.
+ * - Attr1: Name in file (initial config file)
+ * - Attr2: Name in prop (properties object)
+ * - Attr3: Name of Section (in init config file)
+ * - Attr4: Updateable
+ * - Attr5: Type of parameter (INT or BOOL)
+ * - Attr6: Default Value (number only)
+ * - Attr7: Min value
+ * - Attr8: Max value
+ *
+ * Parameter constraints are coded in file Config.cpp.
+ *
+ * *******************************************************************
+ * Parameters used under development should be marked "NOTIMPLEMENTED"
+ * *******************************************************************
+ */
+
+const ConfigInfo::ParamInfo ConfigInfo::m_ParamInfo[] = {
+
+ /****************************************************************************
+ * COMPUTER
+ ***************************************************************************/
+ {
+ KEY_INTERNAL,
+ "COMPUTER",
+ "COMPUTER",
+ "Computer section",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_SECTION,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ "COMPUTER",
+ "Name of computer",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "HostName",
+ "COMPUTER",
+ "Hostname of computer (e.g. mysql.com)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "ByteOrder",
+ "COMPUTER",
+ 0,
+ ConfigInfo::CI_DEPRICATED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0,
+ 0 },
+
+ /****************************************************************************
+ * SYSTEM
+ ***************************************************************************/
+ {
+ CFG_SECTION_SYSTEM,
+ "SYSTEM",
+ "SYSTEM",
+ "System section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)CFG_SECTION_SYSTEM,
+ 0, 0 },
+
+ {
+ CFG_SYS_NAME,
+ "Name",
+ "SYSTEM",
+ "Name of system (NDB Cluster)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_SYS_REPLICATION_ROLE,
+ "ReplicationRole",
+ "SYSTEM",
+ "Role in Global Replication (None, Primary, or Standby)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_SYS_PRIMARY_MGM_NODE,
+ "PrimaryMGMNode",
+ "SYSTEM",
+ "Node id of Primary "MGM_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SYS_CONFIG_GENERATION,
+ "ConfigGenerationNumber",
+ "SYSTEM",
+ "Configuration generation number",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /***************************************************************************
+ * DB
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ DB_TOKEN,
+ DB_TOKEN,
+ "Node section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)NODE_TYPE_DB,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ DB_TOKEN,
+ "Name of computer for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ DB_TOKEN,
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_ID,
+ "Id",
+ DB_TOKEN,
+ "Number identifying the database node ("DB_TOKEN_PRINT")",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ KEY_INTERNAL,
+ "ServerPort",
+ DB_TOKEN,
+ "Port used to setup transporter",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_REPLICAS,
+ "NoOfReplicas",
+ DB_TOKEN,
+ "Number of copies of all data in the database (1-4)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ "4" },
+
+ {
+ CFG_DB_NO_ATTRIBUTES,
+ "MaxNoOfAttributes",
+ DB_TOKEN,
+ "Total number of attributes stored in database. I.e. sum over all tables",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1000",
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_TABLES,
+ "MaxNoOfTables",
+ DB_TOKEN,
+ "Total number of tables stored in the database",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "128",
+ "8",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_ORDERED_INDEXES,
+ "MaxNoOfOrderedIndexes",
+ DB_TOKEN,
+ "Total number of ordered indexes that can be defined in the system",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "128",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_UNIQUE_HASH_INDEXES,
+ "MaxNoOfUniqueHashIndexes",
+ DB_TOKEN,
+ "Total number of unique hash indexes that can be defined in the system",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "64",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_INDEXES,
+ "MaxNoOfIndexes",
+ DB_TOKEN,
+ "Total number of indexes that can be defined in the system",
+ ConfigInfo::CI_DEPRICATED,
+ false,
+ ConfigInfo::CI_INT,
+ "128",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_INDEX_OPS,
+ "MaxNoOfConcurrentIndexOperations",
+ DB_TOKEN,
+ "Total number of index operations that can execute simultaneously on one "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "8K",
+ "0",
+ STR_VALUE(MAX_INT_RNIL)
+ },
+
+ {
+ CFG_DB_NO_TRIGGERS,
+ "MaxNoOfTriggers",
+ DB_TOKEN,
+ "Total number of triggers that can be defined in the system",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "768",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_TRIGGER_OPS,
+ "MaxNoOfFiredTriggers",
+ DB_TOKEN,
+ "Total number of triggers that can fire simultaneously in one "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "4000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ DB_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_DB_NO_SAVE_MSGS,
+ "MaxNoOfSavedMessages",
+ DB_TOKEN,
+ "Max number of error messages in error log and max number of trace files",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "25",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_MEMLOCK,
+ "LockPagesInMainMemory",
+ DB_TOKEN,
+ "If set to yes, then NDB Cluster data will not be swapped out to disk",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_DB_WATCHDOG_INTERVAL,
+ "TimeBetweenWatchDogCheck",
+ DB_TOKEN,
+ "Time between execution checks inside a database node",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "6000",
+ "70",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_STOP_ON_ERROR,
+ "StopOnError",
+ DB_TOKEN,
+ "If set to N, "DB_TOKEN_PRINT" automatically restarts/recovers in case of node failure",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_DB_STOP_ON_ERROR_INSERT,
+ "RestartOnErrorInsert",
+ DB_TOKEN,
+ "See src/kernel/vm/Emulator.hpp NdbRestartType for details",
+ ConfigInfo::CI_INTERNAL,
+ true,
+ ConfigInfo::CI_INT,
+ "2",
+ "0",
+ "4" },
+
+ {
+ CFG_DB_NO_OPS,
+ "MaxNoOfConcurrentOperations",
+ DB_TOKEN,
+ "Max number of operation records in transaction coordinator",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "32k",
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_LOCAL_OPS,
+ "MaxNoOfLocalOperations",
+ DB_TOKEN,
+ "Max number of operation records defined in the local storage node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_LOCAL_SCANS,
+ "MaxNoOfLocalScans",
+ DB_TOKEN,
+ "Max number of fragment scans in parallel in the local storage node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BATCH_SIZE,
+ "BatchSizePerLocalScan",
+ DB_TOKEN,
+ "Used to calculate the number of lock records for scan with hold lock",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ STR_VALUE(DEF_BATCH_SIZE),
+ "1",
+ STR_VALUE(MAX_PARALLEL_OP_PER_SCAN) },
+
+ {
+ CFG_DB_NO_TRANSACTIONS,
+ "MaxNoOfConcurrentTransactions",
+ DB_TOKEN,
+ "Max number of transaction executing concurrently on the "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "4096",
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_SCANS,
+ "MaxNoOfConcurrentScans",
+ DB_TOKEN,
+ "Max number of scans executing concurrently on the "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "256",
+ "2",
+ "500" },
+
+ {
+ CFG_DB_TRANS_BUFFER_MEM,
+ "TransactionBufferMemory",
+ DB_TOKEN,
+ "Dynamic buffer space (in bytes) for key and attribute data allocated for each "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1M",
+ "1K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_INDEX_MEM,
+ "IndexMemory",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for storing indexes",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT64,
+ "18M",
+ "1M",
+ "1024G" },
+
+ {
+ CFG_DB_DATA_MEM,
+ "DataMemory",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for storing data",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT64,
+ "80M",
+ "1M",
+ "1024G" },
+
+ {
+ CFG_DB_UNDO_INDEX_BUFFER,
+ "UndoIndexBuffer",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing UNDO logs for index part",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "2M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL)},
+
+ {
+ CFG_DB_UNDO_DATA_BUFFER,
+ "UndoDataBuffer",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing UNDO logs for data part",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "16M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL)},
+
+ {
+ CFG_DB_REDO_BUFFER,
+ "RedoBuffer",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for writing REDO logs",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "8M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL)},
+
+ {
+ CFG_DB_LONG_SIGNAL_BUFFER,
+ "LongMessageBuffer",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for internal long messages",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1M",
+ "512k",
+ STR_VALUE(MAX_INT_RNIL)},
+
+ {
+ CFG_DB_START_PARTIAL_TIMEOUT,
+ "StartPartialTimeout",
+ DB_TOKEN,
+ "Time to wait before trying to start wo/ all nodes. 0=Wait forever",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "30000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_START_PARTITION_TIMEOUT,
+ "StartPartitionedTimeout",
+ DB_TOKEN,
+ "Time to wait before trying to start partitioned. 0=Wait forever",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "60000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_START_FAILURE_TIMEOUT,
+ "StartFailureTimeout",
+ DB_TOKEN,
+ "Time to wait before terminating. 0=Wait forever",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_HEARTBEAT_INTERVAL,
+ "HeartbeatIntervalDbDb",
+ DB_TOKEN,
+ "Time between "DB_TOKEN_PRINT"-"DB_TOKEN_PRINT" heartbeats. "DB_TOKEN_PRINT" considered dead after 3 missed HBs",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "1500",
+ "10",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_API_HEARTBEAT_INTERVAL,
+ "HeartbeatIntervalDbApi",
+ DB_TOKEN,
+ "Time between "API_TOKEN_PRINT"-"DB_TOKEN_PRINT" heartbeats. "API_TOKEN_PRINT" connection closed after 3 missed HBs",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "1500",
+ "100",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_INTERVAL,
+ "TimeBetweenLocalCheckpoints",
+ DB_TOKEN,
+ "Time between taking snapshots of the database (expressed in 2log of bytes)",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "20",
+ "0",
+ "31" },
+
+ {
+ CFG_DB_GCP_INTERVAL,
+ "TimeBetweenGlobalCheckpoints",
+ DB_TOKEN,
+ "Time between doing group commit of transactions to disk",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "2000",
+ "10",
+ "32000" },
+
+ {
+ CFG_DB_NO_REDOLOG_FILES,
+ "NoOfFragmentLogFiles",
+ DB_TOKEN,
+ "No of 16 Mbyte Redo log files in each of 4 file sets belonging to "DB_TOKEN_PRINT" node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "8",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_MAX_OPEN_FILES,
+ "MaxNoOfOpenFiles",
+ DB_TOKEN,
+ "Max number of files open per "DB_TOKEN_PRINT" node.(One thread is created per file)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "40",
+ "20",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_TRANSACTION_CHECK_INTERVAL,
+ "TimeBetweenInactiveTransactionAbortCheck",
+ DB_TOKEN,
+ "Time between inactive transaction checks",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "1000",
+ "1000",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_TRANSACTION_INACTIVE_TIMEOUT,
+ "TransactionInactiveTimeout",
+ DB_TOKEN,
+ "Time application can wait before executing another transaction part (ms).\n"
+ "This is the time the transaction coordinator waits for the application\n"
+ "to execute or send another part (query, statement) of the transaction.\n"
+ "If the application takes too long time, the transaction gets aborted.\n"
+ "Timeout set to 0 means that we don't timeout at all on application wait.",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ STR_VALUE(MAX_INT_RNIL),
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_TRANSACTION_DEADLOCK_TIMEOUT,
+ "TransactionDeadlockDetectionTimeout",
+ DB_TOKEN,
+ "Time transaction can be executing in a DB node (ms).\n"
+ "This is the time the transaction coordinator waits for each database node\n"
+ "of the transaction to execute a request. If the database node takes too\n"
+ "long time, the transaction gets aborted.",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "1200",
+ "50",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "NoOfDiskPagesToDiskDuringRestartTUP",
+ DB_TOKEN,
+ "?",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "NoOfDiskPagesToDiskAfterRestartTUP",
+ DB_TOKEN,
+ "?",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "NoOfDiskPagesToDiskDuringRestartACC",
+ DB_TOKEN,
+ "?",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "20",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "NoOfDiskPagesToDiskAfterRestartACC",
+ DB_TOKEN,
+ "?",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "20",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+
+ {
+ CFG_DB_DISCLESS,
+ "Diskless",
+ DB_TOKEN,
+ "Run wo/ disk",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true"},
+
+ {
+ KEY_INTERNAL,
+ "Discless",
+ DB_TOKEN,
+ "Diskless",
+ ConfigInfo::CI_DEPRICATED,
+ true,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true"},
+
+
+
+ {
+ CFG_DB_ARBIT_TIMEOUT,
+ "ArbitrationTimeout",
+ DB_TOKEN,
+ "Max time (milliseconds) database partion waits for arbitration signal",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "3000",
+ "10",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_NODE_DATADIR,
+ "DataDir",
+ DB_TOKEN,
+ "Data directory for this node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MYSQLCLUSTERDIR,
+ 0, 0 },
+
+ {
+ CFG_DB_FILESYSTEM_PATH,
+ "FileSystemPath",
+ DB_TOKEN,
+ "Path to directory where the "DB_TOKEN_PRINT" node stores its data (directory must exist)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_LOGLEVEL_STARTUP,
+ "LogLevelStartup",
+ DB_TOKEN,
+ "Node startup info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_SHUTDOWN,
+ "LogLevelShutdown",
+ DB_TOKEN,
+ "Node shutdown info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_STATISTICS,
+ "LogLevelStatistic",
+ DB_TOKEN,
+ "Transaction, operation, transporter info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CHECKPOINT,
+ "LogLevelCheckpoint",
+ DB_TOKEN,
+ "Local and Global checkpoint info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_NODERESTART,
+ "LogLevelNodeRestart",
+ DB_TOKEN,
+ "Node restart, node failure info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CONNECTION,
+ "LogLevelConnection",
+ DB_TOKEN,
+ "Node connect/disconnect info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CONGESTION,
+ "LogLevelCongestion",
+ DB_TOKEN,
+ "Congestion info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_ERROR,
+ "LogLevelError",
+ DB_TOKEN,
+ "Transporter, heartbeat errors printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_INFO,
+ "LogLevelInfo",
+ DB_TOKEN,
+ "Heartbeat and log info printed on stdout",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ /**
+ * Backup
+ */
+ {
+ CFG_DB_PARALLEL_BACKUPS,
+ "ParallelBackups",
+ DB_TOKEN,
+ "Maximum number of parallel backups",
+ ConfigInfo::CI_NOTIMPLEMENTED,
+ false,
+ ConfigInfo::CI_INT,
+ "1",
+ "1",
+ "1" },
+
+ {
+ CFG_DB_BACKUP_DATADIR,
+ "BackupDataDir",
+ DB_TOKEN,
+ "Path to where to store backups",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_DB_BACKUP_MEM,
+ "BackupMemory",
+ DB_TOKEN,
+ "Total memory allocated for backups per node (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "4M", // sum of BackupDataBufferSize and BackupLogBufferSize
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_DATA_BUFFER_MEM,
+ "BackupDataBufferSize",
+ DB_TOKEN,
+ "Default size of databuffer for a backup (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "2M", // remember to change BackupMemory
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_LOG_BUFFER_MEM,
+ "BackupLogBufferSize",
+ DB_TOKEN,
+ "Default size of logbuffer for a backup (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "2M", // remember to change BackupMemory
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_WRITE_SIZE,
+ "BackupWriteSize",
+ DB_TOKEN,
+ "Default size of filesystem writes made by backup (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "32K",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /***************************************************************************
+ * REP
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ "REP",
+ "REP",
+ "Node section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)NODE_TYPE_REP,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ "REP",
+ "Name of computer for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ "REP",
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_ID,
+ "Id",
+ "REP",
+ "Number identifying replication node (REP)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ "REP",
+ "String referencing an earlier defined COMPUTER",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_REP_HEARTBEAT_INTERVAL,
+ "HeartbeatIntervalRepRep",
+ "REP",
+ "Time between REP-REP heartbeats. Connection closed after 3 missed HBs",
+ ConfigInfo::CI_USED,
+ true,
+ ConfigInfo::CI_INT,
+ "3000",
+ "100",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /***************************************************************************
+ * API
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ API_TOKEN,
+ API_TOKEN,
+ "Node section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)NODE_TYPE_API,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ API_TOKEN,
+ "Name of computer for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ API_TOKEN,
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_ID,
+ "Id",
+ API_TOKEN,
+ "Number identifying application node ("API_TOKEN_PRINT")",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ API_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_ARBIT_RANK,
+ "ArbitrationRank",
+ API_TOKEN,
+ "If 0, then "API_TOKEN_PRINT" is not arbitrator. Kernel selects arbitrators in order 1, 2",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ "2" },
+
+ {
+ CFG_NODE_ARBIT_DELAY,
+ "ArbitrationDelay",
+ API_TOKEN,
+ "When asked to arbitrate, arbitrator waits this long before voting (msec)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_MAX_SCAN_BATCH_SIZE,
+ "MaxScanBatchSize",
+ "API",
+ "The maximum collective batch size for one scan",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ STR_VALUE(MAX_SCAN_BATCH_SIZE),
+ "32k",
+ "16M" },
+
+ {
+ CFG_BATCH_BYTE_SIZE,
+ "BatchByteSize",
+ "API",
+ "The default batch size in bytes",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ STR_VALUE(SCAN_BATCH_SIZE),
+ "1k",
+ "1M" },
+
+ {
+ CFG_BATCH_SIZE,
+ "BatchSize",
+ "API",
+ "The default batch size in number of records",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ STR_VALUE(DEF_BATCH_SIZE),
+ "1",
+ STR_VALUE(MAX_PARALLEL_OP_PER_SCAN) },
+
+ /****************************************************************************
+ * MGM
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ MGM_TOKEN,
+ MGM_TOKEN,
+ "Node section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)NODE_TYPE_MGM,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ MGM_TOKEN,
+ "Name of computer for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_DATADIR,
+ "DataDir",
+ MGM_TOKEN,
+ "Data directory for this node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MYSQLCLUSTERDIR,
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ MGM_TOKEN,
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_NODE_ID,
+ "Id",
+ MGM_TOKEN,
+ "Number identifying the management server node ("MGM_TOKEN_PRINT")",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_LOG_DESTINATION,
+ "LogDestination",
+ MGM_TOKEN,
+ "String describing where logmessages are sent",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ MGM_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "MaxNoOfSavedEvents",
+ MGM_TOKEN,
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "100",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_MGM_PORT,
+ "PortNumber",
+ MGM_TOKEN,
+ "Port number to give commands to/fetch configurations from management server",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ NDB_PORT,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "PortNumberStats",
+ MGM_TOKEN,
+ "Port number used to get statistical information from a management server",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_NODE_ARBIT_RANK,
+ "ArbitrationRank",
+ MGM_TOKEN,
+ "If 0, then "MGM_TOKEN_PRINT" is not arbitrator. Kernel selects arbitrators in order 1, 2",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1",
+ "0",
+ "2" },
+
+ {
+ CFG_NODE_ARBIT_DELAY,
+ "ArbitrationDelay",
+ MGM_TOKEN,
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /****************************************************************************
+ * TCP
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "TCP",
+ "TCP",
+ "Connection section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)CONNECTION_TYPE_TCP,
+ 0, 0
+ },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "TCP",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "TCP",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_1,
+ "NodeId1",
+ "TCP",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2,
+ "NodeId2",
+ "TCP",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "TCP",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "55",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "TCP",
+ "Sends id in each signal. Used in trace files.",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "TCP",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "TCP",
+ "Port used for this transporter",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_TCP_SEND_BUFFER_SIZE,
+ "SendBufferMemory",
+ "TCP",
+ "Bytes of buffer for signals sent from this node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "256K",
+ "16K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_TCP_RECEIVE_BUFFER_SIZE,
+ "ReceiveBufferMemory",
+ "TCP",
+ "Bytes of buffer for signals received by this node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "64K",
+ "16K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_TCP_PROXY,
+ "Proxy",
+ "TCP",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "TCP",
+ "System for node 1 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "TCP",
+ "System for node 2 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+
+ /****************************************************************************
+ * SHM
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "SHM",
+ "SHM",
+ "Connection section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)CONNECTION_TYPE_SHM,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "SHM",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "SHM",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "SHM",
+ "Port used for this transporter",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SHM_SIGNUM,
+ "Signum",
+ "SHM",
+ "Signum to be used for signalling",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1,
+ "NodeId1",
+ "SHM",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2,
+ "NodeId2",
+ "SHM",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "SHM",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "35",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "SHM",
+ "Sends id in each signal. Used in trace files.",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "SHM",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_SHM_KEY,
+ "ShmKey",
+ "SHM",
+ "A shared memory key",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SHM_BUFFER_MEM,
+ "ShmSize",
+ "SHM",
+ "Size of shared memory segment",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1M",
+ "4K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "SHM",
+ "System for node 1 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "SHM",
+ "System for node 2 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ /****************************************************************************
+ * SCI
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "SCI",
+ "SCI",
+ "Connection section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)CONNECTION_TYPE_SCI,
+ 0, 0
+ },
+
+ {
+ CFG_CONNECTION_NODE_1,
+ "NodeId1",
+ "SCI",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_2,
+ "NodeId2",
+ "SCI",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "SCI",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "15",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "SCI",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "SCI",
+ "Name/IP of computer on one side of the connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "SCI",
+ "Port used for this transporter",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SCI_HOST1_ID_0,
+ "Host1SciId0",
+ "SCI",
+ "SCI-node id for adapter 0 on Host1 (a computer can have two adapters)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SCI_HOST1_ID_1,
+ "Host1SciId1",
+ "SCI",
+ "SCI-node id for adapter 1 on Host1 (a computer can have two adapters)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SCI_HOST2_ID_0,
+ "Host2SciId0",
+ "SCI",
+ "SCI-node id for adapter 0 on Host2 (a computer can have two adapters)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SCI_HOST2_ID_1,
+ "Host2SciId1",
+ "SCI",
+ "SCI-node id for adapter 1 on Host2 (a computer can have two adapters)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "SCI",
+ "Sends id in each signal. Used in trace files.",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "SCI",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_SCI_SEND_LIMIT,
+ "SendLimit",
+ "SCI",
+ "Transporter send buffer contents are sent when this no of bytes is buffered",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "8K",
+ "128",
+ "32K" },
+
+ {
+ CFG_SCI_BUFFER_MEM,
+ "SharedBufferSize",
+ "SCI",
+ "Size of shared memory segment",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1M",
+ "64K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "SCI",
+ "System for node 1 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "SCI",
+ "System for node 2 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ /****************************************************************************
+ * OSE
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "OSE",
+ "OSE",
+ "Connection section",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_SECTION,
+ (const char *)CONNECTION_TYPE_OSE,
+ 0, 0
+ },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "OSE",
+ "Name of computer on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "OSE",
+ "Name of computer on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_1,
+ "NodeId1",
+ "OSE",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_2,
+ "NodeId2",
+ "OSE",
+ "Id of node ("DB_TOKEN_PRINT", "API_TOKEN_PRINT" or "MGM_TOKEN_PRINT") on one side of the connection",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ UNDEFINED,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "OSE",
+ "Sends id in each signal. Used in trace files.",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "OSE",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_OSE_PRIO_A_SIZE,
+ "PrioASignalSize",
+ "OSE",
+ "Size of priority A signals (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_OSE_PRIO_B_SIZE,
+ "PrioBSignalSize",
+ "OSE",
+ "Size of priority B signals (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "1000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_OSE_RECEIVE_ARRAY_SIZE,
+ "ReceiveArraySize",
+ "OSE",
+ "Number of OSE signals checked for correct ordering (in no of OSE signals)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "10",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "OSE",
+ "System for node 1 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "OSE",
+ "System for node 2 in connection",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+};
+
+const int ConfigInfo::m_NoOfParams = sizeof(m_ParamInfo) / sizeof(ParamInfo);
+
+
+/****************************************************************************
+ * Ctor
+ ****************************************************************************/
+static void require(bool v) { if(!v) abort();}
+
+ConfigInfo::ConfigInfo()
+ : m_info(true), m_systemDefaults(true)
+{
+ int i;
+ Properties *section;
+ const Properties *oldpinfo;
+
+ for (i=0; i<m_NoOfParams; i++) {
+ const ParamInfo & param = m_ParamInfo[i];
+ Uint64 default_uint64;
+ bool default_bool;
+
+ // Create new section if it did not exist
+ if (!m_info.getCopy(param._section, &section)) {
+ Properties newsection(true);
+ m_info.put(param._section, &newsection);
+ }
+
+ // Get copy of section
+ m_info.getCopy(param._section, &section);
+
+ // Create pinfo (parameter info) entry
+ Properties pinfo(true);
+ pinfo.put("Id", param._paramId);
+ pinfo.put("Fname", param._fname);
+ pinfo.put("Description", param._description);
+ pinfo.put("Updateable", param._updateable);
+ pinfo.put("Type", param._type);
+ pinfo.put("Status", param._status);
+
+ if(param._default == MANDATORY){
+ pinfo.put("Mandatory", (Uint32)1);
+ }
+
+ switch (param._type) {
+ case CI_BOOL:
+ {
+ bool tmp_bool;
+ require(InitConfigFileParser::convertStringToBool(param._min, tmp_bool));
+ pinfo.put64("Min", tmp_bool);
+ require(InitConfigFileParser::convertStringToBool(param._max, tmp_bool));
+ pinfo.put64("Max", tmp_bool);
+ break;
+ }
+ case CI_INT:
+ case CI_INT64:
+ {
+ Uint64 tmp_uint64;
+ require(InitConfigFileParser::convertStringToUint64(param._min, tmp_uint64));
+ pinfo.put64("Min", tmp_uint64);
+ require(InitConfigFileParser::convertStringToUint64(param._max, tmp_uint64));
+ pinfo.put64("Max", tmp_uint64);
+ break;
+ }
+ case CI_SECTION:
+ pinfo.put("SectionType", (Uint32)UintPtr(param._default));
+ break;
+ case CI_STRING:
+ break;
+ }
+
+ // Check that pinfo is really new
+ if (section->get(param._fname, &oldpinfo)) {
+ ndbout << "Error: Parameter " << param._fname
+ << " defined twice in section " << param._section
+ << "." << endl;
+ exit(-1);
+ }
+
+ // Add new pinfo to section
+ section->put(param._fname, &pinfo);
+
+ // Replace section with modified section
+ m_info.put(param._section, section, true);
+
+ if(param._type != ConfigInfo::CI_SECTION){
+ Properties * p;
+ if(!m_systemDefaults.getCopy(param._section, &p)){
+ p = new Properties(true);
+ }
+ if(param._default != UNDEFINED &&
+ param._default != MANDATORY){
+ switch (param._type)
+ {
+ case CI_SECTION:
+ break;
+ case CI_STRING:
+ require(p->put(param._fname, param._default));
+ break;
+ case CI_BOOL:
+ {
+ bool tmp_bool;
+ require(InitConfigFileParser::convertStringToBool(param._default, default_bool));
+ require(p->put(param._fname, default_bool));
+ break;
+ }
+ case CI_INT:
+ case CI_INT64:
+ {
+ Uint64 tmp_uint64;
+ require(InitConfigFileParser::convertStringToUint64(param._default, default_uint64));
+ require(p->put(param._fname, default_uint64));
+ break;
+ }
+ }
+ }
+ require(m_systemDefaults.put(param._section, p, true));
+ delete p;
+ }
+ }
+
+ for (i=0; i<m_NoOfParams; i++) {
+ if(m_ParamInfo[i]._section == NULL){
+ ndbout << "Check that each entry has a section failed." << endl;
+ ndbout << "Parameter \"" << m_ParamInfo[i]._fname << endl;
+ ndbout << "Edit file " << __FILE__ << "." << endl;
+ exit(-1);
+ }
+
+ if(m_ParamInfo[i]._type == ConfigInfo::CI_SECTION)
+ continue;
+
+ const Properties * p = getInfo(m_ParamInfo[i]._section);
+ if (!p || !p->contains(m_ParamInfo[i]._fname)) {
+ ndbout << "Check that each pname has an fname failed." << endl;
+ ndbout << "Parameter \"" << m_ParamInfo[i]._fname
+ << "\" does not exist in section \""
+ << m_ParamInfo[i]._section << "\"." << endl;
+ ndbout << "Edit file " << __FILE__ << "." << endl;
+ exit(-1);
+ }
+ }
+}
+
+/****************************************************************************
+ * Getters
+ ****************************************************************************/
+inline void warning(const char * src, const char * arg){
+ ndbout << "Illegal call to ConfigInfo::" << src << "() - " << arg << endl;
+ abort();
+}
+
+const Properties *
+ConfigInfo::getInfo(const char * section) const {
+ const Properties * p;
+ if(!m_info.get(section, &p)){
+ return 0;
+ // warning("getInfo", section);
+ }
+ return p;
+}
+
+const Properties *
+ConfigInfo::getDefaults(const char * section) const {
+ const Properties * p;
+ if(!m_systemDefaults.get(section, &p)){
+ return 0;
+ //warning("getDefaults", section);
+ }
+ return p;
+}
+
+static
+Uint64
+getInfoInt(const Properties * section,
+ const char* fname, const char * type){
+ Uint32 val32;
+ const Properties * p;
+ if (section->get(fname, &p) && p->get(type, &val32)) {
+ return val32;
+ }
+
+ Uint64 val64;
+ if(p && p->get(type, &val64)){
+ return val64;
+ }
+
+ section->print();
+ if(section->get(fname, &p)){
+ p->print();
+ }
+
+ warning(type, fname);
+ return 0;
+}
+
+static
+const char *
+getInfoString(const Properties * section,
+ const char* fname, const char * type){
+ const char* val;
+ const Properties * p;
+ if (section->get(fname, &p) && p->get(type, &val)) {
+ return val;
+ }
+ warning(type, fname);
+ return val;
+}
+
+Uint64
+ConfigInfo::getMax(const Properties * section, const char* fname) const {
+ return getInfoInt(section, fname, "Max");
+}
+
+Uint64
+ConfigInfo::getMin(const Properties * section, const char* fname) const {
+ return getInfoInt(section, fname, "Min");
+}
+
+Uint64
+ConfigInfo::getDefault(const Properties * section, const char* fname) const {
+ return getInfoInt(section, fname, "Default");
+}
+
+const char*
+ConfigInfo::getDescription(const Properties * section,
+ const char* fname) const {
+ return getInfoString(section, fname, "Description");
+}
+
+bool
+ConfigInfo::isSection(const char * section) const {
+ for (int i = 0; i<m_noOfSectionNames; i++) {
+ if(!strcasecmp(section, m_sectionNames[i])) return true;
+ }
+ return false;
+}
+
+const char*
+ConfigInfo::getAlias(const char * section) const {
+ for (int i = 0; m_sectionNameAliases[i].name != 0; i++)
+ if(!strcasecmp(section, m_sectionNameAliases[i].alias))
+ return m_sectionNameAliases[i].name;
+ return 0;
+}
+
+bool
+ConfigInfo::verify(const Properties * section, const char* fname,
+ Uint64 value) const {
+ Uint64 min, max;
+
+ min = getInfoInt(section, fname, "Min");
+ max = getInfoInt(section, fname, "Max");
+ if(min > max){
+ warning("verify", fname);
+ }
+ if (value >= min && value <= max)
+ return true;
+ else
+ return false;
+}
+
+ConfigInfo::Type
+ConfigInfo::getType(const Properties * section, const char* fname) const {
+ return (ConfigInfo::Type) getInfoInt(section, fname, "Type");
+}
+
+ConfigInfo::Status
+ConfigInfo::getStatus(const Properties * section, const char* fname) const {
+ return (ConfigInfo::Status) getInfoInt(section, fname, "Status");
+}
+
+/****************************************************************************
+ * Printers
+ ****************************************************************************/
+
+void ConfigInfo::print() const {
+ Properties::Iterator it(&m_info);
+ for (const char* n = it.first(); n != NULL; n = it.next()) {
+ print(n);
+ }
+}
+
+void ConfigInfo::print(const char* section) const {
+ ndbout << "****** " << section << " ******" << endl << endl;
+ const Properties * sec = getInfo(section);
+ Properties::Iterator it(sec);
+ for (const char* n = it.first(); n != NULL; n = it.next()) {
+ // Skip entries with different F- and P-names
+ if (getStatus(sec, n) == ConfigInfo::CI_INTERNAL) continue;
+ if (getStatus(sec, n) == ConfigInfo::CI_DEPRICATED) continue;
+ if (getStatus(sec, n) == ConfigInfo::CI_NOTIMPLEMENTED) continue;
+ print(sec, n);
+ }
+}
+
+void ConfigInfo::print(const Properties * section,
+ const char* parameter) const {
+ ndbout << parameter;
+ // ndbout << getDescription(section, parameter) << endl;
+ switch (getType(section, parameter)) {
+ case ConfigInfo::CI_BOOL:
+ ndbout << " (Boolean value)" << endl;
+ ndbout << getDescription(section, parameter) << endl;
+ if (getDefault(section, parameter) == false) {
+ ndbout << "Default: N (Legal values: Y, N)" << endl;
+ } else if (getDefault(section, parameter) == true) {
+ ndbout << "Default: Y (Legal values: Y, N)" << endl;
+ } else if (getDefault(section, parameter) == (UintPtr)MANDATORY) {
+ ndbout << "MANDATORY (Legal values: Y, N)" << endl;
+ } else {
+ ndbout << "UNKNOWN" << endl;
+ }
+ ndbout << endl;
+ break;
+
+ case ConfigInfo::CI_INT:
+ case ConfigInfo::CI_INT64:
+ ndbout << " (Non-negative Integer)" << endl;
+ ndbout << getDescription(section, parameter) << endl;
+ if (getDefault(section, parameter) == (UintPtr)MANDATORY) {
+ ndbout << "MANDATORY (";
+ } else if (getDefault(section, parameter) == (UintPtr)UNDEFINED) {
+ ndbout << "UNDEFINED (";
+ } else {
+ ndbout << "Default: " << getDefault(section, parameter) << " (";
+ }
+ ndbout << "Min: " << getMin(section, parameter) << ", ";
+ ndbout << "Max: " << getMax(section, parameter) << ")" << endl;
+ ndbout << endl;
+ break;
+
+ case ConfigInfo::CI_STRING:
+ ndbout << " (String)" << endl;
+ ndbout << getDescription(section, parameter) << endl;
+ if (getDefault(section, parameter) == (UintPtr)MANDATORY) {
+ ndbout << "MANDATORY" << endl;
+ } else {
+ ndbout << "No default value" << endl;
+ }
+ ndbout << endl;
+ break;
+ case ConfigInfo::CI_SECTION:
+ break;
+ }
+}
+
+/****************************************************************************
+ * Section Rules
+ ****************************************************************************/
+
+/**
+ * Node rule: Add "Type" and update "NoOfNodes"
+ */
+bool
+transformNode(InitConfigFileParser::Context & ctx, const char * data){
+
+ Uint32 id;
+ if(!ctx.m_currentSection->get("Id", &id)){
+ Uint32 nextNodeId= 1;
+ ctx.m_userProperties.get("NextNodeId", &nextNodeId);
+ id= nextNodeId;
+ while (ctx.m_userProperties.get("AllocatedNodeId_", id, &id))
+ id++;
+ ctx.m_userProperties.put("NextNodeId", id+1, true);
+ ctx.m_currentSection->put("Id", id);
+#if 0
+ ctx.reportError("Mandatory parameter Id missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+#endif
+ } else if(ctx.m_userProperties.get("AllocatedNodeId_", id, &id)) {
+ ctx.reportError("Duplicate Id in section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ ctx.m_userProperties.put("AllocatedNodeId_", id, id);
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Node_%d", id);
+
+ ctx.m_currentSection->put("Type", ctx.fname);
+
+ Uint32 nodes = 0;
+ ctx.m_userProperties.get("NoOfNodes", &nodes);
+ ctx.m_userProperties.put("NoOfNodes", ++nodes, true);
+
+ /**
+ * Update count (per type)
+ */
+ nodes = 0;
+ ctx.m_userProperties.get(ctx.fname, &nodes);
+ ctx.m_userProperties.put(ctx.fname, ++nodes, true);
+
+ return true;
+}
+
+static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx)
+{
+ DBUG_ENTER("checkLocalhostHostnameMix");
+ const char * hostname= 0;
+ ctx.m_currentSection->get("HostName", &hostname);
+ if (hostname == 0 || hostname[0] == 0)
+ DBUG_RETURN(true);
+
+ Uint32 localhost_used= 0;
+ if(!strcmp(hostname, "localhost") || !strcmp(hostname, "127.0.0.1")){
+ localhost_used= 1;
+ ctx.m_userProperties.put("$computer-localhost-used", localhost_used);
+ if(!ctx.m_userProperties.get("$computer-localhost", &hostname))
+ DBUG_RETURN(true);
+ } else {
+ ctx.m_userProperties.get("$computer-localhost-used", &localhost_used);
+ ctx.m_userProperties.put("$computer-localhost", hostname);
+ }
+
+ if (localhost_used) {
+ ctx.reportError("Mixing of localhost with other hostname(%s) is illegal",
+ hostname);
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(true);
+}
+
+bool
+fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data){
+
+ const char * hostname;
+ if (ctx.m_currentSection->get("HostName", &hostname))
+ return checkLocalhostHostnameMix(ctx);
+
+ const char * compId;
+ if(!ctx.m_currentSection->get("ExecuteOnComputer", &compId)){
+ const char * type;
+ if(ctx.m_currentSection->get("Type", &type) && strcmp(type,DB_TOKEN) == 0)
+ require(ctx.m_currentSection->put("HostName", "localhost"));
+ else
+ require(ctx.m_currentSection->put("HostName", ""));
+ return checkLocalhostHostnameMix(ctx);
+ }
+
+ const Properties * computer;
+ char tmp[255];
+ BaseString::snprintf(tmp, sizeof(tmp), "Computer_%s", compId);
+ if(!ctx.m_config->get(tmp, &computer)){
+ ctx.reportError("Computer \"%s\" not declared"
+ "- [%s] starting at line: %d",
+ compId, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ if(!computer->get("HostName", &hostname)){
+ ctx.reportError("HostName missing in [COMPUTER] (Id: %d) "
+ " - [%s] starting at line: %d",
+ compId, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ require(ctx.m_currentSection->put("HostName", hostname));
+ return checkLocalhostHostnameMix(ctx);
+}
+
+bool
+fixFileSystemPath(InitConfigFileParser::Context & ctx, const char * data){
+ DBUG_ENTER("fixFileSystemPath");
+
+ const char * path;
+ if (ctx.m_currentSection->get("FileSystemPath", &path))
+ DBUG_RETURN(true);
+
+ if (ctx.m_currentSection->get("DataDir", &path)) {
+ require(ctx.m_currentSection->put("FileSystemPath", path));
+ DBUG_RETURN(true);
+ }
+
+ require(false);
+ DBUG_RETURN(false);
+}
+
+bool
+fixBackupDataDir(InitConfigFileParser::Context & ctx, const char * data){
+
+ const char * path;
+ if (ctx.m_currentSection->get("BackupDataDir", &path))
+ return true;
+
+ if (ctx.m_currentSection->get("FileSystemPath", &path)) {
+ require(ctx.m_currentSection->put("BackupDataDir", path));
+ return true;
+ }
+
+ require(false);
+ return false;
+}
+
+bool
+transformExtNode(InitConfigFileParser::Context & ctx, const char * data){
+
+ Uint32 id;
+ const char * systemName;
+
+ if(!ctx.m_currentSection->get("Id", &id)){
+ ctx.reportError("Mandatory parameter 'Id' missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ if(!ctx.m_currentSection->get("System", &systemName)){
+ ctx.reportError("Mandatory parameter 'System' missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ ctx.m_currentSection->put("Type", ctx.fname);
+
+ Uint32 nodes = 0;
+ ctx.m_userProperties.get("ExtNoOfNodes", &nodes);
+ require(ctx.m_userProperties.put("ExtNoOfNodes",++nodes, true));
+
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s:Node_%d",
+ systemName, id);
+
+ return true;
+}
+
+/**
+ * Connection rule: Check support of connection
+ */
+bool
+checkConnectionSupport(InitConfigFileParser::Context & ctx, const char * data)
+{
+ int error= 0;
+ if (strcasecmp("TCP",ctx.fname) == 0)
+ {
+ // always enabled
+ }
+ else if (strcasecmp("SHM",ctx.fname) == 0)
+ {
+#ifndef NDB_SHM_TRANSPORTER
+ error= 1;
+#endif
+ }
+ else if (strcasecmp("SCI",ctx.fname) == 0)
+ {
+#ifndef NDB_SCI_TRANSPORTER
+ error= 1;
+#endif
+ }
+ else if (strcasecmp("OSE",ctx.fname) == 0)
+ {
+#ifndef NDB_OSE_TRANSPORTER
+ error= 1;
+#endif
+ }
+ if (error)
+ {
+ ctx.reportError("Binary not compiled with this connection support, "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ return true;
+}
+
+/**
+ * Connection rule: Update "NoOfConnections"
+ */
+bool
+transformConnection(InitConfigFileParser::Context & ctx, const char * data)
+{
+ Uint32 connections = 0;
+ ctx.m_userProperties.get("NoOfConnections", &connections);
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Connection_%d", connections);
+ ctx.m_userProperties.put("NoOfConnections", ++connections, true);
+
+ ctx.m_currentSection->put("Type", ctx.fname);
+ return true;
+}
+
+/**
+ * System rule: Just add it
+ */
+bool
+transformSystem(InitConfigFileParser::Context & ctx, const char * data){
+
+ const char * name;
+ if(!ctx.m_currentSection->get("Name", &name)){
+ ctx.reportError("Mandatory parameter Name missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ ndbout << "transformSystem " << name << endl;
+
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "SYSTEM_%s", name);
+
+ return true;
+}
+
+/**
+ * External system rule: Just add it
+ */
+bool
+transformExternalSystem(InitConfigFileParser::Context & ctx, const char * data){
+ const char * name;
+ if(!ctx.m_currentSection->get("Name", &name)){
+ ctx.reportError("Mandatory parameter Name missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "EXTERNAL SYSTEM_%s", name);
+
+ return true;
+}
+
+/**
+ * Computer rule: Update "NoOfComputers", add "Type"
+ */
+bool
+transformComputer(InitConfigFileParser::Context & ctx, const char * data){
+ const char * id;
+ if(!ctx.m_currentSection->get("Id", &id)){
+ ctx.reportError("Mandatory parameter Id missing from section "
+ "[%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), "Computer_%s", id);
+
+ Uint32 computers = 0;
+ ctx.m_userProperties.get("NoOfComputers", &computers);
+ ctx.m_userProperties.put("NoOfComputers", ++computers, true);
+
+ const char * hostname = 0;
+ ctx.m_currentSection->get("HostName", &hostname);
+ if(!hostname){
+ return true;
+ }
+
+ return checkLocalhostHostnameMix(ctx);
+}
+
+/**
+ * Apply default values
+ */
+void
+applyDefaultValues(InitConfigFileParser::Context & ctx,
+ const Properties * defaults){
+ if(defaults != NULL){
+ Properties::Iterator it(defaults);
+
+ for(const char * name = it.first(); name != NULL; name = it.next()){
+ ConfigInfo::Status st = ctx.m_info->getStatus(ctx.m_currentInfo, name);
+ if(!ctx.m_currentSection->contains(name)){
+ switch (ctx.m_info->getType(ctx.m_currentInfo, name)){
+ case ConfigInfo::CI_INT:
+ case ConfigInfo::CI_BOOL:{
+ Uint32 val = 0;
+ ::require(defaults->get(name, &val));
+ ctx.m_currentSection->put(name, val);
+ break;
+ }
+ case ConfigInfo::CI_INT64:{
+ Uint64 val = 0;
+ ::require(defaults->get(name, &val));
+ ctx.m_currentSection->put64(name, val);
+ break;
+ }
+ case ConfigInfo::CI_STRING:{
+ const char * val;
+ ::require(defaults->get(name, &val));
+ ctx.m_currentSection->put(name, val);
+ break;
+ }
+ case ConfigInfo::CI_SECTION:
+ break;
+ }
+ }
+ }
+ }
+}
+
+bool
+applyDefaultValues(InitConfigFileParser::Context & ctx, const char * data){
+
+ if(strcmp(data, "user") == 0)
+ applyDefaultValues(ctx, ctx.m_userDefaults);
+ else if (strcmp(data, "system") == 0)
+ applyDefaultValues(ctx, ctx.m_systemDefaults);
+ else
+ return false;
+
+ return true;
+}
+
+/**
+ * Check that a section contains all MANDATORY parameters
+ */
+bool
+checkMandatory(InitConfigFileParser::Context & ctx, const char * data){
+
+ Properties::Iterator it(ctx.m_currentInfo);
+ for(const char * name = it.first(); name != NULL; name = it.next()){
+ const Properties * info = NULL;
+ ::require(ctx.m_currentInfo->get(name, &info));
+ Uint32 val;
+ if(info->get("Mandatory", &val)){
+ const char * fname;
+ ::require(info->get("Fname", &fname));
+ if(!ctx.m_currentSection->contains(fname)){
+ ctx.reportError("Mandatory parameter %s missing from section "
+ "[%s] starting at line: %d",
+ fname, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+/**
+ * Connection rule: Fix node id
+ *
+ * Transform a string "NodeidX" (e.g. "uppsala.32")
+ * into a Uint32 "NodeIdX" (e.g. 32) and a string "SystemX" (e.g. "uppsala").
+ */
+static bool fixNodeId(InitConfigFileParser::Context & ctx, const char * data)
+{
+ char buf[] = "NodeIdX"; buf[6] = data[sizeof("NodeI")];
+ char sysbuf[] = "SystemX"; sysbuf[6] = data[sizeof("NodeI")];
+ const char* nodeId;
+ require(ctx.m_currentSection->get(buf, &nodeId));
+
+ char tmpLine[MAX_LINE_LENGTH];
+ strncpy(tmpLine, nodeId, MAX_LINE_LENGTH);
+ char* token1 = strtok(tmpLine, ".");
+ char* token2 = strtok(NULL, ".");
+ Uint32 id;
+
+ if (token2 == NULL) { // Only a number given
+ errno = 0;
+ char* p;
+ id = strtol(token1, &p, 10);
+ if (errno != 0) warning("STRTOK1", nodeId);
+ require(ctx.m_currentSection->put(buf, id, true));
+ } else { // A pair given (e.g. "uppsala.32")
+ errno = 0;
+ char* p;
+ id = strtol(token2, &p, 10);
+ if (errno != 0) warning("STRTOK2", nodeId);
+ require(ctx.m_currentSection->put(buf, id, true));
+ require(ctx.m_currentSection->put(sysbuf, token1));
+ }
+ return true;
+}
+
+/**
+ * @returns true if connection is external (one node is external)
+ * Also returns:
+ * - name of external system in parameter extSystemName, and
+ * - nodeId of external node in parameter extSystemNodeId.
+ */
+static bool
+isExtConnection(InitConfigFileParser::Context & ctx,
+ const char **extSystemName, Uint32 * extSystemNodeId){
+
+ Uint32 nodeId1, nodeId2;
+
+ if (ctx.m_currentSection->contains("System1") &&
+ ctx.m_currentSection->get("System1", extSystemName) &&
+ ctx.m_currentSection->get("NodeId1", &nodeId1)) {
+ *extSystemNodeId = nodeId1;
+ return true;
+ }
+
+ if (ctx.m_currentSection->contains("System2") &&
+ ctx.m_currentSection->get("System2", extSystemName) &&
+ ctx.m_currentSection->get("NodeId2", &nodeId2)) {
+ *extSystemNodeId = nodeId2;
+ return true;
+ }
+
+ return false;
+}
+
+/**
+ * External Connection Rule:
+ * If connection is to an external system, then move connection into
+ * external system configuration (i.e. a sub-property).
+ */
+static bool
+fixExtConnection(InitConfigFileParser::Context & ctx, const char * data){
+
+ const char * extSystemName;
+ Uint32 extSystemNodeId;
+
+ if (isExtConnection(ctx, &extSystemName, &extSystemNodeId)) {
+
+ Uint32 connections = 0;
+ ctx.m_userProperties.get("ExtNoOfConnections", &connections);
+ require(ctx.m_userProperties.put("ExtNoOfConnections",++connections, true));
+
+ char tmpLine1[MAX_LINE_LENGTH];
+ BaseString::snprintf(tmpLine1, MAX_LINE_LENGTH, "Connection_%d", connections-1);
+
+ /**
+ * Section: EXTERNAL SYSTEM_<Ext System Name>
+ */
+ char extSystemPropName[MAX_LINE_LENGTH];
+ strncpy(extSystemPropName, "EXTERNAL SYSTEM_", MAX_LINE_LENGTH);
+ strncat(extSystemPropName, extSystemName, MAX_LINE_LENGTH);
+ strncat(extSystemPropName, ":", MAX_LINE_LENGTH);
+ strncat(extSystemPropName, tmpLine1, MAX_LINE_LENGTH);
+
+ /**
+ * Increase number of external connections for the system
+ *
+ * @todo Limitation: Only one external system is allowed
+ */
+ require(ctx.m_userProperties.put("ExtSystem", extSystemName, true));
+
+ /**
+ * Make sure section is stored in right place
+ */
+ strncpy(ctx.pname, extSystemPropName, MAX_LINE_LENGTH);
+
+ /**
+ * Since this is an external connection,
+ * decrease number of internal connections
+ */
+ require(ctx.m_userProperties.get("NoOfConnections", &connections));
+ require(ctx.m_userProperties.put("NoOfConnections", --connections, true));
+ }
+
+ return true;
+}
+
+/**
+ * Connection rule: Fix hostname
+ *
+ * Unless Hostname is not already specified, do steps:
+ * -# Via Connection's NodeId lookup Node
+ * -# Via Node's ExecuteOnComputer lookup Hostname
+ * -# Add HostName to Connection
+ */
+static bool
+fixHostname(InitConfigFileParser::Context & ctx, const char * data){
+
+ char buf[] = "NodeIdX"; buf[6] = data[sizeof("HostNam")];
+ char sysbuf[] = "SystemX"; sysbuf[6] = data[sizeof("HostNam")];
+
+ if(!ctx.m_currentSection->contains(data)){
+ Uint32 id = 0;
+ require(ctx.m_currentSection->get(buf, &id));
+
+ const Properties * node;
+ if(!ctx.m_config->get("Node", id, &node))
+ {
+ ctx.reportError("Unknown node: \"%d\" specified in connection "
+ "[%s] starting at line: %d",
+ id, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ const char * hostname;
+ require(node->get("HostName", &hostname));
+ require(ctx.m_currentSection->put(data, hostname));
+ }
+ return true;
+}
+
+/**
+ * Connection rule: Fix port number (using a port number adder)
+ */
+static bool
+fixPortNumber(InitConfigFileParser::Context & ctx, const char * data){
+
+ DBUG_ENTER("fixPortNumber");
+
+ Uint32 id1= 0, id2= 0;
+ const char *hostName1;
+ const char *hostName2;
+ require(ctx.m_currentSection->get("NodeId1", &id1));
+ require(ctx.m_currentSection->get("NodeId2", &id2));
+ require(ctx.m_currentSection->get("HostName1", &hostName1));
+ require(ctx.m_currentSection->get("HostName2", &hostName2));
+ DBUG_PRINT("info",("NodeId1=%d HostName1=\"%s\"",id1,hostName1));
+ DBUG_PRINT("info",("NodeId2=%d HostName2=\"%s\"",id2,hostName2));
+
+ if (id1 > id2) {
+ Uint32 tmp= id1;
+ const char *tmp_name= hostName1;
+ hostName1= hostName2;
+ id1= id2;
+ hostName2= tmp_name;
+ id2= tmp;
+ }
+
+ const Properties * node;
+ require(ctx.m_config->get("Node", id1, &node));
+
+ BaseString hostname(hostName1);
+
+ if (hostname.c_str()[0] == 0) {
+ ctx.reportError("Hostname required on nodeid %d since it will "
+ "act as server.", id1);
+ DBUG_RETURN(false);
+ }
+
+ Uint32 port= 0;
+ const char * type1;
+ const char * type2;
+ const Properties * node2;
+
+ node->get("Type", &type1);
+ ctx.m_config->get("Node", id2, &node2);
+ node2->get("Type", &type2);
+
+ if(strcmp(type1, MGM_TOKEN)==0)
+ node->get("PortNumber",&port);
+ else if(strcmp(type2, MGM_TOKEN)==0)
+ node2->get("PortNumber",&port);
+
+ if (!port &&
+ !node->get("ServerPort", &port) &&
+ !ctx.m_userProperties.get("ServerPort_", id1, &port))
+ {
+ Uint32 base= 0;
+ /*
+ * If the connection doesn't involve an mgm server,
+ * and a default port number has been set, behave the old
+ * way of allocating port numbers for transporters.
+ */
+ if(ctx.m_userDefaults && ctx.m_userDefaults->get("PortNumber", &base))
+ {
+ Uint32 adder= 0;
+ {
+ BaseString server_port_adder(hostname);
+ server_port_adder.append("_ServerPortAdder");
+ ctx.m_userProperties.get(server_port_adder.c_str(), &adder);
+ ctx.m_userProperties.put(server_port_adder.c_str(), adder+1, true);
+ }
+
+ if (!ctx.m_userProperties.get("ServerPortBase", &base)){
+ if(!(ctx.m_userDefaults &&
+ ctx.m_userDefaults->get("PortNumber", &base)) &&
+ !ctx.m_systemDefaults->get("PortNumber", &base)) {
+ base= strtoll(NDB_TCP_BASE_PORT,0,0);
+ }
+ ctx.m_userProperties.put("ServerPortBase", base);
+ }
+
+ port= base + adder;
+ ctx.m_userProperties.put("ServerPort_", id1, port);
+ }
+ }
+
+ if(ctx.m_currentSection->contains("PortNumber")) {
+ ndbout << "PortNumber should no longer be specificied "
+ << "per connection, please remove from config. "
+ << "Will be changed to " << port << endl;
+ ctx.m_currentSection->put("PortNumber", port, true);
+ }
+ else
+ {
+ ctx.m_currentSection->put("PortNumber", port);
+ }
+
+ DBUG_PRINT("info", ("connection %d-%d port %d host %s",
+ id1, id2, port, hostname.c_str()));
+
+ DBUG_RETURN(true);
+}
+
+static bool
+fixShmUniqueId(InitConfigFileParser::Context & ctx, const char * data)
+{
+ DBUG_ENTER("fixShmUniqueId");
+ Uint32 nodes= 0;
+ ctx.m_userProperties.get(ctx.fname, &nodes);
+ if (nodes == 1) // first management server
+ {
+ Uint32 portno= atoi(NDB_PORT);
+ ctx.m_currentSection->get("PortNumber", &portno);
+ ctx.m_userProperties.put("ShmUniqueId", portno);
+ }
+ DBUG_RETURN(true);
+}
+
+static
+bool
+fixShmKey(InitConfigFileParser::Context & ctx, const char *)
+{
+ DBUG_ENTER("fixShmKey");
+ {
+ static int last_signum= -1;
+ Uint32 signum;
+ if(!ctx.m_currentSection->get("Signum", &signum))
+ {
+ signum= OPT_NDB_SHM_SIGNUM_DEFAULT;
+ if (signum <= 0)
+ {
+ ctx.reportError("Unable to set default parameter for [SHM]Signum"
+ " please specify [SHM DEFAULT]Signum");
+ return false;
+ }
+ ctx.m_currentSection->put("Signum", signum);
+ DBUG_PRINT("info",("Added Signum=%u", signum));
+ }
+ if ( last_signum != (int)signum && last_signum >= 0 )
+ {
+ ctx.reportError("All shared memory transporters must have same [SHM]Signum defined."
+ " Use [SHM DEFAULT]Signum");
+ return false;
+ }
+ last_signum= (int)signum;
+ }
+ {
+ Uint32 id1= 0, id2= 0, key= 0;
+ require(ctx.m_currentSection->get("NodeId1", &id1));
+ require(ctx.m_currentSection->get("NodeId2", &id2));
+ if(!ctx.m_currentSection->get("ShmKey", &key))
+ {
+ require(ctx.m_userProperties.get("ShmUniqueId", &key));
+ key= key << 16 | (id1 > id2 ? id1 << 8 | id2 : id2 << 8 | id1);
+ ctx.m_currentSection->put("ShmKey", key);
+ DBUG_PRINT("info",("Added ShmKey=0x%x", key));
+ }
+ }
+ DBUG_RETURN(true);
+}
+
+/**
+ * DB Node rule: Check various constraints
+ */
+static bool
+checkDbConstraints(InitConfigFileParser::Context & ctx, const char *){
+
+ Uint32 t1 = 0, t2 = 0;
+ ctx.m_currentSection->get("MaxNoOfConcurrentOperations", &t1);
+ ctx.m_currentSection->get("MaxNoOfConcurrentTransactions", &t2);
+
+ if (t1 < t2) {
+ ctx.reportError("MaxNoOfConcurrentOperations must be greater than "
+ "MaxNoOfConcurrentTransactions - [%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ Uint32 replicas = 0, otherReplicas;
+ ctx.m_currentSection->get("NoOfReplicas", &replicas);
+ if(ctx.m_userProperties.get("NoOfReplicas", &otherReplicas)){
+ if(replicas != otherReplicas){
+ ctx.reportError("NoOfReplicas defined differently on different nodes"
+ " - [%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ } else {
+ ctx.m_userProperties.put("NoOfReplicas", replicas);
+ }
+
+ return true;
+}
+
+/**
+ * Connection rule: Check varius constraints
+ */
+static bool
+checkConnectionConstraints(InitConfigFileParser::Context & ctx, const char *){
+
+ Uint32 id1 = 0, id2 = 0;
+ ctx.m_currentSection->get("NodeId1", &id1);
+ ctx.m_currentSection->get("NodeId2", &id2);
+
+ // If external connection, just accept it
+ if (ctx.m_currentSection->contains("System1") ||
+ ctx.m_currentSection->contains("System2"))
+ return true;
+
+ if(id1 == id2){
+ ctx.reportError("Illegal connection from node to itself"
+ " - [%s] starting at line: %d",
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ const Properties * node1;
+ if(!ctx.m_config->get("Node", id1, &node1)){
+ ctx.reportError("Connection refering to undefined node: %d"
+ " - [%s] starting at line: %d",
+ id1, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ const Properties * node2;
+ if(!ctx.m_config->get("Node", id2, &node2)){
+ ctx.reportError("Connection refering to undefined node: %d"
+ " - [%s] starting at line: %d",
+ id2, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ const char * type1;
+ const char * type2;
+ require(node1->get("Type", &type1));
+ require(node2->get("Type", &type2));
+
+ /**
+ * Report error if the following are true
+ * -# None of the nodes is of type DB
+ * -# Not both of them are MGMs
+ * -# None of them contain a "SystemX" name
+ */
+ if((strcmp(type1, DB_TOKEN) != 0 && strcmp(type2, DB_TOKEN) != 0) &&
+ !(strcmp(type1, MGM_TOKEN) == 0 && strcmp(type2, MGM_TOKEN) == 0) &&
+ !ctx.m_currentSection->contains("System1") &&
+ !ctx.m_currentSection->contains("System2")){
+ ctx.reportError("Invalid connection between node %d (%s) and node %d (%s)"
+ " - [%s] starting at line: %d",
+ id1, type1, id2, type2,
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ return true;
+}
+
+static bool
+checkTCPConstraints(InitConfigFileParser::Context & ctx, const char * data){
+
+ const char * host;
+ struct in_addr addr;
+ if(ctx.m_currentSection->get(data, &host) && strlen(host) &&
+ Ndb_getInAddr(&addr, host)){
+ ctx.reportError("Unable to lookup/illegal hostname %s"
+ " - [%s] starting at line: %d",
+ host, ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ return true;
+}
+
+static
+bool
+transform(InitConfigFileParser::Context & ctx,
+ Properties & dst,
+ const char * oldName,
+ const char * newName,
+ double add, double mul){
+
+ if(ctx.m_currentSection->contains(newName)){
+ ctx.reportError("Both %s and %s specified"
+ " - [%s] starting at line: %d",
+ oldName, newName,
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ PropertiesType oldType;
+ require(ctx.m_currentSection->getTypeOf(oldName, &oldType));
+ ConfigInfo::Type newType = ctx.m_info->getType(ctx.m_currentInfo, newName);
+ if(!((oldType == PropertiesType_Uint32 || oldType == PropertiesType_Uint64)
+ && (newType == ConfigInfo::CI_INT || newType == ConfigInfo::CI_INT64 || newType == ConfigInfo::CI_BOOL))){
+ ndbout << "oldType: " << (int)oldType << ", newType: " << (int)newType << endl;
+ ctx.reportError("Unable to handle type conversion w.r.t deprication %s %s"
+ "- [%s] starting at line: %d",
+ oldName, newName,
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+ Uint64 oldVal;
+ require(ctx.m_currentSection->get(oldName, &oldVal));
+
+ Uint64 newVal = (Uint64)((Int64)oldVal * mul + add);
+ if(!ctx.m_info->verify(ctx.m_currentInfo, newName, newVal)){
+ ctx.reportError("Unable to handle deprication, new value not within bounds"
+ "%s %s - [%s] starting at line: %d",
+ oldName, newName,
+ ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ if(newType == ConfigInfo::CI_INT || newType == ConfigInfo::CI_BOOL){
+ require(dst.put(newName, (Uint32)newVal));
+ } else if(newType == ConfigInfo::CI_INT64) {
+ require(dst.put64(newName, newVal));
+ }
+ return true;
+}
+
+static bool
+fixDepricated(InitConfigFileParser::Context & ctx, const char * data){
+ const char * name;
+ /**
+ * Transform old values to new values
+ * Transform new values to old values (backward compatible)
+ */
+ Properties tmp(true);
+ Properties::Iterator it(ctx.m_currentSection);
+ for (name = it.first(); name != NULL; name = it.next()) {
+ const DepricationTransform * p = &f_deprication[0];
+ while(p->m_section != 0){
+ if(strcmp(p->m_section, ctx.fname) == 0){
+ double mul = p->m_mul;
+ double add = p->m_add;
+ if(strcmp(name, p->m_oldName) == 0){
+ if(!transform(ctx, tmp, name, p->m_newName, add, mul)){
+ return false;
+ }
+ } else if(strcmp(name, p->m_newName) == 0) {
+ if(!transform(ctx, tmp, name, p->m_oldName, -add/mul,1.0/mul)){
+ return false;
+ }
+ }
+ }
+ p++;
+ }
+ }
+
+ Properties::Iterator it2(&tmp);
+ for (name = it2.first(); name != NULL; name = it2.next()) {
+ PropertiesType type;
+ require(tmp.getTypeOf(name, &type));
+ switch(type){
+ case PropertiesType_Uint32:{
+ Uint32 val;
+ require(tmp.get(name, &val));
+ ::require(ctx.m_currentSection->put(name, val));
+ break;
+ }
+ case PropertiesType_char:{
+ const char * val;
+ require(tmp.get(name, &val));
+ ::require(ctx.m_currentSection->put(name, val));
+ break;
+ }
+ case PropertiesType_Uint64:{
+ Uint64 val;
+ require(tmp.get(name, &val));
+ ::require(ctx.m_currentSection->put64(name, val));
+ break;
+ }
+ case PropertiesType_Properties:
+ default:
+ abort();
+ }
+ }
+ return true;
+}
+
+static bool
+saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){
+ const Properties * sec;
+ if(!ctx.m_currentInfo->get(ctx.fname, &sec)){
+ abort();
+ return false;
+ }
+
+ do {
+ const char *secName;
+ Uint32 id, status, typeVal;
+ require(sec->get("Fname", &secName));
+ require(sec->get("Id", &id));
+ require(sec->get("Status", &status));
+ require(sec->get("SectionType", &typeVal));
+
+ if(id == KEY_INTERNAL || status == ConfigInfo::CI_INTERNAL){
+ ndbout_c("skipping section %s", ctx.fname);
+ break;
+ }
+
+ Uint32 no = 0;
+ ctx.m_userProperties.get("$Section", id, &no);
+ ctx.m_userProperties.put("$Section", id, no+1, true);
+
+ ctx.m_configValues.openSection(id, no);
+ ctx.m_configValues.put(CFG_TYPE_OF_SECTION, typeVal);
+
+ Properties::Iterator it(ctx.m_currentSection);
+ for (const char* n = it.first(); n != NULL; n = it.next()) {
+ const Properties * info;
+ if(!ctx.m_currentInfo->get(n, &info))
+ continue;
+
+ Uint32 id = 0;
+ info->get("Id", &id);
+
+ if(id == KEY_INTERNAL)
+ continue;
+
+ bool ok = true;
+ PropertiesType type;
+ require(ctx.m_currentSection->getTypeOf(n, &type));
+ switch(type){
+ case PropertiesType_Uint32:{
+ Uint32 val;
+ require(ctx.m_currentSection->get(n, &val));
+ ok = ctx.m_configValues.put(id, val);
+ break;
+ }
+ case PropertiesType_Uint64:{
+ Uint64 val;
+ require(ctx.m_currentSection->get(n, &val));
+ ok = ctx.m_configValues.put64(id, val);
+ break;
+ }
+ case PropertiesType_char:{
+ const char * val;
+ require(ctx.m_currentSection->get(n, &val));
+ ok = ctx.m_configValues.put(id, val);
+ break;
+ }
+ default:
+ abort();
+ }
+ require(ok);
+ }
+ ctx.m_configValues.closeSection();
+ } while(0);
+ return true;
+}
+
+static bool
+sanity_checks(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data)
+{
+ Uint32 db_nodes = 0;
+ Uint32 mgm_nodes = 0;
+ Uint32 api_nodes = 0;
+ if (!ctx.m_userProperties.get("DB", &db_nodes)) {
+ ctx.reportError("At least one database node should be defined in config file");
+ return false;
+ }
+ if (!ctx.m_userProperties.get("MGM", &mgm_nodes)) {
+ ctx.reportError("At least one management server node should be defined in config file");
+ return false;
+ }
+ if (!ctx.m_userProperties.get("API", &api_nodes)) {
+ ctx.reportError("At least one application node (for the mysqld) should be defined in config file");
+ return false;
+ }
+ return true;
+}
+
+static void
+add_a_connection(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ Uint32 nodeId1, Uint32 nodeId2, bool use_shm)
+{
+ ConfigInfo::ConfigRuleSection s;
+ const char *hostname1= 0, *hostname2= 0;
+ const Properties *tmp;
+
+ require(ctx.m_config->get("Node", nodeId1, &tmp));
+ tmp->get("HostName", &hostname1);
+
+ require(ctx.m_config->get("Node", nodeId2, &tmp));
+ tmp->get("HostName", &hostname2);
+
+ char buf[16];
+ s.m_sectionData= new Properties(true);
+ BaseString::snprintf(buf, sizeof(buf), "%u", nodeId1);
+ s.m_sectionData->put("NodeId1", buf);
+ BaseString::snprintf(buf, sizeof(buf), "%u", nodeId2);
+ s.m_sectionData->put("NodeId2", buf);
+
+ if (use_shm &&
+ hostname1 && hostname1[0] &&
+ hostname2 && hostname2[0] &&
+ strcmp(hostname1,hostname2) == 0)
+ {
+ s.m_sectionType= BaseString("SHM");
+ DBUG_PRINT("info",("adding SHM connection %d %d",nodeId1,nodeId2));
+ }
+ else
+ {
+ s.m_sectionType= BaseString("TCP");
+ DBUG_PRINT("info",("adding TCP connection %d %d",nodeId1,nodeId2));
+ }
+
+ sections.push_back(s);
+}
+
+static bool
+add_node_connections(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data)
+{
+ DBUG_ENTER("add_node_connections");
+ Uint32 i;
+ Properties * props= ctx.m_config;
+ Properties p_connections(true);
+ Properties p_connections2(true);
+
+ for (i = 0;; i++){
+ const Properties * tmp;
+ Uint32 nodeId1, nodeId2;
+
+ if(!props->get("Connection", i, &tmp)) break;
+
+ if(!tmp->get("NodeId1", &nodeId1)) continue;
+ p_connections.put("", nodeId1, nodeId1);
+ if(!tmp->get("NodeId2", &nodeId2)) continue;
+ p_connections.put("", nodeId2, nodeId2);
+
+ p_connections2.put("", nodeId1 + nodeId2<<16, nodeId1);
+ p_connections2.put("", nodeId2 + nodeId1<<16, nodeId2);
+ }
+
+ Uint32 nNodes;
+ ctx.m_userProperties.get("NoOfNodes", &nNodes);
+
+ Properties p_db_nodes(true);
+ Properties p_api_nodes(true);
+ Properties p_mgm_nodes(true);
+
+ Uint32 i_db= 0, i_api= 0, i_mgm= 0, n;
+ for (i= 0, n= 0; n < nNodes; i++){
+ const Properties * tmp;
+ if(!props->get("Node", i, &tmp)) continue;
+ n++;
+
+ const char * type;
+ if(!tmp->get("Type", &type)) continue;
+
+ if (strcmp(type,DB_TOKEN) == 0)
+ p_db_nodes.put("", i_db++, i);
+ else if (strcmp(type,API_TOKEN) == 0)
+ p_api_nodes.put("", i_api++, i);
+ else if (strcmp(type,MGM_TOKEN) == 0)
+ p_mgm_nodes.put("", i_mgm++, i);
+ }
+
+ Uint32 nodeId1, nodeId2, dummy;
+
+ for (i= 0; p_db_nodes.get("", i, &nodeId1); i++){
+ for (Uint32 j= i+1;; j++){
+ if(!p_db_nodes.get("", j, &nodeId2)) break;
+ if(!p_connections2.get("", nodeId1+nodeId2<<16, &dummy)) {
+ add_a_connection(sections,ctx,nodeId1,nodeId2,opt_ndb_shm);
+ }
+ }
+ }
+
+ for (i= 0; p_api_nodes.get("", i, &nodeId1); i++){
+ if(!p_connections.get("", nodeId1, &dummy)) {
+ for (Uint32 j= 0;; j++){
+ if(!p_db_nodes.get("", j, &nodeId2)) break;
+ add_a_connection(sections,ctx,nodeId1,nodeId2,opt_ndb_shm);
+ }
+ }
+ }
+
+ for (i= 0; p_mgm_nodes.get("", i, &nodeId1); i++){
+ if(!p_connections.get("", nodeId1, &dummy)) {
+ for (Uint32 j= 0;; j++){
+ if(!p_db_nodes.get("", j, &nodeId2)) break;
+ add_a_connection(sections,ctx,nodeId1,nodeId2,0);
+ }
+ }
+ }
+
+ DBUG_RETURN(true);
+}
+
+static bool set_connection_priorities(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data)
+{
+ DBUG_ENTER("set_connection_priorities");
+ DBUG_RETURN(true);
+}
+
+static bool add_server_ports(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data)
+{
+#if 0
+ Properties * props= ctx.m_config;
+ Properties computers(true);
+ Uint32 port_base = NDB_TCP_BASE_PORT;
+
+ Uint32 nNodes;
+ ctx.m_userProperties.get("NoOfNodes", &nNodes);
+
+ for (Uint32 i= 0, n= 0; n < nNodes; i++){
+ Properties * tmp;
+ if(!props->get("Node", i, &tmp)) continue;
+ n++;
+
+ const char * type;
+ if(!tmp->get("Type", &type)) continue;
+
+ Uint32 port;
+ if (tmp->get("ServerPort", &port)) continue;
+
+ Uint32 computer;
+ if (!tmp->get("ExecuteOnComputer", &computer)) continue;
+
+ Uint32 adder= 0;
+ computers.get("",computer, &adder);
+
+ if (strcmp(type,DB_TOKEN) == 0) {
+ adder++;
+ tmp->put("ServerPort", port_base+adder);
+ computers.put("",computer, adder);
+ }
+ }
+#endif
+ return true;
+}
+
+static bool
+check_node_vs_replicas(Vector<ConfigInfo::ConfigRuleSection>&sections,
+ struct InitConfigFileParser::Context &ctx,
+ const char * rule_data)
+{
+ Uint32 db_nodes= 0;
+ Uint32 replicas= 0;
+ Uint32 db_host_count= 0;
+ ctx.m_userProperties.get(DB_TOKEN, &db_nodes);
+ ctx.m_userProperties.get("NoOfReplicas", &replicas);
+ if((db_nodes % replicas) != 0){
+ ctx.reportError("Invalid no of db nodes wrt no of replicas.\n"
+ "No of nodes must be dividable with no or replicas");
+ return false;
+ }
+ // check that node groups and arbitrators are ok
+ // just issue warning if not
+ if(replicas > 1){
+ Properties * props= ctx.m_config;
+ Properties p_db_hosts(true); // store hosts which db nodes run on
+ Properties p_arbitrators(true); // store hosts which arbitrators run on
+ // arbitrator should not run together with db node on same host
+ Uint32 i, n, group= 0, i_group= 0;
+ Uint32 n_nodes;
+ BaseString node_group_warning, arbitration_warning;
+ const char *arbit_warn_fmt=
+ "\n arbitrator with id %d and db node with id %d on same host %s";
+ const char *arbit_warn_fmt2=
+ "\n arbitrator with id %d has no hostname specified";
+
+ ctx.m_userProperties.get("NoOfNodes", &n_nodes);
+ for (i= 0, n= 0; n < n_nodes; i++){
+ const Properties * tmp;
+ if(!props->get("Node", i, &tmp)) continue;
+ n++;
+
+ const char * type;
+ if(!tmp->get("Type", &type)) continue;
+
+ const char* host= 0;
+ tmp->get("HostName", &host);
+
+ if (strcmp(type,DB_TOKEN) == 0)
+ {
+ {
+ Uint32 ii;
+ if (!p_db_hosts.get(host,&ii))
+ db_host_count++;
+ p_db_hosts.put(host,i);
+ if (p_arbitrators.get(host,&ii))
+ {
+ arbitration_warning.appfmt(arbit_warn_fmt, ii, i, host);
+ p_arbitrators.remove(host); // only one warning per db node
+ }
+ }
+ {
+ unsigned j;
+ BaseString str, str2;
+ str.assfmt("#group%d_",group);
+ p_db_hosts.put(str.c_str(),i_group,host);
+ str2.assfmt("##group%d_",group);
+ p_db_hosts.put(str2.c_str(),i_group,i);
+ for (j= 0; j < i_group; j++)
+ {
+ const char *other_host;
+ p_db_hosts.get(str.c_str(),j,&other_host);
+ if (strcmp(host,other_host) == 0) {
+ unsigned int other_i, c= 0;
+ p_db_hosts.get(str2.c_str(),j,&other_i);
+ p_db_hosts.get(str.c_str(),&c);
+ if (c == 0) // first warning in this node group
+ node_group_warning.appfmt(" Node group %d", group);
+ c|= 1 << j;
+ p_db_hosts.put(str.c_str(),c);
+
+ node_group_warning.appfmt(",\n db node with id %d and id %d "
+ "on same host %s", other_i, i, host);
+ }
+ }
+ i_group++;
+ DBUG_ASSERT(i_group <= replicas);
+ if (i_group == replicas)
+ {
+ unsigned c= 0;
+ p_db_hosts.get(str.c_str(),&c);
+ if (c+1 == (1u << (replicas-1))) // all nodes on same machine
+ node_group_warning.append(".\n Host failure will "
+ "cause complete cluster shutdown.");
+ else if (c > 0)
+ node_group_warning.append(".\n Host failure may "
+ "cause complete cluster shutdown.");
+ group++;
+ i_group= 0;
+ }
+ }
+ }
+ else if (strcmp(type,API_TOKEN) == 0 ||
+ strcmp(type,MGM_TOKEN) == 0)
+ {
+ Uint32 rank;
+ if(tmp->get("ArbitrationRank", &rank) && rank > 0)
+ {
+ if(host && host[0] != 0)
+ {
+ Uint32 ii;
+ p_arbitrators.put(host,i);
+ if (p_db_hosts.get(host,&ii))
+ {
+ arbitration_warning.appfmt(arbit_warn_fmt, i, ii, host);
+ }
+ }
+ else
+ {
+ arbitration_warning.appfmt(arbit_warn_fmt2, i);
+ }
+ }
+ }
+ }
+ if (db_host_count > 1 && node_group_warning.length() > 0)
+ ndbout_c("Cluster configuration warning:\n%s",node_group_warning.c_str());
+ if (db_host_count > 1 && arbitration_warning.length() > 0)
+ ndbout_c("Cluster configuration warning:%s%s",arbitration_warning.c_str(),
+ "\n Running arbitrator on the same host as a database node may"
+ "\n cause complete cluster shutdown in case of host failure.");
+ }
+ return true;
+}
+
+template class Vector<ConfigInfo::ConfigRuleSection>;