summaryrefslogtreecommitdiff
path: root/storage/ndb/src/mgmsrv
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/mgmsrv')
-rw-r--r--storage/ndb/src/mgmsrv/Config.cpp181
-rw-r--r--storage/ndb/src/mgmsrv/Config.hpp82
-rw-r--r--storage/ndb/src/mgmsrv/ConfigInfo.cpp3727
-rw-r--r--storage/ndb/src/mgmsrv/ConfigInfo.hpp143
-rw-r--r--storage/ndb/src/mgmsrv/InitConfigFileParser.cpp970
-rw-r--r--storage/ndb/src/mgmsrv/InitConfigFileParser.hpp145
-rw-r--r--storage/ndb/src/mgmsrv/Makefile.am60
-rw-r--r--storage/ndb/src/mgmsrv/MgmtSrvr.cpp2941
-rw-r--r--storage/ndb/src/mgmsrv/MgmtSrvr.hpp683
-rw-r--r--storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp76
-rw-r--r--storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp22
-rw-r--r--storage/ndb/src/mgmsrv/ParamInfo.cpp2077
-rw-r--r--storage/ndb/src/mgmsrv/ParamInfo.hpp44
-rw-r--r--storage/ndb/src/mgmsrv/Services.cpp1857
-rw-r--r--storage/ndb/src/mgmsrv/Services.hpp143
-rw-r--r--storage/ndb/src/mgmsrv/SignalQueue.cpp104
-rw-r--r--storage/ndb/src/mgmsrv/SignalQueue.hpp100
-rw-r--r--storage/ndb/src/mgmsrv/convertStrToInt.cpp43
-rw-r--r--storage/ndb/src/mgmsrv/convertStrToInt.hpp25
-rw-r--r--storage/ndb/src/mgmsrv/main.cpp388
-rw-r--r--storage/ndb/src/mgmsrv/mkconfig/Makefile13
-rw-r--r--storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp61
22 files changed, 13885 insertions, 0 deletions
diff --git a/storage/ndb/src/mgmsrv/Config.cpp b/storage/ndb/src/mgmsrv/Config.cpp
new file mode 100644
index 00000000000..6ff5fb789f0
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Config.cpp
@@ -0,0 +1,181 @@
+/* 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 "Config.hpp"
+#include <ctype.h>
+#include <string.h>
+#include "MgmtErrorReporter.hpp"
+#include <Properties.hpp>
+
+//*****************************************************************************
+// Ctor / Dtor
+//*****************************************************************************
+
+Config::Config() {
+ m_oldConfig = 0;
+ m_configValues = 0;
+}
+
+Config::~Config() {
+ if(m_configValues != 0){
+ free(m_configValues);
+ }
+
+ if(m_oldConfig != 0)
+ delete m_oldConfig;
+}
+
+/*****************************************************************************/
+
+void
+Config::printAllNameValuePairs(NdbOut &out,
+ const Properties *prop,
+ const char* s) const {
+ Properties::Iterator it(prop);
+ const Properties * section = m_info.getInfo(s);
+ for (const char* n = it.first(); n != NULL; n = it.next()) {
+ Uint32 int_value;
+ const char* str_value;
+ Uint64 int_64;
+
+ if(!section->contains(n))
+ continue;
+ if (m_info.getStatus(section, n) == ConfigInfo::CI_INTERNAL)
+ continue;
+ if (m_info.getStatus(section, n) == ConfigInfo::CI_DEPRICATED)
+ continue;
+ if (m_info.getStatus(section, n) == ConfigInfo::CI_NOTIMPLEMENTED)
+ continue;
+
+ out << n << ": ";
+
+ switch (m_info.getType(section, n)) {
+ case ConfigInfo::CI_INT:
+ MGM_REQUIRE(prop->get(n, &int_value));
+ out << int_value;
+ break;
+
+ case ConfigInfo::CI_INT64:
+ MGM_REQUIRE(prop->get(n, &int_64));
+ out << int_64;
+ break;
+
+ case ConfigInfo::CI_BOOL:
+ MGM_REQUIRE(prop->get(n, &int_value));
+ if (int_value) {
+ out << "Y";
+ } else {
+ out << "N";
+ }
+ break;
+ case ConfigInfo::CI_STRING:
+ MGM_REQUIRE(prop->get(n, &str_value));
+ out << str_value;
+ break;
+ case ConfigInfo::CI_SECTION:
+ out << "SECTION";
+ break;
+ }
+ out << endl;
+ }
+}
+
+/*****************************************************************************/
+
+void Config::printConfigFile(NdbOut &out) const {
+#if 0
+ Uint32 noOfNodes, noOfConnections, noOfComputers;
+ MGM_REQUIRE(get("NoOfNodes", &noOfNodes));
+ MGM_REQUIRE(get("NoOfConnections", &noOfConnections));
+ MGM_REQUIRE(get("NoOfComputers", &noOfComputers));
+
+ out <<
+ "######################################################################" <<
+ endl <<
+ "#" << endl <<
+ "# NDB Cluster System configuration" << endl <<
+ "#" << endl <<
+ "######################################################################" <<
+ endl <<
+ "# No of nodes (DB, API or MGM): " << noOfNodes << endl <<
+ "# No of connections: " << noOfConnections << endl <<
+ "######################################################################" <<
+ endl;
+
+ /**************************
+ * Print COMPUTER configs *
+ **************************/
+ const char * name;
+ Properties::Iterator it(this);
+ for(name = it.first(); name != NULL; name = it.next()){
+ if(strncasecmp("Computer_", name, 9) == 0){
+
+ const Properties *prop;
+ out << endl << "[COMPUTER]" << endl;
+ MGM_REQUIRE(get(name, &prop));
+ printAllNameValuePairs(out, prop, "COMPUTER");
+
+ out << endl <<
+ "###################################################################" <<
+ endl;
+
+ } else if(strncasecmp("Node_", name, 5) == 0){
+ /**********************
+ * Print NODE configs *
+ **********************/
+ const Properties *prop;
+ const char *s;
+
+ MGM_REQUIRE(get(name, &prop));
+ MGM_REQUIRE(prop->get("Type", &s));
+ out << endl << "[" << s << "]" << endl;
+ printAllNameValuePairs(out, prop, s);
+
+ out << endl <<
+ "###################################################################" <<
+ endl;
+ } else if(strncasecmp("Connection_", name, 11) == 0){
+ /****************************
+ * Print CONNECTION configs *
+ ****************************/
+ const Properties *prop;
+ const char *s;
+
+ MGM_REQUIRE(get(name, &prop));
+ MGM_REQUIRE(prop->get("Type", &s));
+ out << endl << "[" << s << "]" << endl;
+ printAllNameValuePairs(out, prop, s);
+
+ out << endl <<
+ "###################################################################" <<
+ endl;
+ } else if(strncasecmp("SYSTEM", name, strlen("SYSTEM")) == 0) {
+ /************************
+ * Print SYSTEM configs *
+ ************************/
+ const Properties *prop;
+
+ MGM_REQUIRE(get(name, &prop));
+ out << endl << "[SYSTEM]" << endl;
+ printAllNameValuePairs(out, prop, "SYSTEM");
+
+ out << endl <<
+ "###################################################################" <<
+ endl;
+ }
+ }
+#endif
+}
diff --git a/storage/ndb/src/mgmsrv/Config.hpp b/storage/ndb/src/mgmsrv/Config.hpp
new file mode 100644
index 00000000000..05a48ad91f0
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Config.hpp
@@ -0,0 +1,82 @@
+/* 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 */
+
+#ifndef Config_H
+#define Config_H
+
+#include <LogLevel.hpp>
+
+#include <kernel_types.h>
+
+#include <NdbOut.hpp>
+#include <ndb_limits.h>
+#include <Properties.hpp>
+#include <ConfigInfo.hpp>
+
+class ConfigInfo;
+
+/**
+ * @class Config
+ * @brief Cluster Configuration (corresponds to initial configuration file)
+ *
+ * Contains all cluster configuration parameters.
+ *
+ * The information includes all configurable parameters for a NDB cluster:
+ * - DB, API and MGM nodes with all their properties,
+ * - Connections between nodes and computers the nodes will execute on.
+ *
+ * The following categories (sections) of configuration parameters exists:
+ * - COMPUTER, DB, MGM, API, TCP, SCI, SHM
+ *
+ */
+
+class Config {
+public:
+ /**
+ * Constructor which loads the object with an Properties object
+ */
+ Config();
+ virtual ~Config();
+
+ /**
+ * Prints the configuration in configfile format
+ */
+ void printConfigFile(NdbOut &out = ndbout) const;
+ void printConfigFile(OutputStream &out) const {
+ NdbOut ndb(out);
+ printConfigFile(ndb);
+ }
+
+ /**
+ * Info
+ */
+ const ConfigInfo * getConfigInfo() const { return &m_info;}
+private:
+ ConfigInfo m_info;
+
+ void printAllNameValuePairs(NdbOut &out,
+ const Properties *prop,
+ const char* section) const;
+
+ /**
+ * Information about parameters (min, max values etc)
+ */
+public:
+ Properties * m_oldConfig;
+ struct ndb_mgm_configuration * m_configValues;
+};
+
+#endif // Config_H
diff --git a/storage/ndb/src/mgmsrv/ConfigInfo.cpp b/storage/ndb/src/mgmsrv/ConfigInfo.cpp
new file mode 100644
index 00000000000..def349cf744
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.cpp
@@ -0,0 +1,3727 @@
+/* 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;
+extern my_bool opt_core;
+
+#define MAX_LINE_LENGTH 255
+#define KEY_INTERNAL 0
+#define MAX_INT_RNIL 0xfffffeff
+#define MAX_PORT_NO 65535
+
+#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",
+ "COMPUTER",
+
+ DB_TOKEN,
+ MGM_TOKEN,
+ API_TOKEN,
+
+ "TCP",
+ "SCI",
+ "SHM"
+};
+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 transformNode(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 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);
+static bool checkLocalhostHostnameMix(InitConfigFileParser::Context & ctx, const char * data);
+
+const ConfigInfo::SectionRule
+ConfigInfo::m_SectionRules[] = {
+ { "SYSTEM", transformSystem, 0 },
+ { "COMPUTER", transformComputer, 0 },
+
+ { DB_TOKEN, transformNode, 0 },
+ { API_TOKEN, transformNode, 0 },
+ { MGM_TOKEN, transformNode, 0 },
+
+ { MGM_TOKEN, fixShmUniqueId, 0 },
+
+ { "TCP", checkConnectionSupport, 0 },
+ { "SHM", checkConnectionSupport, 0 },
+ { "SCI", checkConnectionSupport, 0 },
+
+ { "TCP", transformConnection, 0 },
+ { "SHM", transformConnection, 0 },
+ { "SCI", transformConnection, 0 },
+
+ { DB_TOKEN, fixNodeHostname, 0 },
+ { API_TOKEN, fixNodeHostname, 0 },
+ { MGM_TOKEN, fixNodeHostname, 0 },
+
+ { "TCP", fixNodeId, "NodeId1" },
+ { "TCP", fixNodeId, "NodeId2" },
+ { "SHM", fixNodeId, "NodeId1" },
+ { "SHM", fixNodeId, "NodeId2" },
+ { "SCI", fixNodeId, "NodeId1" },
+ { "SCI", 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" },
+
+ { "TCP", fixPortNumber, 0 }, // has to come after fixHostName
+ { "SHM", fixPortNumber, 0 }, // has to come after fixHostName
+ { "SCI", fixPortNumber, 0 }, // has to come after fixHostName
+
+ { "*", applyDefaultValues, "user" },
+ { "*", fixDepricated, 0 },
+ { "*", applyDefaultValues, "system" },
+
+ { "SHM", fixShmKey, 0 }, // has to come after apply default values
+
+ { DB_TOKEN, checkLocalhostHostnameMix, 0 },
+ { API_TOKEN, checkLocalhostHostnameMix, 0 },
+ { MGM_TOKEN, checkLocalhostHostnameMix, 0 },
+
+ { DB_TOKEN, fixFileSystemPath, 0 },
+ { DB_TOKEN, fixBackupDataDir, 0 },
+
+ { DB_TOKEN, checkDbConstraints, 0 },
+
+ { "TCP", checkConnectionConstraints, 0 },
+ { "SHM", checkConnectionConstraints, 0 },
+ { "SCI", 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 },
+
+ { "TCP", saveInConfigValues, 0 },
+ { "SHM", saveInConfigValues, 0 },
+ { "SCI", 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 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 },
+ { 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 },
+ { DB_TOKEN, "Id", "NodeId", 0, 1 },
+ { API_TOKEN, "Id", "NodeId", 0, 1 },
+ { MGM_TOKEN, "Id", "NodeId", 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_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,
+ "localhost",
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ DB_TOKEN,
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ DB_TOKEN,
+ "",
+ ConfigInfo::CI_DEPRICATED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ 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_PORT_NO) },
+
+ {
+ 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_DISK_PAGE_BUFFER_MEMORY,
+ "DiskPageBufferMemory",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for disk page buffer cache",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT64,
+ "64M",
+ "4M",
+ "1024G" },
+
+ {
+ CFG_DB_SGA,
+ "SharedGlobalMemory",
+ DB_TOKEN,
+ "Total number bytes on each "DB_TOKEN_PRINT" node allocated for any use",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT64,
+ "20M",
+ "0",
+ "65536G" }, // 32k pages * 32-bit i value
+
+ {
+ 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,
+ "16",
+ "3",
+ 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_INITIAL_OPEN_FILES,
+ "InitialNoOfOpenFiles",
+ DB_TOKEN,
+ "Initial number of files open per "DB_TOKEN_PRINT" node.(One thread is created per file)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "27",
+ "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) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_TUP_SR,
+ "NoOfDiskPagesToDiskDuringRestartTUP",
+ DB_TOKEN,
+ "DiskCheckpointSpeedSr",
+ ConfigInfo::CI_DEPRICATED,
+ true,
+ ConfigInfo::CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_TUP,
+ "NoOfDiskPagesToDiskAfterRestartTUP",
+ DB_TOKEN,
+ "DiskCheckpointSpeed",
+ ConfigInfo::CI_DEPRICATED,
+ true,
+ ConfigInfo::CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_ACC_SR,
+ "NoOfDiskPagesToDiskDuringRestartACC",
+ DB_TOKEN,
+ "DiskCheckpointSpeedSr",
+ ConfigInfo::CI_DEPRICATED,
+ true,
+ ConfigInfo::CI_INT,
+ "20",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_ACC,
+ "NoOfDiskPagesToDiskAfterRestartACC",
+ DB_TOKEN,
+ "DiskCheckpointSpeed",
+ ConfigInfo::CI_DEPRICATED,
+ 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_DISK_SYNCH_SIZE,
+ "DiskSyncSize",
+ DB_TOKEN,
+ "Data written to a file before a synch is forced",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "4M",
+ "32k",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_CHECKPOINT_SPEED,
+ "DiskCheckpointSpeed",
+ DB_TOKEN,
+ "Bytes per second allowed to be written by checkpoint",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "10M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_CHECKPOINT_SPEED_SR,
+ "DiskCheckpointSpeedInRestart",
+ DB_TOKEN,
+ "Bytes per second allowed to be written by checkpoint during restart",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "100M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ 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",
+ "2K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_MAX_WRITE_SIZE,
+ "BackupMaxWriteSize",
+ DB_TOKEN,
+ "Max size of filesystem writes made by backup (in bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "256K",
+ "2K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_STRING_MEMORY,
+ "StringMemory",
+ DB_TOKEN,
+ "Default size of string memory (0 -> 5% of max 1-100 -> %of max, >100 -> actual bytes)",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "0",
+ "0",
+ 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,
+ "",
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ API_TOKEN,
+ "Name of system for this node",
+ ConfigInfo::CI_INTERNAL,
+ false,
+ ConfigInfo::CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ API_TOKEN,
+ "",
+ ConfigInfo::CI_DEPRICATED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ 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,
+ "",
+ 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 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ MGM_TOKEN,
+ "",
+ ConfigInfo::CI_DEPRICATED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ 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_PORT_NO) },
+
+ {
+ 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_PORT_NO) },
+
+ {
+ 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_NODE_ID_SERVER,
+ "NodeIdServer",
+ "TCP",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ 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_PORT_NO) },
+
+ {
+ CFG_TCP_SEND_BUFFER_SIZE,
+ "SendBufferMemory",
+ "TCP",
+ "Bytes of buffer for signals sent from this node",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ "256K",
+ "64K",
+ 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_PORT_NO) },
+
+ {
+ 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_NODE_ID_SERVER,
+ "NodeIdServer",
+ "SHM",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ 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,
+ UNDEFINED,
+ "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",
+ "64K",
+ 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_NODE_ID_SERVER,
+ "NodeIdServer",
+ "SCI",
+ "",
+ ConfigInfo::CI_USED,
+ false,
+ ConfigInfo::CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ 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_PORT_NO) },
+
+ {
+ 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 }
+};
+
+const int ConfigInfo::m_NoOfParams = sizeof(m_ParamInfo) / sizeof(ParamInfo);
+
+
+/****************************************************************************
+ * Ctor
+ ****************************************************************************/
+static void require(bool v)
+{
+ if(!v)
+ {
+ if (opt_core)
+ abort();
+ else
+ exit(-1);
+ }
+}
+
+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;
+ require(false);
+ }
+
+ // Add new pinfo to section
+ section->put(param._fname, &pinfo);
+
+ // Replace section with modified section
+ m_info.put(param._section, section, true);
+ delete section;
+
+ 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;
+ require(false);
+ }
+
+ 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;
+ require(false);
+ }
+ }
+}
+
+/****************************************************************************
+ * Getters
+ ****************************************************************************/
+inline void warning(const char * src, const char * arg){
+ ndbout << "Illegal call to ConfigInfo::" << src << "() - " << arg << endl;
+ require(false);
+}
+
+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::nameToAlias(const char * name) {
+ for (int i = 0; m_sectionNameAliases[i].name != 0; i++)
+ if(!strcasecmp(name, m_sectionNameAliases[i].name))
+ return m_sectionNameAliases[i].alias;
+ return 0;
+}
+
+const char*
+ConfigInfo::getAlias(const char * section) {
+ 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, line;
+ if(!ctx.m_currentSection->get("NodeId", &id) && !ctx.m_currentSection->get("Id", &id)){
+ Uint32 nextNodeId= 1;
+ ctx.m_userProperties.get("NextNodeId", &nextNodeId);
+ id= nextNodeId;
+ while (ctx.m_userProperties.get("AllocatedNodeId_", id, &line))
+ id++;
+ if (id != nextNodeId)
+ {
+ fprintf(stderr,"Cluster configuration warning line %d: "
+ "Could not use next node id %d for section [%s], "
+ "using next unused node id %d.\n",
+ ctx.m_sectionLineno, nextNodeId, ctx.fname, id);
+ }
+ ctx.m_currentSection->put("NodeId", id);
+ } else if(ctx.m_userProperties.get("AllocatedNodeId_", id, &line)) {
+ ctx.reportError("Duplicate nodeid in section "
+ "[%s] starting at line: %d. Previously used on line %d.",
+ ctx.fname, ctx.m_sectionLineno, line);
+ return false;
+ }
+
+ if(id >= MAX_NODES)
+ {
+ ctx.reportError("too many nodes configured, only up to %d nodes supported.",
+ MAX_NODES);
+ return false;
+ }
+
+ // next node id _always_ next numbers after last used id
+ ctx.m_userProperties.put("NextNodeId", id+1, true);
+
+ ctx.m_userProperties.put("AllocatedNodeId_", id, ctx.m_sectionLineno);
+ 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, const char * data)
+{
+ 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 (default for [NDBD]HostName) with other hostname(%s) is illegal",
+ hostname);
+ DBUG_RETURN(false);
+ }
+
+ DBUG_RETURN(true);
+}
+
+bool
+fixNodeHostname(InitConfigFileParser::Context & ctx, const char * data)
+{
+ const char * hostname;
+ DBUG_ENTER("fixNodeHostname");
+
+ if (ctx.m_currentSection->get("HostName", &hostname))
+ DBUG_RETURN(checkLocalhostHostnameMix(ctx,0));
+
+ const char * compId;
+ if(!ctx.m_currentSection->get("ExecuteOnComputer", &compId))
+ DBUG_RETURN(true);
+
+ 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);
+ DBUG_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);
+ DBUG_RETURN(false);
+ }
+
+ require(ctx.m_currentSection->put("HostName", hostname));
+ DBUG_RETURN(checkLocalhostHostnameMix(ctx,0));
+}
+
+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;
+}
+
+/**
+ * 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
+ }
+
+ 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;
+}
+
+/**
+ * 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,0);
+}
+
+/**
+ * Apply default values
+ */
+void
+applyDefaultValues(InitConfigFileParser::Context & ctx,
+ const Properties * defaults)
+{
+ DBUG_ENTER("applyDefaultValues");
+ 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);
+ DBUG_PRINT("info",("%s=%d #default",name,val));
+ break;
+ }
+ case ConfigInfo::CI_INT64:{
+ Uint64 val = 0;
+ ::require(defaults->get(name, &val));
+ ctx.m_currentSection->put64(name, val);
+ DBUG_PRINT("info",("%s=%lld #default",name,val));
+ break;
+ }
+ case ConfigInfo::CI_STRING:{
+ const char * val;
+ ::require(defaults->get(name, &val));
+ ctx.m_currentSection->put(name, val);
+ DBUG_PRINT("info",("%s=%s #default",name,val));
+ break;
+ }
+ case ConfigInfo::CI_SECTION:
+ break;
+ }
+ }
+#ifndef DBUG_OFF
+ else
+ {
+ switch (ctx.m_info->getType(ctx.m_currentInfo, name)){
+ case ConfigInfo::CI_INT:
+ case ConfigInfo::CI_BOOL:{
+ Uint32 val = 0;
+ ::require(ctx.m_currentSection->get(name, &val));
+ DBUG_PRINT("info",("%s=%d",name,val));
+ break;
+ }
+ case ConfigInfo::CI_INT64:{
+ Uint64 val = 0;
+ ::require(ctx.m_currentSection->get(name, &val));
+ DBUG_PRINT("info",("%s=%lld",name,val));
+ break;
+ }
+ case ConfigInfo::CI_STRING:{
+ const char * val;
+ ::require(ctx.m_currentSection->get(name, &val));
+ DBUG_PRINT("info",("%s=%s",name,val));
+ break;
+ }
+ case ConfigInfo::CI_SECTION:
+ break;
+ }
+ }
+#endif
+ }
+ }
+ DBUG_VOID_RETURN;
+}
+
+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;
+}
+
+/**
+ * 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, id2;
+ 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));
+
+ const Properties *node1, *node2;
+ require(ctx.m_config->get("Node", id1, &node1));
+ require(ctx.m_config->get("Node", id2, &node2));
+
+ const char *type1, *type2;
+ require(node1->get("Type", &type1));
+ require(node2->get("Type", &type2));
+
+ /* add NodeIdServer info */
+ {
+ Uint32 nodeIdServer = id1 < id2 ? id1 : id2;
+ if(strcmp(type1, API_TOKEN) == 0 || strcmp(type2, MGM_TOKEN) == 0)
+ nodeIdServer = id2;
+ else if(strcmp(type2, API_TOKEN) == 0 || strcmp(type1, MGM_TOKEN) == 0)
+ nodeIdServer = id1;
+ ctx.m_currentSection->put("NodeIdServer", nodeIdServer);
+
+ if (id2 == nodeIdServer) {
+ {
+ const char *tmp= hostName1;
+ hostName1= hostName2;
+ hostName2= tmp;
+ }
+ {
+ Uint32 tmp= id1;
+ id1= id2;
+ id2= tmp;
+ }
+ {
+ const Properties *tmp= node1;
+ node1= node2;
+ node2= tmp;
+ }
+ {
+ const char *tmp= type1;
+ type1= type2;
+ type2= tmp;
+ }
+ }
+ }
+
+ 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;
+ if(strcmp(type1, MGM_TOKEN)==0)
+ node1->get("PortNumber",&port);
+ else if(strcmp(type2, MGM_TOKEN)==0)
+ node2->get("PortNumber",&port);
+
+ if (!port &&
+ !node1->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);
+ }
+
+ /**
+ * In kernel, will calculate the MaxNoOfMeataTables use the following sum:
+ * Uint32 noOfMetaTables = noOfTables + noOfOrderedIndexes +
+ * noOfUniqueHashIndexes + 2
+ * 2 is the number of the SysTables.
+ * So must check that the sum does't exceed the max value of Uint32.
+ */
+ Uint32 noOfTables = 0,
+ noOfOrderedIndexes = 0,
+ noOfUniqueHashIndexes = 0;
+ ctx.m_currentSection->get("MaxNoOfTables", &noOfTables);
+ ctx.m_currentSection->get("MaxNoOfOrderedIndexes", &noOfOrderedIndexes);
+ ctx.m_currentSection->get("MaxNoOfUniqueHashIndexes", &noOfUniqueHashIndexes);
+
+ Uint64 sum= (Uint64)noOfTables + noOfOrderedIndexes + noOfUniqueHashIndexes;
+
+ if (sum > ((Uint32)~0 - 2)) {
+ ctx.reportError("The sum of MaxNoOfTables, MaxNoOfOrderedIndexes and"
+ " MaxNoOfUniqueHashIndexes must not exceed %u - [%s]"
+ " starting at line: %d",
+ ((Uint32)~0 - 2), ctx.fname, ctx.m_sectionLineno);
+ return false;
+ }
+
+ 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(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
+ */
+ if((strcmp(type1, DB_TOKEN) != 0 && strcmp(type2, DB_TOKEN) != 0) &&
+ !(strcmp(type1, MGM_TOKEN) == 0 && strcmp(type2, MGM_TOKEN) == 0))
+ {
+ 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(strcasecmp(name, p->m_oldName) == 0){
+ if(!transform(ctx, tmp, name, p->m_newName, add, mul)){
+ return false;
+ }
+ } else if(strcasecmp(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:
+ ::require(false);
+ }
+ }
+ return true;
+}
+
+extern int g_print_full_config;
+
+static bool
+saveInConfigValues(InitConfigFileParser::Context & ctx, const char * data){
+ const Properties * sec;
+ if(!ctx.m_currentInfo->get(ctx.fname, &sec)){
+ require(false);
+ 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;
+ }
+
+ if (g_print_full_config)
+ {
+ const char *alias= ConfigInfo::nameToAlias(ctx.fname);
+ printf("[%s]\n", alias ? alias : ctx.fname);
+ }
+
+ 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);
+ if (g_print_full_config)
+ printf("%s=%u\n", n, val);
+ break;
+ }
+ case PropertiesType_Uint64:{
+ Uint64 val;
+ require(ctx.m_currentSection->get(n, &val));
+ ok = ctx.m_configValues.put64(id, val);
+ if (g_print_full_config)
+ printf("%s=%llu\n", n, val);
+ break;
+ }
+ case PropertiesType_char:{
+ const char * val;
+ require(ctx.m_currentSection->get(n, &val));
+ ok = ctx.m_configValues.put(id, val);
+ if (g_print_full_config)
+ printf("%s=%s\n", n, val);
+ break;
+ }
+ default:
+ require(false);
+ }
+ 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 (ndbd) should be defined in config file");
+ return false;
+ }
+ if (!ctx.m_userProperties.get("MGM", &mgm_nodes)) {
+ ctx.reportError("At least one management server node (ndb_mgmd) 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
+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>;
diff --git a/storage/ndb/src/mgmsrv/ConfigInfo.hpp b/storage/ndb/src/mgmsrv/ConfigInfo.hpp
new file mode 100644
index 00000000000..788619db7fe
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/ConfigInfo.hpp
@@ -0,0 +1,143 @@
+/* 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 */
+
+#ifndef ConfigInfo_H
+#define ConfigInfo_H
+
+#include <kernel_types.h>
+#include <Properties.hpp>
+#include <ndb_limits.h>
+#include <NdbOut.hpp>
+#include "InitConfigFileParser.hpp"
+
+/**
+ * A MANDATORY parameters must be specified in the config file
+ * An UNDEFINED parameter may or may not be specified in the config file
+ */
+static const char* MANDATORY = (char*)~(UintPtr)0;// Default value for mandatory params.
+static const char* UNDEFINED = 0; // Default value for undefined params.
+
+/**
+ * @class ConfigInfo
+ * @brief Metainformation about ALL cluster configuration parameters
+ *
+ * Use the getters to find out metainformation about parameters.
+ */
+class ConfigInfo {
+public:
+ enum Type { CI_BOOL, CI_INT, CI_INT64, CI_STRING, CI_SECTION };
+ enum Status { CI_USED, ///< Active
+ CI_DEPRICATED, ///< Can be, but shouldn't
+ CI_NOTIMPLEMENTED, ///< Is ignored.
+ CI_INTERNAL ///< Not configurable by the user
+ };
+
+ /**
+ * Entry for one configuration parameter
+ */
+ struct ParamInfo {
+ Uint32 _paramId;
+ const char* _fname;
+ const char* _section;
+ const char* _description;
+ Status _status;
+ bool _updateable;
+ Type _type;
+ const char* _default;
+ const char* _min;
+ const char* _max;
+ };
+
+ struct AliasPair{
+ const char * name;
+ const char * alias;
+ };
+
+ /**
+ * Entry for one section rule
+ */
+ struct SectionRule {
+ const char * m_section;
+ bool (* m_sectionRule)(struct InitConfigFileParser::Context &,
+ const char * m_ruleData);
+ const char * m_ruleData;
+ };
+
+ /**
+ * Entry for config rule
+ */
+ struct ConfigRuleSection {
+ BaseString m_sectionType;
+ Properties * m_sectionData;
+ };
+
+ struct ConfigRule {
+ bool (* m_configRule)(Vector<ConfigRuleSection>&,
+ struct InitConfigFileParser::Context &,
+ const char * m_ruleData);
+ const char * m_ruleData;
+ };
+
+ ConfigInfo();
+
+ /**
+ * Checks if the suggested value is valid for the suggested parameter
+ * (i.e. if it is >= than min and <= than max).
+ *
+ * @param section Init Config file section name
+ * @param fname Name of parameter
+ * @param value Value to check
+ * @return true if parameter value is valid.
+ *
+ * @note Result is not defined if section/name are wrong!
+ */
+ bool verify(const Properties* secti, const char* fname, Uint64 value) const;
+ static const char* nameToAlias(const char*);
+ static const char* getAlias(const char*);
+ bool isSection(const char*) const;
+
+ const char* getDescription(const Properties * sec, const char* fname) const;
+ Type getType(const Properties * section, const char* fname) const;
+ Status getStatus(const Properties* section, const char* fname) const;
+ Uint64 getMin(const Properties * section, const char* fname) const;
+ Uint64 getMax(const Properties * section, const char* fname) const;
+ Uint64 getDefault(const Properties * section, const char* fname) const;
+
+ const Properties * getInfo(const char * section) const;
+ const Properties * getDefaults(const char * section) const;
+
+ void print() const;
+ void print(const char* section) const;
+ void print(const Properties * section, const char* parameter) const;
+
+private:
+ Properties m_info;
+ Properties m_systemDefaults;
+
+ static const AliasPair m_sectionNameAliases[];
+ static const char* m_sectionNames[];
+ static const int m_noOfSectionNames;
+
+public:
+ static const ParamInfo m_ParamInfo[];
+ static const int m_NoOfParams;
+
+ static const SectionRule m_SectionRules[];
+ static const ConfigRule m_ConfigRules[];
+ static const int m_NoOfRules;
+};
+
+#endif // ConfigInfo_H
diff --git a/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp b/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp
new file mode 100644
index 00000000000..bf5cb9d726e
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/InitConfigFileParser.cpp
@@ -0,0 +1,970 @@
+/* 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 "InitConfigFileParser.hpp"
+#include "Config.hpp"
+#include "MgmtErrorReporter.hpp"
+#include <NdbOut.hpp>
+#include "ConfigInfo.hpp"
+#include <m_string.h>
+
+const int MAX_LINE_LENGTH = 1024; // Max length of line of text in config file
+static void trim(char *);
+
+static void require(bool v) { if(!v) abort();}
+
+//****************************************************************************
+// Ctor / Dtor
+//****************************************************************************
+InitConfigFileParser::InitConfigFileParser(FILE * out)
+{
+ m_info = new ConfigInfo();
+ m_errstream = out ? out : stdout;
+}
+
+InitConfigFileParser::~InitConfigFileParser() {
+ delete m_info;
+}
+
+//****************************************************************************
+// Read Config File
+//****************************************************************************
+InitConfigFileParser::Context::Context(const ConfigInfo * info, FILE * out)
+ : m_userProperties(true), m_configValues(1000, 20) {
+
+ m_config = new Properties(true);
+ m_defaults = new Properties(true);
+ m_errstream = out;
+}
+
+InitConfigFileParser::Context::~Context(){
+ if(m_config != 0)
+ delete m_config;
+
+ if(m_defaults != 0)
+ delete m_defaults;
+}
+
+Config *
+InitConfigFileParser::parseConfig(const char * filename) {
+ FILE * file = fopen(filename, "r");
+ if(file == 0){
+ fprintf(m_errstream, "Error opening file: %s\n", filename);
+ return 0;
+ }
+
+ Config * ret = parseConfig(file);
+ fclose(file);
+ return ret;
+}
+
+Config *
+InitConfigFileParser::parseConfig(FILE * file) {
+
+ char line[MAX_LINE_LENGTH];
+
+ Context ctx(m_info, m_errstream);
+ ctx.m_lineno = 0;
+ ctx.m_currentSection = 0;
+
+ /*************
+ * Open file *
+ *************/
+ if (file == NULL) {
+ return 0;
+ }
+
+ /***********************
+ * While lines to read *
+ ***********************/
+ while (fgets(line, MAX_LINE_LENGTH, file)) {
+ ctx.m_lineno++;
+
+ trim(line);
+
+ if (isEmptyLine(line)) // Skip if line is empty or comment
+ continue;
+
+ // End with NULL instead of newline
+ if (line[strlen(line)-1] == '\n')
+ line[strlen(line)-1] = '\0';
+
+ /********************************
+ * 1. Parse new default section *
+ ********************************/
+ if (char* section = parseDefaultSectionHeader(line)) {
+ if(!storeSection(ctx)){
+ free(section);
+ ctx.reportError("Could not store previous default section "
+ "of configuration file.");
+ return 0;
+ }
+ BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section); free(section);
+ ctx.type = InitConfigFileParser::DefaultSection;
+ ctx.m_sectionLineno = ctx.m_lineno;
+ ctx.m_currentSection = new Properties(true);
+ ctx.m_userDefaults = NULL;
+ require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
+ require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
+ continue;
+ }
+
+ /************************
+ * 2. Parse new section *
+ ************************/
+ if (char* section = parseSectionHeader(line)) {
+ if(!storeSection(ctx)){
+ free(section);
+ ctx.reportError("Could not store previous section "
+ "of configuration file.");
+ return 0;
+ }
+ BaseString::snprintf(ctx.fname, sizeof(ctx.fname), section);
+ free(section);
+ ctx.type = InitConfigFileParser::Section;
+ ctx.m_sectionLineno = ctx.m_lineno;
+ ctx.m_currentSection = new Properties(true);
+ ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults);
+ require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
+ require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
+ continue;
+ }
+
+ /****************************
+ * 3. Parse name-value pair *
+ ****************************/
+ if (!parseNameValuePair(ctx, line)) {
+ ctx.reportError("Could not parse name-value pair in config file.");
+ return 0;
+ }
+ }
+
+ if (ferror(file)){
+ ctx.reportError("Failure in reading");
+ return 0;
+ }
+
+ if(!storeSection(ctx)) {
+ ctx.reportError("Could not store section of configuration file.");
+ return 0;
+ }
+
+ return run_config_rules(ctx);
+}
+
+Config*
+InitConfigFileParser::run_config_rules(Context& ctx)
+{
+ for(size_t i = 0; ConfigInfo::m_ConfigRules[i].m_configRule != 0; i++){
+ ctx.type = InitConfigFileParser::Undefined;
+ ctx.m_currentSection = 0;
+ ctx.m_userDefaults = 0;
+ ctx.m_currentInfo = 0;
+ ctx.m_systemDefaults = 0;
+
+ Vector<ConfigInfo::ConfigRuleSection> tmp;
+ if(!(* ConfigInfo::m_ConfigRules[i].m_configRule)(tmp, ctx,
+ ConfigInfo::m_ConfigRules[i].m_ruleData))
+ return 0;
+
+ for(size_t j = 0; j<tmp.size(); j++){
+ BaseString::snprintf(ctx.fname, sizeof(ctx.fname), tmp[j].m_sectionType.c_str());
+ ctx.type = InitConfigFileParser::Section;
+ ctx.m_currentSection = tmp[j].m_sectionData;
+ ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults);
+ require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
+ require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
+ if(!storeSection(ctx))
+ return 0;
+ }
+ }
+
+ Uint32 nConnections = 0;
+ Uint32 nComputers = 0;
+ Uint32 nNodes = 0;
+ Uint32 nExtConnections = 0;
+ const char * system = "?";
+ ctx.m_userProperties.get("NoOfConnections", &nConnections);
+ ctx.m_userProperties.get("NoOfComputers", &nComputers);
+ ctx.m_userProperties.get("NoOfNodes", &nNodes);
+ ctx.m_userProperties.get("ExtNoOfConnections", &nExtConnections);
+ ctx.m_userProperties.get("ExtSystem", &system);
+ ctx.m_config->put("NoOfConnections", nConnections);
+ ctx.m_config->put("NoOfComputers", nComputers);
+ ctx.m_config->put("NoOfNodes", nNodes);
+
+ char tmpLine[MAX_LINE_LENGTH];
+ BaseString::snprintf(tmpLine, MAX_LINE_LENGTH, "EXTERNAL SYSTEM_");
+ strncat(tmpLine, system, MAX_LINE_LENGTH);
+ strncat(tmpLine, ":NoOfConnections", MAX_LINE_LENGTH);
+ ctx.m_config->put(tmpLine, nExtConnections);
+
+ Config * ret = new Config();
+ ret->m_configValues = (struct ndb_mgm_configuration*)ctx.m_configValues.getConfigValues();
+ ret->m_oldConfig = ctx.m_config; ctx.m_config = 0;
+ return ret;
+}
+
+//****************************************************************************
+// Parse Name-Value Pair
+//****************************************************************************
+
+bool InitConfigFileParser::parseNameValuePair(Context& ctx, const char* line)
+{
+ if (ctx.m_currentSection == NULL){
+ ctx.reportError("Value specified outside section");
+ return false;
+ }
+
+ // *************************************
+ // Split string at first occurrence of
+ // '=' or ':'
+ // *************************************
+
+ Vector<BaseString> tmp_string_split;
+ if (BaseString(line).split(tmp_string_split,
+ "=:", 2) != 2)
+ {
+ ctx.reportError("Parse error");
+ return false;
+ }
+
+ // *************************************
+ // Remove all after #
+ // *************************************
+
+ Vector<BaseString> tmp_string_split2;
+ tmp_string_split[1].split(tmp_string_split2,
+ "#", 2);
+ tmp_string_split[1]=tmp_string_split2[0];
+
+ // *************************************
+ // Remove leading and trailing chars
+ // *************************************
+ {
+ for (int i = 0; i < 2; i++)
+ tmp_string_split[i].trim("\r\n \t");
+ }
+
+ // *************************************
+ // First in split is fname
+ // *************************************
+
+ const char *fname= tmp_string_split[0].c_str();
+
+ if (!ctx.m_currentInfo->contains(fname)) {
+ ctx.reportError("[%s] Unknown parameter: %s", ctx.fname, fname);
+ return false;
+ }
+ ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
+ if (status == ConfigInfo::CI_NOTIMPLEMENTED) {
+ ctx.reportWarning("[%s] %s not yet implemented", ctx.fname, fname);
+ }
+ if (status == ConfigInfo::CI_DEPRICATED) {
+ const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
+ if(desc && desc[0]){
+ ctx.reportWarning("[%s] %s is depricated, use %s instead",
+ ctx.fname, fname, desc);
+ } else if (desc == 0){
+ ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname);
+ }
+ }
+
+ // ***********************
+ // Store name-value pair
+ // ***********************
+
+ return storeNameValuePair(ctx, fname, tmp_string_split[1].c_str());
+}
+
+
+//****************************************************************************
+// STORE NAME-VALUE pair in properties section
+//****************************************************************************
+
+bool
+InitConfigFileParser::storeNameValuePair(Context& ctx,
+ const char* fname,
+ const char* value) {
+
+ const char * pname = fname;
+
+ if (ctx.m_currentSection->contains(pname)) {
+ ctx.reportError("[%s] Parameter %s specified twice", ctx.fname, fname);
+ return false;
+ }
+
+ // ***********************
+ // Store name-value pair
+ // ***********************
+
+ const ConfigInfo::Type type = m_info->getType(ctx.m_currentInfo, fname);
+ switch(type){
+ case ConfigInfo::CI_BOOL: {
+ bool value_bool;
+ if (!convertStringToBool(value, value_bool)) {
+ ctx.reportError("Illegal boolean value for parameter %s", fname);
+ return false;
+ }
+ MGM_REQUIRE(ctx.m_currentSection->put(pname, value_bool));
+ break;
+ }
+ case ConfigInfo::CI_INT:
+ case ConfigInfo::CI_INT64:{
+ Uint64 value_int;
+ if (!convertStringToUint64(value, value_int)) {
+ ctx.reportError("Illegal integer value for parameter %s", fname);
+ return false;
+ }
+ if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) {
+ ctx.reportError("Illegal value %s for parameter %s.\n"
+ "Legal values are between %Lu and %Lu", value, fname,
+ m_info->getMin(ctx.m_currentInfo, fname),
+ m_info->getMax(ctx.m_currentInfo, fname));
+ return false;
+ }
+ if(type == ConfigInfo::CI_INT){
+ MGM_REQUIRE(ctx.m_currentSection->put(pname, (Uint32)value_int));
+ } else {
+ MGM_REQUIRE(ctx.m_currentSection->put64(pname, value_int));
+ }
+ break;
+ }
+ case ConfigInfo::CI_STRING:
+ MGM_REQUIRE(ctx.m_currentSection->put(pname, value));
+ break;
+ case ConfigInfo::CI_SECTION:
+ abort();
+ }
+ return true;
+}
+
+//****************************************************************************
+// Is Empty Line
+//****************************************************************************
+
+bool InitConfigFileParser::isEmptyLine(const char* line) const {
+ int i;
+
+ // Check if it is a comment line
+ if (line[0] == '#') return true;
+
+ // Check if it is a line with only spaces
+ for (i = 0; i < MAX_LINE_LENGTH && line[i] != '\n' && line[i] != '\0'; i++) {
+ if (line[i] != ' ' && line[i] != '\t') return false;
+ }
+ return true;
+}
+
+//****************************************************************************
+// Convert String to Int
+//****************************************************************************
+bool InitConfigFileParser::convertStringToUint64(const char* s,
+ Uint64& val,
+ Uint32 log10base) {
+ if (s == NULL)
+ return false;
+ if (strlen(s) == 0)
+ return false;
+
+ errno = 0;
+ char* p;
+ Int64 v = strtoll(s, &p, log10base);
+ if (errno != 0)
+ return false;
+
+ long mul = 0;
+ if (p != &s[strlen(s)]){
+ char * tmp = strdup(p);
+ trim(tmp);
+ switch(tmp[0]){
+ case 'k':
+ case 'K':
+ mul = 10;
+ break;
+ case 'M':
+ mul = 20;
+ break;
+ case 'G':
+ mul = 30;
+ break;
+ default:
+ free(tmp);
+ return false;
+ }
+ free(tmp);
+ }
+
+ val = (v << mul);
+ return true;
+}
+
+bool InitConfigFileParser::convertStringToBool(const char* s, bool& val) {
+ if (s == NULL) return false;
+ if (strlen(s) == 0) return false;
+
+ if (!strcmp(s, "Y") || !strcmp(s, "y") ||
+ !strcmp(s, "Yes") || !strcmp(s, "YES") || !strcmp(s, "yes") ||
+ !strcmp(s, "True") || !strcmp(s, "TRUE") || !strcmp(s, "true") ||
+ !strcmp(s, "1")) {
+ val = true;
+ return true;
+ }
+
+ if (!strcmp(s, "N") || !strcmp(s, "n") ||
+ !strcmp(s, "No") || !strcmp(s, "NO") || !strcmp(s, "no") ||
+ !strcmp(s, "False") || !strcmp(s, "FALSE") || !strcmp(s, "false") ||
+ !strcmp(s, "0")) {
+ val = false;
+ return true;
+ }
+
+ return false; // Failure to convert
+}
+
+//****************************************************************************
+// Parse Section Header
+//****************************************************************************
+static void
+trim(char * str){
+ int len = strlen(str);
+ for(len--;
+ (str[len] == '\r' || str[len] == '\n' ||
+ str[len] == ' ' || str[len] == '\t') &&
+ len > 0;
+ len--)
+ str[len] = 0;
+
+ int pos = 0;
+ while(str[pos] == ' ' || str[pos] == '\t')
+ pos++;
+
+ if(str[pos] == '\"' && str[len] == '\"') {
+ pos++;
+ str[len] = 0;
+ len--;
+ }
+
+ memmove(str, &str[pos], len - pos + 2);
+}
+
+char*
+InitConfigFileParser::parseSectionHeader(const char* line) const {
+ char * tmp = strdup(line);
+
+ if(tmp[0] != '['){
+ free(tmp);
+ return NULL;
+ }
+
+ if(tmp[strlen(tmp)-1] != ']'){
+ free(tmp);
+ return NULL;
+ }
+ tmp[strlen(tmp)-1] = 0;
+
+ tmp[0] = ' ';
+ trim(tmp);
+
+ // Get the correct header name if an alias
+ {
+ const char *tmp_alias= m_info->getAlias(tmp);
+ if (tmp_alias) {
+ free(tmp);
+ tmp= strdup(tmp_alias);
+ }
+ }
+
+ // Lookup token among sections
+ if(!m_info->isSection(tmp)) {
+ free(tmp);
+ return NULL;
+ }
+ if(m_info->getInfo(tmp)) return tmp;
+
+ free(tmp);
+ return NULL;
+}
+
+//****************************************************************************
+// Parse Default Section Header
+//****************************************************************************
+
+char*
+InitConfigFileParser::parseDefaultSectionHeader(const char* line) const {
+ static char token1[MAX_LINE_LENGTH], token2[MAX_LINE_LENGTH];
+
+ int no = sscanf(line, "[%120[A-Z_a-z] %120[A-Z_a-z]]", token1, token2);
+
+ // Not correct no of tokens
+ if (no != 2) return NULL;
+
+ // Not correct keyword at end
+ if (!strcasecmp(token2, "DEFAULT") == 0) return NULL;
+
+ const char *token1_alias= m_info->getAlias(token1);
+ if (token1_alias == 0)
+ token1_alias= token1;
+
+ if(m_info->getInfo(token1_alias)){
+ return strdup(token1_alias);
+ }
+
+ // Did not find section
+ return NULL;
+}
+
+const Properties *
+InitConfigFileParser::getSection(const char * name, const Properties * src){
+ const Properties * p;
+ if(src && src->get(name, &p))
+ return p;
+
+ return 0;
+}
+
+//****************************************************************************
+// STORE section
+//****************************************************************************
+bool
+InitConfigFileParser::storeSection(Context& ctx){
+ if(ctx.m_currentSection == NULL)
+ return true;
+ for(int i = strlen(ctx.fname) - 1; i>=0; i--){
+ ctx.fname[i] = toupper(ctx.fname[i]);
+ }
+ BaseString::snprintf(ctx.pname, sizeof(ctx.pname), ctx.fname);
+ char buf[255];
+ if(ctx.type == InitConfigFileParser::Section)
+ BaseString::snprintf(buf, sizeof(buf), "%s", ctx.fname);
+ if(ctx.type == InitConfigFileParser::DefaultSection)
+ BaseString::snprintf(buf, sizeof(buf), "%s DEFAULT", ctx.fname);
+ BaseString::snprintf(ctx.fname, sizeof(ctx.fname), buf);
+ if(ctx.type == InitConfigFileParser::Section){
+ for(int i = 0; i<m_info->m_NoOfRules; i++){
+ const ConfigInfo::SectionRule & rule = m_info->m_SectionRules[i];
+ if(!strcmp(rule.m_section, "*") || !strcmp(rule.m_section, ctx.fname)){
+ if(!(* rule.m_sectionRule)(ctx, rule.m_ruleData)){
+ return false;
+ }
+ }
+ }
+ }
+ if(ctx.type == InitConfigFileParser::DefaultSection &&
+ !ctx.m_defaults->put(ctx.pname, ctx.m_currentSection))
+ {
+ ctx.reportError("Duplicate default section not allowed");
+ return false;
+ }
+ if(ctx.type == InitConfigFileParser::Section)
+ require(ctx.m_config->put(ctx.pname, ctx.m_currentSection));
+ delete ctx.m_currentSection; ctx.m_currentSection = NULL;
+ return true;
+}
+
+void
+InitConfigFileParser::Context::reportError(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ va_end(ap);
+ fprintf(m_errstream, "Error line %d: %s\n",
+ m_lineno, buf);
+
+ //m_currentSection->print();
+}
+
+void
+InitConfigFileParser::Context::reportWarning(const char * fmt, ...){
+ va_list ap;
+ char buf[1000];
+
+ va_start(ap, fmt);
+ if (fmt != 0)
+ BaseString::vsnprintf(buf, sizeof(buf)-1, fmt, ap);
+ va_end(ap);
+ fprintf(m_errstream, "Warning line %d: %s\n",
+ m_lineno, buf);
+}
+
+#include <my_sys.h>
+#include <my_getopt.h>
+
+static int order = 1;
+static
+my_bool
+parse_mycnf_opt(int, const struct my_option * opt, char * value)
+{
+ if(opt->comment)
+ ((struct my_option *)opt)->app_type++;
+ else
+ ((struct my_option *)opt)->app_type = order++;
+ return 0;
+}
+
+bool
+InitConfigFileParser::store_in_properties(Vector<struct my_option>& options,
+ InitConfigFileParser::Context& ctx,
+ const char * name)
+{
+ for(unsigned i = 0; i<options.size(); i++)
+ {
+ if(options[i].comment &&
+ options[i].app_type &&
+ strcmp(options[i].comment, name) == 0)
+ {
+ Uint64 value_int;
+ switch(options[i].var_type){
+ case GET_INT:
+ value_int = *(Uint32*)options[i].value;
+ break;
+ case GET_LL:
+ value_int = *(Uint64*)options[i].value;
+ break;
+ case GET_STR:
+ ctx.m_currentSection->put(options[i].name, *(char**)options[i].value);
+ continue;
+ default:
+ abort();
+ }
+
+ const char * fname = options[i].name;
+ if (!m_info->verify(ctx.m_currentInfo, fname, value_int)) {
+ ctx.reportError("Illegal value %lld for parameter %s.\n"
+ "Legal values are between %Lu and %Lu",
+ value_int, fname,
+ m_info->getMin(ctx.m_currentInfo, fname),
+ m_info->getMax(ctx.m_currentInfo, fname));
+ return false;
+ }
+
+ ConfigInfo::Status status = m_info->getStatus(ctx.m_currentInfo, fname);
+ if (status == ConfigInfo::CI_DEPRICATED) {
+ const char * desc = m_info->getDescription(ctx.m_currentInfo, fname);
+ if(desc && desc[0]){
+ ctx.reportWarning("[%s] %s is depricated, use %s instead",
+ ctx.fname, fname, desc);
+ } else if (desc == 0){
+ ctx.reportWarning("[%s] %s is depricated", ctx.fname, fname);
+ }
+ }
+
+ if (options[i].var_type == GET_INT)
+ ctx.m_currentSection->put(options[i].name, (Uint32)value_int);
+ else
+ ctx.m_currentSection->put(options[i].name, value_int);
+ }
+ }
+ return true;
+}
+
+bool
+InitConfigFileParser::handle_mycnf_defaults(Vector<struct my_option>& options,
+ InitConfigFileParser::Context& ctx,
+ const char * name)
+{
+ strcpy(ctx.fname, name);
+ ctx.type = InitConfigFileParser::DefaultSection;
+ ctx.m_currentSection = new Properties(true);
+ ctx.m_userDefaults = NULL;
+ require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
+ require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname)) != 0);
+ if(store_in_properties(options, ctx, name))
+ return storeSection(ctx);
+ return false;
+}
+
+static
+int
+load_defaults(Vector<struct my_option>& options, const char* groups[])
+{
+ int argc = 1;
+ const char * argv[] = { "ndb_mgmd", 0, 0, 0, 0 };
+ BaseString file;
+ BaseString extra_file;
+ BaseString group_suffix;
+
+ const char *save_file = defaults_file;
+ char *save_extra_file = defaults_extra_file;
+ const char *save_group_suffix = defaults_group_suffix;
+
+ if (defaults_file)
+ {
+ file.assfmt("--defaults-file=%s", defaults_file);
+ argv[argc++] = file.c_str();
+ }
+
+ if (defaults_extra_file)
+ {
+ extra_file.assfmt("--defaults-extra-file=%s", defaults_extra_file);
+ argv[argc++] = extra_file.c_str();
+ }
+
+ if (defaults_group_suffix)
+ {
+ group_suffix.assfmt("--defaults-group-suffix=%s", defaults_group_suffix);
+ argv[argc++] = group_suffix.c_str();
+ }
+
+ char ** tmp = (char**)argv;
+ int ret = load_defaults("my", groups, &argc, &tmp);
+
+ defaults_file = save_file;
+ defaults_extra_file = save_extra_file;
+ defaults_group_suffix = save_group_suffix;
+
+ if (ret == 0)
+ {
+ return handle_options(&argc, &tmp, options.getBase(), parse_mycnf_opt);
+ }
+
+ return ret;
+}
+
+bool
+InitConfigFileParser::load_mycnf_groups(Vector<struct my_option> & options,
+ InitConfigFileParser::Context& ctx,
+ const char * name,
+ const char *groups[])
+{
+ unsigned i;
+ Vector<struct my_option> copy;
+ for(i = 0; i<options.size(); i++)
+ {
+ if(options[i].comment && strcmp(options[i].comment, name) == 0)
+ {
+ options[i].app_type = 0;
+ copy.push_back(options[i]);
+ }
+ }
+
+ struct my_option end;
+ bzero(&end, sizeof(end));
+ copy.push_back(end);
+
+ if (load_defaults(copy, groups))
+ return false;
+
+ return store_in_properties(copy, ctx, name);
+}
+
+Config *
+InitConfigFileParser::parse_mycnf()
+{
+ int i;
+ Config * res = 0;
+ Vector<struct my_option> options;
+ for(i = 0; i<ConfigInfo::m_NoOfParams; i++)
+ {
+ {
+ struct my_option opt;
+ bzero(&opt, sizeof(opt));
+ const ConfigInfo::ParamInfo& param = ConfigInfo::m_ParamInfo[i];
+ switch(param._type){
+ case ConfigInfo::CI_BOOL:
+ opt.value = (gptr*)malloc(sizeof(int));
+ opt.var_type = GET_INT;
+ break;
+ case ConfigInfo::CI_INT:
+ opt.value = (gptr*)malloc(sizeof(int));
+ opt.var_type = GET_INT;
+ break;
+ case ConfigInfo::CI_INT64:
+ opt.value = (gptr*)malloc(sizeof(Int64));
+ opt.var_type = GET_LL;
+ break;
+ case ConfigInfo::CI_STRING:
+ opt.value = (gptr*)malloc(sizeof(char *));
+ opt.var_type = GET_STR;
+ break;
+ default:
+ continue;
+ }
+ opt.name = param._fname;
+ opt.id = 256;
+ opt.app_type = 0;
+ opt.arg_type = REQUIRED_ARG;
+ opt.comment = param._section;
+ options.push_back(opt);
+ }
+ }
+
+ struct my_option *ndbd, *ndb_mgmd, *mysqld, *api;
+
+ /**
+ * Add ndbd, ndb_mgmd, api/mysqld
+ */
+ Uint32 idx = options.size();
+ {
+ struct my_option opt;
+ bzero(&opt, sizeof(opt));
+ opt.name = "ndbd";
+ opt.id = 256;
+ opt.value = (gptr*)malloc(sizeof(char*));
+ opt.var_type = GET_STR;
+ opt.arg_type = REQUIRED_ARG;
+ options.push_back(opt);
+
+ opt.name = "ndb_mgmd";
+ opt.id = 256;
+ opt.value = (gptr*)malloc(sizeof(char*));
+ opt.var_type = GET_STR;
+ opt.arg_type = REQUIRED_ARG;
+ options.push_back(opt);
+
+ opt.name = "mysqld";
+ opt.id = 256;
+ opt.value = (gptr*)malloc(sizeof(char*));
+ opt.var_type = GET_STR;
+ opt.arg_type = REQUIRED_ARG;
+ options.push_back(opt);
+
+ opt.name = "api";
+ opt.id = 256;
+ opt.value = (gptr*)malloc(sizeof(char*));
+ opt.var_type = GET_STR;
+ opt.arg_type = REQUIRED_ARG;
+ options.push_back(opt);
+
+ bzero(&opt, sizeof(opt));
+ options.push_back(opt);
+
+ ndbd = &options[idx];
+ ndb_mgmd = &options[idx+1];
+ mysqld = &options[idx+2];
+ api = &options[idx+3];
+ }
+
+
+ Context ctx(m_info, m_errstream);
+ const char *groups[]= { "cluster_config", 0 };
+ if (load_defaults(options, groups))
+ goto end;
+
+ ctx.m_lineno = 0;
+ if(!handle_mycnf_defaults(options, ctx, "DB"))
+ goto end;
+ if(!handle_mycnf_defaults(options, ctx, "API"))
+ goto end;
+ if(!handle_mycnf_defaults(options, ctx, "MGM"))
+ goto end;
+ if(!handle_mycnf_defaults(options, ctx, "TCP"))
+ goto end;
+ if(!handle_mycnf_defaults(options, ctx, "SHM"))
+ goto end;
+ if(!handle_mycnf_defaults(options, ctx, "SCI"))
+ goto end;
+
+ {
+ struct sect { struct my_option* src; const char * name; } sections[] =
+ {
+ { ndb_mgmd, "MGM" }
+ ,{ ndbd, "DB" }
+ ,{ mysqld, "API" }
+ ,{ api, "API" }
+ ,{ 0, 0 }, { 0, 0 }
+ };
+
+ for(i = 0; sections[i].src; i++)
+ {
+ for(int j = i + 1; sections[j].src; j++)
+ {
+ if (sections[j].src->app_type < sections[i].src->app_type)
+ {
+ sect swap = sections[i];
+ sections[i] = sections[j];
+ sections[j] = swap;
+ }
+ }
+ }
+
+ ctx.type = InitConfigFileParser::Section;
+ ctx.m_sectionLineno = ctx.m_lineno;
+ for(i = 0; sections[i].src; i++)
+ {
+ if (sections[i].src->app_type)
+ {
+ strcpy(ctx.fname, sections[i].name);
+ BaseString str(*(char**)sections[i].src->value);
+ Vector<BaseString> list;
+ str.split(list, ",");
+
+ const char * defaults_groups[] = { 0, 0, 0 };
+ for(unsigned j = 0; j<list.size(); j++)
+ {
+ BaseString group_idx;
+ BaseString group_host;
+ group_idx.assfmt("%s.%s.%d", groups[0],
+ sections[i].src->name, j + 1);
+ group_host.assfmt("%s.%s.%s", groups[0],
+ sections[i].src->name, list[j].c_str());
+ defaults_groups[0] = group_idx.c_str();
+ if(list[j].length())
+ defaults_groups[1] = group_host.c_str();
+ else
+ defaults_groups[1] = 0;
+
+ ctx.m_currentSection = new Properties(true);
+ ctx.m_userDefaults = getSection(ctx.fname, ctx.m_defaults);
+ require((ctx.m_currentInfo = m_info->getInfo(ctx.fname)) != 0);
+ require((ctx.m_systemDefaults = m_info->getDefaults(ctx.fname))!= 0);
+ ctx.m_currentSection->put("HostName", list[j].c_str());
+ if(!load_mycnf_groups(options, ctx, sections[i].name,
+ defaults_groups))
+ goto end;
+
+ if(!storeSection(ctx))
+ goto end;
+ }
+ }
+ }
+ }
+
+ res = run_config_rules(ctx);
+
+end:
+ for(i = 0; options[i].name; i++)
+ free(options[i].value);
+
+ return res;
+}
+
+template class Vector<struct my_option>;
+
+#if 0
+struct my_option
+{
+ const char *name; /* Name of the option */
+ int id; /* unique id or short option */
+ const char *comment; /* option comment, for autom. --help */
+ gptr *value; /* The variable value */
+ gptr *u_max_value; /* The user def. max variable value */
+ const char **str_values; /* Pointer to possible values */
+ ulong var_type;
+ enum get_opt_arg_type arg_type;
+ longlong def_value; /* Default value */
+ longlong min_value; /* Min allowed value */
+ longlong max_value; /* Max allowed value */
+ longlong sub_size; /* Subtract this from given value */
+ long block_size; /* Value should be a mult. of this */
+ int app_type; /* To be used by an application */
+};
+#endif
diff --git a/storage/ndb/src/mgmsrv/InitConfigFileParser.hpp b/storage/ndb/src/mgmsrv/InitConfigFileParser.hpp
new file mode 100644
index 00000000000..616fd5a62fb
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/InitConfigFileParser.hpp
@@ -0,0 +1,145 @@
+/* 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 */
+
+#ifndef InitConfigFileParser_H
+#define InitConfigFileParser_H
+
+#include <ndb_global.h>
+
+#include <Properties.hpp>
+#include <ConfigValues.hpp>
+
+class Config;
+class ConfigInfo;
+
+/**
+ * @class InitConfigFileParser
+ * @brief Reads initial config file and returns Config object
+ *
+ * This class contains one public method InitConfigFileParser::parseConfig,
+ * which reads an initial configuration file and returns a Config
+ * object if the config file has correct syntax and semantic.
+ */
+class InitConfigFileParser {
+ FILE * m_errstream;
+public:
+ /**
+ * Constructor
+ */
+ InitConfigFileParser(FILE * errstream = stdout);
+ ~InitConfigFileParser();
+
+ /**
+ * Reads the initial configuration file, checks syntax and semantic
+ * and stores internally the values of all parameters.
+ *
+ * @returns Config or NULL on failure
+ * @note must be freed by caller
+ */
+ Config * parseConfig(FILE * file);
+ Config * parseConfig(const char * filename);
+ Config * parse_mycnf();
+
+ /**
+ * Parser context struct
+ */
+ enum ContextSectionType { Undefined, Section, DefaultSection };
+
+ /**
+ * Context = Which section in init config file we are currently parsing
+ */
+ struct Context {
+ Context(const ConfigInfo *, FILE * out);
+ ~Context();
+
+ ContextSectionType type; ///< Section type (e.g. default section,section)
+ char fname[256]; ///< Section name occuring in init config file
+ char pname[256]; ///< Section name stored in properties object
+ Uint32 m_lineno; ///< Current line no in config file
+ Uint32 m_sectionLineno; ///< Where did current section start
+
+ const ConfigInfo * m_info; // The config info
+ Properties * m_config; // The config object
+ Properties * m_defaults; // The user defaults
+
+ Properties * m_currentSection; // The current section I'm in
+ const Properties * m_userDefaults; // The defaults of this section
+ const Properties * m_systemDefaults; // The syst. defaults for this section
+ const Properties * m_currentInfo; // The "info" for this section
+
+ Properties m_userProperties; // User properties (temporary values)
+ ConfigValuesFactory m_configValues; //
+
+ public:
+ FILE * m_errstream;
+ void reportError(const char * msg, ...);
+ void reportWarning(const char * msg, ...);
+ };
+
+ static bool convertStringToUint64(const char* s, Uint64& val, Uint32 log10base = 0);
+ static bool convertStringToBool(const char* s, bool& val);
+
+private:
+ /**
+ * Check if line only contains space/comments
+ * @param line: The line to check
+ * @return true if spaces/comments only, false otherwise
+ */
+ bool isEmptyLine(const char* line) const;
+
+ /**
+ * Checks if line contains a section header
+ * @param line: String to search
+ * @return section header if matching some section header, NULL otherwise
+ */
+ char* parseSectionHeader(const char* line) const;
+
+ /**
+ * Checks if line contains a default header
+ * @param line: String to search
+ * @return section header if matching some section header, NULL otherwise
+ */
+ char* parseDefaultSectionHeader(const char* line) const;
+
+ bool parseNameValuePair(Context&, const char* line);
+ bool storeNameValuePair(Context&, const char* fname, const char* value);
+
+ bool storeSection(Context&);
+
+ const Properties* getSection(const char * name, const Properties* src);
+
+ /**
+ * Information about parameters (min, max values etc)
+ */
+ ConfigInfo* m_info;
+
+ bool handle_mycnf_defaults(Vector<struct my_option>& options,
+ InitConfigFileParser::Context& ctx,
+ const char * name);
+
+ bool load_mycnf_groups(Vector<struct my_option> & options,
+ InitConfigFileParser::Context& ctx,
+ const char * name,
+ const char *groups[]);
+
+ bool store_in_properties(Vector<struct my_option>& options,
+ InitConfigFileParser::Context& ctx,
+ const char * name);
+
+ Config* run_config_rules(Context& ctx);
+};
+
+#endif // InitConfigFileParser_H
diff --git a/storage/ndb/src/mgmsrv/Makefile.am b/storage/ndb/src/mgmsrv/Makefile.am
new file mode 100644
index 00000000000..d0c1b1219a4
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Makefile.am
@@ -0,0 +1,60 @@
+MYSQLDATAdir = $(localstatedir)
+MYSQLSHAREdir = $(pkgdatadir)
+MYSQLBASEdir= $(prefix)
+#MYSQLCLUSTERdir= $(prefix)/mysql-cluster
+MYSQLCLUSTERdir= .
+
+ndbbin_PROGRAMS = ndb_mgmd
+
+ndb_mgmd_SOURCES = \
+ MgmtSrvr.cpp \
+ MgmtSrvrGeneralSignalHandling.cpp \
+ main.cpp \
+ Services.cpp \
+ convertStrToInt.cpp \
+ SignalQueue.cpp \
+ MgmtSrvrConfig.cpp \
+ ConfigInfo.cpp \
+ InitConfigFileParser.cpp \
+ Config.cpp
+
+INCLUDES_LOC = -I$(top_srcdir)/storage/ndb/src/ndbapi \
+ -I$(top_srcdir)/storage/ndb/src/mgmapi \
+ -I$(top_srcdir)/storage/ndb/src/common/mgmcommon \
+ -I$(top_srcdir)/storage/ndb/src/mgmclient
+
+LDADD_LOC = $(top_builddir)/storage/ndb/src/mgmclient/CommandInterpreter.o \
+ $(top_builddir)/storage/ndb/src/libndbclient.la \
+ $(top_builddir)/dbug/libdbug.a \
+ $(top_builddir)/mysys/libmysys.a \
+ $(top_builddir)/strings/libmystrings.a \
+ @readline_link@ \
+ @NDB_SCI_LIBS@ \
+ @TERMCAP_LIB@
+
+DEFS_LOC = -DDEFAULT_MYSQL_HOME="\"$(MYSQLBASEdir)\"" \
+ -DDATADIR="\"$(MYSQLDATAdir)\"" \
+ -DSHAREDIR="\"$(MYSQLSHAREdir)\"" \
+ -DMYSQLCLUSTERDIR="\"$(MYSQLCLUSTERdir)\""
+
+include $(top_srcdir)/storage/ndb/config/common.mk.am
+include $(top_srcdir)/storage/ndb/config/type_ndbapi.mk.am
+
+ndb_mgmd_LDFLAGS = @ndb_bin_am_ldflags@
+
+# Don't update the files from bitkeeper
+%::SCCS/s.%
+
+windoze-dsp: ndb_mgmd.dsp
+
+ndb_mgmd.dsp: Makefile \
+ $(top_srcdir)/storage/ndb/config/win-prg.am \
+ $(top_srcdir)/storage/ndb/config/win-name \
+ $(top_srcdir)/storage/ndb/config/win-includes \
+ $(top_srcdir)/storage/ndb/config/win-sources \
+ $(top_srcdir)/storage/ndb/config/win-libraries
+ cat $(top_srcdir)/storage/ndb/config/win-prg.am > $@
+ @$(top_srcdir)/storage/ndb/config/win-name $@ $(ndbbin_PROGRAMS)
+ @$(top_srcdir)/storage/ndb/config/win-includes $@ $(INCLUDES)
+ @$(top_srcdir)/storage/ndb/config/win-sources $@ $(ndb_mgmd_SOURCES)
+ @$(top_srcdir)/storage/ndb/config/win-libraries $@ LINK $(LDADD)
diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp
new file mode 100644
index 00000000000..29b1daf2e2a
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp
@@ -0,0 +1,2941 @@
+/* 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 <my_pthread.h>
+
+#include "MgmtSrvr.hpp"
+#include "MgmtErrorReporter.hpp"
+#include <ConfigRetriever.hpp>
+
+#include <NdbOut.hpp>
+#include <NdbApiSignal.hpp>
+#include <kernel_types.h>
+#include <RefConvert.hpp>
+#include <BlockNumbers.h>
+#include <GlobalSignalNumbers.h>
+#include <signaldata/TestOrd.hpp>
+#include <signaldata/TamperOrd.hpp>
+#include <signaldata/StartOrd.hpp>
+#include <signaldata/ApiVersion.hpp>
+#include <signaldata/ResumeReq.hpp>
+#include <signaldata/SetLogLevelOrd.hpp>
+#include <signaldata/EventSubscribeReq.hpp>
+#include <signaldata/EventReport.hpp>
+#include <signaldata/DumpStateOrd.hpp>
+#include <signaldata/BackupSignalData.hpp>
+#include <signaldata/ManagementServer.hpp>
+#include <signaldata/NFCompleteRep.hpp>
+#include <signaldata/NodeFailRep.hpp>
+#include <signaldata/AllocNodeId.hpp>
+#include <NdbSleep.h>
+#include <EventLogger.hpp>
+#include <DebuggerNames.hpp>
+#include <ndb_version.h>
+
+#include <SocketServer.hpp>
+#include <NdbConfig.h>
+
+#include <NdbAutoPtr.hpp>
+
+#include <ndberror.h>
+
+#include <mgmapi.h>
+#include <mgmapi_configuration.hpp>
+#include <mgmapi_config_parameters.h>
+#include <m_string.h>
+
+#include <SignalSender.hpp>
+
+//#define MGM_SRV_DEBUG
+#ifdef MGM_SRV_DEBUG
+#define DEBUG(x) do ndbout << x << endl; while(0)
+#else
+#define DEBUG(x)
+#endif
+
+#define INIT_SIGNAL_SENDER(ss,nodeId) \
+ SignalSender ss(theFacade); \
+ ss.lock(); /* lock will be released on exit */ \
+ {\
+ int result = okToSendTo(nodeId, true);\
+ if (result != 0) {\
+ return result;\
+ }\
+ }
+
+extern int g_no_nodeid_checks;
+extern my_bool opt_core;
+
+static void require(bool v)
+{
+ if(!v)
+ {
+ if (opt_core)
+ abort();
+ else
+ exit(-1);
+ }
+}
+
+void *
+MgmtSrvr::logLevelThread_C(void* m)
+{
+ MgmtSrvr *mgm = (MgmtSrvr*)m;
+ mgm->logLevelThreadRun();
+ return 0;
+}
+
+extern EventLogger g_eventLogger;
+
+static NdbOut&
+operator<<(NdbOut& out, const LogLevel & ll)
+{
+ out << "[LogLevel: ";
+ for(size_t i = 0; i<LogLevel::LOGLEVEL_CATEGORIES; i++)
+ out << ll.getLogLevel((LogLevel::EventCategory)i) << " ";
+ out << "]";
+ return out;
+}
+
+void
+MgmtSrvr::logLevelThreadRun()
+{
+ while (!_isStopThread) {
+ /**
+ * Handle started nodes
+ */
+ m_started_nodes.lock();
+ if (m_started_nodes.size() > 0)
+ {
+ // calculate max log level
+ EventSubscribeReq req;
+ {
+ LogLevel tmp;
+ m_event_listner.lock();
+ for(int i = m_event_listner.m_clients.size() - 1; i >= 0; i--)
+ tmp.set_max(m_event_listner[i].m_logLevel);
+ m_event_listner.unlock();
+ req = tmp;
+ }
+ req.blockRef = _ownReference;
+ while (m_started_nodes.size() > 0)
+ {
+ Uint32 node = m_started_nodes[0];
+ m_started_nodes.erase(0, false);
+ m_started_nodes.unlock();
+
+ setEventReportingLevelImpl(node, req);
+
+ SetLogLevelOrd ord;
+ ord = m_nodeLogLevel[node];
+ setNodeLogLevelImpl(node, ord);
+
+ m_started_nodes.lock();
+ }
+ }
+ m_started_nodes.unlock();
+
+ m_log_level_requests.lock();
+ while (m_log_level_requests.size() > 0)
+ {
+ EventSubscribeReq req = m_log_level_requests[0];
+ m_log_level_requests.erase(0, false);
+ m_log_level_requests.unlock();
+
+ if(req.blockRef == 0){
+ req.blockRef = _ownReference;
+ setEventReportingLevelImpl(0, req);
+ } else {
+ SetLogLevelOrd ord;
+ ord = req;
+ setNodeLogLevelImpl(req.blockRef, ord);
+ }
+ m_log_level_requests.lock();
+ }
+ m_log_level_requests.unlock();
+ NdbSleep_MilliSleep(_logLevelThreadSleep);
+ }
+}
+
+void
+MgmtSrvr::startEventLog()
+{
+ NdbMutex_Lock(m_configMutex);
+
+ g_eventLogger.setCategory("MgmSrvr");
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.find(CFG_NODE_ID, _ownNodeId) != 0){
+ NdbMutex_Unlock(m_configMutex);
+ return;
+ }
+
+ const char * tmp;
+ char errStr[100];
+ int err= 0;
+ BaseString logdest;
+ char *clusterLog= NdbConfig_ClusterLogFileName(_ownNodeId);
+ NdbAutoPtr<char> tmp_aptr(clusterLog);
+
+ if(iter.get(CFG_LOG_DESTINATION, &tmp) == 0){
+ logdest.assign(tmp);
+ }
+ NdbMutex_Unlock(m_configMutex);
+
+ if(logdest.length() == 0 || logdest == "") {
+ logdest.assfmt("FILE:filename=%s,maxsize=1000000,maxfiles=6",
+ clusterLog);
+ }
+ errStr[0]='\0';
+ if(!g_eventLogger.addHandler(logdest, &err, sizeof(errStr), errStr)) {
+ ndbout << "Warning: could not add log destination \""
+ << logdest.c_str() << "\". Reason: ";
+ if(err)
+ ndbout << strerror(err);
+ if(err && errStr[0]!='\0')
+ ndbout << ", ";
+ if(errStr[0]!='\0')
+ ndbout << errStr;
+ ndbout << endl;
+ }
+}
+
+void
+MgmtSrvr::stopEventLog()
+{
+ // Nothing yet
+}
+
+class ErrorItem
+{
+public:
+ int _errorCode;
+ const char * _errorText;
+};
+
+bool
+MgmtSrvr::setEventLogFilter(int severity, int enable)
+{
+ Logger::LoggerLevel level = (Logger::LoggerLevel)severity;
+ if (enable > 0) {
+ g_eventLogger.enable(level);
+ } else if (enable == 0) {
+ g_eventLogger.disable(level);
+ } else if (g_eventLogger.isEnable(level)) {
+ g_eventLogger.disable(level);
+ } else {
+ g_eventLogger.enable(level);
+ }
+ return g_eventLogger.isEnable(level);
+}
+
+bool
+MgmtSrvr::isEventLogFilterEnabled(int severity)
+{
+ return g_eventLogger.isEnable((Logger::LoggerLevel)severity);
+}
+
+static ErrorItem errorTable[] =
+{
+ {MgmtSrvr::NO_CONTACT_WITH_PROCESS, "No contact with the process (dead ?)."},
+ {MgmtSrvr::PROCESS_NOT_CONFIGURED, "The process is not configured."},
+ {MgmtSrvr::WRONG_PROCESS_TYPE,
+ "The process has wrong type. Expected a DB process."},
+ {MgmtSrvr::COULD_NOT_ALLOCATE_MEMORY, "Could not allocate memory."},
+ {MgmtSrvr::SEND_OR_RECEIVE_FAILED, "Send to process or receive failed."},
+ {MgmtSrvr::INVALID_LEVEL, "Invalid level. Should be between 1 and 30."},
+ {MgmtSrvr::INVALID_ERROR_NUMBER, "Invalid error number. Should be >= 0."},
+ {MgmtSrvr::INVALID_TRACE_NUMBER, "Invalid trace number."},
+ {MgmtSrvr::NOT_IMPLEMENTED, "Not implemented."},
+ {MgmtSrvr::INVALID_BLOCK_NAME, "Invalid block name"},
+
+ {MgmtSrvr::CONFIG_PARAM_NOT_EXIST,
+ "The configuration parameter does not exist for the process type."},
+ {MgmtSrvr::CONFIG_PARAM_NOT_UPDATEABLE,
+ "The configuration parameter is not possible to update."},
+ {MgmtSrvr::VALUE_WRONG_FORMAT_INT_EXPECTED,
+ "Incorrect value. Expected integer."},
+ {MgmtSrvr::VALUE_TOO_LOW, "Value is too low."},
+ {MgmtSrvr::VALUE_TOO_HIGH, "Value is too high."},
+ {MgmtSrvr::VALUE_WRONG_FORMAT_BOOL_EXPECTED,
+ "Incorrect value. Expected TRUE or FALSE."},
+
+ {MgmtSrvr::CONFIG_FILE_OPEN_WRITE_ERROR,
+ "Could not open configuration file for writing."},
+ {MgmtSrvr::CONFIG_FILE_OPEN_READ_ERROR,
+ "Could not open configuration file for reading."},
+ {MgmtSrvr::CONFIG_FILE_WRITE_ERROR,
+ "Write error when writing configuration file."},
+ {MgmtSrvr::CONFIG_FILE_READ_ERROR,
+ "Read error when reading configuration file."},
+ {MgmtSrvr::CONFIG_FILE_CLOSE_ERROR, "Could not close configuration file."},
+
+ {MgmtSrvr::CONFIG_CHANGE_REFUSED_BY_RECEIVER,
+ "The change was refused by the receiving process."},
+ {MgmtSrvr::COULD_NOT_SYNC_CONFIG_CHANGE_AGAINST_PHYSICAL_MEDIUM,
+ "The change could not be synced against physical medium."},
+ {MgmtSrvr::CONFIG_FILE_CHECKSUM_ERROR,
+ "The config file is corrupt. Checksum error."},
+ {MgmtSrvr::NOT_POSSIBLE_TO_SEND_CONFIG_UPDATE_TO_PROCESS_TYPE,
+ "It is not possible to send an update of a configuration variable "
+ "to this kind of process."},
+ {MgmtSrvr::NODE_SHUTDOWN_IN_PROGESS, "Node shutdown in progress" },
+ {MgmtSrvr::SYSTEM_SHUTDOWN_IN_PROGRESS, "System shutdown in progress" },
+ {MgmtSrvr::NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH,
+ "Node shutdown would cause system crash" },
+ {MgmtSrvr::UNSUPPORTED_NODE_SHUTDOWN,
+ "Unsupported multi node shutdown. Abort option required." },
+ {MgmtSrvr::NODE_NOT_API_NODE, "The specified node is not an API node." },
+ {MgmtSrvr::OPERATION_NOT_ALLOWED_START_STOP,
+ "Operation not allowed while nodes are starting or stopping."},
+ {MgmtSrvr::NO_CONTACT_WITH_DB_NODES, "No contact with database nodes" }
+};
+
+int MgmtSrvr::translateStopRef(Uint32 errCode)
+{
+ switch(errCode){
+ case StopRef::NodeShutdownInProgress:
+ return NODE_SHUTDOWN_IN_PROGESS;
+ break;
+ case StopRef::SystemShutdownInProgress:
+ return SYSTEM_SHUTDOWN_IN_PROGRESS;
+ break;
+ case StopRef::NodeShutdownWouldCauseSystemCrash:
+ return NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH;
+ break;
+ case StopRef::UnsupportedNodeShutdown:
+ return UNSUPPORTED_NODE_SHUTDOWN;
+ break;
+ }
+ return 4999;
+}
+
+static int noOfErrorCodes = sizeof(errorTable) / sizeof(ErrorItem);
+
+int
+MgmtSrvr::getNodeCount(enum ndb_mgm_node_type type) const
+{
+ int count = 0;
+ NodeId nodeId = 0;
+
+ while (getNextNodeId(&nodeId, type)) {
+ count++;
+ }
+ return count;
+}
+
+int
+MgmtSrvr::getPort() const
+{
+ if(NdbMutex_Lock(m_configMutex))
+ return 0;
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.find(CFG_NODE_ID, getOwnNodeId()) != 0){
+ ndbout << "Could not retrieve configuration for Node "
+ << getOwnNodeId() << " in config file." << endl
+ << "Have you set correct NodeId for this node?" << endl;
+ NdbMutex_Unlock(m_configMutex);
+ return 0;
+ }
+
+ unsigned type;
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0 ||
+ type != NODE_TYPE_MGM){
+ ndbout << "Local node id " << getOwnNodeId()
+ << " is not defined as management server" << endl
+ << "Have you set correct NodeId for this node?" << endl;
+ NdbMutex_Unlock(m_configMutex);
+ return 0;
+ }
+
+ Uint32 port = 0;
+ if(iter.get(CFG_MGM_PORT, &port) != 0){
+ ndbout << "Could not find PortNumber in the configuration file." << endl;
+ NdbMutex_Unlock(m_configMutex);
+ return 0;
+ }
+
+ NdbMutex_Unlock(m_configMutex);
+
+ return port;
+}
+
+/* Constructor */
+int MgmtSrvr::init()
+{
+ if ( _ownNodeId > 0)
+ return 0;
+ return -1;
+}
+
+MgmtSrvr::MgmtSrvr(SocketServer *socket_server,
+ const char *config_filename,
+ const char *connect_string) :
+ _blockNumber(1), // Hard coded block number since it makes it easy to send
+ // signals to other management servers.
+ m_socket_server(socket_server),
+ _ownReference(0),
+ theSignalIdleList(NULL),
+ theWaitState(WAIT_SUBSCRIBE_CONF),
+ m_local_mgm_handle(0),
+ m_event_listner(this),
+ m_master_node(0)
+{
+
+ DBUG_ENTER("MgmtSrvr::MgmtSrvr");
+
+ _ownNodeId= 0;
+
+ _config = NULL;
+
+ _isStopThread = false;
+ _logLevelThread = NULL;
+ _logLevelThreadSleep = 500;
+
+ theFacade = 0;
+
+ m_newConfig = NULL;
+ if (config_filename)
+ m_configFilename.assign(config_filename);
+
+ m_nextConfigGenerationNumber = 0;
+
+ m_config_retriever= new ConfigRetriever(connect_string,
+ NDB_VERSION, NDB_MGM_NODE_TYPE_MGM);
+ // if connect_string explicitly given or
+ // no config filename is given then
+ // first try to allocate nodeid from another management server
+ if ((connect_string || config_filename == NULL) &&
+ (m_config_retriever->do_connect(0,0,0) == 0))
+ {
+ int tmp_nodeid= 0;
+ tmp_nodeid= m_config_retriever->allocNodeId(0 /*retry*/,0 /*delay*/);
+ if (tmp_nodeid == 0)
+ {
+ ndbout_c(m_config_retriever->getErrorString());
+ require(false);
+ }
+ // read config from other managent server
+ _config= fetchConfig();
+ if (_config == 0)
+ {
+ ndbout << m_config_retriever->getErrorString() << endl;
+ require(false);
+ }
+ _ownNodeId= tmp_nodeid;
+ }
+
+ if (_ownNodeId == 0)
+ {
+ // read config locally
+ _config= readConfig();
+ if (_config == 0) {
+ if (config_filename != NULL)
+ ndbout << "Invalid configuration file: " << config_filename << endl;
+ else
+ ndbout << "Invalid configuration file" << endl;
+ exit(-1);
+ }
+ }
+
+ theMgmtWaitForResponseCondPtr = NdbCondition_Create();
+
+ m_configMutex = NdbMutex_Create();
+
+ /**
+ * Fill the nodeTypes array
+ */
+ for(Uint32 i = 0; i<MAX_NODES; i++) {
+ nodeTypes[i] = (enum ndb_mgm_node_type)-1;
+ m_connect_address[i].s_addr= 0;
+ }
+
+ {
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ for(iter.first(); iter.valid(); iter.next()){
+ unsigned type, id;
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0)
+ continue;
+
+ if(iter.get(CFG_NODE_ID, &id) != 0)
+ continue;
+
+ MGM_REQUIRE(id < MAX_NODES);
+
+ switch(type){
+ case NODE_TYPE_DB:
+ nodeTypes[id] = NDB_MGM_NODE_TYPE_NDB;
+ break;
+ case NODE_TYPE_API:
+ nodeTypes[id] = NDB_MGM_NODE_TYPE_API;
+ break;
+ case NODE_TYPE_MGM:
+ nodeTypes[id] = NDB_MGM_NODE_TYPE_MGM;
+ break;
+ default:
+ break;
+ }
+ }
+ }
+
+ _props = NULL;
+ BaseString error_string;
+
+ if ((m_node_id_mutex = NdbMutex_Create()) == 0)
+ {
+ ndbout << "mutex creation failed line = " << __LINE__ << endl;
+ require(false);
+ }
+
+ if (_ownNodeId == 0) // we did not get node id from other server
+ {
+ NodeId tmp= m_config_retriever->get_configuration_nodeid();
+ int error_code;
+
+ if (!alloc_node_id(&tmp, NDB_MGM_NODE_TYPE_MGM,
+ 0, 0, error_code, error_string)){
+ ndbout << "Unable to obtain requested nodeid: "
+ << error_string.c_str() << endl;
+ require(false);
+ }
+ _ownNodeId = tmp;
+ }
+
+ {
+ DBUG_PRINT("info", ("verifyConfig"));
+ if (!m_config_retriever->verifyConfig(_config->m_configValues,
+ _ownNodeId))
+ {
+ ndbout << m_config_retriever->getErrorString() << endl;
+ require(false);
+ }
+ }
+
+ // Setup clusterlog as client[0] in m_event_listner
+ {
+ Ndb_mgmd_event_service::Event_listener se;
+ se.m_socket = NDB_INVALID_SOCKET;
+ for(size_t t = 0; t<LogLevel::LOGLEVEL_CATEGORIES; t++){
+ se.m_logLevel.setLogLevel((LogLevel::EventCategory)t, 7);
+ }
+ se.m_logLevel.setLogLevel(LogLevel::llError, 15);
+ se.m_logLevel.setLogLevel(LogLevel::llConnection, 8);
+ se.m_logLevel.setLogLevel(LogLevel::llBackup, 15);
+ m_event_listner.m_clients.push_back(se);
+ m_event_listner.m_logLevel = se.m_logLevel;
+ }
+
+ DBUG_VOID_RETURN;
+}
+
+
+//****************************************************************************
+//****************************************************************************
+bool
+MgmtSrvr::check_start()
+{
+ if (_config == 0) {
+ DEBUG("MgmtSrvr.cpp: _config is NULL.");
+ return false;
+ }
+
+ return true;
+}
+
+bool
+MgmtSrvr::start(BaseString &error_string)
+{
+ int mgm_connect_result;
+
+ DBUG_ENTER("MgmtSrvr::start");
+ if (_props == NULL) {
+ if (!check_start()) {
+ error_string.append("MgmtSrvr.cpp: check_start() failed.");
+ DBUG_RETURN(false);
+ }
+ }
+ theFacade= new TransporterFacade();
+
+ if(theFacade == 0) {
+ DEBUG("MgmtSrvr.cpp: theFacade is NULL.");
+ error_string.append("MgmtSrvr.cpp: theFacade is NULL.");
+ DBUG_RETURN(false);
+ }
+ if ( theFacade->start_instance
+ (_ownNodeId, (ndb_mgm_configuration*)_config->m_configValues) < 0) {
+ DEBUG("MgmtSrvr.cpp: TransporterFacade::start_instance < 0.");
+ DBUG_RETURN(false);
+ }
+
+ MGM_REQUIRE(_blockNumber == 1);
+
+ // Register ourself at TransporterFacade to be able to receive signals
+ // and to be notified when a database process has died.
+ _blockNumber = theFacade->open(this,
+ signalReceivedNotification,
+ nodeStatusNotification);
+
+ if(_blockNumber == -1){
+ DEBUG("MgmtSrvr.cpp: _blockNumber is -1.");
+ error_string.append("MgmtSrvr.cpp: _blockNumber is -1.");
+ theFacade->stop_instance();
+ theFacade = 0;
+ DBUG_RETURN(false);
+ }
+
+ if((mgm_connect_result= connect_to_self()) < 0)
+ {
+ ndbout_c("Unable to connect to our own ndb_mgmd (Error %d)",
+ mgm_connect_result);
+ ndbout_c("This is probably a bug.");
+ }
+
+ TransporterRegistry *reg = theFacade->get_registry();
+ for(unsigned int i=0;i<reg->m_transporter_interface.size();i++) {
+ BaseString msg;
+ DBUG_PRINT("info",("Setting dynamic port %d->%d : %d",
+ reg->get_localNodeId(),
+ reg->m_transporter_interface[i].m_remote_nodeId,
+ reg->m_transporter_interface[i].m_s_service_port
+ )
+ );
+ int res = setConnectionDbParameter((int)reg->get_localNodeId(),
+ (int)reg->m_transporter_interface[i]
+ .m_remote_nodeId,
+ (int)CFG_CONNECTION_SERVER_PORT,
+ reg->m_transporter_interface[i]
+ .m_s_service_port,
+ msg);
+ DBUG_PRINT("info",("Set result: %d: %s",res,msg.c_str()));
+ }
+
+ _ownReference = numberToRef(_blockNumber, _ownNodeId);
+
+ startEventLog();
+ // Set the initial confirmation count for subscribe requests confirm
+ // from NDB nodes in the cluster.
+ //
+ // Loglevel thread
+ _logLevelThread = NdbThread_Create(logLevelThread_C,
+ (void**)this,
+ 32768,
+ "MgmtSrvr_Loglevel",
+ NDB_THREAD_PRIO_LOW);
+
+ DBUG_RETURN(true);
+}
+
+
+//****************************************************************************
+//****************************************************************************
+MgmtSrvr::~MgmtSrvr()
+{
+ if(theFacade != 0){
+ theFacade->stop_instance();
+ delete theFacade;
+ theFacade = 0;
+ }
+
+ stopEventLog();
+
+ NdbMutex_Destroy(m_node_id_mutex);
+ NdbCondition_Destroy(theMgmtWaitForResponseCondPtr);
+ NdbMutex_Destroy(m_configMutex);
+
+ if(m_newConfig != NULL)
+ free(m_newConfig);
+
+ if(_config != NULL)
+ delete _config;
+
+ // End set log level thread
+ void* res = 0;
+ _isStopThread = true;
+
+ if (_logLevelThread != NULL) {
+ NdbThread_WaitFor(_logLevelThread, &res);
+ NdbThread_Destroy(&_logLevelThread);
+ }
+
+ if (m_config_retriever)
+ delete m_config_retriever;
+}
+
+//****************************************************************************
+//****************************************************************************
+
+int MgmtSrvr::okToSendTo(NodeId nodeId, bool unCond)
+{
+ if(nodeId == 0 || getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB)
+ return WRONG_PROCESS_TYPE;
+ // Check if we have contact with it
+ if(unCond){
+ if(theFacade->theClusterMgr->getNodeInfo(nodeId).connected)
+ return 0;
+ }
+ else if (theFacade->get_node_alive(nodeId) == true)
+ return 0;
+ return NO_CONTACT_WITH_PROCESS;
+}
+
+void report_unknown_signal(SimpleSignal *signal)
+{
+ g_eventLogger.error("Unknown signal received. SignalNumber: "
+ "%i from (%d, %x)",
+ signal->readSignalNumber(),
+ refToNode(signal->header.theSendersBlockRef),
+ refToBlock(signal->header.theSendersBlockRef));
+}
+
+/*****************************************************************************
+ * Starting and stopping database nodes
+ ****************************************************************************/
+
+int
+MgmtSrvr::start(int nodeId)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ StartOrd* const startOrd = CAST_PTR(StartOrd, ssig.getDataPtrSend());
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_START_ORD, StartOrd::SignalLength);
+ startOrd->restartInfo = 0;
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+/*****************************************************************************
+ * Version handling
+ *****************************************************************************/
+
+int
+MgmtSrvr::versionNode(int nodeId, Uint32 &version, const char **address)
+{
+ version= 0;
+ if (getOwnNodeId() == nodeId)
+ {
+ /**
+ * If we're inquiring about our own node id,
+ * We know what version we are (version implies connected for mgm)
+ * but would like to find out from elsewhere what address they're using
+ * to connect to us. This means that secondary mgm servers
+ * can list ip addresses for mgm servers.
+ *
+ * If we don't get an address (i.e. no db nodes),
+ * we get the address from the configuration.
+ */
+ sendVersionReq(nodeId, version, address);
+ version= NDB_VERSION;
+ if(!*address)
+ {
+ ndb_mgm_configuration_iterator
+ iter(*_config->m_configValues, CFG_SECTION_NODE);
+ unsigned tmp= 0;
+ for(iter.first();iter.valid();iter.next())
+ {
+ if(iter.get(CFG_NODE_ID, &tmp)) require(false);
+ if((unsigned)nodeId!=tmp)
+ continue;
+ if(iter.get(CFG_NODE_HOST, address)) require(false);
+ break;
+ }
+ }
+ }
+ else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB)
+ {
+ ClusterMgr::Node node= theFacade->theClusterMgr->getNodeInfo(nodeId);
+ if(node.connected)
+ version= node.m_info.m_version;
+ *address= get_connect_address(nodeId);
+ }
+ else if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API ||
+ getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM)
+ {
+ return sendVersionReq(nodeId, version, address);
+ }
+
+ return 0;
+}
+
+int
+MgmtSrvr::sendVersionReq(int v_nodeId, Uint32 &version, const char **address)
+{
+ SignalSender ss(theFacade);
+ ss.lock();
+
+ SimpleSignal ssig;
+ ApiVersionReq* req = CAST_PTR(ApiVersionReq, ssig.getDataPtrSend());
+ req->senderRef = ss.getOwnRef();
+ req->nodeId = v_nodeId;
+ ssig.set(ss, TestOrd::TraceAPI, QMGR, GSN_API_VERSION_REQ,
+ ApiVersionReq::SignalLength);
+
+ int do_send = 1;
+ NodeId nodeId;
+
+ while (1)
+ {
+ if (do_send)
+ {
+ bool next;
+ nodeId = 0;
+
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ okToSendTo(nodeId, true) != 0);
+
+ const ClusterMgr::Node &node=
+ theFacade->theClusterMgr->getNodeInfo(nodeId);
+ if(next && node.m_state.startLevel != NodeState::SL_STARTED)
+ {
+ NodeId tmp=nodeId;
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ okToSendTo(nodeId, true) != 0);
+ if(!next)
+ nodeId= tmp;
+ }
+
+ if(!next) return NO_CONTACT_WITH_DB_NODES;
+
+ if (ss.sendSignal(nodeId, &ssig) != SEND_OK) {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ do_send = 0;
+ }
+
+ SimpleSignal *signal = ss.waitFor();
+
+ int gsn = signal->readSignalNumber();
+ switch (gsn) {
+ case GSN_API_VERSION_CONF: {
+ const ApiVersionConf * const conf =
+ CAST_CONSTPTR(ApiVersionConf, signal->getDataPtr());
+ assert((int) conf->nodeId == v_nodeId);
+ version = conf->version;
+ struct in_addr in;
+ in.s_addr= conf->inet_addr;
+ *address= inet_ntoa(in);
+ return 0;
+ }
+ case GSN_NF_COMPLETEREP:{
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+ if (rep->failedNodeId == nodeId)
+ do_send = 1; // retry with other node
+ continue;
+ }
+ case GSN_NODE_FAILREP:{
+ const NodeFailRep * const rep =
+ CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
+ if (NodeBitmask::get(rep->theNodes,nodeId))
+ do_send = 1; // retry with other node
+ continue;
+ }
+ default:
+ report_unknown_signal(signal);
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ break;
+ } // while(1)
+
+ return 0;
+}
+
+int MgmtSrvr::sendStopMgmd(NodeId nodeId,
+ bool abort,
+ bool stop,
+ bool restart,
+ bool nostart,
+ bool initialStart)
+{
+ const char* hostname;
+ Uint32 port;
+ BaseString connect_string;
+
+ {
+ Guard g(m_configMutex);
+ {
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.first()) return SEND_OR_RECEIVE_FAILED;
+ if(iter.find(CFG_NODE_ID, nodeId)) return SEND_OR_RECEIVE_FAILED;
+ if(iter.get(CFG_NODE_HOST, &hostname)) return SEND_OR_RECEIVE_FAILED;
+ }
+ {
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+
+ if(iter.first()) return SEND_OR_RECEIVE_FAILED;
+ if(iter.find(CFG_NODE_ID, nodeId)) return SEND_OR_RECEIVE_FAILED;
+ if(iter.get(CFG_MGM_PORT, &port)) return SEND_OR_RECEIVE_FAILED;
+ }
+ if( strlen(hostname) == 0 )
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ connect_string.assfmt("%s:%u",hostname,port);
+
+ DBUG_PRINT("info",("connect string: %s",connect_string.c_str()));
+
+ NdbMgmHandle h= ndb_mgm_create_handle();
+ if ( h && connect_string.length() > 0 )
+ {
+ ndb_mgm_set_connectstring(h,connect_string.c_str());
+ if(ndb_mgm_connect(h,1,0,0))
+ {
+ DBUG_PRINT("info",("failed ndb_mgm_connect"));
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ if(!restart)
+ {
+ if(ndb_mgm_stop(h, 1, (const int*)&nodeId) < 0)
+ {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ }
+ else
+ {
+ int nodes[1];
+ nodes[0]= (int)nodeId;
+ if(ndb_mgm_restart2(h, 1, nodes, initialStart, nostart, abort) < 0)
+ {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ }
+ }
+ ndb_mgm_destroy_handle(&h);
+
+ return 0;
+}
+
+/*
+ * Common method for handeling all STOP_REQ signalling that
+ * is used by Stopping, Restarting and Single user commands
+ *
+ * In the event that we need to stop a mgmd, we create a mgm
+ * client connection to that mgmd and stop it that way.
+ * This allows us to stop mgm servers when there isn't any real
+ * distributed communication up.
+ *
+ * node_ids.size()==0 means to stop all DB nodes.
+ * MGM nodes will *NOT* be stopped.
+ *
+ * If we work out we should be stopping or restarting ourselves,
+ * we return <0 in stopSelf for restart, >0 for stop
+ * and 0 for do nothing.
+ */
+
+int MgmtSrvr::sendSTOP_REQ(const Vector<NodeId> &node_ids,
+ NodeBitmask &stoppedNodes,
+ Uint32 singleUserNodeId,
+ bool abort,
+ bool stop,
+ bool restart,
+ bool nostart,
+ bool initialStart,
+ int* stopSelf)
+{
+ int error = 0;
+ DBUG_ENTER("MgmtSrvr::sendSTOP_REQ");
+ DBUG_PRINT("enter", ("no of nodes: %d singleUseNodeId: %d "
+ "abort: %d stop: %d restart: %d "
+ "nostart: %d initialStart: %d",
+ node_ids.size(), singleUserNodeId,
+ abort, stop, restart, nostart, initialStart));
+
+ stoppedNodes.clear();
+
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
+ SimpleSignal ssig;
+ StopReq* const stopReq = CAST_PTR(StopReq, ssig.getDataPtrSend());
+ ssig.set(ss, TestOrd::TraceAPI, NDBCNTR, GSN_STOP_REQ, StopReq::SignalLength);
+
+ NdbNodeBitmask notstarted;
+ for (Uint32 i = 0; i<node_ids.size(); i++)
+ {
+ Uint32 nodeId = node_ids[i];
+ ClusterMgr::Node node = theFacade->theClusterMgr->getNodeInfo(nodeId);
+ if (node.m_state.startLevel != NodeState::SL_STARTED)
+ notstarted.set(nodeId);
+ }
+
+ stopReq->requestInfo = 0;
+ stopReq->apiTimeout = 5000;
+ stopReq->transactionTimeout = 1000;
+ stopReq->readOperationTimeout = 1000;
+ stopReq->operationTimeout = 1000;
+ stopReq->senderData = 12;
+ stopReq->senderRef = ss.getOwnRef();
+ if (singleUserNodeId)
+ {
+ stopReq->singleuser = 1;
+ stopReq->singleUserApi = singleUserNodeId;
+ StopReq::setSystemStop(stopReq->requestInfo, false);
+ StopReq::setPerformRestart(stopReq->requestInfo, false);
+ StopReq::setStopAbort(stopReq->requestInfo, false);
+ }
+ else
+ {
+ stopReq->singleuser = 0;
+ StopReq::setSystemStop(stopReq->requestInfo, stop);
+ StopReq::setPerformRestart(stopReq->requestInfo, restart);
+ StopReq::setStopAbort(stopReq->requestInfo, abort);
+ StopReq::setNoStart(stopReq->requestInfo, nostart);
+ StopReq::setInitialStart(stopReq->requestInfo, initialStart);
+ }
+
+ // send the signals
+ NodeBitmask nodes;
+ NodeId nodeId= 0;
+ int use_master_node= 0;
+ int do_send= 0;
+ *stopSelf= 0;
+ NdbNodeBitmask nodes_to_stop;
+ {
+ for (unsigned i= 0; i < node_ids.size(); i++)
+ {
+ nodeId= node_ids[i];
+ ndbout << "asked to stop " << nodeId << endl;
+
+ if ((getNodeType(nodeId) != NDB_MGM_NODE_TYPE_MGM)
+ &&(getNodeType(nodeId) != NDB_MGM_NODE_TYPE_NDB))
+ return WRONG_PROCESS_TYPE;
+
+ if (getNodeType(nodeId) != NDB_MGM_NODE_TYPE_MGM)
+ nodes_to_stop.set(nodeId);
+ else if (nodeId != getOwnNodeId())
+ {
+ error= sendStopMgmd(nodeId, abort, stop, restart,
+ nostart, initialStart);
+ if (error == 0)
+ stoppedNodes.set(nodeId);
+ }
+ else
+ {
+ ndbout << "which is me" << endl;
+ *stopSelf= (restart)? -1 : 1;
+ stoppedNodes.set(nodeId);
+ }
+ }
+ }
+ int no_of_nodes_to_stop= nodes_to_stop.count();
+ if (node_ids.size())
+ {
+ if (no_of_nodes_to_stop)
+ {
+ do_send= 1;
+ if (no_of_nodes_to_stop == 1)
+ {
+ nodeId= nodes_to_stop.find(0);
+ }
+ else // multi node stop, send to master
+ {
+ use_master_node= 1;
+ nodes_to_stop.copyto(NdbNodeBitmask::Size, stopReq->nodes);
+ StopReq::setStopNodes(stopReq->requestInfo, 1);
+ }
+ }
+ }
+ else
+ {
+ nodeId= 0;
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB))
+ {
+ if(okToSendTo(nodeId, true) == 0)
+ {
+ SendStatus result = ss.sendSignal(nodeId, &ssig);
+ if (result == SEND_OK)
+ nodes.set(nodeId);
+ }
+ }
+ }
+
+ // now wait for the replies
+ while (!nodes.isclear() || do_send)
+ {
+ if (do_send)
+ {
+ int r;
+ assert(nodes.count() == 0);
+ if (use_master_node)
+ nodeId= m_master_node;
+ if ((r= okToSendTo(nodeId, true)) != 0)
+ {
+ bool next;
+ if (!use_master_node)
+ DBUG_RETURN(r);
+ m_master_node= nodeId= 0;
+ while((next= getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ (r= okToSendTo(nodeId, true)) != 0);
+ if (!next)
+ DBUG_RETURN(NO_CONTACT_WITH_DB_NODES);
+ }
+ if (ss.sendSignal(nodeId, &ssig) != SEND_OK)
+ DBUG_RETURN(SEND_OR_RECEIVE_FAILED);
+ nodes.set(nodeId);
+ do_send= 0;
+ }
+ SimpleSignal *signal = ss.waitFor();
+ int gsn = signal->readSignalNumber();
+ switch (gsn) {
+ case GSN_STOP_REF:{
+ const StopRef * const ref = CAST_CONSTPTR(StopRef, signal->getDataPtr());
+ const NodeId nodeId = refToNode(signal->header.theSendersBlockRef);
+#ifdef VM_TRACE
+ ndbout_c("Node %d refused stop", nodeId);
+#endif
+ assert(nodes.get(nodeId));
+ nodes.clear(nodeId);
+ if (ref->errorCode == StopRef::MultiNodeShutdownNotMaster)
+ {
+ assert(use_master_node);
+ m_master_node= ref->masterNodeId;
+ do_send= 1;
+ continue;
+ }
+ error = translateStopRef(ref->errorCode);
+ break;
+ }
+ case GSN_STOP_CONF:{
+ const StopConf * const ref = CAST_CONSTPTR(StopConf, signal->getDataPtr());
+ const NodeId nodeId = refToNode(signal->header.theSendersBlockRef);
+#ifdef VM_TRACE
+ ndbout_c("Node %d single user mode", nodeId);
+#endif
+ assert(nodes.get(nodeId));
+ if (singleUserNodeId != 0)
+ {
+ stoppedNodes.set(nodeId);
+ }
+ else
+ {
+ assert(no_of_nodes_to_stop > 1);
+ stoppedNodes.bitOR(nodes_to_stop);
+ }
+ nodes.clear(nodeId);
+ break;
+ }
+ case GSN_NF_COMPLETEREP:{
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("sendSTOP_REQ Node %d fail completed", rep->failedNodeId);
+#endif
+ nodes.clear(rep->failedNodeId); // clear the failed node
+ if (singleUserNodeId == 0)
+ stoppedNodes.set(rep->failedNodeId);
+ break;
+ }
+ case GSN_NODE_FAILREP:{
+ const NodeFailRep * const rep =
+ CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
+ NdbNodeBitmask mask;
+ char buf[100];
+ mask.assign(NdbNodeBitmask::Size, rep->theNodes);
+ mask.bitAND(notstarted);
+ nodes.bitANDC(mask);
+
+ if (singleUserNodeId == 0)
+ stoppedNodes.bitOR(mask);
+ break;
+ }
+ default:
+ report_unknown_signal(signal);
+#ifdef VM_TRACE
+ ndbout_c("Unknown signal %d", gsn);
+#endif
+ DBUG_RETURN(SEND_OR_RECEIVE_FAILED);
+ }
+ }
+ if (error && *stopSelf)
+ {
+ *stopSelf= 0;
+ }
+ DBUG_RETURN(error);
+}
+
+/*
+ * Stop one nodes
+ */
+
+int MgmtSrvr::stopNodes(const Vector<NodeId> &node_ids,
+ int *stopCount, bool abort, int* stopSelf)
+{
+ if (!abort)
+ {
+ NodeId nodeId = 0;
+ ClusterMgr::Node node;
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB))
+ {
+ node = theFacade->theClusterMgr->getNodeInfo(nodeId);
+ if((node.m_state.startLevel != NodeState::SL_STARTED) &&
+ (node.m_state.startLevel != NodeState::SL_NOTHING))
+ return OPERATION_NOT_ALLOWED_START_STOP;
+ }
+ }
+ NodeBitmask nodes;
+ int ret= sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ false,
+ false,
+ false,
+ false,
+ stopSelf);
+ if (stopCount)
+ *stopCount= nodes.count();
+ return ret;
+}
+
+int MgmtSrvr::shutdownMGM(int *stopCount, bool abort, int *stopSelf)
+{
+ NodeId nodeId = 0;
+ int error;
+
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_MGM))
+ {
+ if(nodeId==getOwnNodeId())
+ continue;
+ error= sendStopMgmd(nodeId, abort, true, false,
+ false, false);
+ if (error == 0)
+ *stopCount++;
+ }
+
+ *stopSelf= 1;
+ *stopCount++;
+
+ return 0;
+}
+
+/*
+ * Perform DB nodes shutdown.
+ * MGM servers are left in their current state
+ */
+
+int MgmtSrvr::shutdownDB(int * stopCount, bool abort)
+{
+ NodeBitmask nodes;
+ Vector<NodeId> node_ids;
+
+ int tmp;
+
+ int ret = sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ true,
+ false,
+ false,
+ false,
+ &tmp);
+ if (stopCount)
+ *stopCount = nodes.count();
+ return ret;
+}
+
+/*
+ * Enter single user mode on all live nodes
+ */
+
+int MgmtSrvr::enterSingleUser(int * stopCount, Uint32 singleUserNodeId)
+{
+ if (getNodeType(singleUserNodeId) != NDB_MGM_NODE_TYPE_API)
+ return NODE_NOT_API_NODE;
+ NodeId nodeId = 0;
+ ClusterMgr::Node node;
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB))
+ {
+ node = theFacade->theClusterMgr->getNodeInfo(nodeId);
+ if((node.m_state.startLevel != NodeState::SL_STARTED) &&
+ (node.m_state.startLevel != NodeState::SL_NOTHING))
+ return OPERATION_NOT_ALLOWED_START_STOP;
+ }
+ NodeBitmask nodes;
+ Vector<NodeId> node_ids;
+ int stopSelf;
+ int ret = sendSTOP_REQ(node_ids,
+ nodes,
+ singleUserNodeId,
+ false,
+ false,
+ false,
+ false,
+ false,
+ &stopSelf);
+ if (stopCount)
+ *stopCount = nodes.count();
+ return ret;
+}
+
+/*
+ * Perform node restart
+ */
+
+int MgmtSrvr::restartNodes(const Vector<NodeId> &node_ids,
+ int * stopCount, bool nostart,
+ bool initialStart, bool abort,
+ int *stopSelf)
+{
+ NodeBitmask nodes;
+ int ret= sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ false,
+ true,
+ true,
+ initialStart,
+ stopSelf);
+
+ if (ret)
+ return ret;
+
+ if (stopCount)
+ *stopCount = nodes.count();
+
+ // start up the nodes again
+ int waitTime = 12000;
+ NDB_TICKS maxTime = NdbTick_CurrentMillisecond() + waitTime;
+ for (unsigned i = 0; i < node_ids.size(); i++)
+ {
+ NodeId nodeId= node_ids[i];
+ enum ndb_mgm_node_status s;
+ s = NDB_MGM_NODE_STATUS_NO_CONTACT;
+#ifdef VM_TRACE
+ ndbout_c("Waiting for %d not started", nodeId);
+#endif
+ while (s != NDB_MGM_NODE_STATUS_NOT_STARTED && waitTime > 0)
+ {
+ Uint32 startPhase = 0, version = 0, dynamicId = 0, nodeGroup = 0;
+ Uint32 connectCount = 0;
+ bool system;
+ const char *address;
+ status(nodeId, &s, &version, &startPhase,
+ &system, &dynamicId, &nodeGroup, &connectCount, &address);
+ NdbSleep_MilliSleep(100);
+ waitTime = (maxTime - NdbTick_CurrentMillisecond());
+ }
+ }
+
+ if (nostart)
+ return 0;
+
+ for (unsigned i = 0; i < node_ids.size(); i++)
+ {
+ int result = start(node_ids[i]);
+ }
+ return 0;
+}
+
+/*
+ * Perform restart of all DB nodes
+ */
+
+int MgmtSrvr::restartDB(bool nostart, bool initialStart,
+ bool abort, int * stopCount)
+{
+ NodeBitmask nodes;
+ Vector<NodeId> node_ids;
+ int tmp;
+
+ int ret = sendSTOP_REQ(node_ids,
+ nodes,
+ 0,
+ abort,
+ true,
+ true,
+ true,
+ initialStart,
+ &tmp);
+
+ if (ret)
+ return ret;
+
+ if (stopCount)
+ *stopCount = nodes.count();
+
+#ifdef VM_TRACE
+ ndbout_c("Stopped %d nodes", nodes.count());
+#endif
+ /**
+ * Here all nodes were correctly stopped,
+ * so we wait for all nodes to be contactable
+ */
+ int waitTime = 12000;
+ NodeId nodeId = 0;
+ NDB_TICKS maxTime = NdbTick_CurrentMillisecond() + waitTime;
+
+ ndbout_c(" %d", nodes.get(1));
+ ndbout_c(" %d", nodes.get(2));
+
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) {
+ if (!nodes.get(nodeId))
+ continue;
+ enum ndb_mgm_node_status s;
+ s = NDB_MGM_NODE_STATUS_NO_CONTACT;
+#ifdef VM_TRACE
+ ndbout_c("Waiting for %d not started", nodeId);
+#endif
+ while (s != NDB_MGM_NODE_STATUS_NOT_STARTED && waitTime > 0) {
+ Uint32 startPhase = 0, version = 0, dynamicId = 0, nodeGroup = 0;
+ Uint32 connectCount = 0;
+ bool system;
+ const char *address;
+ status(nodeId, &s, &version, &startPhase,
+ &system, &dynamicId, &nodeGroup, &connectCount, &address);
+ NdbSleep_MilliSleep(100);
+ waitTime = (maxTime - NdbTick_CurrentMillisecond());
+ }
+ }
+
+ if(nostart)
+ return 0;
+
+ /**
+ * Now we start all database nodes (i.e. we make them non-idle)
+ * We ignore the result we get from the start command.
+ */
+ nodeId = 0;
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) {
+ if (!nodes.get(nodeId))
+ continue;
+ int result;
+ result = start(nodeId);
+ DEBUG("Starting node " << nodeId << " with result " << result);
+ /**
+ * Errors from this call are deliberately ignored.
+ * Maybe the user only wanted to restart a subset of the nodes.
+ * It is also easy for the user to check which nodes have
+ * started and which nodes have not.
+ */
+ }
+
+ return 0;
+}
+
+int
+MgmtSrvr::exitSingleUser(int * stopCount, bool abort)
+{
+ NodeId nodeId = 0;
+ int count = 0;
+
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
+ SimpleSignal ssig;
+ ResumeReq* const resumeReq =
+ CAST_PTR(ResumeReq, ssig.getDataPtrSend());
+ ssig.set(ss,TestOrd::TraceAPI, NDBCNTR, GSN_RESUME_REQ,
+ ResumeReq::SignalLength);
+ resumeReq->senderData = 12;
+ resumeReq->senderRef = ss.getOwnRef();
+
+ while(getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){
+ if(okToSendTo(nodeId, true) == 0){
+ SendStatus result = ss.sendSignal(nodeId, &ssig);
+ if (result == SEND_OK)
+ count++;
+ }
+ }
+
+ if(stopCount != 0)
+ * stopCount = count;
+
+ return 0;
+}
+
+/*****************************************************************************
+ * Status
+ ****************************************************************************/
+
+#include <ClusterMgr.hpp>
+
+void
+MgmtSrvr::updateStatus()
+{
+ theFacade->theClusterMgr->forceHB();
+}
+
+int
+MgmtSrvr::status(int nodeId,
+ ndb_mgm_node_status * _status,
+ Uint32 * version,
+ Uint32 * _phase,
+ bool * _system,
+ Uint32 * dynamic,
+ Uint32 * nodegroup,
+ Uint32 * connectCount,
+ const char **address)
+{
+ if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_API ||
+ getNodeType(nodeId) == NDB_MGM_NODE_TYPE_MGM) {
+ versionNode(nodeId, *version, address);
+ } else {
+ *address= get_connect_address(nodeId);
+ }
+
+ const ClusterMgr::Node node =
+ theFacade->theClusterMgr->getNodeInfo(nodeId);
+
+ if(!node.connected){
+ * _status = NDB_MGM_NODE_STATUS_NO_CONTACT;
+ return 0;
+ }
+
+ if (getNodeType(nodeId) == NDB_MGM_NODE_TYPE_NDB) {
+ * version = node.m_info.m_version;
+ }
+
+ * dynamic = node.m_state.dynamicId;
+ * nodegroup = node.m_state.nodeGroup;
+ * connectCount = node.m_info.m_connectCount;
+
+ switch(node.m_state.startLevel){
+ case NodeState::SL_CMVMI:
+ * _status = NDB_MGM_NODE_STATUS_NOT_STARTED;
+ * _phase = 0;
+ return 0;
+ break;
+ case NodeState::SL_STARTING:
+ * _status = NDB_MGM_NODE_STATUS_STARTING;
+ * _phase = node.m_state.starting.startPhase;
+ return 0;
+ break;
+ case NodeState::SL_STARTED:
+ * _status = NDB_MGM_NODE_STATUS_STARTED;
+ * _phase = 0;
+ return 0;
+ break;
+ case NodeState::SL_STOPPING_1:
+ * _status = NDB_MGM_NODE_STATUS_SHUTTING_DOWN;
+ * _phase = 1;
+ * _system = node.m_state.stopping.systemShutdown != 0;
+ return 0;
+ break;
+ case NodeState::SL_STOPPING_2:
+ * _status = NDB_MGM_NODE_STATUS_SHUTTING_DOWN;
+ * _phase = 2;
+ * _system = node.m_state.stopping.systemShutdown != 0;
+ return 0;
+ break;
+ case NodeState::SL_STOPPING_3:
+ * _status = NDB_MGM_NODE_STATUS_SHUTTING_DOWN;
+ * _phase = 3;
+ * _system = node.m_state.stopping.systemShutdown != 0;
+ return 0;
+ break;
+ case NodeState::SL_STOPPING_4:
+ * _status = NDB_MGM_NODE_STATUS_SHUTTING_DOWN;
+ * _phase = 4;
+ * _system = node.m_state.stopping.systemShutdown != 0;
+ return 0;
+ break;
+ case NodeState::SL_SINGLEUSER:
+ * _status = NDB_MGM_NODE_STATUS_SINGLEUSER;
+ * _phase = 0;
+ return 0;
+ break;
+ default:
+ * _status = NDB_MGM_NODE_STATUS_UNKNOWN;
+ * _phase = 0;
+ return 0;
+ }
+
+ return -1;
+}
+
+int
+MgmtSrvr::setEventReportingLevelImpl(int nodeId,
+ const EventSubscribeReq& ll)
+{
+ SignalSender ss(theFacade);
+ ss.lock();
+
+ SimpleSignal ssig;
+ EventSubscribeReq * dst =
+ CAST_PTR(EventSubscribeReq, ssig.getDataPtrSend());
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_EVENT_SUBSCRIBE_REQ,
+ EventSubscribeReq::SignalLength);
+ *dst = ll;
+
+ NodeBitmask nodes;
+ nodes.clear();
+ Uint32 max = (nodeId == 0) ? (nodeId = 1, MAX_NDB_NODES) : nodeId;
+ for(; (Uint32) nodeId <= max; nodeId++)
+ {
+ if (nodeTypes[nodeId] != NODE_TYPE_DB)
+ continue;
+ if (okToSendTo(nodeId, true))
+ continue;
+ if (ss.sendSignal(nodeId, &ssig) == SEND_OK)
+ {
+ nodes.set(nodeId);
+ }
+ }
+
+ int error = 0;
+ while (!nodes.isclear())
+ {
+ SimpleSignal *signal = ss.waitFor();
+ int gsn = signal->readSignalNumber();
+ nodeId = refToNode(signal->header.theSendersBlockRef);
+ switch (gsn) {
+ case GSN_EVENT_SUBSCRIBE_CONF:{
+ nodes.clear(nodeId);
+ break;
+ }
+ case GSN_EVENT_SUBSCRIBE_REF:{
+ nodes.clear(nodeId);
+ error = 1;
+ break;
+ }
+ case GSN_NF_COMPLETEREP:{
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+ nodes.clear(rep->failedNodeId);
+ break;
+ }
+ case GSN_NODE_FAILREP:{
+ // ignore, NF_COMPLETEREP will arrive later
+ break;
+ }
+ default:
+ report_unknown_signal(signal);
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ }
+ if (error)
+ return SEND_OR_RECEIVE_FAILED;
+ return 0;
+}
+
+//****************************************************************************
+//****************************************************************************
+int
+MgmtSrvr::setNodeLogLevelImpl(int nodeId, const SetLogLevelOrd & ll)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_SET_LOGLEVELORD,
+ SetLogLevelOrd::SignalLength);
+ SetLogLevelOrd* const dst = CAST_PTR(SetLogLevelOrd, ssig.getDataPtrSend());
+ *dst = ll;
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+//****************************************************************************
+//****************************************************************************
+
+int
+MgmtSrvr::insertError(int nodeId, int errorNo)
+{
+ if (errorNo < 0) {
+ return INVALID_ERROR_NUMBER;
+ }
+
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TAMPER_ORD,
+ TamperOrd::SignalLength);
+ TamperOrd* const tamperOrd = CAST_PTR(TamperOrd, ssig.getDataPtrSend());
+ tamperOrd->errorNo = errorNo;
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+
+
+//****************************************************************************
+//****************************************************************************
+
+int
+MgmtSrvr::setTraceNo(int nodeId, int traceNo)
+{
+ if (traceNo < 0) {
+ return INVALID_TRACE_NUMBER;
+ }
+
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength);
+ TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend());
+ testOrd->clear();
+ // Assume TRACE command causes toggling. Not really defined... ? TODO
+ testOrd->setTraceCommand(TestOrd::Toggle,
+ (TestOrd::TraceSpecification)traceNo);
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+//****************************************************************************
+//****************************************************************************
+
+int
+MgmtSrvr::getBlockNumber(const BaseString &blockName)
+{
+ short bno = getBlockNo(blockName.c_str());
+ if(bno != 0)
+ return bno;
+ return -1;
+}
+
+//****************************************************************************
+//****************************************************************************
+
+int
+MgmtSrvr::setSignalLoggingMode(int nodeId, LogMode mode,
+ const Vector<BaseString>& blocks)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ // Convert from MgmtSrvr format...
+
+ TestOrd::Command command;
+ if (mode == Off) {
+ command = TestOrd::Off;
+ }
+ else {
+ command = TestOrd::On;
+ }
+
+ TestOrd::SignalLoggerSpecification logSpec;
+ switch (mode) {
+ case In:
+ logSpec = TestOrd::InputSignals;
+ break;
+ case Out:
+ logSpec = TestOrd::OutputSignals;
+ break;
+ case InOut:
+ logSpec = TestOrd::InputOutputSignals;
+ break;
+ case Off:
+ // In MgmtSrvr interface it's just possible to switch off all logging, both
+ // "in" and "out" (this should probably be changed).
+ logSpec = TestOrd::InputOutputSignals;
+ break;
+ default:
+ ndbout_c("Unexpected value %d, MgmtSrvr::setSignalLoggingMode, line %d",
+ (unsigned)mode, __LINE__);
+ assert(false);
+ return -1;
+ }
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength);
+
+ TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend());
+ testOrd->clear();
+
+ if (blocks.size() == 0 || blocks[0] == "ALL") {
+ // Logg command for all blocks
+ testOrd->addSignalLoggerCommand(command, logSpec);
+ } else {
+ for(unsigned i = 0; i < blocks.size(); i++){
+ int blockNumber = getBlockNumber(blocks[i]);
+ if (blockNumber == -1) {
+ return INVALID_BLOCK_NAME;
+ }
+ testOrd->addSignalLoggerCommand(blockNumber, command, logSpec);
+ } // for
+ } // else
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+/*****************************************************************************
+ * Signal tracing
+ *****************************************************************************/
+int MgmtSrvr::startSignalTracing(int nodeId)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength);
+
+ TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend());
+ testOrd->clear();
+ testOrd->setTestCommand(TestOrd::On);
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+int
+MgmtSrvr::stopSignalTracing(int nodeId)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ SimpleSignal ssig;
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_TEST_ORD, TestOrd::SignalLength);
+ TestOrd* const testOrd = CAST_PTR(TestOrd, ssig.getDataPtrSend());
+ testOrd->clear();
+ testOrd->setTestCommand(TestOrd::Off);
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+
+/*****************************************************************************
+ * Dump state
+ *****************************************************************************/
+
+int
+MgmtSrvr::dumpState(int nodeId, const char* args)
+{
+ // Convert the space separeted args
+ // string to an int array
+ Uint32 args_array[25];
+ Uint32 numArgs = 0;
+
+ char buf[10];
+ int b = 0;
+ memset(buf, 0, 10);
+ for (size_t i = 0; i <= strlen(args); i++){
+ if (args[i] == ' ' || args[i] == 0){
+ args_array[numArgs] = atoi(buf);
+ numArgs++;
+ memset(buf, 0, 10);
+ b = 0;
+ } else {
+ buf[b] = args[i];
+ b++;
+ }
+ }
+
+ return dumpState(nodeId, args_array, numArgs);
+}
+
+int
+MgmtSrvr::dumpState(int nodeId, const Uint32 args[], Uint32 no)
+{
+ INIT_SIGNAL_SENDER(ss,nodeId);
+
+ const Uint32 len = no > 25 ? 25 : no;
+
+ SimpleSignal ssig;
+ DumpStateOrd * const dumpOrd =
+ CAST_PTR(DumpStateOrd, ssig.getDataPtrSend());
+ ssig.set(ss,TestOrd::TraceAPI, CMVMI, GSN_DUMP_STATE_ORD, len);
+ for(Uint32 i = 0; i<25; i++){
+ if (i < len)
+ dumpOrd->args[i] = args[i];
+ else
+ dumpOrd->args[i] = 0;
+ }
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+
+//****************************************************************************
+//****************************************************************************
+
+const char* MgmtSrvr::getErrorText(int errorCode, char *buf, int buf_sz)
+{
+
+ for (int i = 0; i < noOfErrorCodes; ++i) {
+ if (errorCode == errorTable[i]._errorCode) {
+ BaseString::snprintf(buf, buf_sz, errorTable[i]._errorText);
+ buf[buf_sz-1]= 0;
+ return buf;
+ }
+ }
+
+ ndb_error_string(errorCode, buf, buf_sz);
+ buf[buf_sz-1]= 0;
+
+ return buf;
+}
+
+void
+MgmtSrvr::handleReceivedSignal(NdbApiSignal* signal)
+{
+ // The way of handling a received signal is taken from the Ndb class.
+ int gsn = signal->readSignalNumber();
+
+ switch (gsn) {
+ case GSN_EVENT_SUBSCRIBE_CONF:
+ break;
+ case GSN_EVENT_SUBSCRIBE_REF:
+ break;
+ case GSN_EVENT_REP:
+ {
+ eventReport(signal->getDataPtr());
+ break;
+ }
+
+ case GSN_NF_COMPLETEREP:
+ break;
+ case GSN_NODE_FAILREP:
+ break;
+
+ default:
+ g_eventLogger.error("Unknown signal received. SignalNumber: "
+ "%i from (%d, %x)",
+ gsn,
+ refToNode(signal->theSendersBlockRef),
+ refToBlock(signal->theSendersBlockRef));
+ }
+
+ if (theWaitState == NO_WAIT) {
+ NdbCondition_Signal(theMgmtWaitForResponseCondPtr);
+ }
+}
+
+void
+MgmtSrvr::handleStatus(NodeId nodeId, bool alive, bool nfComplete)
+{
+ DBUG_ENTER("MgmtSrvr::handleStatus");
+ Uint32 theData[25];
+ EventReport *rep = (EventReport *)theData;
+
+ theData[1] = nodeId;
+ if (alive) {
+ m_started_nodes.push_back(nodeId);
+ rep->setEventType(NDB_LE_Connected);
+ } else {
+ rep->setEventType(NDB_LE_Connected);
+ if(nfComplete)
+ {
+ DBUG_VOID_RETURN;
+ }
+ }
+ rep->setNodeId(_ownNodeId);
+ eventReport(theData);
+ DBUG_VOID_RETURN;
+}
+
+//****************************************************************************
+//****************************************************************************
+
+void
+MgmtSrvr::signalReceivedNotification(void* mgmtSrvr,
+ NdbApiSignal* signal,
+ LinearSectionPtr ptr[3])
+{
+ ((MgmtSrvr*)mgmtSrvr)->handleReceivedSignal(signal);
+}
+
+
+//****************************************************************************
+//****************************************************************************
+void
+MgmtSrvr::nodeStatusNotification(void* mgmSrv, Uint32 nodeId,
+ bool alive, bool nfComplete)
+{
+ DBUG_ENTER("MgmtSrvr::nodeStatusNotification");
+ DBUG_PRINT("enter",("nodeid= %d, alive= %d, nfComplete= %d", nodeId, alive, nfComplete));
+ ((MgmtSrvr*)mgmSrv)->handleStatus(nodeId, alive, nfComplete);
+ DBUG_VOID_RETURN;
+}
+
+enum ndb_mgm_node_type
+MgmtSrvr::getNodeType(NodeId nodeId) const
+{
+ if(nodeId >= MAX_NODES)
+ return (enum ndb_mgm_node_type)-1;
+
+ return nodeTypes[nodeId];
+}
+
+const char *MgmtSrvr::get_connect_address(Uint32 node_id)
+{
+ if (m_connect_address[node_id].s_addr == 0 &&
+ theFacade && theFacade->theTransporterRegistry &&
+ theFacade->theClusterMgr &&
+ getNodeType(node_id) == NDB_MGM_NODE_TYPE_NDB)
+ {
+ const ClusterMgr::Node &node=
+ theFacade->theClusterMgr->getNodeInfo(node_id);
+ if (node.connected)
+ {
+ m_connect_address[node_id]=
+ theFacade->theTransporterRegistry->get_connect_address(node_id);
+ }
+ }
+ return inet_ntoa(m_connect_address[node_id]);
+}
+
+void
+MgmtSrvr::get_connected_nodes(NodeBitmask &connected_nodes) const
+{
+ if (theFacade && theFacade->theClusterMgr)
+ {
+ for(Uint32 i = 0; i < MAX_NODES; i++)
+ {
+ if (getNodeType(i) == NDB_MGM_NODE_TYPE_NDB)
+ {
+ const ClusterMgr::Node &node= theFacade->theClusterMgr->getNodeInfo(i);
+ connected_nodes.bitOR(node.m_state.m_connected_nodes);
+ }
+ }
+ }
+}
+
+int
+MgmtSrvr::alloc_node_id_req(NodeId free_node_id, enum ndb_mgm_node_type type)
+{
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
+ SimpleSignal ssig;
+ AllocNodeIdReq* req = CAST_PTR(AllocNodeIdReq, ssig.getDataPtrSend());
+ ssig.set(ss, TestOrd::TraceAPI, QMGR, GSN_ALLOC_NODEID_REQ,
+ AllocNodeIdReq::SignalLength);
+
+ req->senderRef = ss.getOwnRef();
+ req->senderData = 19;
+ req->nodeId = free_node_id;
+ req->nodeType = type;
+
+ int do_send = 1;
+ NodeId nodeId = 0;
+ while (1)
+ {
+ if (nodeId == 0)
+ {
+ bool next;
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ theFacade->get_node_alive(nodeId) == false);
+ if (!next)
+ return NO_CONTACT_WITH_DB_NODES;
+ do_send = 1;
+ }
+ if (do_send)
+ {
+ if (ss.sendSignal(nodeId, &ssig) != SEND_OK) {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ do_send = 0;
+ }
+
+ SimpleSignal *signal = ss.waitFor();
+
+ int gsn = signal->readSignalNumber();
+ switch (gsn) {
+ case GSN_ALLOC_NODEID_CONF:
+ {
+ const AllocNodeIdConf * const conf =
+ CAST_CONSTPTR(AllocNodeIdConf, signal->getDataPtr());
+ return 0;
+ }
+ case GSN_ALLOC_NODEID_REF:
+ {
+ const AllocNodeIdRef * const ref =
+ CAST_CONSTPTR(AllocNodeIdRef, signal->getDataPtr());
+ if (ref->errorCode == AllocNodeIdRef::NotMaster ||
+ ref->errorCode == AllocNodeIdRef::Busy)
+ {
+ do_send = 1;
+ nodeId = refToNode(ref->masterRef);
+ continue;
+ }
+ return ref->errorCode;
+ }
+ case GSN_NF_COMPLETEREP:
+ {
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Node %d fail completed", rep->failedNodeId);
+#endif
+ if (rep->failedNodeId == nodeId)
+ {
+ do_send = 1;
+ nodeId = 0;
+ }
+ continue;
+ }
+ case GSN_NODE_FAILREP:{
+ // ignore NF_COMPLETEREP will come
+ continue;
+ }
+ default:
+ report_unknown_signal(signal);
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ }
+ return 0;
+}
+
+bool
+MgmtSrvr::alloc_node_id(NodeId * nodeId,
+ enum ndb_mgm_node_type type,
+ struct sockaddr *client_addr,
+ SOCKET_SIZE_TYPE *client_addr_len,
+ int &error_code, BaseString &error_string,
+ int log_event)
+{
+ DBUG_ENTER("MgmtSrvr::alloc_node_id");
+ DBUG_PRINT("enter", ("nodeid: %d type: %d client_addr: 0x%ld",
+ *nodeId, type, (long) client_addr));
+ if (g_no_nodeid_checks) {
+ if (*nodeId == 0) {
+ error_string.appfmt("no-nodeid-checks set in management server.\n"
+ "node id must be set explicitly in connectstring");
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ DBUG_RETURN(false);
+ }
+ DBUG_RETURN(true);
+ }
+ Guard g(m_node_id_mutex);
+ int no_mgm= 0;
+ NodeBitmask connected_nodes(m_reserved_nodes);
+ get_connected_nodes(connected_nodes);
+ {
+ for(Uint32 i = 0; i < MAX_NODES; i++)
+ if (getNodeType(i) == NDB_MGM_NODE_TYPE_MGM)
+ no_mgm++;
+ }
+ bool found_matching_id= false;
+ bool found_matching_type= false;
+ bool found_free_node= false;
+ unsigned id_found= 0;
+ const char *config_hostname= 0;
+ struct in_addr config_addr= {0};
+ int r_config_addr= -1;
+ unsigned type_c= 0;
+
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ // should not happen
+ error_string.appfmt("unable to lock configuration mutex");
+ error_code = NDB_MGM_ALLOCID_ERROR;
+ DBUG_RETURN(false);
+ }
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+ for(iter.first(); iter.valid(); iter.next()) {
+ unsigned tmp= 0;
+ if(iter.get(CFG_NODE_ID, &tmp)) require(false);
+ if (*nodeId && *nodeId != tmp)
+ continue;
+ found_matching_id= true;
+ if(iter.get(CFG_TYPE_OF_SECTION, &type_c)) require(false);
+ if(type_c != (unsigned)type)
+ continue;
+ found_matching_type= true;
+ if (connected_nodes.get(tmp))
+ continue;
+ found_free_node= true;
+ if(iter.get(CFG_NODE_HOST, &config_hostname)) require(false);
+ if (config_hostname && config_hostname[0] == 0)
+ config_hostname= 0;
+ else if (client_addr) {
+ // check hostname compatability
+ const void *tmp_in= &(((sockaddr_in*)client_addr)->sin_addr);
+ if((r_config_addr= Ndb_getInAddr(&config_addr, config_hostname)) != 0
+ || memcmp(&config_addr, tmp_in, sizeof(config_addr)) != 0) {
+ struct in_addr tmp_addr;
+ if(Ndb_getInAddr(&tmp_addr, "localhost") != 0
+ || memcmp(&tmp_addr, tmp_in, sizeof(config_addr)) != 0) {
+ // not localhost
+#if 0
+ ndbout << "MgmtSrvr::getFreeNodeId compare failed for \""
+ << config_hostname
+ << "\" id=" << tmp << endl;
+#endif
+ continue;
+ }
+ // connecting through localhost
+ // check if config_hostname is local
+ if (!SocketServer::tryBind(0,config_hostname)) {
+ continue;
+ }
+ }
+ } else { // client_addr == 0
+ if (!SocketServer::tryBind(0,config_hostname)) {
+ continue;
+ }
+ }
+ if (*nodeId != 0 ||
+ type != NDB_MGM_NODE_TYPE_MGM ||
+ no_mgm == 1) { // any match is ok
+
+ if (config_hostname == 0 &&
+ *nodeId == 0 &&
+ type != NDB_MGM_NODE_TYPE_MGM)
+ {
+ if (!id_found) // only set if not set earlier
+ id_found= tmp;
+ continue; /* continue looking for a nodeid with specified
+ * hostname
+ */
+ }
+ assert(id_found == 0);
+ id_found= tmp;
+ break;
+ }
+ if (id_found) { // mgmt server may only have one match
+ error_string.appfmt("Ambiguous node id's %d and %d.\n"
+ "Suggest specifying node id in connectstring,\n"
+ "or specifying unique host names in config file.",
+ id_found, tmp);
+ NdbMutex_Unlock(m_configMutex);
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ DBUG_RETURN(false);
+ }
+ if (config_hostname == 0) {
+ error_string.appfmt("Ambiguity for node id %d.\n"
+ "Suggest specifying node id in connectstring,\n"
+ "or specifying unique host names in config file,\n"
+ "or specifying just one mgmt server in config file.",
+ tmp);
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ DBUG_RETURN(false);
+ }
+ id_found= tmp; // mgmt server matched, check for more matches
+ }
+ NdbMutex_Unlock(m_configMutex);
+
+ if (id_found && client_addr != 0)
+ {
+ int res = alloc_node_id_req(id_found, type);
+ unsigned save_id_found = id_found;
+ switch (res)
+ {
+ case 0:
+ // ok continue
+ break;
+ case NO_CONTACT_WITH_DB_NODES:
+ // ok continue
+ break;
+ default:
+ // something wrong
+ id_found = 0;
+ break;
+
+ }
+ if (id_found == 0)
+ {
+ char buf[128];
+ ndb_error_string(res, buf, sizeof(buf));
+ error_string.appfmt("Cluster refused allocation of id %d. Error: %d (%s).",
+ save_id_found, res, buf);
+ g_eventLogger.warning("Cluster refused allocation of id %d. "
+ "Connection from ip %s. "
+ "Returned error string \"%s\"", save_id_found,
+ inet_ntoa(((struct sockaddr_in *)(client_addr))->sin_addr),
+ error_string.c_str());
+ DBUG_RETURN(false);
+ }
+ }
+
+ if (id_found)
+ {
+ *nodeId= id_found;
+ DBUG_PRINT("info", ("allocating node id %d",*nodeId));
+ {
+ int r= 0;
+ if (client_addr)
+ m_connect_address[id_found]=
+ ((struct sockaddr_in *)client_addr)->sin_addr;
+ else if (config_hostname)
+ r= Ndb_getInAddr(&(m_connect_address[id_found]), config_hostname);
+ else {
+ char name[256];
+ r= gethostname(name, sizeof(name));
+ if (r == 0) {
+ name[sizeof(name)-1]= 0;
+ r= Ndb_getInAddr(&(m_connect_address[id_found]), name);
+ }
+ }
+ if (r)
+ m_connect_address[id_found].s_addr= 0;
+ }
+ m_reserved_nodes.set(id_found);
+ if (theFacade && id_found != theFacade->ownId())
+ {
+ /**
+ * Make sure we're ready to accept connections from this node
+ */
+ theFacade->lock_mutex();
+ theFacade->doConnect(id_found);
+ theFacade->unlock_mutex();
+ }
+
+ char tmp_str[128];
+ m_reserved_nodes.getText(tmp_str);
+ g_eventLogger.info("Mgmt server state: nodeid %d reserved for ip %s, "
+ "m_reserved_nodes %s.",
+ id_found, get_connect_address(id_found), tmp_str);
+ DBUG_RETURN(true);
+ }
+
+ if (found_matching_type && !found_free_node) {
+ // we have a temporary error which might be due to that
+ // we have got the latest connect status from db-nodes. Force update.
+ updateStatus();
+ }
+
+ BaseString type_string, type_c_string;
+ {
+ const char *alias, *str;
+ alias= ndb_mgm_get_node_type_alias_string(type, &str);
+ type_string.assfmt("%s(%s)", alias, str);
+ alias= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)type_c,
+ &str);
+ type_c_string.assfmt("%s(%s)", alias, str);
+ }
+
+ if (*nodeId == 0)
+ {
+ if (found_matching_id)
+ {
+ if (found_matching_type)
+ {
+ if (found_free_node)
+ {
+ error_string.appfmt("Connection done from wrong host ip %s.",
+ (client_addr)?
+ inet_ntoa(((struct sockaddr_in *)
+ (client_addr))->sin_addr):"");
+ error_code = NDB_MGM_ALLOCID_ERROR;
+ }
+ else
+ {
+ error_string.appfmt("No free node id found for %s.",
+ type_string.c_str());
+ error_code = NDB_MGM_ALLOCID_ERROR;
+ }
+ }
+ else
+ {
+ error_string.appfmt("No %s node defined in config file.",
+ type_string.c_str());
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ }
+ }
+ else
+ {
+ error_string.append("No nodes defined in config file.");
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ }
+ }
+ else
+ {
+ if (found_matching_id)
+ {
+ if (found_matching_type)
+ {
+ if (found_free_node)
+ {
+ // have to split these into two since inet_ntoa overwrites itself
+ error_string.appfmt("Connection with id %d done from wrong host ip %s,",
+ *nodeId, inet_ntoa(((struct sockaddr_in *)
+ (client_addr))->sin_addr));
+ error_string.appfmt(" expected %s(%s).", config_hostname,
+ r_config_addr ?
+ "lookup failed" : inet_ntoa(config_addr));
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ }
+ else
+ {
+ error_string.appfmt("Id %d already allocated by another node.",
+ *nodeId);
+ error_code = NDB_MGM_ALLOCID_ERROR;
+ }
+ }
+ else
+ {
+ error_string.appfmt("Id %d configured as %s, connect attempted as %s.",
+ *nodeId, type_c_string.c_str(),
+ type_string.c_str());
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ }
+ }
+ else
+ {
+ error_string.appfmt("No node defined with id=%d in config file.",
+ *nodeId);
+ error_code = NDB_MGM_ALLOCID_CONFIG_MISMATCH;
+ }
+ }
+
+ if (log_event || error_code == NDB_MGM_ALLOCID_CONFIG_MISMATCH)
+ {
+ g_eventLogger.warning("Allocate nodeid (%d) failed. Connection from ip %s."
+ " Returned error string \"%s\"",
+ *nodeId,
+ client_addr != 0
+ ? inet_ntoa(((struct sockaddr_in *)
+ (client_addr))->sin_addr)
+ : "<none>",
+ error_string.c_str());
+
+ NodeBitmask connected_nodes2;
+ get_connected_nodes(connected_nodes2);
+ BaseString tmp_connected, tmp_not_connected;
+ for(Uint32 i = 0; i < MAX_NODES; i++)
+ {
+ if (connected_nodes2.get(i))
+ {
+ if (!m_reserved_nodes.get(i))
+ tmp_connected.appfmt(" %d", i);
+ }
+ else if (m_reserved_nodes.get(i))
+ {
+ tmp_not_connected.appfmt(" %d", i);
+ }
+ }
+ if (tmp_connected.length() > 0)
+ g_eventLogger.info("Mgmt server state: node id's %s connected but not reserved",
+ tmp_connected.c_str());
+ if (tmp_not_connected.length() > 0)
+ g_eventLogger.info("Mgmt server state: node id's %s not connected but reserved",
+ tmp_not_connected.c_str());
+ }
+ DBUG_RETURN(false);
+}
+
+bool
+MgmtSrvr::getNextNodeId(NodeId * nodeId, enum ndb_mgm_node_type type) const
+{
+ NodeId tmp = * nodeId;
+
+ tmp++;
+ while(nodeTypes[tmp] != type && tmp < MAX_NODES)
+ tmp++;
+
+ if(tmp == MAX_NODES){
+ return false;
+ }
+
+ * nodeId = tmp;
+ return true;
+}
+
+#include "Services.hpp"
+
+void
+MgmtSrvr::eventReport(const Uint32 * theData)
+{
+ const EventReport * const eventReport = (EventReport *)&theData[0];
+
+ NodeId nodeId = eventReport->getNodeId();
+ Ndb_logevent_type type = eventReport->getEventType();
+ // Log event
+ g_eventLogger.log(type, theData, nodeId,
+ &m_event_listner[0].m_logLevel);
+ m_event_listner.log(type, theData, nodeId);
+}
+
+/***************************************************************************
+ * Backup
+ ***************************************************************************/
+
+int
+MgmtSrvr::startBackup(Uint32& backupId, int waitCompleted)
+{
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
+ NodeId nodeId = m_master_node;
+ if (okToSendTo(nodeId, false) != 0)
+ {
+ bool next;
+ nodeId = m_master_node = 0;
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ okToSendTo(nodeId, false) != 0);
+ if(!next)
+ return NO_CONTACT_WITH_DB_NODES;
+ }
+
+ SimpleSignal ssig;
+ BackupReq* req = CAST_PTR(BackupReq, ssig.getDataPtrSend());
+ ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_BACKUP_REQ,
+ BackupReq::SignalLength);
+
+ req->senderData = 19;
+ req->backupDataLen = 0;
+ assert(waitCompleted < 3);
+ req->flags = waitCompleted & 0x3;
+
+ BackupEvent event;
+ int do_send = 1;
+ while (1) {
+ if (do_send)
+ {
+ if (ss.sendSignal(nodeId, &ssig) != SEND_OK) {
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ if (waitCompleted == 0)
+ return 0;
+ do_send = 0;
+ }
+ SimpleSignal *signal = ss.waitFor();
+
+ int gsn = signal->readSignalNumber();
+ switch (gsn) {
+ case GSN_BACKUP_CONF:{
+ const BackupConf * const conf =
+ CAST_CONSTPTR(BackupConf, signal->getDataPtr());
+ event.Event = BackupEvent::BackupStarted;
+ event.Started.BackupId = conf->backupId;
+ event.Nodes = conf->nodes;
+#ifdef VM_TRACE
+ ndbout_c("Backup(%d) master is %d", conf->backupId,
+ refToNode(signal->header.theSendersBlockRef));
+#endif
+ backupId = conf->backupId;
+ if (waitCompleted == 1)
+ return 0;
+ // wait for next signal
+ break;
+ }
+ case GSN_BACKUP_COMPLETE_REP:{
+ const BackupCompleteRep * const rep =
+ CAST_CONSTPTR(BackupCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Backup(%d) completed", rep->backupId);
+#endif
+ event.Event = BackupEvent::BackupCompleted;
+ event.Completed.BackupId = rep->backupId;
+
+ event.Completed.NoOfBytes = rep->noOfBytesLow;
+ event.Completed.NoOfLogBytes = rep->noOfLogBytes;
+ event.Completed.NoOfRecords = rep->noOfRecordsLow;
+ event.Completed.NoOfLogRecords = rep->noOfLogRecords;
+ event.Completed.stopGCP = rep->stopGCP;
+ event.Completed.startGCP = rep->startGCP;
+ event.Nodes = rep->nodes;
+
+ if (signal->header.theLength >= BackupCompleteRep::SignalLength)
+ {
+ event.Completed.NoOfBytes += ((Uint64)rep->noOfBytesHigh) << 32;
+ event.Completed.NoOfRecords += ((Uint64)rep->noOfRecordsHigh) << 32;
+ }
+
+ backupId = rep->backupId;
+ return 0;
+ }
+ case GSN_BACKUP_REF:{
+ const BackupRef * const ref =
+ CAST_CONSTPTR(BackupRef, signal->getDataPtr());
+ if(ref->errorCode == BackupRef::IAmNotMaster){
+ m_master_node = nodeId = refToNode(ref->masterRef);
+#ifdef VM_TRACE
+ ndbout_c("I'm not master resending to %d", nodeId);
+#endif
+ do_send = 1; // try again
+ continue;
+ }
+ event.Event = BackupEvent::BackupFailedToStart;
+ event.FailedToStart.ErrorCode = ref->errorCode;
+ return ref->errorCode;
+ }
+ case GSN_BACKUP_ABORT_REP:{
+ const BackupAbortRep * const rep =
+ CAST_CONSTPTR(BackupAbortRep, signal->getDataPtr());
+ event.Event = BackupEvent::BackupAborted;
+ event.Aborted.Reason = rep->reason;
+ event.Aborted.BackupId = rep->backupId;
+ event.Aborted.ErrorCode = rep->reason;
+#ifdef VM_TRACE
+ ndbout_c("Backup %d aborted", rep->backupId);
+#endif
+ return rep->reason;
+ }
+ case GSN_NF_COMPLETEREP:{
+ const NFCompleteRep * const rep =
+ CAST_CONSTPTR(NFCompleteRep, signal->getDataPtr());
+#ifdef VM_TRACE
+ ndbout_c("Node %d fail completed", rep->failedNodeId);
+#endif
+ if (rep->failedNodeId == nodeId ||
+ waitCompleted == 1)
+ return 1326;
+ // wait for next signal
+ // master node will report aborted backup
+ break;
+ }
+ case GSN_NODE_FAILREP:{
+ const NodeFailRep * const rep =
+ CAST_CONSTPTR(NodeFailRep, signal->getDataPtr());
+ if (NodeBitmask::get(rep->theNodes,nodeId) ||
+ waitCompleted == 1)
+ return 1326;
+ // wait for next signal
+ // master node will report aborted backup
+ break;
+ }
+ default:
+ report_unknown_signal(signal);
+ return SEND_OR_RECEIVE_FAILED;
+ }
+ }
+}
+
+int
+MgmtSrvr::abortBackup(Uint32 backupId)
+{
+ SignalSender ss(theFacade);
+ ss.lock(); // lock will be released on exit
+
+ bool next;
+ NodeId nodeId = 0;
+ while((next = getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)) == true &&
+ theFacade->get_node_alive(nodeId) == false);
+
+ if(!next){
+ return NO_CONTACT_WITH_DB_NODES;
+ }
+
+ SimpleSignal ssig;
+
+ AbortBackupOrd* ord = CAST_PTR(AbortBackupOrd, ssig.getDataPtrSend());
+ ssig.set(ss, TestOrd::TraceAPI, BACKUP, GSN_ABORT_BACKUP_ORD,
+ AbortBackupOrd::SignalLength);
+
+ ord->requestType = AbortBackupOrd::ClientAbort;
+ ord->senderData = 19;
+ ord->backupId = backupId;
+
+ return ss.sendSignal(nodeId, &ssig) == SEND_OK ? 0 : SEND_OR_RECEIVE_FAILED;
+}
+
+
+MgmtSrvr::Allocated_resources::Allocated_resources(MgmtSrvr &m)
+ : m_mgmsrv(m)
+{
+ m_reserved_nodes.clear();
+ m_alloc_timeout= 0;
+}
+
+MgmtSrvr::Allocated_resources::~Allocated_resources()
+{
+ Guard g(m_mgmsrv.m_node_id_mutex);
+ if (!m_reserved_nodes.isclear()) {
+ m_mgmsrv.m_reserved_nodes.bitANDC(m_reserved_nodes);
+ // node has been reserved, force update signal to ndb nodes
+ m_mgmsrv.updateStatus();
+
+ char tmp_str[128];
+ m_mgmsrv.m_reserved_nodes.getText(tmp_str);
+ g_eventLogger.info("Mgmt server state: nodeid %d freed, m_reserved_nodes %s.",
+ get_nodeid(), tmp_str);
+ }
+}
+
+void
+MgmtSrvr::Allocated_resources::reserve_node(NodeId id, NDB_TICKS timeout)
+{
+ m_reserved_nodes.set(id);
+ m_alloc_timeout= NdbTick_CurrentMillisecond() + timeout;
+}
+
+bool
+MgmtSrvr::Allocated_resources::is_timed_out(NDB_TICKS tick)
+{
+ if (m_alloc_timeout && tick > m_alloc_timeout)
+ {
+ g_eventLogger.info("Mgmt server state: nodeid %d timed out.",
+ get_nodeid());
+ return true;
+ }
+ return false;
+}
+
+NodeId
+MgmtSrvr::Allocated_resources::get_nodeid() const
+{
+ for(Uint32 i = 0; i < MAX_NODES; i++)
+ {
+ if (m_reserved_nodes.get(i))
+ return i;
+ }
+ return 0;
+}
+
+int
+MgmtSrvr::setDbParameter(int node, int param, const char * value,
+ BaseString& msg){
+
+ if(NdbMutex_Lock(m_configMutex))
+ return -1;
+
+ /**
+ * Check parameter
+ */
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_NODE);
+ if(iter.first() != 0){
+ msg.assign("Unable to find node section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ }
+
+ Uint32 type = NODE_TYPE_DB + 1;
+ if(node != 0){
+ if(iter.find(CFG_NODE_ID, node) != 0){
+ msg.assign("Unable to find node (iter.find())");
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ }
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
+ msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ }
+ } else {
+ do {
+ if(iter.get(CFG_TYPE_OF_SECTION, &type) != 0){
+ msg.assign("Unable to get node type(iter.get(CFG_TYPE_OF_SECTION))");
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ }
+ if(type == NODE_TYPE_DB)
+ break;
+ } while(iter.next() == 0);
+ }
+
+ if(type != NODE_TYPE_DB){
+ msg.assfmt("Invalid node type or no such node (%d %d)",
+ type, NODE_TYPE_DB);
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ }
+
+ int p_type;
+ unsigned val_32;
+ Uint64 val_64;
+ const char * val_char;
+ do {
+ p_type = 0;
+ if(iter.get(param, &val_32) == 0){
+ val_32 = atoi(value);
+ break;
+ }
+
+ p_type++;
+ if(iter.get(param, &val_64) == 0){
+ val_64 = strtoll(value, 0, 10);
+ break;
+ }
+ p_type++;
+ if(iter.get(param, &val_char) == 0){
+ val_char = value;
+ break;
+ }
+ msg.assign("Could not get parameter");
+ NdbMutex_Unlock(m_configMutex);
+ return -1;
+ } while(0);
+
+ bool res = false;
+ do {
+ int ret = iter.get(CFG_TYPE_OF_SECTION, &type);
+ assert(ret == 0);
+
+ if(type != NODE_TYPE_DB)
+ continue;
+
+ Uint32 node;
+ ret = iter.get(CFG_NODE_ID, &node);
+ assert(ret == 0);
+
+ ConfigValues::Iterator i2(_config->m_configValues->m_config,
+ iter.m_config);
+ switch(p_type){
+ case 0:
+ res = i2.set(param, val_32);
+ ndbout_c("Updating node %d param: %d to %d", node, param, val_32);
+ break;
+ case 1:
+ res = i2.set(param, val_64);
+ ndbout_c("Updating node %d param: %d to %u", node, param, val_32);
+ break;
+ case 2:
+ res = i2.set(param, val_char);
+ ndbout_c("Updating node %d param: %d to %s", node, param, val_char);
+ break;
+ default:
+ require(false);
+ }
+ assert(res);
+ } while(node == 0 && iter.next() == 0);
+
+ msg.assign("Success");
+ NdbMutex_Unlock(m_configMutex);
+ return 0;
+}
+int
+MgmtSrvr::setConnectionDbParameter(int node1,
+ int node2,
+ int param,
+ int value,
+ BaseString& msg){
+ Uint32 current_value,new_value;
+
+ DBUG_ENTER("MgmtSrvr::setConnectionDbParameter");
+
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ DBUG_RETURN(-1);
+ }
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+
+ if(iter.first() != 0){
+ msg.assign("Unable to find connection section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ for(;iter.valid();iter.next()) {
+ Uint32 n1,n2;
+ iter.get(CFG_CONNECTION_NODE_1, &n1);
+ iter.get(CFG_CONNECTION_NODE_2, &n2);
+ if((n1 == (unsigned)node1 && n2 == (unsigned)node2)
+ || (n1 == (unsigned)node2 && n2 == (unsigned)node1))
+ break;
+ }
+ if(!iter.valid()) {
+ msg.assign("Unable to find connection between nodes");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-2);
+ }
+
+ if(iter.get(param, &current_value) != 0) {
+ msg.assign("Unable to get current value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-3);
+ }
+
+ ConfigValues::Iterator i2(_config->m_configValues->m_config,
+ iter.m_config);
+
+ if(i2.set(param, (unsigned)value) == false) {
+ msg.assign("Unable to set new value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-4);
+ }
+
+ if(iter.get(param, &new_value) != 0) {
+ msg.assign("Unable to get parameter after setting it.");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-5);
+ }
+
+ msg.assfmt("%u -> %u",current_value,new_value);
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(1);
+}
+
+
+int
+MgmtSrvr::getConnectionDbParameter(int node1,
+ int node2,
+ int param,
+ int *value,
+ BaseString& msg){
+ DBUG_ENTER("MgmtSrvr::getConnectionDbParameter");
+
+ if(NdbMutex_Lock(m_configMutex))
+ {
+ DBUG_RETURN(-1);
+ }
+
+ ndb_mgm_configuration_iterator
+ iter(* _config->m_configValues, CFG_SECTION_CONNECTION);
+
+ if(iter.first() != 0){
+ msg.assign("Unable to find connection section (iter.first())");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ for(;iter.valid();iter.next()) {
+ Uint32 n1=0,n2=0;
+ iter.get(CFG_CONNECTION_NODE_1, &n1);
+ iter.get(CFG_CONNECTION_NODE_2, &n2);
+ if((n1 == (unsigned)node1 && n2 == (unsigned)node2)
+ || (n1 == (unsigned)node2 && n2 == (unsigned)node1))
+ break;
+ }
+ if(!iter.valid()) {
+ msg.assign("Unable to find connection between nodes");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ if(iter.get(param, (Uint32*)value) != 0) {
+ msg.assign("Unable to get current value of parameter");
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(-1);
+ }
+
+ msg.assfmt("%d",*value);
+ NdbMutex_Unlock(m_configMutex);
+ DBUG_RETURN(1);
+}
+
+void MgmtSrvr::transporter_connect(NDB_SOCKET_TYPE sockfd)
+{
+ if (theFacade->get_registry()->connect_server(sockfd))
+ {
+ /**
+ * Force an update_connections() so that the
+ * ClusterMgr and TransporterFacade is up to date
+ * with the new connection.
+ * Important for correct node id reservation handling
+ */
+ NdbMutex_Lock(theFacade->theMutexPtr);
+ theFacade->get_registry()->update_connections();
+ NdbMutex_Unlock(theFacade->theMutexPtr);
+ }
+}
+
+int MgmtSrvr::connect_to_self(void)
+{
+ int r= 0;
+ m_local_mgm_handle= ndb_mgm_create_handle();
+ snprintf(m_local_mgm_connect_string,sizeof(m_local_mgm_connect_string),
+ "localhost:%u",getPort());
+ ndb_mgm_set_connectstring(m_local_mgm_handle, m_local_mgm_connect_string);
+
+ if((r= ndb_mgm_connect(m_local_mgm_handle, 0, 0, 0)) < 0)
+ {
+ ndb_mgm_destroy_handle(&m_local_mgm_handle);
+ return r;
+ }
+ // TransporterRegistry now owns this NdbMgmHandle and will destroy it.
+ theFacade->get_registry()->set_mgm_handle(m_local_mgm_handle);
+
+ return 0;
+}
+
+
+
+template class MutexVector<unsigned short>;
+template class MutexVector<Ndb_mgmd_event_service::Event_listener>;
+template class MutexVector<EventSubscribeReq>;
diff --git a/storage/ndb/src/mgmsrv/MgmtSrvr.hpp b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp
new file mode 100644
index 00000000000..5eee7447c98
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.hpp
@@ -0,0 +1,683 @@
+/* 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 */
+
+#ifndef MgmtSrvr_H
+#define MgmtSrvr_H
+
+#include <kernel_types.h>
+#include "Config.hpp"
+#include <NdbCondition.h>
+#include <mgmapi.h>
+
+#include <NdbTCP.h>
+#include <ConfigRetriever.hpp>
+#include <Vector.hpp>
+#include <NodeBitmask.hpp>
+#include <signaldata/ManagementServer.hpp>
+#include <ndb_version.h>
+#include <EventLogger.hpp>
+#include <signaldata/EventSubscribeReq.hpp>
+
+#include <SignalSender.hpp>
+
+/**
+ * @desc Block number for Management server.
+ * @todo This should probably be somewhere else. I don't know where atm.
+ */
+#define MGMSRV 1
+
+class ConfigInfoServer;
+class NdbApiSignal;
+class Config;
+class SetLogLevelOrd;
+class SocketServer;
+
+class Ndb_mgmd_event_service : public EventLoggerBase
+{
+ friend class MgmtSrvr;
+public:
+ struct Event_listener : public EventLoggerBase {
+ NDB_SOCKET_TYPE m_socket;
+ Uint32 m_parsable;
+ };
+
+private:
+ class MgmtSrvr * m_mgmsrv;
+ MutexVector<Event_listener> m_clients;
+public:
+ Ndb_mgmd_event_service(class MgmtSrvr * m) : m_clients(5) {
+ m_mgmsrv = m;
+ }
+
+ void add_listener(const Event_listener&);
+ void check_listeners();
+ void update_max_log_level(const LogLevel&);
+ void update_log_level(const LogLevel&);
+
+ void log(int eventType, const Uint32* theData, NodeId nodeId);
+
+ void stop_sessions();
+
+ Event_listener& operator[](unsigned i) { return m_clients[i]; }
+ const Event_listener& operator[](unsigned i) const { return m_clients[i]; }
+ void lock() { m_clients.lock(); }
+ void unlock(){ m_clients.unlock(); }
+};
+
+/**
+ * @class MgmtSrvr
+ * @brief Main class for the management server.
+ *
+ * It has one interface to be used by a local client.
+ * With the methods it's possible to send different kind of commands to
+ * DB processes, as log level, set trace number etc.
+ *
+ * A MgmtSrvr creates a ConfigInfoServer which serves request on TCP sockets.
+ * The requests come typical from DB and API processes which want
+ * to fetch its configuration parameters. The MgmtSrvr knows about the
+ * configuration by reading a configuration file.
+ *
+ * The MgmtSrvr class corresponds in some ways to the Ndb class in API.
+ * It creates a TransporterFacade, receives signals and defines signals
+ * to send and receive.
+ */
+class MgmtSrvr {
+
+public:
+ // some compilers need all of this
+ class Allocated_resources;
+ friend class Allocated_resources;
+ class Allocated_resources {
+ public:
+ Allocated_resources(class MgmtSrvr &m);
+ ~Allocated_resources();
+ // methods to reserve/allocate resources which
+ // will be freed when running destructor
+ void reserve_node(NodeId id, NDB_TICKS timeout);
+ bool is_timed_out(NDB_TICKS tick);
+ bool is_reserved(NodeId nodeId) { return m_reserved_nodes.get(nodeId); }
+ bool is_reserved(NodeBitmask mask) { return !mask.bitAND(m_reserved_nodes).isclear(); }
+ bool isclear() { return m_reserved_nodes.isclear(); }
+ NodeId get_nodeid() const;
+ private:
+ MgmtSrvr &m_mgmsrv;
+ NodeBitmask m_reserved_nodes;
+ NDB_TICKS m_alloc_timeout;
+ };
+ NdbMutex *m_node_id_mutex;
+
+ /**
+ * Start/initate the event log.
+ */
+ void startEventLog();
+
+ /**
+ * Stop the event log.
+ */
+ void stopEventLog();
+
+ /**
+ * Enable/disable eventlog log levels/severities.
+ *
+ * @param serverity the log level/serverity.
+ * @return true if the severity was enabled.
+ */
+ bool setEventLogFilter(int severity, int enable);
+
+ /**
+ * Returns true if the log level/severity is enabled.
+ *
+ * @param severity the severity level.
+ */
+ bool isEventLogFilterEnabled(int severity);
+
+ STATIC_CONST( NO_CONTACT_WITH_PROCESS = 5000 );
+ STATIC_CONST( PROCESS_NOT_CONFIGURED = 5001 );
+ STATIC_CONST( WRONG_PROCESS_TYPE = 5002 );
+ STATIC_CONST( COULD_NOT_ALLOCATE_MEMORY = 5003 );
+ STATIC_CONST( SEND_OR_RECEIVE_FAILED = 5005 );
+ STATIC_CONST( INVALID_LEVEL = 5006 );
+ STATIC_CONST( INVALID_ERROR_NUMBER = 5007 );
+ STATIC_CONST( INVALID_TRACE_NUMBER = 5008 );
+ STATIC_CONST( NOT_IMPLEMENTED = 5009 );
+ STATIC_CONST( INVALID_BLOCK_NAME = 5010 );
+
+ STATIC_CONST( CONFIG_PARAM_NOT_EXIST = 5011 );
+ STATIC_CONST( CONFIG_PARAM_NOT_UPDATEABLE = 5012 );
+ STATIC_CONST( VALUE_WRONG_FORMAT_INT_EXPECTED = 5013 );
+ STATIC_CONST( VALUE_TOO_LOW = 5014 );
+ STATIC_CONST( VALUE_TOO_HIGH = 5015 );
+ STATIC_CONST( VALUE_WRONG_FORMAT_BOOL_EXPECTED = 5016 );
+
+ STATIC_CONST( CONFIG_FILE_OPEN_WRITE_ERROR = 5017 );
+ STATIC_CONST( CONFIG_FILE_OPEN_READ_ERROR = 5018 );
+ STATIC_CONST( CONFIG_FILE_WRITE_ERROR = 5019 );
+ STATIC_CONST( CONFIG_FILE_READ_ERROR = 5020 );
+ STATIC_CONST( CONFIG_FILE_CLOSE_ERROR = 5021 );
+
+ STATIC_CONST( CONFIG_CHANGE_REFUSED_BY_RECEIVER = 5022 );
+ STATIC_CONST( COULD_NOT_SYNC_CONFIG_CHANGE_AGAINST_PHYSICAL_MEDIUM = 5023 );
+ STATIC_CONST( CONFIG_FILE_CHECKSUM_ERROR = 5024 );
+ STATIC_CONST( NOT_POSSIBLE_TO_SEND_CONFIG_UPDATE_TO_PROCESS_TYPE = 5025 );
+
+ STATIC_CONST( NODE_SHUTDOWN_IN_PROGESS = 5026 );
+ STATIC_CONST( SYSTEM_SHUTDOWN_IN_PROGRESS = 5027 );
+ STATIC_CONST( NODE_SHUTDOWN_WOULD_CAUSE_SYSTEM_CRASH = 5028 );
+
+ STATIC_CONST( NO_CONTACT_WITH_DB_NODES = 5030 );
+ STATIC_CONST( UNSUPPORTED_NODE_SHUTDOWN = 5031 );
+
+ STATIC_CONST( NODE_NOT_API_NODE = 5062 );
+ STATIC_CONST( OPERATION_NOT_ALLOWED_START_STOP = 5063 );
+
+ /**
+ * This enum specifies the different signal loggig modes possible to set
+ * with the setSignalLoggingMode method.
+ */
+ enum LogMode {In, Out, InOut, Off};
+
+ /* Constructor */
+
+ MgmtSrvr(SocketServer *socket_server,
+ const char *config_filename, /* Where to save config */
+ const char *connect_string);
+ int init();
+ NodeId getOwnNodeId() const {return _ownNodeId;};
+
+ /**
+ * Read (initial) config file, create TransporterFacade,
+ * define signals, create ConfigInfoServer.
+ * @return true if succeeded, otherwise false
+ */
+ bool check_start(); // may be run before start to check that some things are ok
+ bool start(BaseString &error_string);
+
+ ~MgmtSrvr();
+
+ /**
+ * Get status on a node.
+ * address may point to a common area (e.g. from inet_addr)
+ * There is no gaurentee that it is preserved across calls.
+ * Copy the string if you are not going to use it immediately.
+ */
+ int status(int nodeId,
+ ndb_mgm_node_status * status,
+ Uint32 * version,
+ Uint32 * phase,
+ bool * systemShutdown,
+ Uint32 * dynamicId,
+ Uint32 * nodeGroup,
+ Uint32 * connectCount,
+ const char **address);
+
+ // All the functions below may return any of this error codes:
+ // NO_CONTACT_WITH_PROCESS, PROCESS_NOT_CONFIGURED, WRONG_PROCESS_TYPE,
+ // COULD_NOT_ALLOCATE_MEMORY, SEND_OR_RECEIVE_FAILED
+
+ /**
+ * Save a configuration to permanent storage
+ */
+ int saveConfig(const Config *);
+
+ /**
+ * Save the running configuration
+ */
+ int saveConfig() {
+ return saveConfig(_config);
+ };
+
+ /**
+ * Read configuration from file, or from another MGM server
+ */
+ Config *readConfig();
+
+ /**
+ * Fetch configuration from another MGM server
+ */
+ Config *fetchConfig();
+
+ /**
+ * Stop a node
+ *
+ * @param processId: Id of the DB process to stop
+ * @return 0 if succeeded, otherwise: as stated above, plus:
+ */
+ int stopNodes(const Vector<NodeId> &node_ids, int *stopCount, bool abort,
+ int *stopSelf);
+
+ int shutdownMGM(int *stopCount, bool abort, int *stopSelf);
+
+ /**
+ * shutdown the DB nodes
+ */
+ int shutdownDB(int * cnt = 0, bool abort = false);
+
+ /**
+ * print version info about a node
+ *
+ * @param processId: Id of the DB process to stop
+ * @return 0 if succeeded, otherwise: as stated above, plus:
+ */
+ int versionNode(int nodeId, Uint32 &version, const char **address);
+
+ /**
+ * Maintenance on the system
+ */
+ int enterSingleUser(int * cnt = 0, Uint32 singleuserNodeId = 0);
+
+
+ /**
+ * Resume from maintenance on the system
+ */
+ int exitSingleUser(int * cnt = 0, bool abort = false);
+
+ /**
+ * Start DB process.
+ * @param processId: Id of the DB process to start
+ * @return 0 if succeeded, otherwise: as stated above, plus:
+ */
+ int start(int processId);
+
+ /**
+ * Restart nodes
+ * @param processId: Id of the DB process to start
+ */
+ int restartNodes(const Vector<NodeId> &node_ids,
+ int *stopCount, bool nostart,
+ bool initialStart, bool abort, int *stopSelf);
+
+ /**
+ * Restart all DB nodes
+ */
+ int restartDB(bool nostart, bool initialStart,
+ bool abort = false,
+ int * stopCount = 0);
+
+ struct BackupEvent {
+ enum Event {
+ BackupStarted = 1,
+ BackupFailedToStart = 2,
+ BackupCompleted = 3,
+ BackupAborted = 4
+ } Event;
+
+ NdbNodeBitmask Nodes;
+ union {
+ struct {
+ Uint32 BackupId;
+ } Started ;
+ struct {
+ Uint32 ErrorCode;
+ } FailedToStart ;
+ struct {
+ Uint64 NoOfBytes;
+ Uint64 NoOfRecords;
+ Uint32 BackupId;
+ Uint32 NoOfLogBytes;
+ Uint32 NoOfLogRecords;
+ Uint32 startGCP;
+ Uint32 stopGCP;
+ } Completed ;
+ struct {
+ Uint32 BackupId;
+ Uint32 Reason;
+ Uint32 ErrorCode;
+ } Aborted ;
+ };
+ };
+
+ /**
+ * Backup functionallity
+ */
+ int startBackup(Uint32& backupId, int waitCompleted= 2);
+ int abortBackup(Uint32 backupId);
+ int performBackup(Uint32* backupId);
+
+ //**************************************************************************
+ // Description: Set event report level for a DB process
+ // Parameters:
+ // processId: Id of the DB process
+ // level: Event report level
+ // isResend: Flag to indicate for resending log levels during node restart
+ // Returns: 0 if succeeded, otherwise: as stated above, plus:
+ // INVALID_LEVEL
+ //**************************************************************************
+
+ int setEventReportingLevelImpl(int processId, const EventSubscribeReq& ll);
+ int setNodeLogLevelImpl(int processId, const SetLogLevelOrd & ll);
+
+ /**
+ * Insert an error in a DB process.
+ * @param processId: Id of the DB process
+ * @param errorNo: The error number. > 0.
+ * @return 0 if succeeded, otherwise: as stated above, plus:
+ * INVALID_ERROR_NUMBER
+ */
+ int insertError(int processId, int errorNo);
+
+
+
+ int setTraceNo(int processId, int traceNo);
+ //**************************************************************************
+ // Description: Set trace number in a DB process.
+ // Parameters:
+ // processId: Id of the DB process
+ // trace: Trace number
+ // Returns: 0 if succeeded, otherwise: as stated above, plus:
+ // INVALID_TRACE_NUMBER
+ //**************************************************************************
+
+
+ int setSignalLoggingMode(int processId, LogMode mode,
+ const Vector<BaseString> &blocks);
+
+ int setSignalLoggingMode(int processId, LogMode mode,
+ BaseString &block) {
+ Vector<BaseString> v;
+ v.push_back(block);
+ return setSignalLoggingMode(processId, mode, v);
+ }
+ //**************************************************************************
+ // Description: Set signal logging mode for blocks in a DB process.
+ // Parameters:
+ // processId: Id of the DB process
+ // mode: The log mode
+ // blocks: Which blocks to be affected (container of strings)
+ // Returns: 0 if succeeded, otherwise: as stated above, plus:
+ // INVALID_BLOCK_NAME
+ //**************************************************************************
+
+
+ int startSignalTracing(int processId);
+ //**************************************************************************
+ // Description: Start signal tracing for a DB process.
+ // Parameters:
+ // processId: Id of the DB process
+ // Returns: 0 if succeeded, otherwise: as stated above.
+ //**************************************************************************
+
+
+ int stopSignalTracing(int processId);
+ //**************************************************************************
+ // Description: Stop signal tracing for a DB process.
+ // Parameters:
+ // processId: Id of the DB process
+ // Returns: 0 if succeeded, otherwise: as stated above.
+ //**************************************************************************
+
+ /**
+ * Dump State
+ */
+ int dumpState(int processId, const Uint32 args[], Uint32 argNo);
+ int dumpState(int processId, const char* args);
+
+ /**
+ * Get next node id (node id gt that _nodeId)
+ * of specified type and save it in _nodeId
+ *
+ * @return false if none found
+ */
+ bool getNextNodeId(NodeId * _nodeId, enum ndb_mgm_node_type type) const ;
+ bool alloc_node_id(NodeId * _nodeId, enum ndb_mgm_node_type type,
+ struct sockaddr *client_addr,
+ SOCKET_SIZE_TYPE *client_addr_len,
+ int &error_code, BaseString &error_string,
+ int log_event = 1);
+
+ /**
+ *
+ */
+ enum ndb_mgm_node_type getNodeType(NodeId) const;
+
+ /**
+ * Get error text
+ *
+ * @param errorCode: Error code to get a match error text for.
+ * @return The error text.
+ */
+ const char* getErrorText(int errorCode, char *buf, int buf_sz);
+
+ /**
+ * Get configuration
+ */
+ const Config * getConfig() const;
+
+ /**
+ * Returns the node count for the specified node type.
+ *
+ * @param type The node type.
+ * @return The number of nodes of the specified type.
+ */
+ int getNodeCount(enum ndb_mgm_node_type type) const;
+
+ /**
+ * Returns the port number.
+ * @return port number.
+ */
+ int getPort() const;
+
+ int setDbParameter(int node, int parameter, const char * value, BaseString&);
+ int setConnectionDbParameter(int node1, int node2, int param, int value,
+ BaseString& msg);
+ int getConnectionDbParameter(int node1, int node2, int param,
+ int *value, BaseString& msg);
+
+ int connect_to_self(void);
+
+ void transporter_connect(NDB_SOCKET_TYPE sockfd);
+
+ ConfigRetriever *get_config_retriever() { return m_config_retriever; };
+
+ const char *get_connect_address(Uint32 node_id);
+ void get_connected_nodes(NodeBitmask &connected_nodes) const;
+ SocketServer *get_socket_server() { return m_socket_server; }
+
+ void updateStatus();
+
+ //**************************************************************************
+private:
+ //**************************************************************************
+
+ int sendStopMgmd(NodeId nodeId,
+ bool abort,
+ bool stop,
+ bool restart,
+ bool nostart,
+ bool initialStart);
+
+ int sendSTOP_REQ(const Vector<NodeId> &node_ids,
+ NodeBitmask &stoppedNodes,
+ Uint32 singleUserNodeId,
+ bool abort,
+ bool stop,
+ bool restart,
+ bool nostart,
+ bool initialStart,
+ int *stopSelf);
+
+ /**
+ * Check if it is possible to send a signal to a (DB) process
+ *
+ * @param processId: Id of the process to send to
+ * @return 0 OK, 1 process dead, 2 API or MGMT process, 3 not configured
+ */
+ int okToSendTo(NodeId nodeId, bool unCond = false);
+
+ /**
+ * Get block number for a block
+ *
+ * @param blockName: Block to get number for
+ * @return -1 if block not found, otherwise block number
+ */
+ int getBlockNumber(const BaseString &blockName);
+
+ int alloc_node_id_req(NodeId free_node_id, enum ndb_mgm_node_type type);
+ //**************************************************************************
+
+ int _blockNumber;
+ NodeId _ownNodeId;
+ SocketServer *m_socket_server;
+
+ BlockReference _ownReference;
+ NdbMutex *m_configMutex;
+ const Config * _config;
+ Config * m_newConfig;
+ BaseString m_configFilename;
+ Uint32 m_nextConfigGenerationNumber;
+
+ NodeBitmask m_reserved_nodes;
+ struct in_addr m_connect_address[MAX_NODES];
+
+ //**************************************************************************
+ // Specific signal handling methods
+ //**************************************************************************
+
+ static void defineSignals(int blockNumber);
+ //**************************************************************************
+ // Description: Define all signals to be sent or received for a block
+ // Parameters:
+ // blockNumber: The block number send/receive
+ // Returns: -
+ //**************************************************************************
+
+ void handleReceivedSignal(NdbApiSignal* signal);
+ //**************************************************************************
+ // Description: This method is called from "another" thread when a signal
+ // is received. If expect the received signal and succeed to handle it
+ // we signal with a condition variable to the waiting
+ // thread (receiveOptimisedResponse) that the signal has arrived.
+ // Parameters:
+ // signal: The recieved signal
+ // Returns: -
+ //**************************************************************************
+
+ void handleStatus(NodeId nodeId, bool alive, bool nfComplete);
+ //**************************************************************************
+ // Description: Handle the death of a process
+ // Parameters:
+ // processId: Id of the dead process.
+ // Returns: -
+ //**************************************************************************
+
+ //**************************************************************************
+ // Specific signal handling data
+ //**************************************************************************
+
+
+ //**************************************************************************
+ //**************************************************************************
+ // General signal handling methods
+ // This functions are more or less copied from the Ndb class.
+
+
+ /**
+ * WaitSignalType defines states where each state define a set of signals
+ * we accept to receive.
+ * The state is set after we have sent a signal.
+ * When a signal arrives we first check current state (handleReceivedSignal)
+ * to verify that we expect the arrived signal.
+ * It's only then we are in state accepting the arrived signal
+ * we handle the signal.
+ */
+ enum WaitSignalType {
+ NO_WAIT, // We don't expect to receive any signal
+ WAIT_SET_VAR, // Accept SET_VAR_CONF and SET_VAR_REF
+ WAIT_SUBSCRIBE_CONF // Accept event subscription confirmation
+ };
+
+ /**
+ * This function is called from "outside" of MgmtSrvr
+ * when a signal is sent to MgmtSrvr.
+ * @param mgmtSrvr: The MgmtSrvr object which shall recieve the signal.
+ * @param signal: The received signal.
+ */
+ static void signalReceivedNotification(void* mgmtSrvr,
+ NdbApiSignal* signal,
+ struct LinearSectionPtr ptr[3]);
+
+ /**
+ * Called from "outside" of MgmtSrvr when a DB process has died.
+ * @param mgmtSrvr: The MgmtSrvr object wreceiveOptimisedResponsehich
+ * shall receive the notification.
+ * @param processId: Id of the dead process.
+ */
+ static void nodeStatusNotification(void* mgmSrv, Uint32 nodeId,
+ bool alive, bool nfCompleted);
+
+ /**
+ * An event from <i>nodeId</i> has arrived
+ */
+ void eventReport(const Uint32 * theData);
+
+
+ //**************************************************************************
+ //**************************************************************************
+ // General signal handling data
+
+ STATIC_CONST( WAIT_FOR_RESPONSE_TIMEOUT = 300000 ); // Milliseconds
+ // Max time to wait for a signal to arrive
+
+ NdbApiSignal* theSignalIdleList;
+ // List of unused signals
+
+ Uint32 theWaitNode;
+ WaitSignalType theWaitState;
+ // State denoting a set of signals we accept to recieve.
+
+ NdbCondition* theMgmtWaitForResponseCondPtr;
+ // Condition variable used when we wait for a signal to arrive/a
+ // signal arrives.
+ // We wait in receiveOptimisedResponse and signal in handleReceivedSignal.
+
+ NdbMgmHandle m_local_mgm_handle;
+ char m_local_mgm_connect_string[20];
+ class TransporterFacade * theFacade;
+
+ int sendVersionReq( int processId, Uint32 &version, const char **address);
+ int translateStopRef(Uint32 errCode);
+
+ bool _isStopThread;
+ int _logLevelThreadSleep;
+ MutexVector<NodeId> m_started_nodes;
+ MutexVector<EventSubscribeReq> m_log_level_requests;
+ LogLevel m_nodeLogLevel[MAX_NODES];
+ enum ndb_mgm_node_type nodeTypes[MAX_NODES];
+ friend class MgmApiSession;
+ friend class Ndb_mgmd_event_service;
+ Ndb_mgmd_event_service m_event_listner;
+
+ NodeId m_master_node;
+
+ /**
+ * Handles the thread wich upon a 'Node is started' event will
+ * set the node's previous loglevel settings.
+ */
+ struct NdbThread* _logLevelThread;
+ static void *logLevelThread_C(void *);
+ void logLevelThreadRun();
+
+ Config *_props;
+
+ ConfigRetriever *m_config_retriever;
+};
+
+inline
+const Config *
+MgmtSrvr::getConfig() const {
+ return _config;
+}
+
+#endif // MgmtSrvr_H
diff --git a/storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp b/storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp
new file mode 100644
index 00000000000..e56643a3d7e
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/MgmtSrvrConfig.cpp
@@ -0,0 +1,76 @@
+/* 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 <signaldata/TestOrd.hpp>
+#include <OutputStream.hpp>
+
+#include "MgmtSrvr.hpp"
+#include "SignalQueue.hpp"
+#include <InitConfigFileParser.hpp>
+#include <ConfigRetriever.hpp>
+#include <ndb_version.h>
+
+/**
+ * Save a configuration to the running configuration file
+ */
+int
+MgmtSrvr::saveConfig(const Config *conf) {
+ BaseString newfile;
+ newfile.appfmt("%s.new", m_configFilename.c_str());
+
+ /* Open and write to the new config file */
+ FILE *f = fopen(newfile.c_str(), "w");
+ if(f == NULL) {
+ /** @todo Send something apropriate to the log */
+ return -1;
+ }
+ FileOutputStream stream(f);
+ conf->printConfigFile(stream);
+
+ fclose(f);
+
+ /* Rename file to real name */
+ rename(newfile.c_str(), m_configFilename.c_str());
+
+ return 0;
+}
+
+Config *
+MgmtSrvr::readConfig() {
+ Config *conf;
+ InitConfigFileParser parser;
+ if (m_configFilename.length())
+ {
+ conf = parser.parseConfig(m_configFilename.c_str());
+ }
+ else
+ {
+ ndbout_c("Reading cluster configuration using my.cnf");
+ conf = parser.parse_mycnf();
+ }
+ return conf;
+}
+
+Config *
+MgmtSrvr::fetchConfig() {
+ struct ndb_mgm_configuration * tmp = m_config_retriever->getConfig();
+ if(tmp != 0){
+ Config * conf = new Config();
+ conf->m_configValues = tmp;
+ return conf;
+ }
+ return 0;
+}
diff --git a/storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp b/storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp
new file mode 100644
index 00000000000..c99936e1861
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/MgmtSrvrGeneralSignalHandling.cpp
@@ -0,0 +1,22 @@
+/* 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 */
+
+//******************************************************************************
+// General signal handling methods
+// All implementations stolen from the Ndb class.
+// Some kind of reuse should be preferred.
+//******************************************************************************
+
diff --git a/storage/ndb/src/mgmsrv/ParamInfo.cpp b/storage/ndb/src/mgmsrv/ParamInfo.cpp
new file mode 100644
index 00000000000..01662fab588
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/ParamInfo.cpp
@@ -0,0 +1,2077 @@
+/* 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 <../../include/kernel/ndb_limits.h>
+#include "ParamInfo.hpp"
+#include <mgmapi_config_parameters.h>
+
+#ifndef MYSQLCLUSTERDIR
+#define MYSQLCLUSTERDIR "."
+#endif
+
+#define KEY_INTERNAL 0
+#define MAX_INT_RNIL 0xfffffeff
+#define MAX_PORT_NO 65535
+
+#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)"
+
+/**
+ * A MANDATORY parameters must be specified in the config file
+ * An UNDEFINED parameter may or may not be specified in the config file
+ */
+static const char* MANDATORY = (char*)~(UintPtr)0;// Default value for mandatory params.
+static const char* UNDEFINED = 0; // Default value for undefined params.
+
+extern const ParamInfo ParamInfoArray[];
+extern const int ParamInfoNum;
+
+/**
+ * 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 ParamInfo ParamInfoArray[] = {
+
+ /****************************************************************************
+ * COMPUTER
+ ***************************************************************************/
+ {
+ KEY_INTERNAL,
+ "COMPUTER",
+ "COMPUTER",
+ "Computer section",
+ CI_INTERNAL,
+ false,
+ CI_SECTION,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ "COMPUTER",
+ "Name of computer",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "HostName",
+ "COMPUTER",
+ "Hostname of computer (e.g. mysql.com)",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "ByteOrder",
+ "COMPUTER",
+ 0,
+ CI_DEPRICATED,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0,
+ 0 },
+
+ /****************************************************************************
+ * SYSTEM
+ ***************************************************************************/
+ {
+ CFG_SECTION_SYSTEM,
+ "SYSTEM",
+ "SYSTEM",
+ "System section",
+ CI_USED,
+ false,
+ CI_SECTION,
+ (const char *)CFG_SECTION_SYSTEM,
+ 0, 0 },
+
+ {
+ CFG_SYS_NAME,
+ "Name",
+ "SYSTEM",
+ "Name of system (NDB Cluster)",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_SYS_PRIMARY_MGM_NODE,
+ "PrimaryMGMNode",
+ "SYSTEM",
+ "Node id of Primary "MGM_TOKEN_PRINT" node",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SYS_CONFIG_GENERATION,
+ "ConfigGenerationNumber",
+ "SYSTEM",
+ "Configuration generation number",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /***************************************************************************
+ * DB
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ DB_TOKEN,
+ DB_TOKEN,
+ "Node section",
+ CI_USED,
+ false,
+ CI_SECTION,
+ (const char *)NODE_TYPE_DB,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ DB_TOKEN,
+ "Name of computer for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ "localhost",
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ DB_TOKEN,
+ "Name of system for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ DB_TOKEN,
+ "",
+ CI_DEPRICATED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ DB_TOKEN,
+ "Number identifying the database node ("DB_TOKEN_PRINT")",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ KEY_INTERNAL,
+ "ServerPort",
+ DB_TOKEN,
+ "Port used to setup transporter",
+ CI_USED,
+ false,
+ CI_INT,
+ UNDEFINED,
+ "1",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ CFG_DB_NO_REPLICAS,
+ "NoOfReplicas",
+ DB_TOKEN,
+ "Number of copies of all data in the database (1-4)",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ "1000",
+ "32",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_NO_TABLES,
+ "MaxNoOfTables",
+ DB_TOKEN,
+ "Total number of tables stored in the database",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_DEPRICATED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ "4000",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ DB_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_DB_WATCHDOG_INTERVAL,
+ "TimeBetweenWatchDogCheck",
+ DB_TOKEN,
+ "Time between execution checks inside a database node",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_DB_STOP_ON_ERROR_INSERT,
+ "RestartOnErrorInsert",
+ DB_TOKEN,
+ "See src/kernel/vm/Emulator.hpp NdbRestartType for details",
+ CI_INTERNAL,
+ true,
+ CI_INT,
+ "2",
+ "0",
+ "4" },
+
+ {
+ CFG_DB_NO_OPS,
+ "MaxNoOfConcurrentOperations",
+ DB_TOKEN,
+ "Max number of operation records in transaction coordinator",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT64,
+ "18M",
+ "1M",
+ "1024G" },
+
+ {
+ CFG_DB_DATA_MEM,
+ "DataMemory",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for storing data",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ "1M",
+ "512k",
+ STR_VALUE(MAX_INT_RNIL)},
+
+ {
+ CFG_DB_DISK_PAGE_BUFFER_MEMORY,
+ "DiskPageBufferMemory",
+ DB_TOKEN,
+ "Number bytes on each "DB_TOKEN_PRINT" node allocated for disk page buffer cache",
+ CI_USED,
+ false,
+ CI_INT64,
+ "64M",
+ "4M",
+ "1024G" },
+
+ {
+ CFG_DB_SGA,
+ "SharedGlobalMemory",
+ DB_TOKEN,
+ "Total number bytes on each "DB_TOKEN_PRINT" node allocated for any use",
+ CI_USED,
+ false,
+ CI_INT64,
+ "20M",
+ "0",
+ "65536G" }, // 32k pages * 32-bit i value
+
+ {
+ CFG_DB_START_PARTIAL_TIMEOUT,
+ "StartPartialTimeout",
+ DB_TOKEN,
+ "Time to wait before trying to start wo/ all nodes. 0=Wait forever",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ true,
+ 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)",
+ CI_USED,
+ true,
+ CI_INT,
+ "20",
+ "0",
+ "31" },
+
+ {
+ CFG_DB_GCP_INTERVAL,
+ "TimeBetweenGlobalCheckpoints",
+ DB_TOKEN,
+ "Time between doing group commit of transactions to disk",
+ CI_USED,
+ true,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ "16",
+ "3",
+ 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)",
+ CI_USED,
+ false,
+ CI_INT,
+ "40",
+ "20",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_INITIAL_OPEN_FILES,
+ "InitialNoOfOpenFiles",
+ DB_TOKEN,
+ "Initial number of files open per "DB_TOKEN_PRINT" node.(One thread is created per file)",
+ CI_USED,
+ false,
+ CI_INT,
+ "27",
+ "20",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_TRANSACTION_CHECK_INTERVAL,
+ "TimeBetweenInactiveTransactionAbortCheck",
+ DB_TOKEN,
+ "Time between inactive transaction checks",
+ CI_USED,
+ true,
+ 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.",
+ CI_USED,
+ true,
+ 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.",
+ CI_USED,
+ true,
+ CI_INT,
+ "1200",
+ "50",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_TUP_SR,
+ "NoOfDiskPagesToDiskDuringRestartTUP",
+ DB_TOKEN,
+ "DiskCheckpointSpeedSr",
+ CI_DEPRICATED,
+ true,
+ CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_TUP,
+ "NoOfDiskPagesToDiskAfterRestartTUP",
+ DB_TOKEN,
+ "DiskCheckpointSpeed",
+ CI_DEPRICATED,
+ true,
+ CI_INT,
+ "40",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_ACC_SR,
+ "NoOfDiskPagesToDiskDuringRestartACC",
+ DB_TOKEN,
+ "DiskCheckpointSpeedSr",
+ CI_DEPRICATED,
+ true,
+ CI_INT,
+ "20",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_LCP_DISC_PAGES_ACC,
+ "NoOfDiskPagesToDiskAfterRestartACC",
+ DB_TOKEN,
+ "DiskCheckpointSpeed",
+ CI_DEPRICATED,
+ true,
+ CI_INT,
+ "20",
+ "1",
+ STR_VALUE(MAX_INT_RNIL) },
+
+
+ {
+ CFG_DB_DISCLESS,
+ "Diskless",
+ DB_TOKEN,
+ "Run wo/ disk",
+ CI_USED,
+ true,
+ CI_BOOL,
+ "false",
+ "false",
+ "true"},
+
+ {
+ KEY_INTERNAL,
+ "Discless",
+ DB_TOKEN,
+ "Diskless",
+ CI_DEPRICATED,
+ true,
+ CI_BOOL,
+ "false",
+ "false",
+ "true"},
+
+
+
+ {
+ CFG_DB_ARBIT_TIMEOUT,
+ "ArbitrationTimeout",
+ DB_TOKEN,
+ "Max time (milliseconds) database partion waits for arbitration signal",
+ CI_USED,
+ false,
+ CI_INT,
+ "3000",
+ "10",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_NODE_DATADIR,
+ "DataDir",
+ DB_TOKEN,
+ "Data directory for this node",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_LOGLEVEL_STARTUP,
+ "LogLevelStartup",
+ DB_TOKEN,
+ "Node startup info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "1",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_SHUTDOWN,
+ "LogLevelShutdown",
+ DB_TOKEN,
+ "Node shutdown info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_STATISTICS,
+ "LogLevelStatistic",
+ DB_TOKEN,
+ "Transaction, operation, transporter info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CHECKPOINT,
+ "LogLevelCheckpoint",
+ DB_TOKEN,
+ "Local and Global checkpoint info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_NODERESTART,
+ "LogLevelNodeRestart",
+ DB_TOKEN,
+ "Node restart, node failure info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CONNECTION,
+ "LogLevelConnection",
+ DB_TOKEN,
+ "Node connect/disconnect info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_CONGESTION,
+ "LogLevelCongestion",
+ DB_TOKEN,
+ "Congestion info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_ERROR,
+ "LogLevelError",
+ DB_TOKEN,
+ "Transporter, heartbeat errors printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ {
+ CFG_LOGLEVEL_INFO,
+ "LogLevelInfo",
+ DB_TOKEN,
+ "Heartbeat and log info printed on stdout",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "15" },
+
+ /**
+ * Backup
+ */
+ {
+ CFG_DB_PARALLEL_BACKUPS,
+ "ParallelBackups",
+ DB_TOKEN,
+ "Maximum number of parallel backups",
+ CI_NOTIMPLEMENTED,
+ false,
+ CI_INT,
+ "1",
+ "1",
+ "1" },
+
+ {
+ CFG_DB_BACKUP_DATADIR,
+ "BackupDataDir",
+ DB_TOKEN,
+ "Path to where to store backups",
+ CI_USED,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_DB_DISK_SYNCH_SIZE,
+ "DiskSyncSize",
+ DB_TOKEN,
+ "Data written to a file before a synch is forced",
+ CI_USED,
+ false,
+ CI_INT,
+ "4M",
+ "32k",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_CHECKPOINT_SPEED,
+ "DiskCheckpointSpeed",
+ DB_TOKEN,
+ "Bytes per second allowed to be written by checkpoint",
+ CI_USED,
+ false,
+ CI_INT,
+ "10M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_CHECKPOINT_SPEED_SR,
+ "DiskCheckpointSpeedInRestart",
+ DB_TOKEN,
+ "Bytes per second allowed to be written by checkpoint during restart",
+ CI_USED,
+ false,
+ CI_INT,
+ "100M",
+ "1M",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_MEM,
+ "BackupMemory",
+ DB_TOKEN,
+ "Total memory allocated for backups per node (in bytes)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ CI_INT,
+ "32K",
+ "2K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_BACKUP_MAX_WRITE_SIZE,
+ "BackupMaxWriteSize",
+ DB_TOKEN,
+ "Max size of filesystem writes made by backup (in bytes)",
+ CI_USED,
+ false,
+ CI_INT,
+ "256K",
+ "2K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_DB_STRING_MEMORY,
+ "StringMemory",
+ DB_TOKEN,
+ "Default size of string memory (0 -> 5% of max 1-100 -> %of max, >100 -> actual bytes)",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /***************************************************************************
+ * API
+ ***************************************************************************/
+ {
+ CFG_SECTION_NODE,
+ API_TOKEN,
+ API_TOKEN,
+ "Node section",
+ CI_USED,
+ false,
+ CI_SECTION,
+ (const char *)NODE_TYPE_API,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ API_TOKEN,
+ "Name of computer for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ "",
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ API_TOKEN,
+ "Name of system for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ API_TOKEN,
+ "",
+ CI_DEPRICATED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ API_TOKEN,
+ "Number identifying application node ("API_TOKEN_PRINT")",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ API_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ "2" },
+
+ {
+ CFG_NODE_ARBIT_DELAY,
+ "ArbitrationDelay",
+ API_TOKEN,
+ "When asked to arbitrate, arbitrator waits this long before voting (msec)",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_MAX_SCAN_BATCH_SIZE,
+ "MaxScanBatchSize",
+ "API",
+ "The maximum collective batch size for one scan",
+ CI_USED,
+ false,
+ CI_INT,
+ STR_VALUE(MAX_SCAN_BATCH_SIZE),
+ "32k",
+ "16M" },
+
+ {
+ CFG_BATCH_BYTE_SIZE,
+ "BatchByteSize",
+ "API",
+ "The default batch size in bytes",
+ CI_USED,
+ false,
+ CI_INT,
+ STR_VALUE(SCAN_BATCH_SIZE),
+ "1k",
+ "1M" },
+
+ {
+ CFG_BATCH_SIZE,
+ "BatchSize",
+ "API",
+ "The default batch size in number of records",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_SECTION,
+ (const char *)NODE_TYPE_MGM,
+ 0, 0
+ },
+
+ {
+ CFG_NODE_HOST,
+ "HostName",
+ MGM_TOKEN,
+ "Name of computer for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ "",
+ 0, 0 },
+
+ {
+ CFG_NODE_DATADIR,
+ "DataDir",
+ MGM_TOKEN,
+ "Data directory for this node",
+ CI_USED,
+ false,
+ CI_STRING,
+ MYSQLCLUSTERDIR,
+ 0, 0 },
+
+ {
+ CFG_NODE_SYSTEM,
+ "System",
+ MGM_TOKEN,
+ "Name of system for this node",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "Id",
+ MGM_TOKEN,
+ "",
+ CI_DEPRICATED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_NODE_ID,
+ "NodeId",
+ MGM_TOKEN,
+ "Number identifying the management server node ("MGM_TOKEN_PRINT")",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1",
+ STR_VALUE(MAX_NODES) },
+
+ {
+ CFG_LOG_DESTINATION,
+ "LogDestination",
+ MGM_TOKEN,
+ "String describing where logmessages are sent",
+ CI_USED,
+ false,
+ CI_STRING,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "ExecuteOnComputer",
+ MGM_TOKEN,
+ "String referencing an earlier defined COMPUTER",
+ CI_USED,
+ false,
+ CI_STRING,
+ 0,
+ 0, 0 },
+
+ {
+ KEY_INTERNAL,
+ "MaxNoOfSavedEvents",
+ MGM_TOKEN,
+ "",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_INT,
+ NDB_PORT,
+ "0",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ KEY_INTERNAL,
+ "PortNumberStats",
+ MGM_TOKEN,
+ "Port number used to get statistical information from a management server",
+ CI_USED,
+ false,
+ CI_INT,
+ UNDEFINED,
+ "0",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ CFG_NODE_ARBIT_RANK,
+ "ArbitrationRank",
+ MGM_TOKEN,
+ "If 0, then "MGM_TOKEN_PRINT" is not arbitrator. Kernel selects arbitrators in order 1, 2",
+ CI_USED,
+ false,
+ CI_INT,
+ "1",
+ "0",
+ "2" },
+
+ {
+ CFG_NODE_ARBIT_DELAY,
+ "ArbitrationDelay",
+ MGM_TOKEN,
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ "0",
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ /****************************************************************************
+ * TCP
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "TCP",
+ "TCP",
+ "Connection section",
+ CI_USED,
+ false,
+ 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",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "TCP",
+ "Name/IP of computer on one side of the connection",
+ CI_INTERNAL,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "TCP",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ "55",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_NODE_ID_SERVER,
+ "NodeIdServer",
+ "TCP",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "TCP",
+ "Sends id in each signal. Used in trace files.",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "TCP",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "TCP",
+ "Port used for this transporter",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ CFG_TCP_SEND_BUFFER_SIZE,
+ "SendBufferMemory",
+ "TCP",
+ "Bytes of buffer for signals sent from this node",
+ CI_USED,
+ false,
+ CI_INT,
+ "256K",
+ "64K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_TCP_RECEIVE_BUFFER_SIZE,
+ "ReceiveBufferMemory",
+ "TCP",
+ "Bytes of buffer for signals received by this node",
+ CI_USED,
+ false,
+ CI_INT,
+ "64K",
+ "16K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_TCP_PROXY,
+ "Proxy",
+ "TCP",
+ "",
+ CI_USED,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "TCP",
+ "System for node 1 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "TCP",
+ "System for node 2 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+
+ /****************************************************************************
+ * SHM
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "SHM",
+ "SHM",
+ "Connection section",
+ CI_USED,
+ false,
+ 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",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "SHM",
+ "Name/IP of computer on one side of the connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "SHM",
+ "Port used for this transporter",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ CFG_SHM_SIGNUM,
+ "Signum",
+ "SHM",
+ "Signum to be used for signalling",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "SHM",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ "35",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_NODE_ID_SERVER,
+ "NodeIdServer",
+ "SHM",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ CFG_CONNECTION_SEND_SIGNAL_ID,
+ "SendSignalId",
+ "SHM",
+ "Sends id in each signal. Used in trace files.",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "SHM",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_SHM_KEY,
+ "ShmKey",
+ "SHM",
+ "A shared memory key",
+ CI_USED,
+ false,
+ CI_INT,
+ UNDEFINED,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_SHM_BUFFER_MEM,
+ "ShmSize",
+ "SHM",
+ "Size of shared memory segment",
+ CI_USED,
+ false,
+ CI_INT,
+ "1M",
+ "64K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "SHM",
+ "System for node 1 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "SHM",
+ "System for node 2 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ /****************************************************************************
+ * SCI
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "SCI",
+ "SCI",
+ "Connection section",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ CI_STRING,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_GROUP,
+ "Group",
+ "SCI",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ "15",
+ "0", "200" },
+
+ {
+ CFG_CONNECTION_NODE_ID_SERVER,
+ "NodeIdServer",
+ "SCI",
+ "",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "1", "63" },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "SCI",
+ "Name/IP of computer on one side of the connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "SCI",
+ "Name/IP of computer on one side of the connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_SERVER_PORT,
+ "PortNumber",
+ "SCI",
+ "Port used for this transporter",
+ CI_USED,
+ false,
+ CI_INT,
+ MANDATORY,
+ "0",
+ STR_VALUE(MAX_PORT_NO) },
+
+ {
+ CFG_SCI_HOST1_ID_0,
+ "Host1SciId0",
+ "SCI",
+ "SCI-node id for adapter 0 on Host1 (a computer can have two adapters)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ 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)",
+ CI_USED,
+ false,
+ 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.",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "SCI",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_SCI_SEND_LIMIT,
+ "SendLimit",
+ "SCI",
+ "Transporter send buffer contents are sent when this no of bytes is buffered",
+ CI_USED,
+ false,
+ CI_INT,
+ "8K",
+ "128",
+ "32K" },
+
+ {
+ CFG_SCI_BUFFER_MEM,
+ "SharedBufferSize",
+ "SCI",
+ "Size of shared memory segment",
+ CI_USED,
+ false,
+ CI_INT,
+ "1M",
+ "64K",
+ STR_VALUE(MAX_INT_RNIL) },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "SCI",
+ "System for node 1 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "SCI",
+ "System for node 2 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ /****************************************************************************
+ * OSE
+ ***************************************************************************/
+ {
+ CFG_SECTION_CONNECTION,
+ "OSE",
+ "OSE",
+ "Connection section",
+ CI_USED,
+ false,
+ CI_SECTION,
+ (const char *)CONNECTION_TYPE_OSE,
+ 0, 0
+ },
+
+ {
+ CFG_CONNECTION_HOSTNAME_1,
+ "HostName1",
+ "OSE",
+ "Name of computer on one side of the connection",
+ CI_USED,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_HOSTNAME_2,
+ "HostName2",
+ "OSE",
+ "Name of computer on one side of the connection",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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",
+ CI_USED,
+ false,
+ 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.",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "true",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_CHECKSUM,
+ "Checksum",
+ "OSE",
+ "If checksum is enabled, all signals between nodes are checked for errors",
+ CI_USED,
+ false,
+ CI_BOOL,
+ "false",
+ "false",
+ "true" },
+
+ {
+ CFG_CONNECTION_NODE_1_SYSTEM,
+ "NodeId1_System",
+ "OSE",
+ "System for node 1 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+
+ {
+ CFG_CONNECTION_NODE_2_SYSTEM,
+ "NodeId2_System",
+ "OSE",
+ "System for node 2 in connection",
+ CI_INTERNAL,
+ false,
+ CI_STRING,
+ UNDEFINED,
+ 0, 0 },
+};
+
+const int ParamInfoNum = sizeof(ParamInfoArray) / sizeof(ParamInfo);
diff --git a/storage/ndb/src/mgmsrv/ParamInfo.hpp b/storage/ndb/src/mgmsrv/ParamInfo.hpp
new file mode 100644
index 00000000000..7d12cd6252f
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/ParamInfo.hpp
@@ -0,0 +1,44 @@
+#ifndef PARAMINFO_H
+#define PARAMINFO_H
+
+#define DB_TOKEN "DB"
+#define MGM_TOKEN "MGM"
+#define API_TOKEN "API"
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+/**
+ * The Configuration parameter type and status
+ */
+
+enum ParameterType { CI_BOOL, CI_INT, CI_INT64, CI_STRING, CI_SECTION };
+enum ParameterStatus { CI_USED, ///< Active
+ CI_DEPRICATED, ///< Can be, but shouldn't
+ CI_NOTIMPLEMENTED, ///< Is ignored.
+ CI_INTERNAL ///< Not configurable by the user
+};
+
+/**
+ * Entry for one configuration parameter
+ */
+typedef struct m_ParamInfo {
+ Uint32 _paramId;
+ const char* _fname;
+ const char* _section;
+ const char* _description;
+ ParameterStatus _status;
+ bool _updateable;
+ ParameterType _type;
+ const char* _default;
+ const char* _min;
+ const char* _max;
+}ParamInfo;
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp
new file mode 100644
index 00000000000..672e50729df
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Services.cpp
@@ -0,0 +1,1857 @@
+/* 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 <ctype.h>
+
+#include <uucode.h>
+#include <socket_io.h>
+#include <ndb_version.h>
+#include <mgmapi.h>
+#include <EventLogger.hpp>
+#include <signaldata/SetLogLevelOrd.hpp>
+#include <LogLevel.hpp>
+#include <BaseString.hpp>
+
+#include <ConfigValues.hpp>
+#include <mgmapi_configuration.hpp>
+#include <Vector.hpp>
+#include "Services.hpp"
+#include "../mgmapi/ndb_logevent.hpp"
+
+#include <base64.h>
+#include <ndberror.h>
+
+extern bool g_StopServer;
+extern bool g_RestartServer;
+extern EventLogger g_eventLogger;
+
+static const unsigned int MAX_READ_TIMEOUT = 1000 ;
+static const unsigned int MAX_WRITE_TIMEOUT = 100 ;
+
+/**
+ const char * name;
+ const char * realName;
+ const Type type;
+ const ArgType argType;
+ const ArgRequired argRequired;
+ const ArgMinMax argMinMax;
+ const int minVal;
+ const int maxVal;
+ void (T::* function)(const class Properties & args);
+ const char * description;
+*/
+
+#define MGM_CMD(name, fun, desc) \
+ { name, \
+ 0, \
+ ParserRow<MgmApiSession>::Cmd, \
+ ParserRow<MgmApiSession>::String, \
+ ParserRow<MgmApiSession>::Optional, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ 0, 0, \
+ fun, \
+ desc, 0 }
+
+#define MGM_ARG(name, type, opt, desc) \
+ { name, \
+ 0, \
+ ParserRow<MgmApiSession>::Arg, \
+ ParserRow<MgmApiSession>::type, \
+ ParserRow<MgmApiSession>::opt, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ desc, 0 }
+
+#define MGM_ARG2(name, type, opt, min, max, desc) \
+ { name, \
+ 0, \
+ ParserRow<MgmApiSession>::Arg, \
+ ParserRow<MgmApiSession>::type, \
+ ParserRow<MgmApiSession>::opt, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ min, max, \
+ 0, \
+ desc, 0 }
+
+#define MGM_END() \
+ { 0, \
+ 0, \
+ ParserRow<MgmApiSession>::Arg, \
+ ParserRow<MgmApiSession>::Int, \
+ ParserRow<MgmApiSession>::Optional, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ 0, 0 }
+
+#define MGM_CMD_ALIAS(name, realName, fun) \
+ { name, \
+ realName, \
+ ParserRow<MgmApiSession>::CmdAlias, \
+ ParserRow<MgmApiSession>::Int, \
+ ParserRow<MgmApiSession>::Optional, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ 0, 0 }
+
+#define MGM_ARG_ALIAS(name, realName, fun) \
+ { name, \
+ realName, \
+ ParserRow<MgmApiSession>::ArgAlias, \
+ ParserRow<MgmApiSession>::Int, \
+ ParserRow<MgmApiSession>::Optional, \
+ ParserRow<MgmApiSession>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ 0, 0 }
+
+const
+ParserRow<MgmApiSession> commands[] = {
+ MGM_CMD("get config", &MgmApiSession::getConfig, ""),
+ MGM_ARG("version", Int, Mandatory, "Configuration version number"),
+ MGM_ARG("node", Int, Optional, "Node ID"),
+
+ MGM_CMD("get nodeid", &MgmApiSession::get_nodeid, ""),
+ MGM_ARG("version", Int, Mandatory, "Configuration version number"),
+ MGM_ARG("nodetype", Int, Mandatory, "Node type"),
+ MGM_ARG("transporter", String, Optional, "Transporter type"),
+ MGM_ARG("nodeid", Int, Optional, "Node ID"),
+ MGM_ARG("user", String, Mandatory, "Password"),
+ MGM_ARG("password", String, Mandatory, "Password"),
+ MGM_ARG("public key", String, Mandatory, "Public key"),
+ MGM_ARG("endian", String, Optional, "Endianness"),
+ MGM_ARG("name", String, Optional, "Name of connection"),
+ MGM_ARG("timeout", Int, Optional, "Timeout in seconds"),
+ MGM_ARG("log_event", Int, Optional, "Log failure in cluster log"),
+
+ MGM_CMD("get version", &MgmApiSession::getVersion, ""),
+
+ MGM_CMD("get status", &MgmApiSession::getStatus, ""),
+
+ MGM_CMD("get info clusterlog", &MgmApiSession::getInfoClusterLog, ""),
+ MGM_CMD("get cluster loglevel", &MgmApiSession::getClusterLogLevel, ""),
+
+ MGM_CMD("restart node", &MgmApiSession::restart_v1, ""),
+ MGM_ARG("node", String, Mandatory, "Nodes to restart"),
+ MGM_ARG("initialstart", Int, Optional, "Initial start"),
+ MGM_ARG("nostart", Int, Optional, "No start"),
+ MGM_ARG("abort", Int, Optional, "Abort"),
+
+ MGM_CMD("restart node v2", &MgmApiSession::restart_v2, ""),
+ MGM_ARG("node", String, Mandatory, "Nodes to restart"),
+ MGM_ARG("initialstart", Int, Optional, "Initial start"),
+ MGM_ARG("nostart", Int, Optional, "No start"),
+ MGM_ARG("abort", Int, Optional, "Abort"),
+
+ MGM_CMD("restart all", &MgmApiSession::restartAll, ""),
+ MGM_ARG("initialstart", Int, Optional, "Initial start"),
+ MGM_ARG("nostart", Int, Optional, "No start"),
+ MGM_ARG("abort", Int, Optional, "Abort"),
+
+ MGM_CMD("insert error", &MgmApiSession::insertError, ""),
+ MGM_ARG("node", Int, Mandatory, "Node to receive error"),
+ MGM_ARG("error", Int, Mandatory, "Errorcode to insert"),
+
+ MGM_CMD("set trace", &MgmApiSession::setTrace, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+ MGM_ARG("trace", Int, Mandatory, "Trace number"),
+
+ MGM_CMD("log signals", &MgmApiSession::logSignals, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+ MGM_ARG("blocks", String, Mandatory, "Blocks (space separated)"),
+ MGM_ARG("in", Int, Mandatory, "Log input signals"),
+ MGM_ARG("out", Int, Mandatory, "Log output signals"),
+
+ MGM_CMD("start signallog", &MgmApiSession::startSignalLog, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+
+ MGM_CMD("stop signallog", &MgmApiSession::stopSignalLog, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+
+ MGM_CMD("dump state", &MgmApiSession::dumpState, ""),
+ MGM_ARG("node", Int, Mandatory ,"Node"),
+ MGM_ARG("args", String, Mandatory, "Args(space separated int's)"),
+
+ MGM_CMD("start backup", &MgmApiSession::startBackup, ""),
+ MGM_ARG("completed", Int, Optional ,"Wait until completed"),
+
+ MGM_CMD("abort backup", &MgmApiSession::abortBackup, ""),
+ MGM_ARG("id", Int, Mandatory, "Backup id"),
+
+ MGM_CMD("stop", &MgmApiSession::stop_v1, ""),
+ MGM_ARG("node", String, Mandatory, "Node"),
+ MGM_ARG("abort", Int, Mandatory, "Node"),
+
+ MGM_CMD("stop v2", &MgmApiSession::stop_v2, ""),
+ MGM_ARG("node", String, Mandatory, "Node"),
+ MGM_ARG("abort", Int, Mandatory, "Node"),
+
+ MGM_CMD("stop all", &MgmApiSession::stopAll, ""),
+ MGM_ARG("abort", Int, Mandatory, "Node"),
+ MGM_ARG("stop", String, Optional, "MGM/DB or both"),
+
+ MGM_CMD("enter single user", &MgmApiSession::enterSingleUser, ""),
+ MGM_ARG("nodeId", Int, Mandatory, "Node"),
+
+ MGM_CMD("exit single user", &MgmApiSession::exitSingleUser, ""),
+
+
+ MGM_CMD("start", &MgmApiSession::start, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+
+ MGM_CMD("start all", &MgmApiSession::startAll, ""),
+
+ MGM_CMD("bye", &MgmApiSession::bye, ""),
+
+ MGM_CMD("end session", &MgmApiSession::endSession, ""),
+
+ MGM_CMD("set loglevel", &MgmApiSession::setLogLevel, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+ MGM_ARG("category", Int, Mandatory, "Event category"),
+ MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
+
+ MGM_CMD("set cluster loglevel", &MgmApiSession::setClusterLogLevel, ""),
+ MGM_ARG("node", Int, Mandatory, "Node"),
+ MGM_ARG("category", Int, Mandatory, "Event category"),
+ MGM_ARG("level", Int, Mandatory, "Log level (0-15)"),
+
+ MGM_CMD("set logfilter", &MgmApiSession::setLogFilter, ""),
+ MGM_ARG("level", Int, Mandatory, "Severety level"),
+ MGM_ARG("enable", Int, Mandatory, "1=disable, 0=enable, -1=toggle"),
+
+ MGM_CMD("set parameter", &MgmApiSession::setParameter, ""),
+ MGM_ARG("node", String, Mandatory, "Node"),
+ MGM_ARG("parameter", String, Mandatory, "Parameter"),
+ MGM_ARG("value", String, Mandatory, "Value"),
+
+ MGM_CMD("set connection parameter",
+ &MgmApiSession::setConnectionParameter, ""),
+ MGM_ARG("node1", String, Mandatory, "Node1 ID"),
+ MGM_ARG("node2", String, Mandatory, "Node2 ID"),
+ MGM_ARG("param", String, Mandatory, "Parameter"),
+ MGM_ARG("value", String, Mandatory, "Value"),
+
+ MGM_CMD("get connection parameter",
+ &MgmApiSession::getConnectionParameter, ""),
+ MGM_ARG("node1", String, Mandatory, "Node1 ID"),
+ MGM_ARG("node2", String, Mandatory, "Node2 ID"),
+ MGM_ARG("param", String, Mandatory, "Parameter"),
+
+ MGM_CMD("listen event", &MgmApiSession::listen_event, ""),
+ MGM_ARG("node", Int, Optional, "Node"),
+ MGM_ARG("parsable", Int, Optional, "Parsable"),
+ MGM_ARG("filter", String, Mandatory, "Event category"),
+
+ MGM_CMD("purge stale sessions", &MgmApiSession::purge_stale_sessions, ""),
+
+ MGM_CMD("check connection", &MgmApiSession::check_connection, ""),
+
+ MGM_CMD("transporter connect", &MgmApiSession::transporter_connect, ""),
+
+ MGM_CMD("get mgmd nodeid", &MgmApiSession::get_mgmd_nodeid, ""),
+
+ MGM_CMD("report event", &MgmApiSession::report_event, ""),
+ MGM_ARG("length", Int, Mandatory, "Length"),
+ MGM_ARG("data", String, Mandatory, "Data"),
+
+ MGM_CMD("list sessions", &MgmApiSession::listSessions, ""),
+
+ MGM_CMD("get session id", &MgmApiSession::getSessionId, ""),
+
+ MGM_CMD("get session", &MgmApiSession::getSession, ""),
+ MGM_ARG("id", Int, Mandatory, "SessionID"),
+
+ MGM_END()
+};
+
+struct PurgeStruct
+{
+ NodeBitmask free_nodes;/* free nodes as reported
+ * by ndbd in apiRegReqConf
+ */
+ BaseString *str;
+ NDB_TICKS tick;
+};
+
+MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock, Uint64 session_id)
+ : SocketServer::Session(sock), m_mgmsrv(mgm)
+{
+ DBUG_ENTER("MgmApiSession::MgmApiSession");
+ m_input = new SocketInputStream(sock);
+ m_output = new SocketOutputStream(sock);
+ m_parser = new Parser_t(commands, *m_input, true, true, true);
+ m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv);
+ m_stopSelf= 0;
+ m_ctx= NULL;
+ m_session_id= session_id;
+ m_mutex= NdbMutex_Create();
+ DBUG_VOID_RETURN;
+}
+
+MgmApiSession::~MgmApiSession()
+{
+ DBUG_ENTER("MgmApiSession::~MgmApiSession");
+ if (m_input)
+ delete m_input;
+ if (m_output)
+ delete m_output;
+ if (m_parser)
+ delete m_parser;
+ if (m_allocated_resources)
+ delete m_allocated_resources;
+ if(m_socket != NDB_INVALID_SOCKET)
+ {
+ NDB_CLOSE_SOCKET(m_socket);
+ m_socket= NDB_INVALID_SOCKET;
+ }
+ if(m_stopSelf < 0)
+ g_RestartServer= true;
+ if(m_stopSelf)
+ g_StopServer= true;
+ NdbMutex_Destroy(m_mutex);
+ DBUG_VOID_RETURN;
+}
+
+void
+MgmApiSession::runSession()
+{
+ DBUG_ENTER("MgmApiSession::runSession");
+
+ Parser_t::Context ctx;
+ ctx.m_mutex= m_mutex;
+ m_ctx= &ctx;
+ bool stop= false;
+ while(!stop) {
+ NdbMutex_Lock(m_mutex);
+
+ m_parser->run(ctx, *this);
+
+ if(ctx.m_currentToken == 0)
+ {
+ NdbMutex_Unlock(m_mutex);
+ break;
+ }
+
+ switch(ctx.m_status) {
+ case Parser_t::UnknownCommand:
+#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
+ /* Backwards compatibility for old NDBs that still use
+ * the old "GET CONFIG" command.
+ */
+ size_t i;
+ for(i=0; i<strlen(ctx.m_currentToken); i++)
+ ctx.m_currentToken[i] = toupper(ctx.m_currentToken[i]);
+
+ if(strncmp("GET CONFIG ",
+ ctx.m_currentToken,
+ strlen("GET CONFIG ")) == 0)
+ getConfig_old(ctx);
+#endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */
+ break;
+ default:
+ break;
+ }
+
+ stop= m_stop;
+ NdbMutex_Unlock(m_mutex);
+ };
+
+ NdbMutex_Lock(m_mutex);
+ m_ctx= NULL;
+ if(m_socket != NDB_INVALID_SOCKET)
+ {
+ NDB_CLOSE_SOCKET(m_socket);
+ m_socket= NDB_INVALID_SOCKET;
+ }
+ NdbMutex_Unlock(m_mutex);
+ DBUG_VOID_RETURN;
+}
+
+#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
+void
+MgmApiSession::getConfig_old(Parser_t::Context &ctx) {
+ Properties args;
+
+ Uint32 version, node;
+
+ if(sscanf(ctx.m_currentToken, "GET CONFIG %d %d",
+ (int *)&version, (int *)&node) != 2) {
+ m_output->println("Expected 2 arguments for GET CONFIG");
+ return;
+ }
+
+ /* Put arguments in properties object so we can call the real function */
+ args.put("version", version);
+ args.put("node", node);
+ getConfig_common(ctx, args, true);
+}
+#endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */
+
+void
+MgmApiSession::getConfig(Parser_t::Context &ctx,
+ const class Properties &args) {
+ getConfig_common(ctx, args);
+}
+
+static Properties *
+backward(const char * base, const Properties* reply){
+ Properties * ret = new Properties();
+ Properties::Iterator it(reply);
+ for(const char * name = it.first(); name != 0; name=it.next()){
+ PropertiesType type;
+ reply->getTypeOf(name, &type);
+ switch(type){
+ case PropertiesType_Uint32:{
+ Uint32 val;
+ reply->get(name, &val);
+ ret->put(name, val);
+ }
+ break;
+ case PropertiesType_char:
+ {
+ const char * val;
+ reply->get(name, &val);
+ ret->put(name, val);
+ if(!strcmp(name, "Type") && !strcmp(val, "DB")){
+ ret->put("NoOfDiskBufferPages", (unsigned)0);
+ ret->put("NoOfDiskFiles", (unsigned)0);
+ ret->put("NoOfDiskClusters", (unsigned)0);
+ ret->put("NoOfFreeDiskClusters", (unsigned)0);
+ ret->put("NoOfDiskClustersPerDiskFile", (unsigned)0);
+ ret->put("NoOfConcurrentCheckpointsDuringRestart", (unsigned)1);
+ ret->put("NoOfConcurrentCheckpointsAfterRestart", (unsigned)1);
+ ret->put("NoOfConcurrentProcessesHandleTakeover", (unsigned)1);
+ }
+ }
+ break;
+ case PropertiesType_Properties:
+ {
+ const Properties * recurse;
+ reply->get(name, &recurse);
+ Properties * val = backward(name, recurse);
+ ret->put(name, val);
+ }
+ break;
+ case PropertiesType_Uint64:
+ break;
+ }
+ }
+ return ret;
+}
+
+void
+MgmApiSession::get_nodeid(Parser_t::Context &,
+ const class Properties &args)
+{
+ const char *cmd= "get nodeid reply";
+ Uint32 version, nodeid= 0, nodetype= 0xff;
+ Uint32 timeout= 20; // default seconds timeout
+ const char * transporter;
+ const char * user;
+ const char * password;
+ const char * public_key;
+ const char * endian= NULL;
+ const char * name= NULL;
+ Uint32 log_event= 1;
+ bool log_event_version;
+ union { long l; char c[sizeof(long)]; } endian_check;
+
+ args.get("version", &version);
+ args.get("nodetype", &nodetype);
+ args.get("transporter", &transporter);
+ args.get("nodeid", &nodeid);
+ args.get("user", &user);
+ args.get("password", &password);
+ args.get("public key", &public_key);
+ args.get("endian", &endian);
+ args.get("name", &name);
+ args.get("timeout", &timeout);
+ /* for backwards compatability keep track if client uses new protocol */
+ log_event_version= args.get("log_event", &log_event);
+
+ endian_check.l = 1;
+ if(endian
+ && strcmp(endian,(endian_check.c[sizeof(long)-1])?"big":"little")!=0) {
+ m_output->println(cmd);
+ m_output->println("result: Node does not have the same endianness as the management server.");
+ m_output->println("");
+ return;
+ }
+
+ bool compatible;
+ switch (nodetype) {
+ case NODE_TYPE_MGM:
+ case NODE_TYPE_API:
+ compatible = ndbCompatible_mgmt_api(NDB_VERSION, version);
+ break;
+ case NODE_TYPE_DB:
+ compatible = ndbCompatible_mgmt_ndb(NDB_VERSION, version);
+ break;
+ default:
+ m_output->println(cmd);
+ m_output->println("result: unknown nodetype %d", nodetype);
+ m_output->println("");
+ return;
+ }
+
+ struct sockaddr_in addr;
+ SOCKET_SIZE_TYPE addrlen= sizeof(addr);
+ int r = getpeername(m_socket, (struct sockaddr*)&addr, &addrlen);
+ if (r != 0 ) {
+ m_output->println(cmd);
+ m_output->println("result: getpeername(%d) failed, err= %d", m_socket, r);
+ m_output->println("");
+ return;
+ }
+
+ NodeId tmp= nodeid;
+ if(tmp == 0 || !m_allocated_resources->is_reserved(tmp)){
+ BaseString error_string;
+ int error_code;
+ NDB_TICKS tick= 0;
+ /* only report error on second attempt as not to clog the cluster log */
+ while (!m_mgmsrv.alloc_node_id(&tmp, (enum ndb_mgm_node_type)nodetype,
+ (struct sockaddr*)&addr, &addrlen,
+ error_code, error_string,
+ tick == 0 ? 0 : log_event))
+ {
+ /* NDB_MGM_ALLOCID_CONFIG_MISMATCH is a non retriable error */
+ if (tick == 0 && error_code != NDB_MGM_ALLOCID_CONFIG_MISMATCH)
+ {
+ // attempt to free any timed out reservations
+ tick= NdbTick_CurrentMillisecond();
+ struct PurgeStruct ps;
+ m_mgmsrv.get_connected_nodes(ps.free_nodes);
+ // invert connected_nodes to get free nodes
+ ps.free_nodes.bitXORC(NodeBitmask());
+ ps.str= 0;
+ ps.tick= tick;
+ m_mgmsrv.get_socket_server()->
+ foreachSession(stop_session_if_timed_out,&ps);
+ m_mgmsrv.get_socket_server()->checkSessions();
+ error_string = "";
+ continue;
+ }
+ const char *alias;
+ const char *str;
+ alias= ndb_mgm_get_node_type_alias_string((enum ndb_mgm_node_type)
+ nodetype, &str);
+ m_output->println(cmd);
+ m_output->println("result: %s", error_string.c_str());
+ /* only use error_code protocol if client knows about it */
+ if (log_event_version)
+ m_output->println("error_code: %d", error_code);
+ m_output->println("");
+ return;
+ }
+ }
+
+#if 0
+ if (!compatible){
+ m_output->println(cmd);
+ m_output->println("result: incompatible version mgmt 0x%x and node 0x%x",
+ NDB_VERSION, version);
+ m_output->println("");
+ return;
+ }
+#endif
+
+ m_output->println(cmd);
+ m_output->println("nodeid: %u", tmp);
+ m_output->println("result: Ok");
+ m_output->println("");
+ m_allocated_resources->reserve_node(tmp, timeout*1000);
+
+ if (name)
+ g_eventLogger.info("Node %d: %s", tmp, name);
+
+ return;
+}
+
+void
+MgmApiSession::getConfig_common(Parser_t::Context &,
+ const class Properties &args,
+ bool compat) {
+ Uint32 version, node = 0;
+
+ args.get("version", &version);
+ args.get("node", &node);
+
+ const Config *conf = m_mgmsrv.getConfig();
+ if(conf == NULL) {
+ m_output->println("get config reply");
+ m_output->println("result: Could not fetch configuration");
+ m_output->println("");
+ return;
+ }
+
+ if(version > 0 && version < makeVersion(3, 5, 0) && compat){
+ Properties *reply = backward("", conf->m_oldConfig);
+ reply->put("Version", version);
+ reply->put("LocalNodeId", node);
+
+ backward("", reply);
+ //reply->print();
+
+ const Uint32 size = reply->getPackedSize();
+ Uint32 *buffer = new Uint32[size/4+1];
+
+ reply->pack(buffer);
+ delete reply;
+
+ const int uurows = (size + 44)/45;
+ char * uubuf = new char[uurows * 62+5];
+
+ const int uusz = uuencode_mem(uubuf, (char *)buffer, size);
+ delete[] buffer;
+
+ m_output->println("GET CONFIG %d %d %d %d %d",
+ 0, version, node, size, uusz);
+
+ m_output->println("begin 664 Ndb_cfg.bin");
+
+ /* XXX Need to write directly to the socket, because the uubuf is not
+ * NUL-terminated. This could/should probably be done in a nicer way.
+ */
+ write_socket(m_socket, MAX_WRITE_TIMEOUT, uubuf, uusz);
+ delete[] uubuf;
+
+ m_output->println("end");
+ m_output->println("");
+ return;
+ }
+
+ if(compat){
+ m_output->println("GET CONFIG %d %d %d %d %d",1, version, 0, 0, 0);
+ return;
+ }
+
+ if(node != 0){
+ bool compatible;
+ switch (m_mgmsrv.getNodeType(node)) {
+ case NDB_MGM_NODE_TYPE_NDB:
+ compatible = ndbCompatible_mgmt_ndb(NDB_VERSION, version);
+ break;
+ case NDB_MGM_NODE_TYPE_API:
+ case NDB_MGM_NODE_TYPE_MGM:
+ compatible = ndbCompatible_mgmt_api(NDB_VERSION, version);
+ break;
+ default:
+ m_output->println("get config");
+ m_output->println("result: unrecognignized node type");
+ m_output->println("");
+ return;
+ }
+
+ if (!compatible){
+ m_output->println("get config");
+ m_output->println("result: incompatible version mgmt 0x%x and node 0x%x",
+ NDB_VERSION, version);
+ m_output->println("");
+ return;
+ }
+ }
+
+ NdbMutex_Lock(m_mgmsrv.m_configMutex);
+ const ConfigValues * cfg = &conf->m_configValues->m_config;
+ const Uint32 size = cfg->getPackedSize();
+
+ UtilBuffer src;
+ cfg->pack(src);
+ NdbMutex_Unlock(m_mgmsrv.m_configMutex);
+
+ char *tmp_str = (char *) malloc(base64_needed_encoded_length(src.length()));
+ int res = base64_encode(src.get_data(), src.length(), tmp_str);
+
+ m_output->println("get config reply");
+ m_output->println("result: Ok");
+ m_output->println("Content-Length: %d", strlen(tmp_str));
+ m_output->println("Content-Type: ndbconfig/octet-stream");
+ m_output->println("Content-Transfer-Encoding: base64");
+ m_output->println("");
+ m_output->println(tmp_str);
+
+ free(tmp_str);
+ return;
+}
+
+void
+MgmApiSession::insertError(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node = 0, error = 0;
+
+ args.get("node", &node);
+ args.get("error", &error);
+
+ int result = m_mgmsrv.insertError(node, error);
+
+ m_output->println("insert error reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::setTrace(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node = 0, trace = 0;
+
+ args.get("node", &node);
+ args.get("trace", &trace);
+
+ int result = m_mgmsrv.setTraceNo(node, trace);
+
+ m_output->println("set trace reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::getVersion(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ m_output->println("version");
+ m_output->println("id: %d", NDB_VERSION);
+ m_output->println("major: %d", getMajor(NDB_VERSION));
+ m_output->println("minor: %d", getMinor(NDB_VERSION));
+ m_output->println("string: %s", NDB_VERSION_STRING);
+ m_output->println("");
+}
+
+void
+MgmApiSession::startBackup(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ DBUG_ENTER("MgmApiSession::startBackup");
+ unsigned backupId;
+ Uint32 completed= 2;
+ int result;
+
+ args.get("completed", &completed);
+
+ result = m_mgmsrv.startBackup(backupId, completed);
+
+ m_output->println("start backup reply");
+ if(result != 0)
+ {
+ m_output->println("result: %s", get_error_text(result));
+ }
+ else{
+ m_output->println("result: Ok");
+ if (completed)
+ m_output->println("id: %d", backupId);
+ }
+ m_output->println("");
+ DBUG_VOID_RETURN;
+}
+
+void
+MgmApiSession::abortBackup(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 id = 0;
+
+ args.get("id", &id);
+
+ int result = m_mgmsrv.abortBackup(id);
+
+ m_output->println("abort backup reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+/*****************************************************************************/
+
+void
+MgmApiSession::dumpState(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node;
+ BaseString args_str;
+
+ args.get("node", &node);
+ args.get("args", args_str);
+
+ int result = m_mgmsrv.dumpState(node, args_str.c_str());
+ m_output->println("dump state reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+
+void
+MgmApiSession::bye(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ m_stop = true;
+}
+
+void
+MgmApiSession::endSession(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ if(m_allocated_resources)
+ delete m_allocated_resources;
+
+ m_allocated_resources= new MgmtSrvr::Allocated_resources(m_mgmsrv);
+
+ m_output->println("end session reply");
+}
+
+void
+MgmApiSession::getClusterLogLevel(Parser<MgmApiSession>::Context & , Properties const &) {
+ const char* names[] = { "startup",
+ "shutdown",
+ "statistics",
+ "checkpoint",
+ "noderestart",
+ "connection",
+ "info",
+ "warning",
+ "error",
+ "congestion",
+ "debug",
+ "backup" };
+
+ int loglevel_count = (CFG_MAX_LOGLEVEL - CFG_MIN_LOGLEVEL + 1) ;
+ LogLevel::EventCategory category;
+
+ m_output->println("get cluster loglevel");
+ for(int i = 0; i < loglevel_count; i++) {
+ category = (LogLevel::EventCategory) i;
+ m_output->println("%s: %d", names[i], m_mgmsrv.m_event_listner[0].m_logLevel.getLogLevel(category));
+ }
+ m_output->println("");
+}
+
+void
+MgmApiSession::setClusterLogLevel(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ const char *reply= "set cluster loglevel reply";
+ Uint32 node, level, cat;
+ BaseString errorString;
+ SetLogLevelOrd logLevel;
+ int result;
+ DBUG_ENTER("MgmApiSession::setClusterLogLevel");
+ args.get("node", &node);
+ args.get("category", &cat);
+ args.get("level", &level);
+
+ DBUG_PRINT("enter",("node=%d, category=%d, level=%d", node, cat, level));
+
+ /* XXX should use constants for this value */
+ if(level > 15) {
+ m_output->println(reply);
+ m_output->println("result: Invalid loglevel %d", level);
+ m_output->println("");
+ DBUG_VOID_RETURN;
+ }
+
+ LogLevel::EventCategory category=
+ (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
+
+ m_mgmsrv.m_event_listner.lock();
+ if (m_mgmsrv.m_event_listner[0].m_logLevel.setLogLevel(category,level))
+ {
+ m_output->println(reply);
+ m_output->println("result: Invalid category %d", category);
+ m_output->println("");
+ m_mgmsrv.m_event_listner.unlock();
+ DBUG_VOID_RETURN;
+ }
+ m_mgmsrv.m_event_listner.unlock();
+
+ {
+ LogLevel tmp;
+ m_mgmsrv.m_event_listner.update_max_log_level(tmp);
+ }
+
+ m_output->println(reply);
+ m_output->println("result: Ok");
+ m_output->println("");
+ DBUG_VOID_RETURN;
+}
+
+void
+MgmApiSession::setLogLevel(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node = 0, level = 0, cat;
+ BaseString errorString;
+ SetLogLevelOrd logLevel;
+ int result;
+ logLevel.clear();
+ args.get("node", &node);
+ args.get("category", &cat);
+ args.get("level", &level);
+
+ /* XXX should use constants for this value */
+ if(level > 15) {
+ m_output->println("set loglevel reply");
+ m_output->println("result: Invalid loglevel", errorString.c_str());
+ m_output->println("");
+ return;
+ }
+
+ LogLevel::EventCategory category=
+ (LogLevel::EventCategory)(cat-(int)CFG_MIN_LOGLEVEL);
+
+ {
+ LogLevel ll;
+ ll.setLogLevel(category,level);
+ m_mgmsrv.m_event_listner.update_max_log_level(ll);
+ }
+
+ m_output->println("set loglevel reply");
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::stopSignalLog(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node;
+
+ args.get("node", &node);
+
+ int result = m_mgmsrv.stopSignalTracing(node);
+
+ m_output->println("stop signallog");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::restart_v1(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ restart(args,1);
+}
+
+void
+MgmApiSession::restart_v2(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ restart(args,2);
+}
+
+void
+MgmApiSession::restart(Properties const &args, int version) {
+ Uint32
+ nostart = 0,
+ initialstart = 0,
+ abort = 0;
+ char *nodes_str;
+ Vector<NodeId> nodes;
+
+ args.get("initialstart", &initialstart);
+ args.get("nostart", &nostart);
+ args.get("abort", &abort);
+ args.get("node", (const char **)&nodes_str);
+
+ char *p, *last;
+ for((p = strtok_r(nodes_str, " ", &last));
+ p;
+ (p = strtok_r(NULL, " ", &last))) {
+ nodes.push_back(atoi(p));
+ }
+
+ int restarted = 0;
+ int result= m_mgmsrv.restartNodes(nodes,
+ &restarted,
+ nostart != 0,
+ initialstart != 0,
+ abort != 0,
+ &m_stopSelf);
+
+ m_output->println("restart reply");
+ if(result != 0){
+ m_output->println("result: %d-%s", result, get_error_text(result));
+ } else
+ m_output->println("result: Ok");
+ m_output->println("restarted: %d", restarted);
+ if(version>1)
+ m_output->println("disconnect: %d", (m_stopSelf)?1:0);
+ m_output->println("");
+}
+
+void
+MgmApiSession::restartAll(Parser<MgmApiSession>::Context &,
+ Properties const &args)
+{
+ Uint32 nostart = 0;
+ Uint32 initialstart = 0;
+ Uint32 abort = 0;
+
+ args.get("initialstart", &initialstart);
+ args.get("abort", &abort);
+ args.get("nostart", &nostart);
+
+ int count = 0;
+ int result = m_mgmsrv.restartDB(nostart, initialstart, abort, &count);
+
+ m_output->println("restart reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("restarted: %d", count);
+ m_output->println("");
+}
+
+static void
+printNodeStatus(OutputStream *output,
+ MgmtSrvr &mgmsrv,
+ enum ndb_mgm_node_type type) {
+ NodeId nodeId = 0;
+ mgmsrv.updateStatus();
+ while(mgmsrv.getNextNodeId(&nodeId, type)) {
+ enum ndb_mgm_node_status status;
+ Uint32 startPhase = 0,
+ version = 0,
+ dynamicId = 0,
+ nodeGroup = 0,
+ connectCount = 0;
+ bool system;
+ const char *address= NULL;
+ mgmsrv.status(nodeId, &status, &version, &startPhase,
+ &system, &dynamicId, &nodeGroup, &connectCount,
+ &address);
+ output->println("node.%d.type: %s",
+ nodeId,
+ ndb_mgm_get_node_type_string(type));
+ output->println("node.%d.status: %s",
+ nodeId,
+ ndb_mgm_get_node_status_string(status));
+ output->println("node.%d.version: %d", nodeId, version);
+ output->println("node.%d.startphase: %d", nodeId, startPhase);
+ output->println("node.%d.dynamic_id: %d", nodeId, dynamicId);
+ output->println("node.%d.node_group: %d", nodeId, nodeGroup);
+ output->println("node.%d.connect_count: %d", nodeId, connectCount);
+ output->println("node.%d.address: %s", nodeId, address ? address : "");
+ }
+
+}
+
+void
+MgmApiSession::getStatus(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ int noOfNodes = 0;
+
+ NodeId nodeId = 0;
+ while(m_mgmsrv.getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_NDB)){
+ noOfNodes++;
+ }
+ nodeId = 0;
+ while(m_mgmsrv.getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_API)){
+ noOfNodes++;
+ }
+ nodeId = 0;
+ while(m_mgmsrv.getNextNodeId(&nodeId, NDB_MGM_NODE_TYPE_MGM)){
+ noOfNodes++;
+ }
+
+ m_output->println("node status");
+ m_output->println("nodes: %d", noOfNodes);
+ printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_NDB);
+ printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_MGM);
+ printNodeStatus(m_output, m_mgmsrv, NDB_MGM_NODE_TYPE_API);
+
+ nodeId = 0;
+
+ m_output->println("");
+}
+
+void
+MgmApiSession::getInfoClusterLog(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ const char* names[] = { "enabled",
+ "debug",
+ "info",
+ "warning",
+ "error",
+ "critical",
+ "alert" };
+
+ m_output->println("clusterlog");
+ for(int i = 0; i < 7; i++) {
+ m_output->println("%s: %d",
+ names[i], m_mgmsrv.isEventLogFilterEnabled(i));
+ }
+ m_output->println("");
+}
+
+void
+MgmApiSession::stop_v1(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ stop(args,1);
+}
+
+void
+MgmApiSession::stop_v2(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ stop(args,2);
+}
+
+void
+MgmApiSession::stop(Properties const &args, int version) {
+ Uint32 abort;
+ char *nodes_str;
+ Vector<NodeId> nodes;
+
+ args.get("node", (const char **)&nodes_str);
+ if(nodes_str == NULL)
+ {
+ m_output->println("stop reply");
+ m_output->println("result: empty node list");
+ m_output->println("");
+ return;
+ }
+ args.get("abort", &abort);
+
+ char *p, *last;
+ for((p = strtok_r(nodes_str, " ", &last));
+ p;
+ (p = strtok_r(NULL, " ", &last))) {
+ nodes.push_back(atoi(p));
+ }
+
+ int stopped= 0;
+ int result= 0;
+ if (nodes.size())
+ result= m_mgmsrv.stopNodes(nodes, &stopped, abort != 0, &m_stopSelf);
+
+ m_output->println("stop reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("stopped: %d", stopped);
+ if(version>1)
+ m_output->println("disconnect: %d", (m_stopSelf)?1:0);
+ m_output->println("");
+}
+
+void
+MgmApiSession::stopAll(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ int stopped[2] = {0,0};
+ Uint32 abort;
+ args.get("abort", &abort);
+
+ BaseString stop;
+ const char* tostop= "db";
+ int ver=1;
+ if (args.get("stop", stop))
+ {
+ tostop= stop.c_str();
+ ver= 2;
+ }
+
+ int result= 0;
+ if(strstr(tostop,"db"))
+ result= m_mgmsrv.shutdownDB(&stopped[0], abort != 0);
+ if(!result && strstr(tostop,"mgm"))
+ result= m_mgmsrv.shutdownMGM(&stopped[1], abort!=0, &m_stopSelf);
+
+ m_output->println("stop reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("stopped: %d", stopped[0]+stopped[1]);
+ if(ver >1)
+ m_output->println("disconnect: %d", (m_stopSelf)?1:0);
+ m_output->println("");
+}
+
+void
+MgmApiSession::enterSingleUser(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ int stopped = 0;
+ Uint32 nodeId = 0;
+ args.get("nodeId", &nodeId);
+ int result = m_mgmsrv.enterSingleUser(&stopped, nodeId);
+ m_output->println("enter single user reply");
+ if(result != 0) {
+ m_output->println("result: %s", get_error_text(result));
+ }
+ else {
+ m_output->println("result: Ok");
+ }
+ m_output->println("");
+}
+
+void
+MgmApiSession::exitSingleUser(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ int stopped = 0;
+ int result = m_mgmsrv.exitSingleUser(&stopped, false);
+ m_output->println("exit single user reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+
+void
+MgmApiSession::startSignalLog(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node;
+
+ args.get("node", &node);
+
+ int result = m_mgmsrv.startSignalTracing(node);
+
+ m_output->println("start signallog reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::logSignals(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node = 0, in = 0, out = 0;
+ // BaseString blocks;
+ BaseString blockList;
+ char * blockName;
+ args.get("node", &node);
+ args.get("in", &in);
+ args.get("out", &out);
+ args.get("blocks", blockList);
+ // fast fix - pekka
+ char buf[200];
+ BaseString::snprintf(buf, 200, "%s", blockList.c_str());
+ Vector<BaseString> blocks;
+
+ blockName=strtok(buf,"|");
+ while( blockName != NULL)
+ {
+ blocks.push_back(blockName);
+ blockName=strtok(NULL,"|");
+ }
+
+
+ if(in > 1 || out > 1)
+ return; /* Invalid arguments */
+
+ const MgmtSrvr::LogMode modes[] = {
+ MgmtSrvr::Off,
+ MgmtSrvr::Out,
+ MgmtSrvr::In,
+ MgmtSrvr::InOut,
+ };
+ MgmtSrvr::LogMode mode = modes[in<<1 | out];
+
+ int result = m_mgmsrv.setSignalLoggingMode(node, mode, blocks);
+
+ m_output->println("log signals reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::start(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 node;
+
+ args.get("node", &node);
+
+ int result = m_mgmsrv.start(node);
+
+ m_output->println("start reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::startAll(Parser<MgmApiSession>::Context &,
+ Properties const &) {
+ NodeId node = 0;
+ int started = 0;
+
+ while(m_mgmsrv.getNextNodeId(&node, NDB_MGM_NODE_TYPE_NDB))
+ if(m_mgmsrv.start(node) == 0)
+ started++;
+
+ m_output->println("start reply");
+ m_output->println("result: Ok");
+ m_output->println("started: %d", started);
+ m_output->println("");
+}
+
+void
+MgmApiSession::setLogFilter(Parser_t::Context &ctx,
+ const class Properties &args) {
+ Uint32 severity;
+ Uint32 enable;
+
+ args.get("level", &severity);
+ args.get("enable", &enable);
+
+ int result = m_mgmsrv.setEventLogFilter(severity, enable);
+
+ m_output->println("set logfilter reply");
+ m_output->println("result: %d", result);
+ m_output->println("");
+}
+
+static NdbOut&
+operator<<(NdbOut& out, const LogLevel & ll)
+{
+ out << "[LogLevel: ";
+ for(size_t i = 0; i<LogLevel::LOGLEVEL_CATEGORIES; i++)
+ out << ll.getLogLevel((LogLevel::EventCategory)i) << " ";
+ out << "]";
+ return out;
+}
+
+void
+Ndb_mgmd_event_service::log(int eventType, const Uint32* theData, NodeId nodeId){
+
+ Uint32 threshold;
+ LogLevel::EventCategory cat;
+ Logger::LoggerLevel severity;
+ EventLoggerBase::EventTextFunction textF;
+ int i, n;
+ DBUG_ENTER("Ndb_mgmd_event_service::log");
+ DBUG_PRINT("enter",("eventType=%d, nodeid=%d", eventType, nodeId));
+
+ if (EventLoggerBase::event_lookup(eventType,cat,threshold,severity,textF))
+ DBUG_VOID_RETURN;
+
+ char m_text[512];
+ EventLogger::getText(m_text, sizeof(m_text),
+ textF, theData, nodeId);
+
+ BaseString str("log event reply\n");
+ str.appfmt("type=%d\n", eventType);
+ str.appfmt("time=%d\n", 0);
+ str.appfmt("source_nodeid=%d\n", nodeId);
+ for (i= 0; ndb_logevent_body[i].token; i++)
+ {
+ if ( ndb_logevent_body[i].type != eventType)
+ continue;
+ int val= theData[ndb_logevent_body[i].index];
+ if (ndb_logevent_body[i].index_fn)
+ val= (*(ndb_logevent_body[i].index_fn))(val);
+ str.appfmt("%s=%d\n",ndb_logevent_body[i].token, val);
+ if(strcmp(ndb_logevent_body[i].token,"error") == 0)
+ {
+ int m_text_len= strlen(m_text);
+ if(sizeof(m_text)-m_text_len-3 > 0)
+ {
+ BaseString::snprintf(m_text+m_text_len, 4 , " - ");
+ ndb_error_string(val, m_text+(m_text_len+3), sizeof(m_text)-m_text_len-3);
+ }
+ }
+ }
+
+ Vector<NDB_SOCKET_TYPE> copy;
+ m_clients.lock();
+ for(i = m_clients.size() - 1; i >= 0; i--)
+ {
+ if(threshold <= m_clients[i].m_logLevel.getLogLevel(cat))
+ {
+ NDB_SOCKET_TYPE fd= m_clients[i].m_socket;
+ if(fd != NDB_INVALID_SOCKET)
+ {
+ int r;
+ if (m_clients[i].m_parsable)
+ r= println_socket(fd,
+ MAX_WRITE_TIMEOUT, str.c_str());
+ else
+ r= println_socket(fd,
+ MAX_WRITE_TIMEOUT, m_text);
+ if (r == -1) {
+ copy.push_back(fd);
+ m_clients.erase(i, false);
+ }
+ }
+ }
+ }
+ m_clients.unlock();
+
+ if ((n= (int)copy.size()))
+ {
+ for(i= 0; i < n; i++)
+ NDB_CLOSE_SOCKET(copy[i]);
+
+ LogLevel tmp; tmp.clear();
+ m_clients.lock();
+ for(i= m_clients.size() - 1; i >= 0; i--)
+ tmp.set_max(m_clients[i].m_logLevel);
+ m_clients.unlock();
+ update_log_level(tmp);
+ }
+ DBUG_VOID_RETURN;
+}
+
+void
+Ndb_mgmd_event_service::update_max_log_level(const LogLevel &log_level)
+{
+ LogLevel tmp = log_level;
+ m_clients.lock();
+ for(int i = m_clients.size() - 1; i >= 0; i--)
+ tmp.set_max(m_clients[i].m_logLevel);
+ m_clients.unlock();
+ update_log_level(tmp);
+}
+
+void
+Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp)
+{
+ m_logLevel = tmp;
+ EventSubscribeReq req;
+ req = tmp;
+ // send update to all nodes
+ req.blockRef = 0;
+ m_mgmsrv->m_log_level_requests.push_back(req);
+}
+
+void
+Ndb_mgmd_event_service::check_listeners()
+{
+ int i, n= 0;
+ DBUG_ENTER("Ndb_mgmd_event_service::check_listeners");
+ m_clients.lock();
+ for(i= m_clients.size() - 1; i >= 0; i--)
+ {
+ int fd= m_clients[i].m_socket;
+ DBUG_PRINT("info",("%d %d",i,fd));
+ char buf[1];
+ buf[0]=0;
+ if (fd != NDB_INVALID_SOCKET &&
+ println_socket(fd,MAX_WRITE_TIMEOUT,"<PING>") == -1)
+ {
+ NDB_CLOSE_SOCKET(fd);
+ m_clients.erase(i, false);
+ n=1;
+ }
+ }
+ if (n)
+ {
+ LogLevel tmp; tmp.clear();
+ for(i= m_clients.size() - 1; i >= 0; i--)
+ tmp.set_max(m_clients[i].m_logLevel);
+ update_log_level(tmp);
+ }
+ m_clients.unlock();
+ DBUG_VOID_RETURN;
+}
+
+void
+Ndb_mgmd_event_service::add_listener(const Event_listener& client)
+{
+ DBUG_ENTER("Ndb_mgmd_event_service::add_listener");
+ DBUG_PRINT("enter",("client.m_socket: %d", client.m_socket));
+
+ check_listeners();
+
+ m_clients.push_back(client);
+ update_max_log_level(client.m_logLevel);
+
+ DBUG_VOID_RETURN;
+}
+
+void
+Ndb_mgmd_event_service::stop_sessions(){
+ m_clients.lock();
+ for(int i = m_clients.size() - 1; i >= 0; i--){
+ if(m_clients[i].m_socket != NDB_INVALID_SOCKET){
+ NDB_CLOSE_SOCKET(m_clients[i].m_socket);
+ m_clients.erase(i);
+ }
+ }
+ m_clients.unlock();
+}
+
+void
+MgmApiSession::setParameter(Parser_t::Context &,
+ Properties const &args) {
+ BaseString node, param, value;
+ args.get("node", node);
+ args.get("parameter", param);
+ args.get("value", value);
+
+ BaseString result;
+ int ret = m_mgmsrv.setDbParameter(atoi(node.c_str()),
+ atoi(param.c_str()),
+ value.c_str(),
+ result);
+
+ m_output->println("set parameter reply");
+ m_output->println("message: %s", result.c_str());
+ m_output->println("result: %d", ret);
+ m_output->println("");
+}
+
+void
+MgmApiSession::setConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args) {
+ BaseString node1, node2, param, value;
+ args.get("node1", node1);
+ args.get("node2", node2);
+ args.get("param", param);
+ args.get("value", value);
+
+ BaseString result;
+ int ret = m_mgmsrv.setConnectionDbParameter(atoi(node1.c_str()),
+ atoi(node2.c_str()),
+ atoi(param.c_str()),
+ atoi(value.c_str()),
+ result);
+
+ m_output->println("set connection parameter reply");
+ m_output->println("message: %s", result.c_str());
+ m_output->println("result: %s", (ret>0)?"Ok":"Failed");
+ m_output->println("");
+}
+
+void
+MgmApiSession::getConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args) {
+ BaseString node1, node2, param;
+ int value = 0;
+
+ args.get("node1", node1);
+ args.get("node2", node2);
+ args.get("param", param);
+
+ BaseString result;
+ int ret = m_mgmsrv.getConnectionDbParameter(atoi(node1.c_str()),
+ atoi(node2.c_str()),
+ atoi(param.c_str()),
+ &value,
+ result);
+
+ m_output->println("get connection parameter reply");
+ m_output->println("value: %d", value);
+ m_output->println("result: %s", (ret>0)?"Ok":result.c_str());
+ m_output->println("");
+}
+
+void
+MgmApiSession::listen_event(Parser<MgmApiSession>::Context & ctx,
+ Properties const & args) {
+ Uint32 parsable= 0;
+ BaseString node, param, value;
+ args.get("node", node);
+ args.get("filter", param);
+ args.get("parsable", &parsable);
+
+ int result = 0;
+ BaseString msg;
+
+ Ndb_mgmd_event_service::Event_listener le;
+ le.m_parsable = parsable;
+ le.m_socket = m_socket;
+
+ Vector<BaseString> list;
+ param.trim();
+ param.split(list, " ,");
+ for(size_t i = 0; i<list.size(); i++){
+ Vector<BaseString> spec;
+ list[i].trim();
+ list[i].split(spec, "=:");
+ if(spec.size() != 2){
+ msg.appfmt("Invalid filter specification: >%s< >%s< %d",
+ param.c_str(), list[i].c_str(), spec.size());
+ result = -1;
+ goto done;
+ }
+
+ spec[0].trim().ndb_toupper();
+ int category = ndb_mgm_match_event_category(spec[0].c_str());
+ if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
+ category = atoi(spec[0].c_str());
+ if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
+ category > NDB_MGM_MAX_EVENT_CATEGORY){
+ msg.appfmt("Unknown category: >%s<", spec[0].c_str());
+ result = -1;
+ goto done;
+ }
+ }
+
+ int level = atoi(spec[1].c_str());
+ if(level < 0 || level > 15){
+ msg.appfmt("Invalid level: >%s<", spec[1].c_str());
+ result = -1;
+ goto done;
+ }
+ category -= CFG_MIN_LOGLEVEL;
+ le.m_logLevel.setLogLevel((LogLevel::EventCategory)category, level);
+ }
+
+ if(list.size() == 0){
+ msg.appfmt("Empty filter specification");
+ result = -1;
+ goto done;
+ }
+
+done:
+ m_output->println("listen event");
+ m_output->println("result: %d", result);
+ if(result != 0)
+ m_output->println("msg: %s", msg.c_str());
+ m_output->println("");
+
+ if(result==0)
+ {
+ m_mgmsrv.m_event_listner.add_listener(le);
+ m_stop = true;
+ m_socket = NDB_INVALID_SOCKET;
+ }
+}
+
+void
+MgmApiSession::stop_session_if_not_connected(SocketServer::Session *_s, void *data)
+{
+ MgmApiSession *s= (MgmApiSession *)_s;
+ struct PurgeStruct &ps= *(struct PurgeStruct *)data;
+ if (s->m_allocated_resources->is_reserved(ps.free_nodes))
+ {
+ if (ps.str)
+ ps.str->appfmt(" %d", s->m_allocated_resources->get_nodeid());
+ s->stopSession();
+ }
+}
+
+void
+MgmApiSession::stop_session_if_timed_out(SocketServer::Session *_s, void *data)
+{
+ MgmApiSession *s= (MgmApiSession *)_s;
+ struct PurgeStruct &ps= *(struct PurgeStruct *)data;
+ if (s->m_allocated_resources->is_reserved(ps.free_nodes) &&
+ s->m_allocated_resources->is_timed_out(ps.tick))
+ {
+ s->stopSession();
+ }
+}
+
+void
+MgmApiSession::purge_stale_sessions(Parser_t::Context &ctx,
+ const class Properties &args)
+{
+ struct PurgeStruct ps;
+ BaseString str;
+ ps.str = &str;
+
+ m_mgmsrv.get_connected_nodes(ps.free_nodes);
+ ps.free_nodes.bitXORC(NodeBitmask()); // invert connected_nodes to get free nodes
+
+ m_mgmsrv.get_socket_server()->foreachSession(stop_session_if_not_connected,&ps);
+ m_mgmsrv.get_socket_server()->checkSessions();
+
+ m_output->println("purge stale sessions reply");
+ if (str.length() > 0)
+ m_output->println("purged:%s",str.c_str());
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::check_connection(Parser_t::Context &ctx,
+ const class Properties &args)
+{
+ m_output->println("check connection reply");
+ m_output->println("result: Ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::transporter_connect(Parser_t::Context &ctx,
+ Properties const &args)
+{
+ m_mgmsrv.transporter_connect(m_socket);
+
+ m_stop= true;
+ m_stopped= true; // force a stop (no closing socket)
+ m_socket= NDB_INVALID_SOCKET; // so nobody closes it
+}
+
+void
+MgmApiSession::get_mgmd_nodeid(Parser_t::Context &ctx,
+ Properties const &args)
+{
+ m_output->println("get mgmd nodeid reply");
+ m_output->println("nodeid:%u",m_mgmsrv.getOwnNodeId());
+ m_output->println("");
+}
+
+void
+MgmApiSession::report_event(Parser_t::Context &ctx,
+ Properties const &args)
+{
+ Uint32 length;
+ const char *data_string;
+ Uint32 data[25];
+
+ args.get("length", &length);
+ args.get("data", &data_string);
+
+ BaseString tmp(data_string);
+ Vector<BaseString> item;
+ tmp.split(item, " ");
+ for (int i = 0; (Uint32) i < length ; i++)
+ {
+ sscanf(item[i].c_str(), "%u", data+i);
+ }
+
+ m_mgmsrv.eventReport(data);
+ m_output->println("report event reply");
+ m_output->println("result: ok");
+ m_output->println("");
+}
+
+void
+MgmApiSession::list_session(SocketServer::Session *_s, void *data)
+{
+ MgmApiSession *s= (MgmApiSession *)_s;
+ MgmApiSession *lister= (MgmApiSession*) data;
+
+ if(s!=lister)
+ NdbMutex_Lock(s->m_mutex);
+
+ Uint64 id= s->m_session_id;
+ lister->m_output->println("session: %llu",id);
+ lister->m_output->println("session.%llu.m_stopSelf: %d",id,s->m_stopSelf);
+ lister->m_output->println("session.%llu.m_stop: %d",id,s->m_stop);
+ lister->m_output->println("session.%llu.allocated.nodeid: %d",id,s->m_allocated_resources->get_nodeid());
+ if(s->m_ctx)
+ {
+ int l= strlen(s->m_ctx->m_tokenBuffer);
+ char *buf= (char*) malloc(2*l+1);
+ char *b= buf;
+ for(int i=0; i<l;i++)
+ if(s->m_ctx->m_tokenBuffer[i]=='\n')
+ {
+ *b++='\\';
+ *b++='n';
+ }
+ else
+ {
+ *b++= s->m_ctx->m_tokenBuffer[i];
+ }
+ *b= '\0';
+
+ lister->m_output->println("session.%llu.parser.buffer.len: %u",id,l);
+ lister->m_output->println("session.%llu.parser.buffer: %s",id,buf);
+ lister->m_output->println("session.%llu.parser.status: %d",id,s->m_ctx->m_status);
+
+ free(buf);
+ }
+
+ if(s!=lister)
+ NdbMutex_Unlock(s->m_mutex);
+}
+
+void
+MgmApiSession::listSessions(Parser_t::Context &ctx,
+ Properties const &args) {
+ m_mgmsrv.get_socket_server()->foreachSession(list_session,(void*)this);
+
+ m_output->println("");
+}
+
+void
+MgmApiSession::getSessionId(Parser_t::Context &ctx,
+ Properties const &args) {
+ m_output->println("get session id reply");
+ m_output->println("id: %llu",m_session_id);
+ m_output->println("");
+}
+
+struct get_session_param {
+ MgmApiSession *l;
+ Uint64 id;
+ int found;
+};
+
+void
+MgmApiSession::get_session(SocketServer::Session *_s, void *data)
+{
+ struct get_session_param *p= (struct get_session_param*)data;
+ MgmApiSession *s= (MgmApiSession *)_s;
+
+ if(s!=p->l)
+ NdbMutex_Lock(s->m_mutex);
+
+ if(p->id != s->m_session_id)
+ {
+ if(s!=p->l)
+ NdbMutex_Unlock(s->m_mutex);
+ return;
+ }
+
+ p->found= true;
+ p->l->m_output->println("id: %llu",s->m_session_id);
+ p->l->m_output->println("m_stopSelf: %d",s->m_stopSelf);
+ p->l->m_output->println("m_stop: %d",s->m_stop);
+ p->l->m_output->println("nodeid: %d",s->m_allocated_resources->get_nodeid());
+ if(s->m_ctx)
+ {
+ int l= strlen(s->m_ctx->m_tokenBuffer);
+ p->l->m_output->println("parser_buffer_len: %u",l);
+ p->l->m_output->println("parser_status: %d",s->m_ctx->m_status);
+ }
+
+ if(s!=p->l)
+ NdbMutex_Unlock(s->m_mutex);
+}
+
+void
+MgmApiSession::getSession(Parser_t::Context &ctx,
+ Properties const &args) {
+ Uint64 id;
+ struct get_session_param p;
+
+ args.get("id", &id);
+
+ p.l= this;
+ p.id= id;
+ p.found= false;
+
+ m_output->println("get session reply");
+ m_mgmsrv.get_socket_server()->foreachSession(get_session,(void*)&p);
+
+ if(p.found==false)
+ m_output->println("id: 0");
+
+ m_output->println("");
+}
+
+template class MutexVector<int>;
+template class Vector<ParserRow<MgmApiSession> const*>;
diff --git a/storage/ndb/src/mgmsrv/Services.hpp b/storage/ndb/src/mgmsrv/Services.hpp
new file mode 100644
index 00000000000..8b9ca7156b9
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Services.hpp
@@ -0,0 +1,143 @@
+/* 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 */
+
+#ifndef MGMAPI_SERVICE_HPP
+#define MGMAPI_SERVICE_HPP
+
+#include <SocketServer.hpp>
+#include <NdbSleep.h>
+#include <Parser.hpp>
+#include <OutputStream.hpp>
+#include <InputStream.hpp>
+
+#include "MgmtSrvr.hpp"
+
+/** Undefine this to remove backwards compatibility for "GET CONFIG". */
+#define MGM_GET_CONFIG_BACKWARDS_COMPAT
+
+class MgmApiSession : public SocketServer::Session
+{
+ static void stop_session_if_timed_out(SocketServer::Session *_s, void *data);
+ static void stop_session_if_not_connected(SocketServer::Session *_s, void *data);
+ static void list_session(SocketServer::Session *_s, void *data);
+ static void get_session(SocketServer::Session *_s, void *data);
+private:
+ typedef Parser<MgmApiSession> Parser_t;
+
+ class MgmtSrvr & m_mgmsrv;
+ InputStream *m_input;
+ OutputStream *m_output;
+ Parser_t *m_parser;
+ MgmtSrvr::Allocated_resources *m_allocated_resources;
+ char m_err_str[1024];
+ int m_stopSelf; // -1 is restart, 0 do nothing, 1 stop
+ NdbMutex *m_mutex;
+
+ // for listing sessions and other fun:
+ Parser_t::Context *m_ctx;
+ Uint64 m_session_id;
+
+ void getConfig_common(Parser_t::Context &ctx,
+ const class Properties &args,
+ bool compat = false);
+ const char *get_error_text(int err_no)
+ { return m_mgmsrv.getErrorText(err_no, m_err_str, sizeof(m_err_str)); }
+
+public:
+ MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock, Uint64 session_id);
+ virtual ~MgmApiSession();
+ void runSession();
+
+ void getConfig(Parser_t::Context &ctx, const class Properties &args);
+#ifdef MGM_GET_CONFIG_BACKWARDS_COMPAT
+ void getConfig_old(Parser_t::Context &ctx);
+#endif /* MGM_GET_CONFIG_BACKWARDS_COMPAT */
+
+ void get_nodeid(Parser_t::Context &ctx, const class Properties &args);
+ void getVersion(Parser_t::Context &ctx, const class Properties &args);
+ void getStatus(Parser_t::Context &ctx, const class Properties &args);
+ void getInfoClusterLog(Parser_t::Context &ctx, const class Properties &args);
+ void restart(const class Properties &args, int version);
+ void restart_v1(Parser_t::Context &ctx, const class Properties &args);
+ void restart_v2(Parser_t::Context &ctx, const class Properties &args);
+ void restartAll(Parser_t::Context &ctx, const class Properties &args);
+ void insertError(Parser_t::Context &ctx, const class Properties &args);
+ void setTrace(Parser_t::Context &ctx, const class Properties &args);
+ void logSignals(Parser_t::Context &ctx, const class Properties &args);
+ void startSignalLog(Parser_t::Context &ctx, const class Properties &args);
+ void stopSignalLog(Parser_t::Context &ctx, const class Properties &args);
+ void dumpState(Parser_t::Context &ctx, const class Properties &args);
+ void startBackup(Parser_t::Context &ctx, const class Properties &args);
+ void abortBackup(Parser_t::Context &ctx, const class Properties &args);
+ void enterSingleUser(Parser_t::Context &ctx, const class Properties &args);
+ void exitSingleUser(Parser_t::Context &ctx, const class Properties &args);
+ void stop_v1(Parser_t::Context &ctx, const class Properties &args);
+ void stop_v2(Parser_t::Context &ctx, const class Properties &args);
+ void stop(const class Properties &args, int version);
+ void stopAll(Parser_t::Context &ctx, const class Properties &args);
+ void start(Parser_t::Context &ctx, const class Properties &args);
+ void startAll(Parser_t::Context &ctx, const class Properties &args);
+ void bye(Parser_t::Context &ctx, const class Properties &args);
+ void endSession(Parser_t::Context &ctx, const class Properties &args);
+ void setLogLevel(Parser_t::Context &ctx, const class Properties &args);
+ void getClusterLogLevel(Parser_t::Context &ctx,
+ const class Properties &args);
+ void setClusterLogLevel(Parser_t::Context &ctx,
+ const class Properties &args);
+ void setLogFilter(Parser_t::Context &ctx, const class Properties &args);
+
+ void setParameter(Parser_t::Context &ctx, const class Properties &args);
+ void setConnectionParameter(Parser_t::Context &ctx,
+ const class Properties &args);
+ void getConnectionParameter(Parser_t::Context &ctx,
+ Properties const &args);
+
+ void listen_event(Parser_t::Context &ctx, const class Properties &args);
+
+ void purge_stale_sessions(Parser_t::Context &ctx, const class Properties &args);
+ void check_connection(Parser_t::Context &ctx, const class Properties &args);
+
+ void transporter_connect(Parser_t::Context &ctx, Properties const &args);
+
+ void get_mgmd_nodeid(Parser_t::Context &ctx, Properties const &args);
+
+ void report_event(Parser_t::Context &ctx, Properties const &args);
+
+ void listSessions(Parser_t::Context &ctx, Properties const &args);
+
+ void getSessionId(Parser_t::Context &ctx, Properties const &args);
+ void getSession(Parser_t::Context &ctx, Properties const &args);
+};
+
+class MgmApiService : public SocketServer::Service {
+ class MgmtSrvr * m_mgmsrv;
+ Uint64 m_next_session_id; // Protected by m_sessions mutex it SocketServer
+public:
+ MgmApiService(){
+ m_mgmsrv = 0;
+ m_next_session_id= 1;
+ }
+
+ void setMgm(class MgmtSrvr * mgmsrv){
+ m_mgmsrv = mgmsrv;
+ }
+
+ SocketServer::Session * newSession(NDB_SOCKET_TYPE socket){
+ return new MgmApiSession(* m_mgmsrv, socket, m_next_session_id++);
+ }
+};
+
+#endif
diff --git a/storage/ndb/src/mgmsrv/SignalQueue.cpp b/storage/ndb/src/mgmsrv/SignalQueue.cpp
new file mode 100644
index 00000000000..08ad5f363a6
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/SignalQueue.cpp
@@ -0,0 +1,104 @@
+/* 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 "SignalQueue.hpp"
+
+SignalQueue::SignalQueue() {
+ m_mutex = NdbMutex_Create();
+ m_cond = NdbCondition_Create();
+ m_signalQueueHead = NULL;
+}
+
+SignalQueue::~SignalQueue() {
+ {
+ Guard g(m_mutex);
+ while(m_signalQueueHead != NULL)
+ delete pop();
+ }
+ NdbMutex_Destroy(m_mutex);
+ m_mutex = NULL;
+ NdbCondition_Destroy(m_cond);
+ m_cond = NULL;
+}
+
+NdbApiSignal *
+SignalQueue::pop() {
+ NdbApiSignal *ret;
+
+ if(m_signalQueueHead == NULL)
+ return NULL;
+
+ ret = m_signalQueueHead->signal;
+
+ QueueEntry *old = m_signalQueueHead;
+ m_signalQueueHead = m_signalQueueHead->next;
+
+ delete old;
+
+ return ret;
+}
+
+void
+SignalQueue::receive(void *me, NdbApiSignal *signal) {
+ SignalQueue *q = (SignalQueue *)me;
+ q->receive(signal);
+}
+
+void
+SignalQueue::receive(NdbApiSignal *signal) {
+ QueueEntry *n = new QueueEntry();
+ n->signal = signal;
+ n->next = NULL;
+
+ Guard guard(m_mutex);
+
+ if(m_signalQueueHead == NULL) {
+ m_signalQueueHead = n;
+ NdbCondition_Broadcast(m_cond);
+ return;
+ }
+
+ QueueEntry *cur = m_signalQueueHead;
+
+ while(cur->next != NULL)
+ cur = cur->next;
+
+ cur->next = n;
+
+ NdbCondition_Broadcast(m_cond);
+}
+
+NdbApiSignal *
+SignalQueue::waitFor(int gsn, NodeId nodeid, Uint32 timeout) {
+ Guard g(m_mutex);
+
+ if(m_signalQueueHead == NULL)
+ NdbCondition_WaitTimeout(m_cond, m_mutex, timeout);
+
+ if(m_signalQueueHead == NULL)
+ return NULL;
+
+ if(gsn != 0 &&
+ m_signalQueueHead->signal->readSignalNumber() != gsn)
+ return NULL;
+
+ if(nodeid != 0 &&
+ refToNode(m_signalQueueHead->signal->theSendersBlockRef) != nodeid)
+ return NULL;
+
+ return pop();
+}
diff --git a/storage/ndb/src/mgmsrv/SignalQueue.hpp b/storage/ndb/src/mgmsrv/SignalQueue.hpp
new file mode 100644
index 00000000000..bacbad53415
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/SignalQueue.hpp
@@ -0,0 +1,100 @@
+/* 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 */
+
+#ifndef __SIGNALQUEUE_HPP_INCLUDED__
+#define __SIGNALQUEUE_HPP_INCLUDED__
+
+#include <NdbApiSignal.hpp>
+#include <NdbMutex.h>
+#include <NdbCondition.h>
+#include <Vector.hpp>
+
+/* XXX Look for an already existing definition */
+#define DEFAULT_TIMEOUT 5000
+
+class SignalQueue {
+public:
+ typedef void (* SignalHandler)(void *obj, int gsn, NdbApiSignal *signal);
+
+ SignalQueue();
+ ~SignalQueue();
+
+ /**
+ * Static wrapper making it possible to call receive without knowing the
+ * type of the receiver
+ */
+ static void receive(void *me, NdbApiSignal *signal);
+
+ /**
+ * Enqueues a signal, and notifies any thread waiting for signals.
+ */
+ void receive(NdbApiSignal *signal);
+
+ NdbApiSignal *waitFor(int gsn,
+ NodeId nodeid = 0,
+ Uint32 timeout = DEFAULT_TIMEOUT);
+ template<class T> bool waitFor(Vector<T> &t,
+ T **handler,
+ NdbApiSignal **signal,
+ Uint32 timeout = DEFAULT_TIMEOUT);
+private:
+ NdbMutex *m_mutex; /* Locks all data in SignalQueue */
+ NdbCondition *m_cond; /* Notifies about new signal in the queue */
+
+ /**
+ * Returns the last recently received signal. Must be called with
+ * m_mutex locked.
+ * The caller takes responsibility for deleting the returned object.
+ *
+ * @returns NULL if failed, or a received signal
+ */
+ NdbApiSignal *pop();
+
+ class QueueEntry {
+ public:
+ NdbApiSignal *signal;
+ QueueEntry *next;
+ };
+ QueueEntry *m_signalQueueHead; /** Head of the queue.
+ * New entries added on the tail
+ */
+};
+
+template<class T> bool
+SignalQueue::waitFor(Vector<T> &t,
+ T **handler,
+ NdbApiSignal **signal,
+ Uint32 timeout) {
+ Guard g(m_mutex);
+
+ if(m_signalQueueHead == NULL)
+ NdbCondition_WaitTimeout(m_cond, m_mutex, timeout);
+
+ if(m_signalQueueHead == NULL)
+ return false;
+
+ for(size_t i = 0; i < t.size(); i++) {
+ if(t[i].check(m_signalQueueHead->signal)) {
+ * handler = &t[i];
+ * signal = pop();
+ return true;
+ }
+ }
+
+ return false;
+}
+
+#endif /* !__SIGNALQUEUE_HPP_INCLUDED__ */
diff --git a/storage/ndb/src/mgmsrv/convertStrToInt.cpp b/storage/ndb/src/mgmsrv/convertStrToInt.cpp
new file mode 100644
index 00000000000..e5216047d10
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/convertStrToInt.cpp
@@ -0,0 +1,43 @@
+/* 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>
+
+bool convert(const char* s, int& val) {
+
+ if (s == NULL) {
+ return false;
+ }
+
+ if (strlen(s) == 0) {
+ return false;
+ }
+
+ errno = 0;
+ char* p;
+ long v = strtol(s, &p, 10);
+ if (errno != 0) {
+ return false;
+ }
+ if (p != &s[strlen(s)]) {
+ return false;
+ }
+
+ val = v;
+ return true;
+}
+
+
diff --git a/storage/ndb/src/mgmsrv/convertStrToInt.hpp b/storage/ndb/src/mgmsrv/convertStrToInt.hpp
new file mode 100644
index 00000000000..0b2a96ed0bf
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/convertStrToInt.hpp
@@ -0,0 +1,25 @@
+/* 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 */
+
+//******************************************************************************
+// Description:
+//
+// Author: Peter Lind
+//******************************************************************************
+
+extern bool convert(const char* s, int& val);
+
+
diff --git a/storage/ndb/src/mgmsrv/main.cpp b/storage/ndb/src/mgmsrv/main.cpp
new file mode 100644
index 00000000000..dd7f4680dff
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/main.cpp
@@ -0,0 +1,388 @@
+/* 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_opts.h>
+
+#include "MgmtSrvr.hpp"
+#include "EventLogger.hpp"
+#include <Config.hpp>
+#include "InitConfigFileParser.hpp"
+#include <SocketServer.hpp>
+#include "Services.hpp"
+#include <version.h>
+#include <kernel_types.h>
+#include <Properties.hpp>
+#include <NdbOut.hpp>
+#include <NdbMain.h>
+#include <NdbDaemon.h>
+#include <NdbConfig.h>
+#include <NdbHost.h>
+#include <ndb_version.h>
+#include <ConfigRetriever.hpp>
+#include <mgmapi_config_parameters.h>
+
+#include <NdbAutoPtr.hpp>
+
+#include <ndb_mgmclient.hpp>
+
+#undef DEBUG
+#define DEBUG(x) ndbout << x << endl;
+
+const char progname[] = "mgmtsrvr";
+const char *load_default_groups[]= { "mysql_cluster","ndb_mgmd",0 };
+
+// copied from mysql.cc to get readline
+extern "C" {
+#if defined( __WIN__)
+#include <conio.h>
+#elif !defined(__NETWARE__)
+#include <readline/readline.h>
+extern "C" int add_history(const char *command); /* From readline directory */
+#define HAVE_READLINE
+#endif
+}
+
+static int
+read_and_execute(Ndb_mgmclient* com, const char * prompt, int _try_reconnect)
+{
+ static char *line_read = (char *)NULL;
+
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+ if (line_read)
+ {
+ free (line_read);
+ line_read = (char *)NULL;
+ }
+#ifdef HAVE_READLINE
+ /* Get a line from the user. */
+ line_read = readline (prompt);
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+#else
+ static char linebuffer[254];
+ fputs(prompt, stdout);
+ linebuffer[sizeof(linebuffer)-1]=0;
+ line_read = fgets(linebuffer, sizeof(linebuffer)-1, stdin);
+ if (line_read == linebuffer) {
+ char *q=linebuffer;
+ while (*q > 31) q++;
+ *q=0;
+ line_read= strdup(linebuffer);
+ }
+#endif
+ return com->execute(line_read,_try_reconnect);
+}
+
+/**
+ * @struct MgmGlobals
+ * @brief Global Variables used in the management server
+ *****************************************************************************/
+
+/** Command line arguments */
+static int opt_daemon; // NOT bool, bool need not be int
+static int opt_non_interactive;
+static int opt_interactive;
+static const char * opt_config_filename= 0;
+static int opt_mycnf = 0;
+
+struct MgmGlobals {
+ MgmGlobals();
+ ~MgmGlobals();
+
+ /** Stuff found in environment or in local config */
+ NodeId localNodeId;
+ bool use_specific_ip;
+ char * interface_name;
+ short unsigned int port;
+
+ /** The Mgmt Server */
+ MgmtSrvr * mgmObject;
+
+ /** The Socket Server */
+ SocketServer * socketServer;
+};
+
+int g_no_nodeid_checks= 0;
+int g_print_full_config;
+static MgmGlobals *glob= 0;
+
+/******************************************************************************
+ * Function prototypes
+ ******************************************************************************/
+/**
+ * Global variables
+ */
+bool g_StopServer;
+bool g_RestartServer;
+extern EventLogger g_eventLogger;
+
+extern int global_mgmt_server_check;
+
+enum ndb_mgmd_options {
+ OPT_INTERACTIVE = NDB_STD_OPTIONS_LAST,
+ OPT_NO_NODEID_CHECKS,
+ OPT_NO_DAEMON
+};
+NDB_STD_OPTS_VARS;
+
+static struct my_option my_long_options[] =
+{
+ NDB_STD_OPTS("ndb_mgmd"),
+ { "config-file", 'f', "Specify cluster configuration file",
+ (gptr*) &opt_config_filename, (gptr*) &opt_config_filename, 0,
+ GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0 },
+ { "print-full-config", 'P', "Print full config and exit",
+ (gptr*) &g_print_full_config, (gptr*) &g_print_full_config, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "daemon", 'd', "Run ndb_mgmd in daemon mode (default)",
+ (gptr*) &opt_daemon, (gptr*) &opt_daemon, 0,
+ GET_BOOL, NO_ARG, 1, 0, 0, 0, 0, 0 },
+ { "interactive", OPT_INTERACTIVE,
+ "Run interactive. Not supported but provided for testing purposes",
+ (gptr*) &opt_interactive, (gptr*) &opt_interactive, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "no-nodeid-checks", OPT_NO_NODEID_CHECKS,
+ "Do not provide any node id checks",
+ (gptr*) &g_no_nodeid_checks, (gptr*) &g_no_nodeid_checks, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "nodaemon", OPT_NO_DAEMON,
+ "Don't run as daemon, but don't read from stdin",
+ (gptr*) &opt_non_interactive, (gptr*) &opt_non_interactive, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { "mycnf", 256,
+ "Read cluster config from my.cnf",
+ (gptr*) &opt_mycnf, (gptr*) &opt_mycnf, 0,
+ GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
+ { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
+};
+
+static void short_usage_sub(void)
+{
+ printf("Usage: %s [OPTIONS]\n", my_progname);
+}
+static void usage()
+{
+ short_usage_sub();
+ ndb_std_print_version();
+ print_defaults(MYSQL_CONFIG_NAME,load_default_groups);
+ puts("");
+ my_print_help(my_long_options);
+ my_print_variables(my_long_options);
+}
+
+/*
+ * MAIN
+ */
+int main(int argc, char** argv)
+{
+ int mgm_connect_result;
+
+ NDB_INIT(argv[0]);
+
+ load_defaults("my",load_default_groups,&argc,&argv);
+
+ int ho_error;
+#ifndef DBUG_OFF
+ opt_debug= "d:t:O,/tmp/ndb_mgmd.trace";
+#endif
+ if ((ho_error=handle_options(&argc, &argv, my_long_options,
+ ndb_std_get_one_option)))
+ exit(ho_error);
+
+start:
+ glob= new MgmGlobals;
+
+ global_mgmt_server_check = 1;
+
+ if (opt_interactive ||
+ opt_non_interactive ||
+ g_print_full_config) {
+ opt_daemon= 0;
+ }
+
+ if (opt_mycnf && opt_config_filename)
+ {
+ ndbout_c("Both --mycnf and -f is not supported");
+ return 0;
+ }
+
+ if (opt_mycnf == 0 && opt_config_filename == 0)
+ {
+ struct stat buf;
+ if (stat("config.ini", &buf) != -1)
+ opt_config_filename = "config.ini";
+ }
+
+ glob->socketServer = new SocketServer();
+
+ MgmApiService * mapi = new MgmApiService();
+
+ glob->mgmObject = new MgmtSrvr(glob->socketServer,
+ opt_config_filename,
+ opt_connect_str);
+
+ if (g_print_full_config)
+ goto the_end;
+
+ if (glob->mgmObject->init())
+ goto error_end;
+
+ my_setwd(NdbConfig_get_path(0), MYF(0));
+
+ glob->localNodeId= glob->mgmObject->getOwnNodeId();
+ if (glob->localNodeId == 0) {
+ goto error_end;
+ }
+
+ glob->port= glob->mgmObject->getPort();
+
+ if (glob->port == 0)
+ goto error_end;
+
+ glob->interface_name = 0;
+ glob->use_specific_ip = false;
+
+ if(!glob->use_specific_ip){
+ int count= 5; // no of retries for tryBind
+ while(!glob->socketServer->tryBind(glob->port, glob->interface_name)){
+ if (--count > 0) {
+ NdbSleep_MilliSleep(1000);
+ continue;
+ }
+ ndbout_c("Unable to setup port: %s:%d!\n"
+ "Please check if the port is already used,\n"
+ "(perhaps a ndb_mgmd is already running),\n"
+ "and if you are executing on the correct computer",
+ (glob->interface_name ? glob->interface_name : "*"), glob->port);
+ goto error_end;
+ }
+ free(glob->interface_name);
+ glob->interface_name = 0;
+ }
+
+ if(!glob->socketServer->setup(mapi, &glob->port, glob->interface_name))
+ {
+ ndbout_c("Unable to setup management port: %d!\n"
+ "Please check if the port is already used,\n"
+ "(perhaps a ndb_mgmd is already running),\n"
+ "and if you are executing on the correct computer",
+ glob->port);
+ delete mapi;
+ goto error_end;
+ }
+
+ if(!glob->mgmObject->check_start()){
+ ndbout_c("Unable to check start management server.");
+ ndbout_c("Probably caused by illegal initial configuration file.");
+ goto error_end;
+ }
+
+ if (opt_daemon) {
+ // Become a daemon
+ char *lockfile= NdbConfig_PidFileName(glob->localNodeId);
+ char *logfile= NdbConfig_StdoutFileName(glob->localNodeId);
+ NdbAutoPtr<char> tmp_aptr1(lockfile), tmp_aptr2(logfile);
+
+ if (NdbDaemon_Make(lockfile, logfile, 0) == -1) {
+ ndbout << "Cannot become daemon: " << NdbDaemon_ErrorText << endl;
+ return 1;
+ }
+ }
+
+#ifndef NDB_WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+ {
+ BaseString error_string;
+ if(!glob->mgmObject->start(error_string)){
+ ndbout_c("Unable to start management server.");
+ ndbout_c("Probably caused by illegal initial configuration file.");
+ ndbout_c(error_string.c_str());
+ goto error_end;
+ }
+ }
+
+ //glob->mgmObject->saveConfig();
+ mapi->setMgm(glob->mgmObject);
+
+ char msg[256];
+ BaseString::snprintf(msg, sizeof(msg),
+ "NDB Cluster Management Server. %s", NDB_VERSION_STRING);
+ ndbout_c(msg);
+ g_eventLogger.info(msg);
+
+ BaseString::snprintf(msg, 256, "Id: %d, Command port: %d",
+ glob->localNodeId, glob->port);
+ ndbout_c(msg);
+ g_eventLogger.info(msg);
+
+ g_StopServer = false;
+ g_RestartServer= false;
+ glob->socketServer->startServer();
+
+ if(opt_interactive) {
+ BaseString con_str;
+ if(glob->interface_name)
+ con_str.appfmt("host=%s:%d", glob->interface_name, glob->port);
+ else
+ con_str.appfmt("localhost:%d", glob->port);
+ Ndb_mgmclient com(con_str.c_str(), 1);
+ while(g_StopServer != true && read_and_execute(&com, "ndb_mgm> ", 1));
+ } else
+ {
+ while(g_StopServer != true)
+ NdbSleep_MilliSleep(500);
+ }
+
+ if(g_RestartServer)
+ g_eventLogger.info("Restarting server...");
+ else
+ g_eventLogger.info("Shutting down server...");
+ glob->socketServer->stopServer();
+ // We disconnect from the ConfigRetreiver mgmd when we delete glob below
+ glob->socketServer->stopSessions(true);
+ g_eventLogger.info("Shutdown complete");
+ the_end:
+ delete glob;
+ if(g_RestartServer)
+ goto start;
+ ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ return 0;
+ error_end:
+ delete glob;
+ ndb_end(opt_endinfo ? MY_CHECK_ERROR | MY_GIVE_INFO : 0);
+ return 1;
+}
+
+MgmGlobals::MgmGlobals(){
+ // Default values
+ port = 0;
+ interface_name = 0;
+ socketServer = 0;
+ mgmObject = 0;
+}
+
+MgmGlobals::~MgmGlobals(){
+ if (socketServer)
+ delete socketServer;
+ if (mgmObject)
+ delete mgmObject;
+ if (interface_name)
+ free(interface_name);
+}
diff --git a/storage/ndb/src/mgmsrv/mkconfig/Makefile b/storage/ndb/src/mgmsrv/mkconfig/Makefile
new file mode 100644
index 00000000000..43574eefbd1
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/mkconfig/Makefile
@@ -0,0 +1,13 @@
+include .defs.mk
+
+TYPE := ndbapi
+
+BIN_TARGET := mkconfig
+BIN_TARGET_ARCHIVES := logger trace mgmsrvcommon portlib general
+
+SOURCES := mkconfig.cpp
+
+CCFLAGS_LOC += -I.. -I$(call fixpath,$(NDB_TOP)/src/common/mgmcommon)
+CFLAGS_mkconfig.cpp := -I$(call fixpath,$(NDB_TOP)/src/mgmapi)
+
+include $(NDB_TOP)/Epilogue.mk
diff --git a/storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp b/storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp
new file mode 100644
index 00000000000..28823aaa35e
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/mkconfig/mkconfig.cpp
@@ -0,0 +1,61 @@
+/* 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_version.h>
+#include <mgmapi_configuration.hpp>
+
+#include <NdbMain.h>
+#include <Properties.hpp>
+
+#include "InitConfigFileParser.hpp"
+#include <Config.hpp>
+
+void usage(const char * prg){
+ ndbout << "Usage " << prg << ": <Init config> <Binary file>" << endl;
+
+}
+
+NDB_COMMAND(mkconfig,
+ "mkconfig", "mkconfig",
+ "Make a binary configuration from a config file", 16384){
+ ndb_init();
+ if(argc < 3){
+ usage(argv[0]);
+ return 0;
+ }
+
+ InitConfigFileParser parser;
+ Config* _cp;
+
+ if ((_cp = parser.parseConfig(argv[1])) == 0)
+ return false;
+
+ ConfigValues* cp = &_cp->m_configValues->m_config;
+ Uint32 sz = cp->getPackedSize();
+ UtilBuffer buf;
+ if(!cp->pack(buf))
+ return -1;
+
+ FILE * f = fopen(argv[2], "w");
+ if(fwrite(buf.get_data(), 1, buf.length(), f) != sz){
+ fclose(f);
+ unlink(argv[2]);
+ return -1;
+ }
+ fclose(f);
+ return 0;
+}