summaryrefslogtreecommitdiff
path: root/storage/ndb/src/mgmsrv/Services.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/mgmsrv/Services.cpp')
-rw-r--r--storage/ndb/src/mgmsrv/Services.cpp1568
1 files changed, 1568 insertions, 0 deletions
diff --git a/storage/ndb/src/mgmsrv/Services.cpp b/storage/ndb/src/mgmsrv/Services.cpp
new file mode 100644
index 00000000000..bbd3db1e734
--- /dev/null
+++ b/storage/ndb/src/mgmsrv/Services.cpp
@@ -0,0 +1,1568 @@
+/* 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 <Base64.hpp>
+
+#include <ConfigValues.hpp>
+#include <mgmapi_configuration.hpp>
+#include <Vector.hpp>
+#include "Services.hpp"
+#include "../mgmapi/ndb_logevent.hpp"
+
+extern bool g_StopServer;
+
+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 statport", &MgmApiSession::getStatPort, ""),
+
+ 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_CMD("get version", &MgmApiSession::getVersion, ""),
+
+ MGM_CMD("get status", &MgmApiSession::getStatus, ""),
+
+ MGM_CMD("get info clusterlog", &MgmApiSession::getInfoClusterLog, ""),
+
+ MGM_CMD("restart node", &MgmApiSession::restart, ""),
+ 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"),
+
+ /**
+ * Global Replication
+ */
+ MGM_CMD("rep", &MgmApiSession::repCommand, ""),
+ MGM_ARG("request", Int, Mandatory, "Command"),
+
+ MGM_CMD("stop", &MgmApiSession::stop, ""),
+ 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_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("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("config lock", &MgmApiSession::configLock, ""),
+
+ MGM_CMD("config unlock", &MgmApiSession::configUnlock, ""),
+ MGM_ARG("commit", Int, Mandatory, "Commit changes"),
+
+ MGM_CMD("config change", &MgmApiSession::configChange, ""),
+ MGM_ARG("section", String, Mandatory, "Section"),
+ MGM_ARG("parameter", String, Mandatory, "Parameter"),
+ MGM_ARG("value", String, Mandatory, "Value"),
+
+ MGM_CMD("config lock", &MgmApiSession::configLock, ""),
+
+ MGM_CMD("config unlock", &MgmApiSession::configUnlock, ""),
+ MGM_ARG("commit", Int, Mandatory, "Commit changes"),
+
+ 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_END()
+};
+
+MgmApiSession::MgmApiSession(class MgmtSrvr & mgm, NDB_SOCKET_TYPE sock)
+ : SocketServer::Session(sock), m_mgmsrv(mgm) {
+ 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);
+}
+
+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;
+}
+
+void
+MgmApiSession::runSession() {
+ Parser_t::Context ctx;
+ while(!m_stop) {
+ m_parser->run(ctx, *this);
+
+ if(ctx.m_currentToken == 0)
+ 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;
+ }
+ }
+ if(m_socket != NDB_INVALID_SOCKET)
+ NDB_CLOSE_SOCKET(m_socket);
+}
+
+#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 */
+
+inline void require(bool b){ if(!b) abort(); }
+
+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;
+ const char * transporter;
+ const char * user;
+ const char * password;
+ const char * public_key;
+ const char * endian= NULL;
+ 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);
+
+ 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 addr;
+ SOCKET_SIZE_TYPE addrlen= sizeof(addr);
+ int r = getpeername(m_socket, &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;
+ if (!m_mgmsrv.alloc_node_id(&tmp, (enum ndb_mgm_node_type)nodetype,
+ &addr, &addrlen, error_string)){
+ 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());
+ 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);
+
+ 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);
+
+ BaseString str;
+ int res = base64_encode(src, str);
+
+ m_output->println("get config reply");
+ m_output->println("result: Ok");
+ m_output->println("Content-Length: %d", str.length());
+ m_output->println("Content-Type: ndbconfig/octet-stream");
+ m_output->println("Content-Transfer-Encoding: base64");
+ m_output->println("");
+ m_output->println(str.c_str());
+
+ return;
+}
+
+void
+MgmApiSession::getStatPort(Parser_t::Context &,
+ const class Properties &) {
+
+ m_output->println("get statport reply");
+ m_output->println("tcpport: %d", 0);
+ m_output->println("");
+}
+
+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");
+ 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("");
+}
+
+/*****************************************************************************
+ * Global Replication
+ *****************************************************************************/
+
+void
+MgmApiSession::repCommand(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+
+ Uint32 request = 0;
+ args.get("request", &request);
+
+ Uint32 repReqId;
+ int result = m_mgmsrv.repCommand(&repReqId, request, true);
+
+ m_output->println("global replication reply");
+ if(result != 0)
+ m_output->println("result: %s", get_error_text(result));
+ else{
+ m_output->println("result: Ok");
+ m_output->println("id: %d", repReqId);
+ }
+ 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::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 ll;
+ ll.setLogLevel(category,level);
+ m_mgmsrv.m_event_listner.update_max_log_level(ll);
+ }
+
+ 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(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ 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 = 0;
+
+ for(size_t i = 0; i < nodes.size(); i++)
+ if((result = m_mgmsrv.restartNode(nodes[i],
+ nostart != 0,
+ initialstart != 0,
+ abort != 0)) == 0)
+ restarted++;
+
+ 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);
+ 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.restart(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;
+ while(mgmsrv.getNextNodeId(&nodeId, type)) {
+ enum ndb_mgm_node_status status;
+ Uint32 startPhase = 0,
+ version = 0,
+ dynamicId = 0,
+ nodeGroup = 0,
+ connectCount = 0;
+ bool system;
+ mgmsrv.status(nodeId, &status, &version, &startPhase,
+ &system, &dynamicId, &nodeGroup, &connectCount);
+ 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, mgmsrv.get_connect_address(nodeId));
+ }
+
+}
+
+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(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ Uint32 abort;
+ char *nodes_str;
+ Vector<NodeId> nodes;
+
+ args.get("node", (const char **)&nodes_str);
+ if(nodes_str == NULL)
+ 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 stop_self= 0;
+ size_t i;
+
+ for(i=0; i < nodes.size(); i++) {
+ if (nodes[i] == m_mgmsrv.getOwnNodeId()) {
+ stop_self= 1;
+ if (i != nodes.size()-1) {
+ m_output->println("stop reply");
+ m_output->println("result: server must be stopped last");
+ m_output->println("");
+ return;
+ }
+ }
+ }
+
+ int stopped = 0, result = 0;
+
+ for(i=0; i < nodes.size(); i++)
+ if (nodes[i] != m_mgmsrv.getOwnNodeId()) {
+ if((result = m_mgmsrv.stopNode(nodes[i], abort != 0)) == 0)
+ stopped++;
+ } else
+ stopped++;
+
+ 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);
+ m_output->println("");
+
+ if (stop_self)
+ g_StopServer= true;
+}
+
+
+void
+MgmApiSession::stopAll(Parser<MgmApiSession>::Context &,
+ Properties const &args) {
+ int stopped = 0;
+ Uint32 abort;
+ args.get("abort", &abort);
+
+ int result = m_mgmsrv.stop(&stopped, abort != 0);
+
+ 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);
+ 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("");
+}
+
+void
+MgmApiSession::configLock(Parser_t::Context &,
+ Properties const &) {
+ int ret = m_mgmsrv.lockConf();
+ m_output->println("config lock reply");
+ m_output->println("result: %d", ret);
+ m_output->println("");
+}
+
+void
+MgmApiSession::configUnlock(Parser_t::Context &,
+ Properties const &args) {
+ Uint32 commit;
+ args.get("commit", &commit);
+ int ret = m_mgmsrv.unlockConf(commit == 1);
+ m_output->println("config unlock reply");
+ m_output->println("result: %d", ret);
+ m_output->println("");
+}
+
+void
+MgmApiSession::configChange(Parser_t::Context &,
+ Properties const &args) {
+ BaseString section, param, value;
+ args.get("section", section);
+ args.get("parameter", param);
+ args.get("value", value);
+
+ int ret = m_mgmsrv.changeConfig(section.c_str(),
+ param.c_str(),
+ value.c_str());
+ m_output->println("config change reply");
+ m_output->println("result: %d", ret);
+ 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;
+ 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[256];
+ 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);
+ }
+
+ 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)){
+ if(m_clients[i].m_socket != NDB_INVALID_SOCKET)
+ {
+ int r;
+ if (m_clients[i].m_parsable)
+ r= println_socket(m_clients[i].m_socket,
+ MAX_WRITE_TIMEOUT, str.c_str());
+ else
+ r= println_socket(m_clients[i].m_socket,
+ MAX_WRITE_TIMEOUT, m_text);
+ if (r == -1) {
+ copy.push_back(m_clients[i].m_socket);
+ m_clients.erase(i, false);
+ }
+ }
+ }
+ }
+ m_clients.unlock();
+
+ for(i = 0; (unsigned)i < copy.size(); i++){
+ NDB_CLOSE_SOCKET(copy[i]);
+ }
+
+ if(copy.size()){
+ LogLevel tmp; tmp.clear();
+ m_clients.lock();
+ for(i = 0; (unsigned)i < m_clients.size(); 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= m_logLevel;
+ tmp.set_max(log_level);
+ update_log_level(tmp);
+}
+
+void
+Ndb_mgmd_event_service::update_log_level(const LogLevel &tmp)
+{
+ if(!(tmp == m_logLevel)){
+ m_logLevel = tmp;
+ EventSubscribeReq req;
+ req = tmp;
+ req.blockRef = 0;
+ m_mgmsrv->m_log_level_requests.push_back(req);
+ }
+}
+
+void
+Ndb_mgmd_event_service::add_listener(const Event_listener& client){
+ m_clients.push_back(client);
+ update_max_log_level(client.m_logLevel);
+}
+
+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;
+ }
+
+ m_mgmsrv.m_event_listner.add_listener(le);
+
+ m_stop = true;
+ m_socket = NDB_INVALID_SOCKET;
+
+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("");
+}
+
+struct PurgeStruct
+{
+ NodeBitmask free_nodes;/* free nodes as reported
+ * by ndbd in apiRegReqConf
+ */
+ BaseString *str;
+};
+
+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))
+ {
+ ps.str->appfmt(" %d", s->m_allocated_resources->get_nodeid());
+ 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_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("");
+}
+
+template class MutexVector<int>;
+template class Vector<ParserRow<MgmApiSession> const*>;