summaryrefslogtreecommitdiff
path: root/ndb/src/mgmapi/mgmapi.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'ndb/src/mgmapi/mgmapi.cpp')
-rw-r--r--ndb/src/mgmapi/mgmapi.cpp1465
1 files changed, 1465 insertions, 0 deletions
diff --git a/ndb/src/mgmapi/mgmapi.cpp b/ndb/src/mgmapi/mgmapi.cpp
new file mode 100644
index 00000000000..4c1355e8e46
--- /dev/null
+++ b/ndb/src/mgmapi/mgmapi.cpp
@@ -0,0 +1,1465 @@
+/* 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 <NdbTCP.h>
+#include "mgmapi.h"
+#include "mgmapi_debug.h"
+#include <socket_io.h>
+
+#include <stdlib.h>
+
+#include <string.h>
+#include <NdbStdio.h>
+#include <NdbString.h>
+#include <errno.h>
+#include <NdbOut.hpp>
+#include <SocketServer.hpp>
+#include <Parser.hpp>
+#include <OutputStream.hpp>
+#include <InputStream.hpp>
+
+
+#define MGM_CMD(name, fun, desc) \
+ { name, \
+ 0, \
+ ParserRow<ParserDummy>::Cmd, \
+ ParserRow<ParserDummy>::String, \
+ ParserRow<ParserDummy>::Optional, \
+ ParserRow<ParserDummy>::IgnoreMinMax, \
+ 0, 0, \
+ fun, \
+ desc, 0 }
+
+#define MGM_ARG(name, type, opt, desc) \
+ { name, \
+ 0, \
+ ParserRow<ParserDummy>::Arg, \
+ ParserRow<ParserDummy>::type, \
+ ParserRow<ParserDummy>::opt, \
+ ParserRow<ParserDummy>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ desc, 0 }
+
+#define MGM_END() \
+ { 0, \
+ 0, \
+ ParserRow<ParserDummy>::Arg, \
+ ParserRow<ParserDummy>::Int, \
+ ParserRow<ParserDummy>::Optional, \
+ ParserRow<ParserDummy>::IgnoreMinMax, \
+ 0, 0, \
+ 0, \
+ 0, 0 }
+
+class ParserDummy : SocketServer::Session
+{
+public:
+ ParserDummy(NDB_SOCKET_TYPE sock);
+};
+
+ParserDummy::ParserDummy(NDB_SOCKET_TYPE sock) : SocketServer::Session(sock)
+{
+}
+
+typedef Parser<ParserDummy> Parser_t;
+
+#define NDB_MGM_MAX_ERR_DESC_SIZE 256
+
+struct ndb_mgm_handle {
+ char * hostname;
+ unsigned short port;
+
+ int connected;
+ int last_error;
+ int last_error_line;
+ char last_error_desc[NDB_MGM_MAX_ERR_DESC_SIZE];
+ int read_timeout;
+ int write_timeout;
+
+ NDB_SOCKET_TYPE socket;
+
+#ifdef MGMAPI_LOG
+ FILE* logfile;
+#endif
+};
+
+#define SET_ERROR(h, e, s) \
+ { \
+ char tmp[NDB_MGM_MAX_ERR_DESC_SIZE]; \
+ snprintf(tmp, NDB_MGM_MAX_ERR_DESC_SIZE, " (mgmapi.cpp:%d)", __LINE__); \
+ strncpy(h->last_error_desc, s, NDB_MGM_MAX_ERR_DESC_SIZE); \
+ strncat(h->last_error_desc, tmp, NDB_MGM_MAX_ERR_DESC_SIZE); \
+ h->last_error = e; \
+ h->last_error_line = __LINE__; \
+ }
+
+#define CHECK_HANDLE(handle, ret) \
+ if(handle == 0) { \
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_SERVER_HANDLE, ""); \
+ return ret; \
+ }
+
+#define CHECK_CONNECTED(handle, ret) \
+ if (handle->connected != 1) { \
+ SET_ERROR(handle, NDB_MGM_SERVER_NOT_CONNECTED , ""); \
+ return ret; \
+ }
+
+#define CHECK_REPLY(reply, ret) \
+ if(reply == NULL) { \
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_SERVER_REPLY, ""); \
+ return ret; \
+ }
+
+/*****************************************************************************
+ * Handles
+ *****************************************************************************/
+
+extern "C"
+NdbMgmHandle
+ndb_mgm_create_handle()
+{
+ NdbMgmHandle h = (NdbMgmHandle)malloc(sizeof(ndb_mgm_handle));
+ h->connected = 0;
+ h->last_error = 0;
+ h->last_error_line = 0;
+ h->hostname = 0;
+ h->socket = -1;
+ h->read_timeout = 50000;
+ h->write_timeout = 100;
+
+ strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE);
+#ifdef MGMAPI_LOG
+ h->logfile = 0;
+#endif
+
+ return h;
+}
+
+/**
+ * Destroy a handle
+ */
+extern "C"
+void
+ndb_mgm_destroy_handle(NdbMgmHandle * handle)
+{
+ if(!handle)
+ return;
+ if((* handle)->connected){
+ ndb_mgm_disconnect(* handle);
+ }
+ if((* handle)->hostname != 0){
+ free((* handle)->hostname);
+ }
+#ifdef MGMAPI_LOG
+ if ((* handle)->logfile != 0){
+ fclose((* handle)->logfile);
+ (* handle)->logfile = 0;
+ }
+#endif
+ free(* handle);
+ * handle = 0;
+}
+
+/*****************************************************************************
+ * Error handling
+ *****************************************************************************/
+
+/**
+ * Get latest error associated with a handle
+ */
+extern "C"
+int
+ndb_mgm_get_latest_error(const NdbMgmHandle h)
+{
+ return h->last_error;
+}
+
+/**
+ * Get latest error line associated with a handle
+ */
+extern "C"
+int
+ndb_mgm_get_latest_error_line(const NdbMgmHandle h)
+{
+ return h->last_error_line;
+}
+
+extern "C"
+const char *
+ndb_mgm_get_latest_error_msg(const NdbMgmHandle h)
+{
+ for (int i=0; i<ndb_mgm_noOfErrorMsgs; i++) {
+ if (ndb_mgm_error_msgs[i].code == h->last_error)
+ return ndb_mgm_error_msgs[i].msg;
+ }
+
+ return "Error"; // Unknown Error message
+}
+
+extern "C"
+const char *
+ndb_mgm_get_latest_error_desc(const NdbMgmHandle h)
+{
+ return h->last_error_desc;
+}
+
+static
+int
+parse_connect_string(const char * connect_string,
+ NdbMgmHandle handle)
+{
+ if(connect_string == 0){
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, "");
+ return -1;
+ }
+
+ char * line = strdup(connect_string);
+ if(line == 0){
+ SET_ERROR(handle, NDB_MGM_OUT_OF_MEMORY, "");
+ return -1;
+ }
+
+ char * tmp = strchr(line, ':');
+ if(tmp == 0){
+ free(line);
+ SET_ERROR(handle, NDB_MGM_OUT_OF_MEMORY, "");
+ return -1;
+ }
+ * tmp = 0; tmp++;
+
+ int port = 0;
+ if(sscanf(tmp, "%d", &port) != 1){
+ free(line);
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_PORT_NUMBER, "");
+ return -1;
+ }
+
+ if(handle->hostname != 0)
+ free(handle->hostname);
+
+ handle->hostname = strdup(line);
+ handle->port = port;
+ free(line);
+ return 0;
+}
+
+/*
+ * Call an operation, and return the reply
+ */
+static const Properties *
+ndb_mgm_call(NdbMgmHandle handle, const ParserRow<ParserDummy> *command_reply,
+ const char *cmd, const Properties *cmd_args)
+{
+ SocketOutputStream out(handle->socket);
+ SocketInputStream in(handle->socket, handle->read_timeout);
+
+ out.println(cmd);
+#ifdef MGMAPI_LOG
+ /**
+ * Print command to log file
+ */
+ FileOutputStream f(handle->logfile);
+ f.println("OUT: %s", cmd);
+#endif
+
+ if(cmd_args != NULL) {
+ Properties::Iterator iter(cmd_args);
+ const char *name;
+ while((name = iter.next()) != NULL) {
+ PropertiesType t;
+ Uint32 val_i;
+ BaseString val_s;
+
+ cmd_args->getTypeOf(name, &t);
+ switch(t) {
+ case PropertiesType_Uint32:
+ cmd_args->get(name, &val_i);
+ out.println("%s: %d", name, val_i);
+ break;
+ case PropertiesType_char:
+ cmd_args->get(name, val_s);
+ out.println("%s: %s", name, val_s.c_str());
+ break;
+ default:
+ /* Ignore */
+ break;
+ }
+ }
+#ifdef MGMAPI_LOG
+ /**
+ * Print arguments to log file
+ */
+ cmd_args->print(handle->logfile, "OUT: ");
+#endif
+ }
+ out.println("");
+
+ Parser_t::Context ctx;
+ ParserDummy session(handle->socket);
+ Parser_t parser(command_reply, in, true, true, true);
+
+#if 1
+ const Properties* p = parser.parse(ctx, session);
+ if (p == NULL){
+ /**
+ * Print some info about why the parser returns NULL
+ */
+// ndbout << " status=" << ctx.m_status << ", curr="
+// << ctx.m_currentToken << endl;
+ }
+#ifdef MGMAPI_LOG
+ else {
+ /**
+ * Print reply to log file
+ */
+ p->print(handle->logfile, "IN: ");
+ }
+#endif
+ return p;
+#else
+ return parser.parse(ctx, session);
+#endif
+}
+
+/**
+ * Connect to a management server
+ */
+extern "C"
+int
+ndb_mgm_connect(NdbMgmHandle handle, const char * mgmsrv)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect");
+ CHECK_HANDLE(handle, -1);
+
+ if(parse_connect_string(mgmsrv, handle) != 0) {
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, "");
+ return -1;
+ }
+
+#ifdef MGMAPI_LOG
+ /**
+ * Open the log file
+ */
+ char logname[64];
+ snprintf(logname, 64, "mgmapi.log");
+ handle->logfile = fopen(logname, "w");
+#endif
+
+ /**
+ * Do connect
+ */
+ const NDB_SOCKET_TYPE sockfd = socket(AF_INET, SOCK_STREAM, 0);
+ if (sockfd == NDB_INVALID_SOCKET) {
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_SOCKET, "");
+ return -1;
+ }
+
+ struct sockaddr_in servaddr;
+ memset(&servaddr, 0, sizeof(servaddr));
+ servaddr.sin_family = AF_INET;
+ servaddr.sin_port = htons(handle->port);
+ // Convert ip address presentation format to numeric format
+ const int res1 = Ndb_getInAddr(&servaddr.sin_addr, handle->hostname);
+ if (res1 != 0) {
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_IP_ADDRESS, "");
+ return -1;
+ }
+
+ const int res2 = connect(sockfd, (struct sockaddr*) &servaddr,
+ sizeof(servaddr));
+ if (res2 == -1) {
+ NDB_CLOSE_SOCKET(sockfd);
+ SET_ERROR(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, "");
+ return -1;
+ }
+
+ handle->socket = sockfd;
+ handle->connected = 1;
+
+ return 0;
+}
+
+/**
+ * Disconnect from a mgm server
+ */
+extern "C"
+int
+ndb_mgm_disconnect(NdbMgmHandle handle)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_disconnect");
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ NDB_CLOSE_SOCKET(handle->socket);
+ handle->socket = -1;
+ handle->connected = 0;
+
+ return 0;
+}
+
+struct ndb_mgm_type_atoi
+{
+ const char * str;
+ enum ndb_mgm_node_type value;
+};
+
+static struct ndb_mgm_type_atoi type_values[] =
+{
+ { "NDB", NDB_MGM_NODE_TYPE_NDB},
+ { "API", NDB_MGM_NODE_TYPE_API },
+ { "MGM", NDB_MGM_NODE_TYPE_MGM }
+};
+
+const int no_of_type_values = (sizeof(type_values) /
+ sizeof(ndb_mgm_type_atoi));
+
+extern "C"
+enum ndb_mgm_node_type
+ndb_mgm_match_node_type(const char * type)
+{
+ if(type == 0)
+ return NDB_MGM_NODE_TYPE_UNKNOWN;
+
+ for(int i = 0; i<no_of_type_values; i++)
+ if(strcmp(type, type_values[i].str) == 0)
+ return type_values[i].value;
+
+ return NDB_MGM_NODE_TYPE_UNKNOWN;
+}
+
+extern "C"
+const char *
+ndb_mgm_get_node_type_string(enum ndb_mgm_node_type type)
+{
+ for(int i = 0; i<no_of_type_values; i++)
+ if(type_values[i].value == type)
+ return type_values[i].str;
+ return 0;
+}
+
+struct ndb_mgm_status_atoi {
+ const char * str;
+ enum ndb_mgm_node_status value;
+};
+
+static struct ndb_mgm_status_atoi status_values[] =
+{
+ { "UNKNOWN", NDB_MGM_NODE_STATUS_UNKNOWN },
+ { "NO_CONTACT", NDB_MGM_NODE_STATUS_NO_CONTACT },
+ { "NOT_STARTED", NDB_MGM_NODE_STATUS_NOT_STARTED },
+ { "STARTING", NDB_MGM_NODE_STATUS_STARTING },
+ { "STARTED", NDB_MGM_NODE_STATUS_STARTED },
+ { "SHUTTING_DOWN", NDB_MGM_NODE_STATUS_SHUTTING_DOWN },
+ { "RESTARTING", NDB_MGM_NODE_STATUS_RESTARTING },
+ { "SINGLE USER MODE", NDB_MGM_NODE_STATUS_SINGLEUSER }
+};
+
+const int no_of_status_values = (sizeof(status_values) /
+ sizeof(ndb_mgm_status_atoi));
+
+extern "C"
+enum ndb_mgm_node_status
+ndb_mgm_match_node_status(const char * status)
+{
+ if(status == 0)
+ return NDB_MGM_NODE_STATUS_UNKNOWN;
+
+ for(int i = 0; i<no_of_status_values; i++)
+ if(strcmp(status, status_values[i].str) == 0)
+ return status_values[i].value;
+
+ return NDB_MGM_NODE_STATUS_UNKNOWN;
+}
+
+extern "C"
+const char *
+ndb_mgm_get_node_status_string(enum ndb_mgm_node_status status)
+{
+ for(int i = 0; i<no_of_status_values; i++)
+ if(status_values[i].value == status)
+ return status_values[i].str;
+
+ for(int i = 0; i<no_of_status_values; i++)
+ if(status_values[i].value == NDB_MGM_NODE_STATUS_UNKNOWN)
+ return status_values[i].str;
+
+ return 0;
+}
+
+static int
+status_ackumulate(struct ndb_mgm_node_state * state,
+ const char * field,
+ const char * value)
+{
+ if(strcmp("type", field) == 0){
+ state->node_type = ndb_mgm_match_node_type(value);
+ } else if(strcmp("status", field) == 0){
+ state->node_status = ndb_mgm_match_node_status(value);
+ } else if(strcmp("startphase", field) == 0){
+ state->start_phase = atoi(value);
+ } else if(strcmp("dynamic_id", field) == 0){
+ state->dynamic_id = atoi(value);
+ } else if(strcmp("node_group", field) == 0){
+ state->node_group = atoi(value);
+ } else if(strcmp("version", field) == 0){
+ state->version = atoi(value);
+ } else {
+ ndbout_c("Unknown field: %s", field);
+ }
+ return 0;
+}
+
+/**
+ * Compare function for qsort() that sorts ndb_mgm_node_state in
+ * node_id order
+ */
+static int
+cmp_state(const void *_a, const void *_b)
+{
+ struct ndb_mgm_node_state *a, *b;
+
+ a = (struct ndb_mgm_node_state *)_a;
+ b = (struct ndb_mgm_node_state *)_b;
+
+ return a->node_id > b->node_id;
+}
+
+extern "C"
+struct ndb_mgm_cluster_state *
+ndb_mgm_get_status(NdbMgmHandle handle)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_status");
+ CHECK_HANDLE(handle, NULL);
+ CHECK_CONNECTED(handle, NULL);
+
+ SocketOutputStream out(handle->socket);
+ SocketInputStream in(handle->socket, handle->read_timeout);
+
+ out.println("get status");
+ out.println("");
+
+ char buf[1024];
+ in.gets(buf, sizeof(buf));
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+
+ if(strcmp("node status", buf) != 0) {
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_NODE_STATUS, "");
+ return NULL;
+ }
+
+ in.gets(buf, sizeof(buf));
+ if(buf[strlen(buf)-1] == '\n')
+ buf[strlen(buf)-1] = '\0';
+
+ BaseString tmp(buf);
+ Vector<BaseString> split;
+ tmp.split(split, ":");
+ if(split.size() != 2){
+ abort();
+ return NULL;
+ }
+
+ if(!(split[0].trim() == "nodes")){
+ abort();
+ return NULL;
+ }
+
+ const int noOfNodes = atoi(split[1].c_str());
+
+ ndb_mgm_cluster_state *state = (ndb_mgm_cluster_state*)
+ malloc(sizeof(ndb_mgm_cluster_state)+
+ noOfNodes*sizeof(ndb_mgm_node_state));
+
+ state->no_of_nodes = noOfNodes;
+ ndb_mgm_node_state * ptr = &state->node_states[0];
+ int nodeId = 0;
+ int i = -1; ptr--;
+ for(; i<noOfNodes; ){
+ in.gets(buf, sizeof(buf));
+ tmp.assign(buf);
+
+ if(tmp.trim() == ""){
+ break;
+ }
+
+ Vector<BaseString> split;
+ tmp.split(split, ":.");
+ if(split.size() != 4)
+ break;
+
+ const int id = atoi(split[1].c_str());
+ if(id != nodeId){
+ ptr++;
+ i++;
+ nodeId = id;
+ ptr->node_id = id;
+ }
+
+ split[3].trim(" \t\n");
+
+ if(status_ackumulate(ptr,split[2].c_str(), split[3].c_str()) != 0) {
+ break;
+ }
+ }
+
+ if(i+1 != noOfNodes){
+ free(state);
+ abort();
+ return NULL;
+ }
+
+ qsort(state->node_states, state->no_of_nodes, sizeof(state->node_states[0]),
+ cmp_state);
+ return state;
+}
+
+extern "C"
+int
+ndb_mgm_enter_single_user(NdbMgmHandle handle,
+ unsigned int nodeId,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_enter_single_user");
+ const ParserRow<ParserDummy> enter_single_reply[] = {
+ MGM_CMD("enter single user reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("nodeId", nodeId);
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, enter_single_reply, "enter single user", &args);
+ CHECK_REPLY(reply, -1);
+
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_COULD_NOT_ENTER_SINGLE_USER_MODE,
+ result.c_str());
+ delete reply;
+ return -1;
+ }
+
+ delete reply;
+ return 0;
+}
+
+
+extern "C"
+int
+ndb_mgm_exit_single_user(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_exit_single_user");
+ const ParserRow<ParserDummy> exit_single_reply[] = {
+ MGM_CMD("exit single user reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, exit_single_reply, "exit single user", 0);
+ CHECK_REPLY(reply, -1);
+
+ const char * buf;
+ reply->get("result", &buf);
+ if(strcmp(buf,"Ok")!=0) {
+ SET_ERROR(handle, NDB_MGM_COULD_NOT_EXIT_SINGLE_USER_MODE, buf);
+ delete reply;
+ return -1;
+ }
+
+ delete reply;
+ return 0;
+}
+
+extern "C"
+int
+ndb_mgm_stop(NdbMgmHandle handle, int no_of_nodes, const int * node_list)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_stop");
+ return ndb_mgm_stop2(handle, no_of_nodes, node_list, 0);
+}
+
+
+extern "C"
+int
+ndb_mgm_stop2(NdbMgmHandle handle, int no_of_nodes, const int * node_list,
+ int abort)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_stop2");
+ const ParserRow<ParserDummy> stop_reply[] = {
+ MGM_CMD("stop reply", NULL, ""),
+ MGM_ARG("stopped", Int, Optional, "No of stopped nodes"),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ if(no_of_nodes < 0){
+ SET_ERROR(handle, NDB_MGM_ILLEGAL_NUMBER_OF_NODES,
+ "Negative number of nodes requested to stop");
+ return -1;
+ }
+
+ Uint32 stoppedNoOfNodes = 0;
+ if(no_of_nodes == 0){
+ /**
+ * All database nodes should be stopped
+ */
+ Properties args;
+ args.put("abort", abort);
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, stop_reply, "stop all", &args);
+ CHECK_REPLY(reply, -1);
+
+ if(!reply->get("stopped", &stoppedNoOfNodes)){
+ SET_ERROR(handle, NDB_MGM_STOP_FAILED,
+ "Could not get number of stopped nodes from mgm server");
+ delete reply;
+ return -1;
+ }
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_STOP_FAILED, result.c_str());
+ delete reply;
+ return -1;
+ }
+ delete reply;
+ return stoppedNoOfNodes;
+ }
+
+ /**
+ * A list of database nodes should be stopped
+ */
+ Properties args;
+
+ BaseString node_list_str;
+ node_list_str.assfmt("%d", node_list[0]);
+ for(int node = 1; node < no_of_nodes; node++)
+ node_list_str.appfmt(" %d", node_list[node]);
+
+ args.put("node", node_list_str.c_str());
+ args.put("abort", abort);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, stop_reply, "stop", &args);
+ CHECK_REPLY(reply, stoppedNoOfNodes);
+ if(!reply->get("stopped", &stoppedNoOfNodes)){
+ SET_ERROR(handle, NDB_MGM_STOP_FAILED,
+ "Could not get number of stopped nodes from mgm server");
+ delete reply;
+ return -1;
+ }
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_STOP_FAILED, result.c_str());
+ delete reply;
+ return -1;
+ }
+ delete reply;
+ return stoppedNoOfNodes;
+}
+
+extern "C"
+int
+ndb_mgm_restart2(NdbMgmHandle handle, int no_of_nodes, const int * node_list,
+ int initial, int nostart, int abort)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_restart2");
+ Uint32 restarted = 0;
+ const ParserRow<ParserDummy> restart_reply[] = {
+ MGM_CMD("restart reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_ARG("restarted", Int, Optional, "No of restarted nodes"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ if(no_of_nodes < 0){
+ SET_ERROR(handle, NDB_MGM_RESTART_FAILED,
+ "Restart requested of negative number of nodes");
+ return -1;
+ }
+
+ if(no_of_nodes == 0) {
+ Properties args;
+ args.put("abort", abort);
+ args.put("initialstart", initial);
+ args.put("nostart", nostart);
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, restart_reply, "restart all", &args);
+ CHECK_REPLY(reply, -1);
+
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_RESTART_FAILED, result.c_str());
+ delete reply;
+ return -1;
+ }
+ if(!reply->get("restarted", &restarted)){
+ SET_ERROR(handle, NDB_MGM_RESTART_FAILED,
+ "Could not get restarted number of nodes from mgm server");
+ delete reply;
+ return -1;
+ }
+ delete reply;
+ return restarted;
+ }
+
+ BaseString node_list_str;
+ node_list_str.assfmt("%d", node_list[0]);
+ for(int node = 1; node < no_of_nodes; node++)
+ node_list_str.appfmt(" %d", node_list[node]);
+
+ Properties args;
+
+ args.put("node", node_list_str.c_str());
+ args.put("abort", abort);
+ args.put("initialstart", initial);
+ args.put("nostart", nostart);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, restart_reply, "restart node", &args);
+ if(reply != NULL) {
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_RESTART_FAILED, result.c_str());
+ delete reply;
+ return -1;
+ }
+ reply->get("restarted", &restarted);
+ delete reply;
+ }
+
+ return restarted;
+}
+
+extern "C"
+int
+ndb_mgm_restart(NdbMgmHandle handle, int no_of_nodes, const int *node_list)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_restart");
+ return ndb_mgm_restart2(handle, no_of_nodes, node_list, 0, 0, 0);
+}
+
+extern "C"
+unsigned int *
+ndb_mgm_get_logfilter(NdbMgmHandle handle)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_logfilter");
+ static Uint32 enabled[7] = {0,0,0,0,0,0,0};
+ const ParserRow<ParserDummy> getinfo_reply[] = {
+ MGM_CMD("clusterlog", NULL, ""),
+ MGM_ARG("enabled", Int, Mandatory, ""),
+ MGM_ARG("debug", Int, Mandatory, ""),
+ MGM_ARG("info", Int, Mandatory, ""),
+ MGM_ARG("warning", Int, Mandatory, ""),
+ MGM_ARG("error", Int, Mandatory, ""),
+ MGM_ARG("critical", Int, Mandatory, ""),
+ MGM_ARG("alert", Int, Mandatory, ""),
+ };
+ CHECK_HANDLE(handle, NULL);
+ CHECK_CONNECTED(handle, NULL);
+
+ Properties args;
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, getinfo_reply, "get info clusterlog", &args);
+ CHECK_REPLY(reply, NULL);
+
+ const char *names[] = { "enabled", "debug", "info", "warning", "error",
+ "critical", "alert" };
+ for(int i=0; i < 7; i++) {
+ reply->get(names[i], &enabled[i]);
+ }
+ return enabled;
+}
+
+extern "C"
+int
+ndb_mgm_filter_clusterlog(NdbMgmHandle handle,
+ enum ndb_mgm_clusterlog_level level,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_filter_clusterlog");
+ const ParserRow<ParserDummy> filter_reply[] = {
+ MGM_CMD("set logfilter reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("level", level);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, filter_reply, "set logfilter", &args);
+ CHECK_REPLY(reply, retval);
+
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "1") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete reply;
+ return retval;
+}
+
+struct ndb_mgm_event_categories
+{
+ const char* name;
+ enum ndb_mgm_event_category category;
+};
+
+extern "C"
+int
+ndb_mgm_set_loglevel_clusterlog(NdbMgmHandle handle, int nodeId,
+ /*enum ndb_mgm_event_category*/
+ char * category, int level,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR,
+ "Executing: ndb_mgm_set_loglevel_clusterlog");
+ const ParserRow<ParserDummy> clusterlog_reply[] = {
+ MGM_CMD("set cluster loglevel reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("category", category);
+ args.put("level", level);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, clusterlog_reply,
+ "set cluster loglevel", &args);
+ CHECK_REPLY(reply, -1);
+
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ delete reply;
+ return -1;
+ }
+ delete reply;
+ return 0;
+}
+
+extern "C"
+int
+ndb_mgm_set_loglevel_node(NdbMgmHandle handle, int nodeId,
+ /*enum ndb_mgm_event_category category*/
+ char * category, int level,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_set_loglevel_node");
+ const ParserRow<ParserDummy> loglevel_reply[] = {
+ MGM_CMD("set loglevel reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("category", category);
+ args.put("level", level);
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, loglevel_reply, "set loglevel", &args);
+ CHECK_REPLY(reply, -1);
+
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ delete reply;
+ return -1;
+ }
+
+ delete reply;
+ return 0;
+}
+
+extern "C"
+int
+ndb_mgm_get_stat_port(NdbMgmHandle handle, struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_get_stat_port");
+ const ParserRow<ParserDummy> stat_reply[] = {
+ MGM_CMD("error", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_CMD("get statport reply", NULL, ""),
+ MGM_ARG("tcpport", Int, Mandatory, "TCP port for statistics"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, stat_reply, "get statport", &args);
+ CHECK_REPLY(reply, -1);
+
+ Uint32 port;
+ reply->get("tcpport", &port);
+
+ delete reply;
+ return port;
+}
+
+extern "C"
+int
+ndb_mgm_dump_state(NdbMgmHandle handle, int nodeId, int* _args,
+ int _num_args, struct ndb_mgm_reply* /* reply */)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_dump_state");
+ const ParserRow<ParserDummy> dump_state_reply[] = {
+ MGM_CMD("dump state reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ char buf[256];
+ char buf2[6];
+ buf[0] = 0;
+ for (int i = 0; i < _num_args; i++){
+ snprintf(buf2, 6, "%d ", _args[i]);
+ strncat(buf, buf2, 256);
+ }
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("args", buf);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, dump_state_reply, "dump state", &args);
+ CHECK_REPLY(prop, -1);
+
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ delete prop;
+ return -1;
+ }
+
+ delete prop;
+ return 0;
+}
+
+extern "C"
+int
+ndb_mgm_start_signallog(NdbMgmHandle handle, int nodeId,
+ struct ndb_mgm_reply* reply)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_start_signallog");
+ const ParserRow<ParserDummy> start_signallog_reply[] = {
+ MGM_CMD("start signallog reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle,
+ start_signallog_reply,
+ "start signallog",
+ &args);
+
+ if(prop != NULL) {
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete prop;
+ }
+
+ return retval;
+}
+
+extern "C"
+int
+ndb_mgm_stop_signallog(NdbMgmHandle handle, int nodeId,
+ struct ndb_mgm_reply* reply)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_stop_signallog");
+ const ParserRow<ParserDummy> stop_signallog_reply[] = {
+ MGM_CMD("stop signallog reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, stop_signallog_reply, "stop signallog", &args);
+
+ if(prop != NULL) {
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete prop;
+ }
+
+ return retval;
+}
+
+struct ndb_mgm_signal_log_modes
+{
+ const char* name;
+ enum ndb_mgm_signal_log_mode mode;
+};
+
+extern "C"
+int
+ndb_mgm_log_signals(NdbMgmHandle handle, int nodeId,
+ enum ndb_mgm_signal_log_mode mode,
+ const char* blockNames,
+ struct ndb_mgm_reply* reply)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_log_signals");
+ const ParserRow<ParserDummy> stop_signallog_reply[] = {
+ MGM_CMD("log signals reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("blocks", blockNames);
+
+ switch(mode) {
+ case NDB_MGM_SIGNAL_LOG_MODE_IN:
+ args.put("in", (Uint32)1);
+ args.put("out", (Uint32)0);
+ break;
+ case NDB_MGM_SIGNAL_LOG_MODE_OUT:
+ args.put("in", (Uint32)0);
+ args.put("out", (Uint32)1);
+ break;
+ case NDB_MGM_SIGNAL_LOG_MODE_INOUT:
+ args.put("in", (Uint32)1);
+ args.put("out", (Uint32)1);
+ break;
+ case NDB_MGM_SIGNAL_LOG_MODE_OFF:
+ args.put("in", (Uint32)0);
+ args.put("out", (Uint32)0);
+ break;
+ }
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, stop_signallog_reply, "log signals", &args);
+
+ if(prop != NULL) {
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete prop;
+ }
+
+ return retval;
+}
+
+extern "C"
+int
+ndb_mgm_set_trace(NdbMgmHandle handle, int nodeId, int traceNumber,
+ struct ndb_mgm_reply* reply)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_set_trace");
+ const ParserRow<ParserDummy> set_trace_reply[] = {
+ MGM_CMD("set trace reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("trace", traceNumber);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, set_trace_reply, "set trace", &args);
+
+ if(prop != NULL) {
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete prop;
+ }
+
+ return retval;
+}
+
+extern "C"
+int
+ndb_mgm_insert_error(NdbMgmHandle handle, int nodeId, int errorCode,
+ struct ndb_mgm_reply* reply)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_insert_error");
+ const ParserRow<ParserDummy> insert_error_reply[] = {
+ MGM_CMD("insert error reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int retval = -1;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("node", nodeId);
+ args.put("error", errorCode);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, insert_error_reply, "insert error", &args);
+
+ if(prop != NULL) {
+ BaseString result;
+ prop->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ retval = 0;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ retval = -1;
+ }
+ delete prop;
+ }
+
+ return retval;
+}
+
+extern "C"
+int
+ndb_mgm_start(NdbMgmHandle handle, int no_of_nodes, const int * node_list)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_start");
+ const ParserRow<ParserDummy> start_reply[] = {
+ MGM_CMD("start reply", NULL, ""),
+ MGM_ARG("started", Int, Optional, "No of started nodes"),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ int started = 0;
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ if(no_of_nodes < 0){
+ SET_ERROR(handle, EINVAL, "");
+ return -1;
+ }
+
+ if(no_of_nodes == 0){
+ Properties args;
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, start_reply, "start all", &args);
+ CHECK_REPLY(reply, -1);
+
+ Uint32 count = 0;
+ if(!reply->get("started", &count)){
+ delete reply;
+ return -1;
+ }
+ delete reply;
+ return count;
+ }
+
+ for(int node = 0; node < no_of_nodes; node++) {
+ Properties args;
+ args.put("node", node_list[node]);
+
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, start_reply, "start", &args);
+
+ if(reply != NULL) {
+ BaseString result;
+ reply->get("result", result);
+ if(strcmp(result.c_str(), "Ok") == 0) {
+ started++;
+ } else {
+ SET_ERROR(handle, EINVAL, result.c_str());
+ delete reply;
+ return -1;
+ }
+ }
+ delete reply;
+ }
+
+ return started;
+}
+
+/*****************************************************************************
+ * Backup
+ *****************************************************************************/
+extern "C"
+int
+ndb_mgm_start_backup(NdbMgmHandle handle, unsigned int* _backup_id,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_start_backup");
+ const ParserRow<ParserDummy> start_backup_reply[] = {
+ MGM_CMD("start backup reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_ARG("id", Int, Optional, "Id of the started backup"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, start_backup_reply, "start backup", &args);
+ CHECK_REPLY(reply, -1);
+
+ BaseString result;
+ reply->get("result", result);
+ reply->get("id", _backup_id);
+ if(strcmp(result.c_str(), "Ok") != 0) {
+ SET_ERROR(handle, NDB_MGM_COULD_NOT_START_BACKUP, result.c_str());
+ delete reply;
+ return -1;
+ }
+
+ delete reply;
+ return 0;
+}
+
+extern "C"
+int
+ndb_mgm_abort_backup(NdbMgmHandle handle, unsigned int backupId,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_abort_backup");
+ const ParserRow<ParserDummy> stop_backup_reply[] = {
+ MGM_CMD("abort backup reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("id", backupId);
+
+ const Properties *prop;
+ prop = ndb_mgm_call(handle, stop_backup_reply, "abort backup", &args);
+ CHECK_REPLY(prop, -1);
+
+ const char * buf;
+ prop->get("result", &buf);
+ if(strcmp(buf,"Ok")!=0) {
+ SET_ERROR(handle, NDB_MGM_COULD_NOT_ABORT_BACKUP, buf);
+ delete prop;
+ return -1;
+ }
+
+ delete prop;
+ return 0;
+}
+
+/*****************************************************************************
+ * Global Replication
+ *****************************************************************************/
+
+extern "C"
+int
+ndb_mgm_rep_command(NdbMgmHandle handle, unsigned int request,
+ unsigned int* replication_id,
+ struct ndb_mgm_reply* /*reply*/)
+{
+ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_rep_command");
+ const ParserRow<ParserDummy> replication_reply[] = {
+ MGM_CMD("global replication reply", NULL, ""),
+ MGM_ARG("result", String, Mandatory, "Error message"),
+ MGM_ARG("id", Int, Optional, "Id of global replication"),
+ MGM_END()
+ };
+ CHECK_HANDLE(handle, -1);
+ CHECK_CONNECTED(handle, -1);
+
+ Properties args;
+ args.put("request", request);
+ const Properties *reply;
+ reply = ndb_mgm_call(handle, replication_reply, "rep", &args);
+ CHECK_REPLY(reply, -1);
+
+ const char * result;
+ reply->get("result", &result);
+ reply->get("id", replication_id);
+ if(strcmp(result,"Ok")!=0) {
+ delete reply;
+ return -1;
+ }
+
+ delete reply;
+ return 0;
+}