summaryrefslogtreecommitdiff
path: root/ndb/src/mgmclient/CommandInterpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/src/mgmclient/CommandInterpreter.cpp')
-rw-r--r--ndb/src/mgmclient/CommandInterpreter.cpp2013
1 files changed, 2013 insertions, 0 deletions
diff --git a/ndb/src/mgmclient/CommandInterpreter.cpp b/ndb/src/mgmclient/CommandInterpreter.cpp
new file mode 100644
index 00000000000..29d25ebf7d3
--- /dev/null
+++ b/ndb/src/mgmclient/CommandInterpreter.cpp
@@ -0,0 +1,2013 @@
+/* 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 <errno.h>
+#include <string.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <limits.h>
+
+#include <ndb_version.h>
+
+#include <mgmapi.h>
+#include <mgmapi_debug.h>
+#include <version.h>
+#include <NdbOut.hpp>
+#include <NdbSleep.h>
+#include <EventLogger.hpp>
+#include <signaldata/SetLogLevelOrd.hpp>
+#include <signaldata/GrepImpl.hpp>
+#ifdef HAVE_GLOBAL_REPLICATION
+
+#endif // HAVE_GLOBAL_REPLICATION
+#include "MgmtErrorReporter.hpp"
+#include "CommandInterpreter.hpp"
+#include "CpcClient.hpp"
+
+#ifdef NDB_SOLARIS // XXX fix me
+static char* strsep(char** x, const char* y) { return 0; }
+#endif
+
+
+/*****************************************************************************
+ * HELP
+ *****************************************************************************/
+static const char* helpText =
+"---------------------------------------------------------------------------\n"
+" NDB Cluster -- Management Client -- Help\n"
+"---------------------------------------------------------------------------\n"
+"HELP Print help text\n"
+"HELP SHOW Help for SHOW command\n"
+#ifdef HAVE_GLOBAL_REPLICATION
+"HELP REPLICATION Help for global replication\n"
+#endif // HAVE_GLOBAL_REPLICATION
+#ifdef VM_TRACE // DEBUG ONLY
+"HELP DEBUG Help for debug compiled version\n"
+#endif
+"SHOW Print information about cluster\n"
+"SHOW CONFIG Print configuration\n"
+"SHOW PARAMETERS Print configuration parameters\n"
+"START BACKUP Start backup\n"
+"ABORT BACKUP <backup id> Abort backup\n"
+"CLUSTERLOG ON Enable Cluster logging\n"
+"CLUSTERLOG OFF Disable Cluster logging\n"
+"CLUSTERLOG FILTER <severity> Toggle severity filter on/off\n"
+"CLUSTERLOG INFO Print cluster log information\n"
+"<id> START Start DB node (started with -n)\n"
+"<id> RESTART [-n] [-i] Restart DB node\n"
+"<id> STOP Stop DB node\n"
+"ENTER SINGLE USER MODE <api-node> Enter single user mode\n"
+"EXIT SINGLE USER MODE Exit single user mode\n"
+"<id> STATUS Print status\n"
+"<id> CLUSTERLOG {<category>=<level>}+ Set log level for cluster log\n"
+"REP CONNECT <host:port> Connect to REP server on host:port\n"
+"QUIT Quit management client\n"
+;
+
+static const char* helpTextShow =
+"---------------------------------------------------------------------------\n"
+" NDB Cluster -- Management Client -- Help for SHOW command\n"
+"---------------------------------------------------------------------------\n"
+"SHOW prints NDB Cluster information\n\n"
+"SHOW Print information about cluster\n"
+"SHOW CONFIG Print configuration (in initial config file format)\n"
+"SHOW PARAMETERS Print information about configuration parameters\n\n"
+;
+
+#ifdef HAVE_GLOBAL_REPLICATION
+static const char* helpTextRep =
+"---------------------------------------------------------------------------\n"
+" NDB Cluster -- Management Client -- Help for Global Replication\n"
+"---------------------------------------------------------------------------\n"
+"Commands should be executed on the standby NDB Cluster\n"
+"These features are in an experimental release state.\n"
+"\n"
+"Simple Commands:\n"
+"REP START Start Global Replication\n"
+"REP START REQUESTOR Start Global Replication Requestor\n"
+"REP STATUS Show Global Replication status\n"
+"REP STOP Stop Global Replication\n"
+"REP STOP REQUESTOR Stop Global Replication Requestor\n"
+"\n"
+"Advanced Commands:\n"
+"REP START <protocol> Starts protocol\n"
+"REP STOP <protocol> Stops protocol\n"
+"<protocol> = TRANSFER | APPLY | DELETE\n"
+"\n"
+#ifdef VM_TRACE // DEBUG ONLY
+"Debugging commands:\n"
+"REP DELETE Removes epochs stored in primary and standy systems\n"
+"REP DROP <tableid> Drop a table in SS identified by table id\n"
+"REP SLOWSTOP Stop Replication (Tries to synchonize with primary)\n"
+"REP FASTSTOP Stop Replication (Stops in consistent state)\n"
+"<component> = SUBSCRIPTION\n"
+" METALOG | METASCAN | DATALOG | DATASCAN\n"
+" REQUESTOR | TRANSFER | APPLY | DELETE\n"
+#endif
+;
+#endif // HAVE_GLOBAL_REPLICATION
+
+#ifdef VM_TRACE // DEBUG ONLY
+static const char* helpTextDebug =
+"---------------------------------------------------------------------------\n"
+" NDB Cluster -- Management Client -- Help for Debugging (Internal use only)\n"
+"---------------------------------------------------------------------------\n"
+"SHOW PROPERTIES Print config properties object\n"
+"<id> LOGLEVEL {<category>=<level>}+ Set log level\n"
+#ifdef ERROR_INSERT
+"<id> ERROR <errorNo> Inject error into NDB node\n"
+#endif
+"<id> TRACE <traceNo> Set trace number\n"
+"<id> LOG [BLOCK = {ALL|<block>+}] Set logging on in & out signals\n"
+"<id> LOGIN [BLOCK = {ALL|<block>+}] Set logging on in signals\n"
+"<id> LOGOUT [BLOCK = {ALL|<block>+}] Set logging on out signals\n"
+"<id> LOGOFF [BLOCK = {ALL|<block>+}] Unset signal logging\n"
+"<id> TESTON Start signal logging\n"
+"<id> TESTOFF Stop signal logging\n"
+"<id> SET <configParamName> <value> Update configuration variable\n"
+"<id> DUMP <arg> Dump system state to cluster.log\n"
+"<id> GETSTAT Print statistics\n"
+"\n"
+"<id> = ALL | Any database node id\n"
+;
+#endif
+
+static 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;
+}
+
+/*
+ * Constructor
+ */
+CommandInterpreter::CommandInterpreter(const char *_host)
+{
+ m_mgmsrv = ndb_mgm_create_handle();
+ if(m_mgmsrv == NULL) {
+ ndbout_c("Cannot create handle to management server.");
+ printError();
+ }
+
+ connected = false;
+ try_reconnect = 0;
+
+ host = strdup(_host);
+#ifdef HAVE_GLOBAL_REPLICATION
+ rep_host = NULL;
+ m_repserver = NULL;
+ rep_connected = false;
+#endif
+}
+
+/*
+ * Destructor
+ */
+CommandInterpreter::~CommandInterpreter()
+{
+ connected = false;
+ ndb_mgm_destroy_handle(&m_mgmsrv);
+ free((char *)host);
+ host = NULL;
+}
+
+bool
+emptyString(const char* s)
+{
+ if (s == NULL) {
+ return true;
+ }
+
+ for (unsigned int i = 0; i < strlen(s); ++i) {
+ if (! isspace(s[i])) {
+ return false;
+ }
+ }
+
+ return true;
+}
+
+class AutoPtr
+{
+public:
+ AutoPtr(void * ptr) : m_ptr(ptr) {}
+ ~AutoPtr() { free(m_ptr);}
+private:
+ void * m_ptr;
+};
+
+
+void
+CommandInterpreter::printError()
+{
+ ndbout_c("* %5d: %s",
+ ndb_mgm_get_latest_error(m_mgmsrv),
+ ndb_mgm_get_latest_error_msg(m_mgmsrv));
+ ndbout_c("* %s", ndb_mgm_get_latest_error_desc(m_mgmsrv));
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+bool
+CommandInterpreter::connect()
+{
+ if(!connected) {
+ int tries = try_reconnect; // tries == 0 => infinite
+ while(!connected) {
+ if(ndb_mgm_connect(m_mgmsrv, host) == -1) {
+ ndbout << "Cannot connect to management server (" << host << ").";
+ tries--;
+ if (tries == 0)
+ break;
+ ndbout << "Retrying in 5 seconds." << endl;
+ NdbSleep_SecSleep(5);
+ } else
+ connected = true;
+ }
+ }
+ return connected;
+}
+
+bool
+CommandInterpreter::disconnect()
+{
+ if (ndb_mgm_disconnect(m_mgmsrv) == -1) {
+ ndbout_c("Could not disconnect from management server");
+ printError();
+ }
+ connected = false;
+ return true;
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+int
+CommandInterpreter::readAndExecute(int _try_reconnect)
+{
+ if (_try_reconnect >= 0)
+ try_reconnect=_try_reconnect;
+
+ char* _line = readline_gets();
+ char * line;
+ if(_line == NULL) {
+ // ndbout << endl;
+ return false;
+ }
+
+ line = strdup(_line);
+
+ AutoPtr ptr(line);
+
+ if (emptyString(line)) {
+ return true;
+ }
+
+ for (unsigned int i = 0; i < strlen(line); ++i) {
+ line[i] = toupper(line[i]);
+ }
+
+ // if there is anything in the line proceed
+ char* firstToken = strtok(line, " ");
+ char* allAfterFirstToken = strtok(NULL, "");
+
+ if (strcmp(firstToken, "HELP") == 0 ||
+ strcmp(firstToken, "?") == 0) {
+ executeHelp(allAfterFirstToken);
+ return true;
+ }
+ else if (strcmp(firstToken, "SHOW") == 0) {
+ executeShow(allAfterFirstToken);
+ return true;
+ }
+ else if (strcmp(firstToken, "CLUSTERLOG") == 0){
+ executeClusterLog(allAfterFirstToken);
+ return true;
+ }
+ else if(strcmp(firstToken, "START") == 0 &&
+ allAfterFirstToken != NULL &&
+ strncmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
+ executeStartBackup(allAfterFirstToken);
+ return true;
+ }
+ else if(strcmp(firstToken, "ABORT") == 0 &&
+ allAfterFirstToken != NULL &&
+ strncmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
+ executeAbortBackup(allAfterFirstToken);
+ return true;
+ }
+#ifdef HAVE_GLOBAL_REPLICATION
+ else if(strcmp(firstToken, "REPLICATION") == 0 ||
+ strcmp(firstToken, "REP") == 0) {
+ executeRep(allAfterFirstToken);
+ return true;
+ }
+#endif // HAVE_GLOBAL_REPLICATION
+ else if(strcmp(firstToken, "ENTER") == 0 &&
+ allAfterFirstToken != NULL &&
+ strncmp(allAfterFirstToken, "SINGLE USER MODE ",
+ sizeof("SINGLE USER MODE") - 1) == 0){
+ executeEnterSingleUser(allAfterFirstToken);
+ return true;
+ }
+ else if(strcmp(firstToken, "EXIT") == 0 &&
+ allAfterFirstToken != NULL &&
+ strncmp(allAfterFirstToken, "SINGLE USER MODE ",
+ sizeof("SINGLE USER MODE") - 1) == 0){
+ executeExitSingleUser(allAfterFirstToken);
+ return true;
+ }
+ else if (strcmp(firstToken, "ALL") == 0) {
+ analyseAfterFirstToken(-1, allAfterFirstToken);
+ }
+ else if((strcmp(firstToken, "QUIT") == 0 ||
+ strcmp(firstToken, "EXIT") == 0 ||
+ strcmp(firstToken, "BYE") == 0) &&
+ allAfterFirstToken == NULL){
+ return false;
+#if 0
+ } else if(strcmp(firstToken, "CPC") == 0) {
+ executeCpc(allAfterFirstToken);
+#endif
+ } else {
+ /**
+ * First token should be a digit, node ID
+ */
+ int nodeId;
+
+ if (! convert(firstToken, nodeId)) {
+ ndbout << "Invalid command: " << line << endl;
+ ndbout << "Type HELP for help." << endl << endl;
+ return true;
+ }
+
+ if (nodeId < 0) {
+ ndbout << "Invalid node ID: " << firstToken << "." << endl;
+ return true;
+ }
+
+ analyseAfterFirstToken(nodeId, allAfterFirstToken);
+
+ }
+ return true;
+}
+
+
+/**
+ * List of commands used as second command argument
+ */
+static const CommandInterpreter::CommandFunctionPair commands[] = {
+ { "START", &CommandInterpreter::executeStart }
+ ,{ "RESTART", &CommandInterpreter::executeRestart }
+ ,{ "STOP", &CommandInterpreter::executeStop }
+ ,{ "STATUS", &CommandInterpreter::executeStatus }
+ ,{ "LOGLEVEL", &CommandInterpreter::executeLogLevel }
+ ,{ "CLUSTERLOG", &CommandInterpreter::executeEventReporting }
+#ifdef ERROR_INSERT
+ ,{ "ERROR", &CommandInterpreter::executeError }
+#endif
+ ,{ "TRACE", &CommandInterpreter::executeTrace }
+ ,{ "LOG", &CommandInterpreter::executeLog }
+ ,{ "LOGIN", &CommandInterpreter::executeLogIn }
+ ,{ "LOGOUT", &CommandInterpreter::executeLogOut }
+ ,{ "LOGOFF", &CommandInterpreter::executeLogOff }
+ ,{ "TESTON", &CommandInterpreter::executeTestOn }
+ ,{ "TESTOFF", &CommandInterpreter::executeTestOff }
+ ,{ "SET", &CommandInterpreter::executeSet }
+ ,{ "GETSTAT", &CommandInterpreter::executeGetStat }
+ ,{ "DUMP", &CommandInterpreter::executeDumpState }
+};
+
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::analyseAfterFirstToken(int processId,
+ char* allAfterFirstToken) {
+
+ if (emptyString(allAfterFirstToken)) {
+ if (processId == -1) {
+ ndbout << "Expected a command after ALL." << endl;
+ }
+ else {
+ ndbout << "Expected a command after node ID." << endl;
+ }
+ return;
+ }
+
+ char* secondToken = strtok(allAfterFirstToken, " ");
+ char* allAfterSecondToken = strtok(NULL, "\0");
+
+ const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
+ ExecuteFunction fun = 0;
+ const char * command = 0;
+ for(int i = 0; i<tmpSize; i++){
+ if(strcmp(secondToken, commands[i].command) == 0){
+ fun = commands[i].executeFunction;
+ command = commands[i].command;
+ break;
+ }
+ }
+
+ if(fun == 0){
+ ndbout << "Invalid command: " << secondToken << endl;
+ ndbout << "Type HELP for help." << endl << endl;
+ return;
+ }
+
+ if(processId == -1){
+ executeForAll(command, fun, allAfterSecondToken);
+ } else {
+ if(strcmp(command, "STATUS") != 0)
+ ndbout_c("Executing %s on node %d.", command, processId);
+ (this->*fun)(processId, allAfterSecondToken, false);
+ ndbout << endl;
+ }
+}
+
+/**
+ * Get next nodeid larger than the give node_id. node_id will be
+ * set to the next node_id in the list. node_id should be set
+ * to 0 (zero) on the first call.
+ *
+ * @param handle the NDB management handle
+ * @param node_id last node_id retreived, 0 at first call
+ * @param type type of node to look for
+ * @return 1 if a node was found, 0 if no more node exist
+ */
+static
+int
+get_next_nodeid(struct ndb_mgm_cluster_state *cl,
+ int *node_id,
+ enum ndb_mgm_node_type type)
+{
+ int i;
+
+ if(cl == NULL)
+ return 0;
+
+ i=0;
+ while((i < cl->no_of_nodes)) {
+ if((*node_id < cl->node_states[i].node_id) &&
+ (cl->node_states[i].node_type == type)) {
+
+ if(i >= cl->no_of_nodes)
+ return 0;
+
+ *node_id = cl->node_states[i].node_id;
+ return 1;
+ }
+ i++;
+ }
+
+ return 0;
+}
+
+void
+CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun,
+ const char * allAfterSecondToken)
+{
+ int nodeId = 0;
+ if(strcmp(cmd, "STOP") == 0) {
+ ndbout_c("Executing STOP on all nodes.");
+ (this->*fun)(nodeId, allAfterSecondToken, true);
+ } else if(strcmp(cmd, "RESTART") == 0) {
+ ndbout_c("Executing RESTART on all nodes.");
+ ndbout_c("Starting shutdown. This may take a while. Please wait...");
+ (this->*fun)(nodeId, allAfterSecondToken, true);
+ ndbout_c("Trying to start all nodes of system.");
+ ndbout_c("Use ALL STATUS to see the system start-up phases.");
+ } else {
+ connect();
+ struct ndb_mgm_cluster_state *cl;
+ cl = ndb_mgm_get_status(m_mgmsrv);
+ if(cl == 0){
+ ndbout_c("Unable get status from management server");
+ printError();
+ return;
+ }
+ while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB)) {
+ if(strcmp(cmd, "STATUS") != 0)
+ ndbout_c("Executing %s on node %d.", cmd, nodeId);
+ (this->*fun)(nodeId, allAfterSecondToken, true);
+ ndbout << endl;
+ } // while
+ free(cl);
+ }
+}
+
+//*****************************************************************************
+//*****************************************************************************
+bool
+CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
+ Vector<const char*>& blocks)
+{
+ // Parse: [BLOCK = {ALL|<blockName>+}]
+
+ if (emptyString(allAfterLog)) {
+ return true;
+ }
+
+ // Copy allAfterLog since strtok will modify it
+ char* newAllAfterLog = strdup(allAfterLog);
+ char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
+ for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
+ firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
+ }
+
+ if (strcmp(firstTokenAfterLog, "BLOCK") != 0) {
+ ndbout << "Unexpected value: " << firstTokenAfterLog
+ << ". Expected BLOCK." << endl;
+ free(newAllAfterLog);
+ return false;
+ }
+
+ char* allAfterFirstToken = strtok(NULL, "\0");
+ if (emptyString(allAfterFirstToken)) {
+ ndbout << "Expected =." << endl;
+ free(newAllAfterLog);
+ return false;
+ }
+
+ char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
+ if (strcmp(secondTokenAfterLog, "=") != 0) {
+ ndbout << "Unexpected value: " << secondTokenAfterLog
+ << ". Expected =." << endl;
+ free(newAllAfterLog);
+ return false;
+ }
+
+ char* blockName = strtok(NULL, " ");
+ bool all = false;
+ if (blockName != NULL && (strcmp(blockName, "ALL") == 0)) {
+ all = true;
+ }
+ while (blockName != NULL) {
+ blocks.push_back(strdup(blockName));
+ blockName = strtok(NULL, " ");
+ }
+
+ if (blocks.size() == 0) {
+ ndbout << "No block specified." << endl;
+ free(newAllAfterLog);
+ return false;
+ }
+ if (blocks.size() > 1 && all) {
+ // More than "ALL" specified
+ ndbout << "Nothing expected after ALL." << endl;
+ free(newAllAfterLog);
+ return false;
+ }
+
+ free(newAllAfterLog);
+ return true;
+}
+
+
+
+/*****************************************************************************
+ * HELP
+ *****************************************************************************/
+void
+CommandInterpreter::executeHelp(char* parameters)
+{
+ if (emptyString(parameters)) {
+ ndbout << helpText;
+
+ ndbout << endl
+ << "<severity> = "
+ << "ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG"
+ << endl;
+
+ ndbout << "<category> = ";
+ for(Uint32 i = 0; i<EventLogger::noOfEventCategoryNames; i++){
+ ndbout << EventLogger::eventCategoryNames[i].name;
+ if (i < EventLogger::noOfEventCategoryNames - 1) {
+ ndbout << " | ";
+ }
+ }
+ ndbout << endl;
+
+ ndbout << "<level> = " << "0 - 15" << endl;
+ ndbout << "<id> = " << "ALL | Any database node id" << endl;
+ ndbout << endl;
+ } else if (strcmp(parameters, "SHOW") == 0) {
+ ndbout << helpTextShow;
+#ifdef HAVE_GLOBAL_REPLICATION
+ } else if (strcmp(parameters, "REPLICATION") == 0 ||
+ strcmp(parameters, "REP") == 0) {
+ ndbout << helpTextRep;
+#endif // HAVE_GLOBAL_REPLICATION
+#ifdef VM_TRACE // DEBUG ONLY
+ } else if (strcmp(parameters, "DEBUG") == 0) {
+ ndbout << helpTextDebug;
+#endif
+ } else {
+ ndbout << "Invalid argument: " << parameters << endl;
+ ndbout << "Type HELP for help." << endl << endl;
+ }
+}
+
+
+/*****************************************************************************
+ * SHOW
+ *****************************************************************************/
+
+void
+CommandInterpreter::executeShow(char* parameters)
+{
+ connect();
+ if (emptyString(parameters)) {
+ ndbout << "Cluster Configuration" << endl
+ << "---------------------" << endl;
+
+ ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
+ if(state == NULL) {
+ ndbout_c("Could not get status");
+ printError();
+ return;
+ }
+
+ int
+ ndb_nodes = 0,
+ api_nodes = 0,
+ mgm_nodes = 0;
+
+ for(int i=0; i < state->no_of_nodes; i++) {
+ switch(state->node_states[i].node_type) {
+ case NDB_MGM_NODE_TYPE_API:
+ api_nodes++;
+ break;
+ case NDB_MGM_NODE_TYPE_NDB:
+ ndb_nodes++;
+ break;
+ case NDB_MGM_NODE_TYPE_MGM:
+ mgm_nodes++;
+ break;
+ case NDB_MGM_NODE_TYPE_UNKNOWN:
+ ndbout << "Error: Unknown Node Type" << endl;
+ return;
+ }
+ }
+
+ ndbout << ndb_nodes
+ << " NDB Node(s)"
+ << endl;
+
+ for(int i=0; i < state->no_of_nodes; i++) {
+ if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB) {
+ ndbout << "DB node:\t" << state->node_states[i].node_id;
+ if(state->node_states[i].version != 0) {
+ ndbout << " (Version: "
+ << getMajor(state->node_states[i].version) << "."
+ << getMinor(state->node_states[i].version) << "."
+ << getBuild(state->node_states[i].version) << ")" << endl;
+
+ } else
+ {
+ ndbout << " (not connected) " << endl;
+ }
+
+ }
+ }
+ ndbout << endl;
+
+ ndbout << api_nodes
+ << " API Node(s)"
+ << endl;
+
+ for(int i=0; i < state->no_of_nodes; i++) {
+ if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_API) {
+ ndbout << "API node:\t" << state->node_states[i].node_id;
+ if(state->node_states[i].version != 0) {
+ ndbout << " (Version: "
+ << getMajor(state->node_states[i].version) << "."
+ << getMinor(state->node_states[i].version) << "."
+ << getBuild(state->node_states[i].version) << ")" << endl;
+
+ } else
+ {
+ ndbout << " (not connected) " << endl;
+ }
+ }
+ }
+ ndbout << endl;
+
+ ndbout << mgm_nodes
+ << " MGM Node(s)"
+ << endl;
+
+ for(int i=0; i < state->no_of_nodes; i++) {
+ if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_MGM) {
+ ndbout << "MGM node:\t" << state->node_states[i].node_id;
+ if(state->node_states[i].version != 0) {
+ ndbout << " (Version: "
+ << getMajor(state->node_states[i].version) << "."
+ << getMinor(state->node_states[i].version) << "."
+ << getBuild(state->node_states[i].version) << ")" << endl;
+
+ } else
+ {
+ ndbout << " (no version information available) " << endl;
+ }
+ }
+ }
+ ndbout << endl;
+ // ndbout << helpTextShow;
+ return;
+ } else if (strcmp(parameters, "PROPERTIES") == 0 ||
+ strcmp(parameters, "PROP") == 0) {
+ ndbout << "SHOW PROPERTIES is not yet implemented." << endl;
+ // ndbout << "_mgmtSrvr.getConfig()->print();" << endl; /* XXX */
+ } else if (strcmp(parameters, "CONFIGURATION") == 0 ||
+ strcmp(parameters, "CONFIG") == 0){
+ ndbout << "SHOW CONFIGURATION is not yet implemented." << endl;
+ //nbout << "_mgmtSrvr.getConfig()->printConfigFile();" << endl; /* XXX */
+ } else if (strcmp(parameters, "PARAMETERS") == 0 ||
+ strcmp(parameters, "PARAMS") == 0 ||
+ strcmp(parameters, "PARAM") == 0) {
+ ndbout << "SHOW PARAMETERS is not yet implemented." << endl;
+ // ndbout << "_mgmtSrvr.getConfig()->getConfigInfo()->print();"
+ // << endl; /* XXX */
+ } else {
+ ndbout << "Invalid argument." << endl;
+ }
+}
+
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeClusterLog(char* parameters)
+{
+ connect();
+ if (parameters != 0 && strlen(parameters) != 0) {
+ enum ndb_mgm_clusterlog_level severity = NDB_MGM_CLUSTERLOG_ALL;
+ int isOk = true;
+ char name[12];
+ bool noArgs = false;
+
+ char * tmpString = strdup(parameters);
+ char * tmpPtr = 0;
+ char * item = strtok_r(tmpString, " ", &tmpPtr);
+
+ /********************
+ * CLUSTERLOG FILTER
+ ********************/
+ if (strcmp(item, "FILTER") == 0) {
+
+ item = strtok_r(NULL, " ", &tmpPtr);
+ if (item == NULL) {
+ noArgs = true;
+ }
+ while (item != NULL) {
+ snprintf(name, sizeof(name), item);
+
+ if (strcmp(item, "ALL") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_ALL;
+ } else if (strcmp(item, "ALERT") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_ALERT;
+ } else if (strcmp(item, "CRITICAL") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_CRITICAL;
+ } else if (strcmp(item, "ERROR") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_ERROR;
+ } else if (strcmp(item, "WARNING") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_WARNING;
+ } else if (strcmp(item, "INFO") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_INFO;
+ } else if (strcmp(item, "DEBUG") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_DEBUG;
+ } else if (strcmp(item, "OFF") == 0) {
+ severity = NDB_MGM_CLUSTERLOG_OFF;
+ } else {
+ isOk = false;
+ }
+
+ item = strtok_r(NULL, " ", &tmpPtr);
+ } // while(item != NULL){
+ free(tmpString);
+
+ if (noArgs) {
+ ndbout << "Missing argument(s)." << endl;
+ } else if (isOk) {
+ if(ndb_mgm_filter_clusterlog(m_mgmsrv, severity, NULL)) {
+ if(strcmp(name, "ALL") == 0 || strcmp(name, "all") == 0) {
+ ndbout << "All severities levels enabled." << endl;
+ } else if(strcmp(name, "OFF") == 0 || strcmp(name, "off") == 0) {
+ ndbout << "Cluster logging enabled." << endl;
+ } else {
+ ndbout << name << " events disabled." << endl;
+ }
+ } else {
+ if(strcmp(name, "ALL") == 0) {
+ ndbout << "All severities levels disabled." << endl;
+ } else if(strcmp(name, "OFF") == 0) {
+ ndbout << "Cluster logging disabled." << endl;
+ } else {
+ ndbout << name << " events enabled." << endl;
+ }
+ }
+ } else {
+ ndbout << "Invalid severity level." << endl;
+ }
+
+ /********************
+ * CLUSTERLOG INFO
+ ********************/
+ } else if (strcmp(item, "INFO") == 0) {
+ Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv);
+ if(enabled == NULL) {
+ ndbout << "Couldn't get status" << endl;
+ printError();
+ return;
+ }
+ const char* names[] = {"ENABLED", "DEBUG", "INFO", "WARNING", "ERROR",
+ "CRITICAL", "ALERT"};
+ if(enabled[0])
+ ndbout << "Cluster logging is disabled." << endl;
+
+
+ for(int i = 0; i<7;i++)
+ printf("enabled[%d] = %d\n", i, enabled[i]);
+ ndbout << "Severities enabled: ";
+ for(int i = 1; i < 7; i++) {
+ if(enabled[i])
+ ndbout << names[i] << " ";
+ }
+ ndbout << endl;
+
+ /********************
+ * CLUSTERLOG OFF
+ ********************/
+ } else if (strcmp(item, "OFF") == 0) {
+ Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv);
+ if(enabled == NULL) {
+ ndbout << "Couldn't get status" << endl;
+ printError();
+ return;
+ }
+ if(!enabled[0]) {
+ ndb_mgm_filter_clusterlog(m_mgmsrv, NDB_MGM_CLUSTERLOG_OFF, NULL);
+ ndbout << "Cluster logging is disabled." << endl;
+ } else {
+ ndbout << "Cluster logging is already disabled." << endl;
+
+ }
+
+ /********************
+ * CLUSTERLOG ON
+ ********************/
+ } else if (strcmp(item, "ON") == 0) {
+ Uint32 *enabled = ndb_mgm_get_logfilter(m_mgmsrv);
+ if(enabled == NULL) {
+ ndbout << "Could not get status" << endl;
+ printError();
+ return;
+ }
+ if(enabled[0]) {
+ ndb_mgm_filter_clusterlog(m_mgmsrv, NDB_MGM_CLUSTERLOG_OFF, NULL);
+ ndbout << "Cluster logging is enabled." << endl;
+ } else {
+ ndbout << "Cluster logging is already enabled." << endl;
+
+ }
+ } else {
+ ndbout << "Invalid argument." << endl;
+ }
+
+ } else {
+ ndbout << "Missing argument." << endl;
+ }
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+void
+CommandInterpreter::executeStop(int processId, const char *, bool all)
+{
+ connect();
+ int result = 0;
+ if(all) {
+ result = ndb_mgm_stop(m_mgmsrv, 0, 0);
+ } else {
+ result = ndb_mgm_stop(m_mgmsrv, 1, &processId);
+ }
+ if (result <= 0) {
+ ndbout << "Shutdown failed." << endl;
+ printError();
+ } else
+ {
+ if(all)
+ ndbout << "NDB Cluster has shutdown." << endl;
+ else
+ ndbout << "Node " << processId << " has shutdown." << endl;
+ }
+}
+
+void
+CommandInterpreter::executeEnterSingleUser(char* parameters)
+{
+ connect();
+ strtok(parameters, " ");
+ struct ndb_mgm_reply reply;
+ char* id = strtok(NULL, " ");
+ id = strtok(NULL, " ");
+ id = strtok(NULL, "\0");
+ int nodeId = -1;
+ if(id == 0 || sscanf(id, "%d", &nodeId) != 1){
+ ndbout_c("Invalid arguments: expected <NodeId>");
+ ndbout_c("Use SHOW to see what API nodes are configured");
+ return;
+ }
+ int result = ndb_mgm_enter_single_user(m_mgmsrv, nodeId, &reply);
+
+ if (result != 0) {
+ ndbout_c("Entering single user mode for node %d failed", nodeId);
+ printError();
+ } else {
+ ndbout_c("Entering single user mode");
+ ndbout_c("Access will be granted for API node %d only.", nodeId);
+ ndbout_c("Use ALL STATUS to see when single user mode has been entered.");
+ }
+}
+
+void
+CommandInterpreter::executeExitSingleUser(char* parameters)
+{
+ connect();
+ int result = ndb_mgm_exit_single_user(m_mgmsrv, 0);
+ if (result != 0) {
+ ndbout_c("Exiting single user mode failed.");
+ printError();
+ } else {
+ ndbout_c("Exiting single user mode in progress.");
+ ndbout_c("Use ALL STATUS to see when single user mode has been exited.");
+ }
+}
+
+void
+CommandInterpreter::executeStart(int processId, const char* parameters,
+ bool all)
+{
+ connect();
+ int result;
+ if(all) {
+ result = ndb_mgm_start(m_mgmsrv, 0, 0);
+ } else {
+ result = ndb_mgm_start(m_mgmsrv, 1, &processId);
+ }
+
+ if (result <= 0) {
+ ndbout << "Start failed." << endl;
+ printError();
+ } else
+ {
+ if(all)
+ ndbout_c("NDB Cluster is being started.");
+ else
+ ndbout_c("Database node %d is being started.", processId);
+ }
+}
+
+void
+CommandInterpreter::executeRestart(int processId, const char* parameters,
+ bool all)
+{
+ connect();
+ int result;
+ int nostart = 0;
+ int initialstart = 0;
+ int abort = 0;
+
+ if(parameters != 0 && strlen(parameters) != 0){
+ char * tmpString = strdup(parameters);
+ char * tmpPtr = 0;
+ char * item = strtok_r(tmpString, " ", &tmpPtr);
+ while(item != NULL){
+ if(strcmp(item, "-N") == 0)
+ nostart = 1;
+ if(strcmp(item, "-I") == 0)
+ initialstart = 1;
+ if(strcmp(item, "-A") == 0)
+ abort = 1;
+ item = strtok_r(NULL, " ", &tmpPtr);
+ }
+ free(tmpString);
+ }
+
+ if(all) {
+ result = ndb_mgm_restart2(m_mgmsrv, 0, NULL, initialstart, nostart, abort);
+ } else {
+ int v[1];
+ v[0] = processId;
+ result = ndb_mgm_restart2(m_mgmsrv, 1, v, initialstart, nostart, abort);
+ }
+
+ if (result <= 0) {
+ ndbout.println("Restart failed.", result);
+ printError();
+ } else
+ {
+ if(all)
+ ndbout << "NDB Cluster is being restarted." << endl;
+ else
+ ndbout_c("Database node %d is being restarted.", processId);
+ }
+}
+
+void
+CommandInterpreter::executeDumpState(int processId, const char* parameters,
+ bool all)
+{
+ if(parameters == 0 || strlen(parameters) == 0){
+ ndbout << "Expected argument" << endl;
+ return;
+ }
+ connect();
+
+ Uint32 no = 0;
+ int pars[25];
+
+ char * tmpString = strdup(parameters);
+ char * tmpPtr = 0;
+ char * item = strtok_r(tmpString, " ", &tmpPtr);
+ while(item != NULL){
+ if (0x0 <= strtoll(item, NULL, 0) && strtoll(item, NULL, 0) <= 0xffffffff){
+ pars[no] = strtoll(item, NULL, 0);
+ } else {
+ ndbout << "Illegal value in argument to signal." << endl
+ << "(Value must be between 0 and 0xffffffff.)"
+ << endl;
+ return;
+ }
+ no++;
+ item = strtok_r(NULL, " ", &tmpPtr);
+ }
+ ndbout << "Sending dump signal with data:" << endl;
+ for (Uint32 i=0; i<no; i++) {
+ ndbout.setHexFormat(1) << pars[i] << " ";
+ if (!(i+1 & 0x3)) ndbout << endl;
+ }
+ free(tmpString);
+
+ struct ndb_mgm_reply reply;
+ ndb_mgm_dump_state(m_mgmsrv, processId, pars, no, &reply);
+}
+
+void
+CommandInterpreter::executeStatus(int processId,
+ const char* parameters, bool all)
+{
+ if (! emptyString(parameters)) {
+ ndbout << "No parameters expected to this command." << endl;
+ return;
+ }
+
+ connect();
+ ndb_mgm_node_status status;
+ Uint32 startPhase, version;
+ bool system;
+
+ struct ndb_mgm_cluster_state *cl;
+ cl = ndb_mgm_get_status(m_mgmsrv);
+ if(cl == NULL) {
+ ndbout_c("Cannot get status of node %d.", processId);
+ printError();
+ return;
+ }
+
+ int i = 0;
+ while((i < cl->no_of_nodes) && cl->node_states[i].node_id != processId)
+ i++;
+ if(cl->node_states[i].node_id != processId) {
+ ndbout << processId << ": Node not found" << endl;
+ return;
+ }
+ status = cl->node_states[i].node_status;
+ startPhase = cl->node_states[i].start_phase;
+ version = cl->node_states[i].version;
+
+ ndbout << "Node " << processId << ": ";
+ switch(status){
+ case NDB_MGM_NODE_STATUS_NO_CONTACT:
+ ndbout << "No contact" << endl;
+ break;
+ case NDB_MGM_NODE_STATUS_NOT_STARTED:
+ ndbout << "Not started" ;
+ break;
+ case NDB_MGM_NODE_STATUS_STARTING:
+ ndbout << "Starting (Start phase " << startPhase << ")" ;
+ break;
+ case NDB_MGM_NODE_STATUS_STARTED:
+ ndbout << "Started" ;
+ break;
+ case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
+ ndbout << "Shutting down " << (system == false ? "node" : "system")
+ << " (Phase " << startPhase << ")"
+ ;
+ break;
+ case NDB_MGM_NODE_STATUS_RESTARTING:
+ ndbout << "Restarting" ;
+ break;
+ case NDB_MGM_NODE_STATUS_SINGLEUSER:
+ ndbout << "Single user mode" ;
+ break;
+ default:
+ ndbout << "Unknown state" ;
+ break;
+ }
+ if(status != NDB_MGM_NODE_STATUS_NO_CONTACT)
+ ndbout_c(" (Version %d.%d.%d)",
+ getMajor(version) ,
+ getMinor(version),
+ getBuild(version));
+}
+
+
+//*****************************************************************************
+//*****************************************************************************
+
+void
+CommandInterpreter::executeLogLevel(int processId, const char* parameters,
+ bool all)
+{
+ connect();
+ (void) all;
+ (void) parameters;
+
+ SetLogLevelOrd logLevel; logLevel.clear();
+ LogLevel::EventCategory cat;
+ int level;
+ if (emptyString(parameters) || (strcmp(parameters, "ALL") == 0)) {
+ for(Uint32 i = 0; i<EventLogger::noOfEventCategoryNames; i++)
+ logLevel.setLogLevel(EventLogger::eventCategoryNames[i].category, 7);
+ } else {
+
+ char * tmpString = strdup(parameters);
+ char * tmpPtr = 0;
+ char * item = strtok_r(tmpString, ", ", &tmpPtr);
+ while(item != NULL){
+ char categoryTxt[255];
+ const int m = sscanf(item, "%[^=]=%d", categoryTxt, &level);
+ if(m != 2){
+ free(tmpString);
+ ndbout << "Invalid loglevel specification category=level" << endl;
+ return;
+ }
+
+ if(!EventLogger::matchEventCategory(categoryTxt,
+ &cat)){
+ ndbout << "Invalid loglevel specification, unknown category: "
+ << categoryTxt << endl;
+ free(tmpString);
+ return ;
+ }
+ if(level < 0 || level > 15){
+ ndbout << "Invalid loglevel specification row, level 0-15" << endl;
+ free(tmpString);
+ return ;
+ }
+ logLevel.setLogLevel(cat, level);
+
+ item = strtok_r(NULL, ", ", &tmpPtr);
+ }
+ free(tmpString);
+ }
+
+ struct ndb_mgm_reply reply;
+ int result;
+ result = ndb_mgm_set_loglevel_node(m_mgmsrv,
+ processId, // fast fix - pekka
+ (char*)EventLogger::getEventCategoryName(cat),
+ level,
+ &reply);
+
+ if (result < 0) {
+ ndbout_c("Executing LOGLEVEL on node %d failed.", processId);
+ printError();
+ } else {
+ ndbout << "Executing LOGLEVEL on node " << processId << " OK!"
+ << endl;
+ }
+
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void CommandInterpreter::executeError(int processId,
+ const char* parameters, bool /* all */)
+{
+ if (emptyString(parameters)) {
+ ndbout << "Missing error number." << endl;
+ return;
+ }
+
+ connect();
+ // Copy parameters since strtok will modify it
+ char* newpar = strdup(parameters);
+ char* firstParameter = strtok(newpar, " ");
+
+ int errorNo;
+ if (! convert(firstParameter, errorNo)) {
+ ndbout << "Expected an integer." << endl;
+ free(newpar);
+ return;
+ }
+
+ char* allAfterFirstParameter = strtok(NULL, "\0");
+ if (! emptyString(allAfterFirstParameter)) {
+ ndbout << "Nothing expected after error number." << endl;
+ free(newpar);
+ return;
+ }
+
+ ndb_mgm_insert_error(m_mgmsrv, processId, errorNo, NULL);
+
+ free(newpar);
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeTrace(int /*processId*/,
+ const char* /*parameters*/, bool /*all*/)
+{
+#if 0
+ if (emptyString(parameters)) {
+ ndbout << "Missing trace number." << endl;
+ return;
+ }
+
+ char* newpar = strdup(parameters);
+ char* firstParameter = strtok(newpar, " ");
+
+
+ int traceNo;
+ if (! convert(firstParameter, traceNo)) {
+ ndbout << "Expected an integer." << endl;
+ free(newpar);
+ return;
+ }
+ char* allAfterFirstParameter = strtok(NULL, "\0");
+
+ if (! emptyString(allAfterFirstParameter)) {
+ ndbout << "Nothing expected after trace number." << endl;
+ free(newpar);
+ return;
+ }
+
+ int result = _mgmtSrvr.setTraceNo(processId, traceNo);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+ free(newpar);
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+void
+CommandInterpreter::executeLog(int processId,
+ const char* parameters, bool all)
+{
+ connect();
+ struct ndb_mgm_reply reply;
+ Vector<const char *> blocks;
+ if (! parseBlockSpecification(parameters, blocks)) {
+ return;
+ }
+ int len=0;
+ for(Uint32 i=0; i<blocks.size(); i++) {
+ ndbout_c("blocks %s %d",blocks[i], strlen(blocks[i]));
+ len += strlen(blocks[i]);
+ }
+ len += blocks.size()*2;
+ char * blockNames = (char*)malloc(len);
+
+ for(Uint32 i=0; i<blocks.size(); i++) {
+ strcat(blockNames, blocks[i]);
+ strcat(blockNames, "|");
+ }
+ strcat(blockNames, "\0");
+ ndbout_c("blocknames %s", blockNames);
+
+ /*int res =*/ndb_mgm_log_signals(m_mgmsrv,
+ processId,
+ NDB_MGM_SIGNAL_LOG_MODE_INOUT,
+ blockNames,
+ &reply);
+
+#if 0
+ int result =
+ _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::InOut, blocks);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeLogIn(int /* processId */,
+ const char* parameters, bool /* all */)
+{
+ Vector<const char*> blocks;
+ if (! parseBlockSpecification(parameters, blocks)) {
+ return;
+ }
+
+#if 0
+ int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::In, blocks);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeLogOut(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ Vector<const char*> blocks;
+ if (! parseBlockSpecification(parameters, blocks)) {
+ return;
+ }
+
+
+#if 0
+ int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Out,
+ blocks);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeLogOff(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ Vector<const char*> blocks;
+ if (! parseBlockSpecification(parameters, blocks)) {
+ return;
+ }
+
+
+#if 0
+ int result = _mgmtSrvr.setSignalLoggingMode(processId, MgmtSrvr::Off,
+ blocks);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeTestOn(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ if (! emptyString(parameters)) {
+ ndbout << "No parameters expected to this command." << endl;
+ return;
+ }
+
+#if 0
+ int result = _mgmtSrvr.startSignalTracing(processId);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeTestOff(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ if (! emptyString(parameters)) {
+ ndbout << "No parameters expected to this command." << endl;
+ return;
+ }
+
+#if 0
+ int result = _mgmtSrvr.stopSignalTracing(processId);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ }
+#endif
+}
+
+
+//*****************************************************************************
+//*****************************************************************************
+void
+CommandInterpreter::executeSet(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ if (emptyString(parameters)) {
+ ndbout << "Missing parameter name." << endl;
+ return;
+ }
+#if 0
+ // Copy parameters since strtok will modify it
+ char* newpar = strdup(parameters);
+ char* configParameterName = strtok(newpar, " ");
+
+ char* allAfterParameterName = strtok(NULL, "\0");
+ if (emptyString(allAfterParameterName)) {
+ ndbout << "Missing parameter value." << endl;
+ free(newpar);
+ return;
+ }
+
+ char* value = strtok(allAfterParameterName, " ");
+
+ char* allAfterValue = strtok(NULL, "\0");
+ if (! emptyString(allAfterValue)) {
+ ndbout << "Nothing expected after parameter value." << endl;
+ free(newpar);
+ return;
+ }
+
+ bool configBackupFileUpdated;
+ bool configPrimaryFileUpdated;
+
+ // TODO The handling of the primary and backup config files should be
+ // analysed further.
+ // How it should be handled if only the backup is possible to write.
+
+ int result = _mgmtSrvr.updateConfigParam(processId, configParameterName,
+ value, configBackupFileUpdated,
+ configPrimaryFileUpdated);
+ if (result == 0) {
+ if (configBackupFileUpdated && configPrimaryFileUpdated) {
+ ndbout << "The configuration is updated." << endl;
+ }
+ else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
+ ndbout << "The configuration is updated but it was only possible "
+ << "to update the backup configuration file, not the primary."
+ << endl;
+ }
+ else {
+ NDB_ASSERT(false, "");
+ }
+ }
+ else {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ if (configBackupFileUpdated && configPrimaryFileUpdated) {
+ ndbout << "The configuration files are however updated and "
+ << "the value will be used next time the process is restarted."
+ << endl;
+ }
+ else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
+ ndbout << "It was only possible to update the backup "
+ << "configuration file, not the primary." << endl;
+ }
+ else if (!configBackupFileUpdated && !configPrimaryFileUpdated) {
+ ndbout << "The configuration files are not updated." << endl;
+ }
+ else {
+ // The primary is not tried to write if the write of backup file fails
+ NDB_ASSERT(false, "");
+ }
+ }
+ free(newpar);
+#endif
+}
+
+//*****************************************************************************
+//*****************************************************************************
+void CommandInterpreter::executeGetStat(int /*processId*/,
+ const char* parameters, bool /*all*/)
+{
+ if (! emptyString(parameters)) {
+ ndbout << "No parameters expected to this command." << endl;
+ return;
+ }
+
+#if 0
+ MgmtSrvr::Statistics statistics;
+ int result = _mgmtSrvr.getStatistics(processId, statistics);
+ if (result != 0) {
+ ndbout << _mgmtSrvr.getErrorText(result) << endl;
+ return;
+ }
+#endif
+ // Print statistic...
+ /*
+ ndbout << "Number of GETSTAT commands: "
+ << statistics._test1 << endl;
+ */
+}
+
+//*****************************************************************************
+//*****************************************************************************
+
+void
+CommandInterpreter::executeEventReporting(int processId,
+ const char* parameters,
+ bool all)
+{
+ connect();
+ SetLogLevelOrd logLevel; logLevel.clear();
+ char categoryTxt[255];
+ int level;
+ LogLevel::EventCategory cat;
+ if (emptyString(parameters) || (strcmp(parameters, "ALL") == 0)) {
+ for(Uint32 i = 0; i<EventLogger::noOfEventCategoryNames; i++)
+ logLevel.setLogLevel(EventLogger::eventCategoryNames[i].category, 7);
+ } else {
+
+ char * tmpString = strdup(parameters);
+ char * tmpPtr = 0;
+ char * item = strtok_r(tmpString, ", ", &tmpPtr);
+ while(item != NULL){
+ const int m = sscanf(item, "%[^=]=%d", categoryTxt, &level);
+ if(m != 2){
+ free(tmpString);
+ ndbout << "Invalid loglevel specification category=level" << endl;
+ return;
+ }
+
+ if(!EventLogger::matchEventCategory(categoryTxt,
+ &cat)){
+ ndbout << "Invalid loglevel specification, unknown category: "
+ << categoryTxt << endl;
+ free(tmpString);
+ return ;
+ }
+ if(level < 0 || level > 15){
+ ndbout << "Invalid loglevel specification row, level 0-15" << endl;
+ free(tmpString);
+ return ;
+ }
+ logLevel.setLogLevel(cat, level);
+
+ item = strtok_r(NULL, ", ", &tmpPtr);
+ }
+ free(tmpString);
+ }
+ struct ndb_mgm_reply reply;
+ int result;
+
+ result =
+ ndb_mgm_set_loglevel_clusterlog(m_mgmsrv,
+ processId, // fast fix - pekka
+ (char*)
+ EventLogger::getEventCategoryName(cat),
+ level,
+ &reply);
+
+ if (result != 0) {
+ ndbout_c("Executing CLUSTERLOG on node %d failed", processId);
+ printError();
+ } else {
+ ndbout << "Executing CLUSTERLOG on node " << processId << " OK!"
+ << endl;
+ }
+}
+
+/*****************************************************************************
+ * Backup
+ *****************************************************************************/
+void
+CommandInterpreter::executeStartBackup(char* /*parameters*/)
+{
+ connect();
+ struct ndb_mgm_reply reply;
+ unsigned int backupId;
+ int result = ndb_mgm_start_backup(m_mgmsrv, &backupId, &reply);
+ if (result != 0) {
+ ndbout << "Start of backup failed" << endl;
+ printError();
+ } else {
+ ndbout << "Backup started. Backup id " << backupId << "." << endl;
+ }
+}
+
+void
+CommandInterpreter::executeAbortBackup(char* parameters)
+{
+ connect();
+ strtok(parameters, " ");
+ struct ndb_mgm_reply reply;
+ char* id = strtok(NULL, "\0");
+ int bid = -1;
+ if(id == 0 || sscanf(id, "%d", &bid) != 1){
+ ndbout << "Invalid arguments: expected <BackupId>" << endl;
+ return;
+ }
+ int result = ndb_mgm_abort_backup(m_mgmsrv, bid, &reply);
+ if (result != 0) {
+ ndbout << "Abort of backup " << bid << " failed" << endl;
+ printError();
+ } else {
+ ndbout << "Abort of backup " << bid << " ordered" << endl;
+ }
+}
+
+#ifdef HAVE_GLOBAL_REPLICATION
+/*****************************************************************************
+ * Global Replication
+ *
+ * For information about the different commands, see
+ * GrepReq::Request in file signaldata/grepImpl.cpp.
+ *
+ * Below are commands as of 2003-07-05 (may change!):
+ * START = 0, ///< Start Global Replication (all phases)
+ * START_METALOG = 1, ///< Start Global Replication (all phases)
+ * START_METASCAN = 2, ///< Start Global Replication (all phases)
+ * START_DATALOG = 3, ///< Start Global Replication (all phases)
+ * START_DATASCAN = 4, ///< Start Global Replication (all phases)
+ * START_REQUESTOR = 5, ///< Start Global Replication (all phases)
+ * ABORT = 6, ///< Immediate stop (removes subscription)
+ * SLOW_STOP = 7, ///< Stop after finishing applying current GCI epoch
+ * FAST_STOP = 8, ///< Stop after finishing applying all PS GCI epochs
+ * START_TRANSFER = 9, ///< Start SS-PS transfer
+ * STOP_TRANSFER = 10, ///< Stop SS-PS transfer
+ * START_APPLY = 11, ///< Start applying GCI epochs in SS
+ * STOP_APPLY = 12, ///< Stop applying GCI epochs in SS
+ * STATUS = 13, ///< Status
+ * START_SUBSCR = 14,
+ * REMOVE_BUFFERS = 15,
+ * DROP_TABLE = 16
+
+ *****************************************************************************/
+
+void
+CommandInterpreter::executeRep(char* parameters)
+{
+ if (emptyString(parameters)) {
+ ndbout << helpTextRep;
+ return;
+ }
+
+ connect();
+ char * line = strdup(parameters);
+ char * firstToken = strtok(line, " ");
+
+ struct ndb_rep_reply reply;
+ unsigned int repId;
+
+
+ if (!strcmp(firstToken, "CONNECT")) {
+ char * host = strtok(NULL, "\0");
+ for (unsigned int i = 0; i < strlen(host); ++i) {
+ host[i] = tolower(host[i]);
+ }
+
+ if(host == NULL)
+ {
+ ndbout_c("host:port must be specified.");
+ return;
+ }
+
+ if(rep_connected) {
+ if(m_repserver != NULL) {
+ ndb_rep_disconnect(m_repserver);
+ rep_connected = false;
+ }
+ }
+
+ if(m_repserver == NULL)
+ m_repserver = ndb_rep_create_handle();
+ if(ndb_rep_connect(m_repserver, host) < 0)
+ ndbout_c("Failed to connect to %s", host);
+ else
+ rep_connected=true;
+ return;
+
+ if(!rep_connected) {
+ ndbout_c("Not connected to REP server");
+ }
+ }
+
+ /********
+ * START
+ ********/
+ if (!strcmp(firstToken, "START")) {
+
+ unsigned int req;
+ char *startType = strtok(NULL, "\0");
+
+ if (startType == NULL) {
+ req = GrepReq::START;
+ } else if (!strcmp(startType, "SUBSCRIPTION")) {
+ req = GrepReq::START_SUBSCR;
+ } else if (!strcmp(startType, "METALOG")) {
+ req = GrepReq::START_METALOG;
+ } else if (!strcmp(startType, "METASCAN")) {
+ req = GrepReq::START_METASCAN;
+ } else if (!strcmp(startType, "DATALOG")) {
+ req = GrepReq::START_DATALOG;
+ } else if (!strcmp(startType, "DATASCAN")) {
+ req = GrepReq::START_DATASCAN;
+ } else if (!strcmp(startType, "REQUESTOR")) {
+ req = GrepReq::START_REQUESTOR;
+ } else if (!strcmp(startType, "TRANSFER")) {
+ req = GrepReq::START_TRANSFER;
+ } else if (!strcmp(startType, "APPLY")) {
+ req = GrepReq::START_APPLY;
+ } else if (!strcmp(startType, "DELETE")) {
+ req = GrepReq::START_DELETE;
+ } else {
+ ndbout_c("Illegal argument to command 'REPLICATION START'");
+ return;
+ }
+
+ int result = ndb_rep_command(m_repserver, req, &repId, &reply);
+
+ if (result != 0) {
+ ndbout << "Start of Global Replication failed" << endl;
+ } else {
+ ndbout << "Start of Global Replication ordered" << endl;
+ }
+ return;
+ }
+
+ /********
+ * STOP
+ ********/
+ if (!strcmp(firstToken, "STOP")) {
+ unsigned int req;
+ char *startType = strtok(NULL, " ");
+ unsigned int epoch = 0;
+
+ if (startType == NULL) {
+ /**
+ * Stop immediately
+ */
+ req = GrepReq::STOP;
+ } else if (!strcmp(startType, "EPOCH")) {
+ char *strEpoch = strtok(NULL, "\0");
+ if(strEpoch == NULL) {
+ ndbout_c("Epoch expected!");
+ return;
+ }
+ req = GrepReq::STOP;
+ epoch=atoi(strEpoch);
+ } else if (!strcmp(startType, "SUBSCRIPTION")) {
+ req = GrepReq::STOP_SUBSCR;
+ } else if (!strcmp(startType, "METALOG")) {
+ req = GrepReq::STOP_METALOG;
+ } else if (!strcmp(startType, "METASCAN")) {
+ req = GrepReq::STOP_METASCAN;
+ } else if (!strcmp(startType, "DATALOG")) {
+ req = GrepReq::STOP_DATALOG;
+ } else if (!strcmp(startType, "DATASCAN")) {
+ req = GrepReq::STOP_DATASCAN;
+ } else if (!strcmp(startType, "REQUESTOR")) {
+ req = GrepReq::STOP_REQUESTOR;
+ } else if (!strcmp(startType, "TRANSFER")) {
+ req = GrepReq::STOP_TRANSFER;
+ } else if (!strcmp(startType, "APPLY")) {
+ req = GrepReq::STOP_APPLY;
+ } else if (!strcmp(startType, "DELETE")) {
+ req = GrepReq::STOP_DELETE;
+ } else {
+ ndbout_c("Illegal argument to command 'REPLICATION STOP'");
+ return;
+ }
+ int result = ndb_rep_command(m_repserver, req, &repId, &reply, epoch);
+
+ if (result != 0) {
+ ndbout << "Stop command failed" << endl;
+ } else {
+ ndbout << "Stop ordered" << endl;
+ }
+ return;
+ }
+
+ /*********
+ * STATUS
+ *********/
+ if (!strcmp(firstToken, "STATUS")) {
+ struct rep_state repstate;
+ int result =
+ ndb_rep_get_status(m_repserver, &repId, &reply, &repstate);
+
+ if (result != 0) {
+ ndbout << "Status request of Global Replication failed" << endl;
+ } else {
+ ndbout << "Status request of Global Replication ordered" << endl;
+ ndbout << "See printout at one of the DB nodes" << endl;
+ ndbout << "(Better status report is under development.)" << endl;
+ ndbout << " SubscriptionId " << repstate.subid
+ << " SubscriptionKey " << repstate.subkey << endl;
+ }
+ return;
+ }
+
+ /*********
+ * QUERY (see repapi.h for querable counters)
+ *********/
+ if (!strcmp(firstToken, "QUERY")) {
+ char *query = strtok(NULL, "\0");
+ int queryCounter=-1;
+ if(query != NULL) {
+ queryCounter = atoi(query);
+ }
+ struct rep_state repstate;
+ unsigned repId = 0;
+ int result = ndb_rep_query(m_repserver, (QueryCounter)queryCounter,
+ &repId, &reply, &repstate);
+
+ if (result != 0) {
+ ndbout << "Query repserver failed" << endl;
+ } else {
+ ndbout << "Query repserver sucessful" << endl;
+ ndbout_c("repstate : QueryCounter %d, f=%d l=%d"
+ " nodegroups %d" ,
+ repstate.queryCounter,
+ repstate.first[0], repstate.last[0],
+ repstate.no_of_nodegroups );
+ }
+ return;
+ }
+}
+#endif // HAVE_GLOBAL_REPLICATION
+
+
+/*****************************************************************************
+ * CPC
+ *****************************************************************************/
+
+void
+CommandInterpreter::executeCpc(char *parameters)
+{
+ char *host_str = NULL, *port_str = NULL, *end;
+ long port = 1234; /* XXX */
+
+ while((host_str = strsep(&parameters, " \t:")) != NULL &&
+ host_str[0] == '\0');
+
+ if(parameters && parameters[0] != '\0') {
+ while((port_str = strsep(&parameters, " \t:")) != NULL &&
+ port_str[0] == '\0');
+
+ errno = 0;
+ port = strtol(port_str, &end, 0);
+ if(end[0] != '\0')
+ goto error;
+ if((port == LONG_MAX || port == LONG_MIN) &&
+ errno == ERANGE)
+ goto error;
+ }
+
+ {
+ SimpleCpcClient cpc(host_str, port);
+ bool done = false;
+
+ if(cpc.connect() < 0) {
+ ndbout_c("Cannot connect to %s:%d.", cpc.getHost(), cpc.getPort());
+ switch(errno) {
+ case ENOENT:
+ ndbout << ": " << "No such host" << endl;
+ break;
+ default:
+ ndbout << ": " << strerror(errno) << endl;
+ break;
+ }
+ return;
+ }
+
+ while(!done) {
+ char *line = readline("CPC> ");
+ if(line != NULL) {
+ add_history(line);
+
+ char *cmd = strtok(line, " ");
+ char *arg = strtok(NULL, "");
+
+ if(arg != NULL) {
+ while(arg[0] == ' ')
+ arg++;
+ if(strlen(arg) == 0)
+ arg = NULL;
+ }
+
+ if(cmd != NULL) {
+ if(strcmp(cmd, "exit") == 0)
+ done = true;
+ else if(strcmp(cmd, "list") == 0)
+ cpc.cmd_list(arg);
+ else if(strcmp(cmd, "start") == 0)
+ cpc.cmd_start(arg);
+ else if(strcmp(cmd, "stop") == 0)
+ cpc.cmd_stop(arg);
+ else if(strcmp(cmd, "help") == 0)
+ cpc.cmd_help(arg);
+ }
+ } else {
+ done = true;
+ ndbout << endl;
+ }
+ }
+ }
+ return;
+
+ error:
+ ndbout << "Error: expected a tcp port number, got '" << port_str << "'."
+ << endl;
+ return;
+}
+
+#if 0
+static
+void
+CmdBackupCallback(const MgmtSrvr::BackupEvent & event){
+ char str[255];
+
+ ndbout << endl;
+
+ bool ok = false;
+ switch(event.Event){
+ case MgmtSrvr::BackupEvent::BackupStarted:
+ ok = true;
+ snprintf(str, sizeof(str),
+ "Backup %d started", event.Started.BackupId);
+ break;
+ case MgmtSrvr::BackupEvent::BackupFailedToStart:
+ ok = true;
+ snprintf(str, sizeof(str),
+ "Backup failed to start (Error %d)",
+ event.FailedToStart.ErrorCode);
+ break;
+ case MgmtSrvr::BackupEvent::BackupCompleted:
+ ok = true;
+ snprintf(str, sizeof(str),
+ "Backup %d completed",
+ event.Completed.BackupId);
+ ndbout << str << endl;
+
+ snprintf(str, sizeof(str),
+ " StartGCP: %d StopGCP: %d",
+ event.Completed.startGCP, event.Completed.stopGCP);
+ ndbout << str << endl;
+
+ snprintf(str, sizeof(str),
+ " #Records: %d #LogRecords: %d",
+ event.Completed.NoOfRecords, event.Completed.NoOfLogRecords);
+ ndbout << str << endl;
+
+ snprintf(str, sizeof(str),
+ " Data: %d bytes Log: %d bytes",
+ event.Completed.NoOfBytes, event.Completed.NoOfLogBytes);
+ break;
+ case MgmtSrvr::BackupEvent::BackupAborted:
+ ok = true;
+ snprintf(str, sizeof(str),
+ "Backup %d has been aborted reason %d",
+ event.Aborted.BackupId,
+ event.Aborted.Reason);
+ break;
+ }
+ if(!ok){
+ snprintf(str, sizeof(str),
+ "Unknown backup event: %d",
+ event.Event);
+
+ }
+ ndbout << str << endl;
+}
+#endif