📄 mgmapi.cpp
字号:
/* Copyright (C) 2003 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */#include <ndb_global.h>#include <my_sys.h>#include <LocalConfig.hpp>#include <NdbAutoPtr.hpp>#include <NdbSleep.h>#include <NdbTCP.h>#include <mgmapi.h>#include <mgmapi_internal.h>#include <mgmapi_debug.h>#include "mgmapi_configuration.hpp"#include <socket_io.h>#include <NdbOut.hpp>#include <SocketServer.hpp>#include <SocketClient.hpp>#include <Parser.hpp>#include <OutputStream.hpp>#include <InputStream.hpp>#include <base64.h>#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 : private 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 256struct ndb_mgm_handle { int cfg_i; 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; LocalConfig cfg;#ifdef MGMAPI_LOG FILE* logfile;#endif FILE *errstream; char *m_name;};#define SET_ERROR(h, e, s) setError(h, e, __LINE__, s)staticvoidsetError(NdbMgmHandle h, int error, int error_line, const char * msg, ...){ h->last_error = error; \ h->last_error_line = error_line; va_list ap; va_start(ap, msg); BaseString::vsnprintf(h->last_error_desc, sizeof(h->last_error_desc), msg, ap); va_end(ap);}#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"NdbMgmHandlendb_mgm_create_handle(){ DBUG_ENTER("ndb_mgm_create_handle"); NdbMgmHandle h = (NdbMgmHandle)my_malloc(sizeof(ndb_mgm_handle),MYF(MY_WME)); h->connected = 0; h->last_error = 0; h->last_error_line = 0; h->socket = NDB_INVALID_SOCKET; h->read_timeout = 50000; h->write_timeout = 100; h->cfg_i = -1; h->errstream = stdout; h->m_name = 0; strncpy(h->last_error_desc, "No error", NDB_MGM_MAX_ERR_DESC_SIZE); new (&(h->cfg)) LocalConfig; h->cfg.init(0, 0);#ifdef MGMAPI_LOG h->logfile = 0;#endif DBUG_PRINT("info", ("handle=0x%x", (UintPtr)h)); DBUG_RETURN(h);}extern "C"voidndb_mgm_set_name(NdbMgmHandle handle, const char *name){ my_free(handle->m_name, MYF(MY_ALLOW_ZERO_PTR)); handle->m_name= my_strdup(name, MYF(MY_WME));}extern "C"intndb_mgm_set_connectstring(NdbMgmHandle handle, const char * mgmsrv){ DBUG_ENTER("ndb_mgm_set_connectstring"); DBUG_PRINT("info", ("handle=0x%x", (UintPtr)handle)); handle->cfg.~LocalConfig(); new (&(handle->cfg)) LocalConfig; if (!handle->cfg.init(mgmsrv, 0) || handle->cfg.ids.size() == 0) { handle->cfg.~LocalConfig(); new (&(handle->cfg)) LocalConfig; handle->cfg.init(0, 0); /* reset the LocalConfig */ SET_ERROR(handle, NDB_MGM_ILLEGAL_CONNECT_STRING, ""); DBUG_RETURN(-1); } handle->cfg_i= -1; DBUG_RETURN(0);}/** * Destroy a handle */extern "C"voidndb_mgm_destroy_handle(NdbMgmHandle * handle){ DBUG_ENTER("ndb_mgm_destroy_handle"); if(!handle) DBUG_VOID_RETURN; DBUG_PRINT("info", ("handle=0x%x", (UintPtr)(* handle))); /** * important! only disconnect if connected * other code relies on this */ if((* handle)->connected){ ndb_mgm_disconnect(* handle); }#ifdef MGMAPI_LOG if ((* handle)->logfile != 0){ fclose((* handle)->logfile); (* handle)->logfile = 0; }#endif (*handle)->cfg.~LocalConfig(); my_free((*handle)->m_name, MYF(MY_ALLOW_ZERO_PTR)); my_free((char*)* handle,MYF(MY_ALLOW_ZERO_PTR)); * handle = 0; DBUG_VOID_RETURN;}extern "C" voidndb_mgm_set_error_stream(NdbMgmHandle handle, FILE * file){ handle->errstream = file;}/***************************************************************************** * Error handling *****************************************************************************//** * Get latest error associated with a handle */extern "C"intndb_mgm_get_latest_error(const NdbMgmHandle h){ return h->last_error;}extern "C"const char *ndb_mgm_get_latest_error_desc(const NdbMgmHandle h){ return h->last_error_desc;}extern "C"intndb_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}/* * 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) { DBUG_ENTER("ndb_mgm_call"); DBUG_PRINT("enter",("handle->socket: %d, cmd: %s", handle->socket, cmd)); 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; Uint64 val_64; 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_Uint64: cmd_args->get(name, &val_64); out.println("%s: %Ld", name, val_64); break; case PropertiesType_char: cmd_args->get(name, val_s); out.println("%s: %s", name, val_s.c_str()); break; case PropertiesType_Properties: DBUG_PRINT("info",("Ignoring PropertiesType_Properties.")); /* Ignore */ break; default: DBUG_PRINT("info",("Ignoring PropertiesType: %d.",t)); } }#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); const Properties* p = parser.parse(ctx, session); if (p == NULL){ if(!ndb_mgm_is_connected(handle)) { DBUG_RETURN(NULL); } else { if(ctx.m_status==Parser_t::Eof || ctx.m_status==Parser_t::NoLine) { ndb_mgm_disconnect(handle); DBUG_RETURN(NULL); } /** * Print some info about why the parser returns NULL */ fprintf(handle->errstream, "Error in mgm protocol parser. cmd: >%s< status: %d curr: %d\n", cmd, (Uint32)ctx.m_status, ctx.m_currentToken); DBUG_PRINT("info",("ctx.status: %d, ctx.m_currentToken: %s", ctx.m_status, ctx.m_currentToken)); } }#ifdef MGMAPI_LOG else { /** * Print reply to log file */ p->print(handle->logfile, "IN: "); }#endif DBUG_RETURN(p);}/** * Returns true if connected */extern "C"int ndb_mgm_is_connected(NdbMgmHandle handle){ if(!handle) return 0; if(handle->connected) { if(Ndb_check_socket_hup(handle->socket)) { handle->connected= 0; NDB_CLOSE_SOCKET(handle->socket); } } return handle->connected;}/** * Connect to a management server */extern "C"intndb_mgm_connect(NdbMgmHandle handle, int no_retries, int retry_delay_in_seconds, int verbose){ SET_ERROR(handle, NDB_MGM_NO_ERROR, "Executing: ndb_mgm_connect"); CHECK_HANDLE(handle, -1); DBUG_ENTER("ndb_mgm_connect");#ifdef MGMAPI_LOG /** * Open the log file */ char logname[64]; BaseString::snprintf(logname, 64, "mgmapi.log"); handle->logfile = fopen(logname, "w");#endif /** * Do connect */ LocalConfig &cfg= handle->cfg; NDB_SOCKET_TYPE sockfd= NDB_INVALID_SOCKET; Uint32 i; while (sockfd == NDB_INVALID_SOCKET) { // do all the mgmt servers for (i = 0; i < cfg.ids.size(); i++) { if (cfg.ids[i].type != MgmId_TCP) continue; SocketClient s(cfg.ids[i].name.c_str(), cfg.ids[i].port); sockfd = s.connect(); if (sockfd != NDB_INVALID_SOCKET) break; } if (sockfd != NDB_INVALID_SOCKET) break;#ifndef DBUG_OFF { char buf[1024]; DBUG_PRINT("info",("Unable to connect with connect string: %s", cfg.makeConnectString(buf,sizeof(buf)))); }#endif if (verbose > 0) { char buf[1024]; fprintf(handle->errstream, "Unable to connect with connect string: %s\n", cfg.makeConnectString(buf,sizeof(buf))); verbose= -1; } if (no_retries == 0) { char buf[1024]; setError(handle, NDB_MGM_COULD_NOT_CONNECT_TO_SOCKET, __LINE__, "Unable to connect with connect string: %s", cfg.makeConnectString(buf,sizeof(buf))); if (verbose == -2) fprintf(handle->errstream, ", failed.\n"); DBUG_RETURN(-1); } if (verbose == -1) { fprintf(handle->errstream, "Retrying every %d seconds", retry_delay_in_seconds); if (no_retries > 0) fprintf(handle->errstream, ". Attempts left:"); else fprintf(handle->errstream, ", until connected."); fflush(handle->errstream); verbose= -2; } if (no_retries > 0) { if (verbose == -2) { fprintf(handle->errstream, " %d", no_retries); fflush(handle->errstream); } no_retries--; } NdbSleep_SecSleep(retry_delay_in_seconds); } if (verbose == -2) { fprintf(handle->errstream, "\n"); fflush(handle->errstream); } handle->cfg_i = i; handle->socket = sockfd; handle->connected = 1; DBUG_RETURN(0);}/** * Disconnect from a mgm server */extern "C"intndb_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 = NDB_INVALID_SOCKET; handle->connected = 0; return 0;}struct ndb_mgm_type_atoi { const char * str; const char * alias; enum ndb_mgm_node_type value;};static struct ndb_mgm_type_atoi type_values[] = { { "NDB", "ndbd", NDB_MGM_NODE_TYPE_NDB}, { "API", "mysqld", NDB_MGM_NODE_TYPE_API }, { "MGM", "ndb_mgmd", NDB_MGM_NODE_TYPE_MGM }};const int no_of_type_values = (sizeof(type_values) / sizeof(ndb_mgm_type_atoi));extern "C"ndb_mgm_node_typendb_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; else if(strcmp(type, type_values[i].alias) == 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;}extern "C"const char * ndb_mgm_get_node_type_alias_string(enum ndb_mgm_node_type type, const char** str){ for(int i = 0; i<no_of_type_values; i++) if(type_values[i].value == type) { if (str) *str= type_values[i].str; return type_values[i].alias; } 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));
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -