1 /* Copyright (C) 2008 MySQL AB, 2008, 2009 Sun Microsystems, Inc. 2 All rights reserved. Use is subject to license terms. 3 4 This program is free software; you can redistribute it and/or modify 5 it under the terms of the GNU General Public License, version 2.0, 6 as published by the Free Software Foundation. 7 8 This program is also distributed with certain software (including 9 but not limited to OpenSSL) that is licensed under separate terms, 10 as designated in a particular file or component or in included license 11 documentation. The authors of MySQL hereby grant you an additional 12 permission to link the program and your derivative works with the 13 separately licensed software that they have included with MySQL. 14 15 This program is distributed in the hope that it will be useful, 16 but WITHOUT ANY WARRANTY; without even the implied warranty of 17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 GNU General Public License, version 2.0, for more details. 19 20 You should have received a copy of the GNU General Public License 21 along with this program; if not, write to the Free Software 22 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ 23 24 #ifndef NDB_MGMD_HPP 25 #define NDB_MGMD_HPP 26 27 #include <mgmapi.h> 28 #include <mgmapi_internal.h> 29 30 #include <BaseString.hpp> 31 #include <Properties.hpp> 32 33 #include <OutputStream.hpp> 34 #include <SocketInputStream2.hpp> 35 36 #include "../../src/mgmsrv/Config.hpp" 37 38 class NdbMgmd { 39 BaseString m_connect_str; 40 NdbMgmHandle m_handle; 41 Uint32 m_nodeid; 42 bool m_verbose; 43 unsigned int m_timeout; error(const char * msg,...)44 void error(const char* msg, ...) ATTRIBUTE_FORMAT(printf, 2, 3) 45 { 46 if (!m_verbose) 47 return; 48 49 va_list args; 50 printf("NdbMgmd::"); 51 va_start(args, msg); 52 vprintf(msg, args); 53 va_end(args); 54 printf("\n"); 55 56 if (m_handle){ 57 ndbout_c(" error: %d, line: %d, desc: %s", 58 ndb_mgm_get_latest_error(m_handle), 59 ndb_mgm_get_latest_error_line(m_handle), 60 ndb_mgm_get_latest_error_desc(m_handle)); 61 } 62 } 63 public: NdbMgmd()64 NdbMgmd() : 65 m_handle(NULL), m_nodeid(0), m_verbose(true), m_timeout(0) 66 { 67 const char* connect_string= getenv("NDB_CONNECTSTRING"); 68 if (connect_string) 69 m_connect_str.assign(connect_string); 70 } 71 ~NdbMgmd()72 ~NdbMgmd() 73 { 74 close(); 75 } 76 close(void)77 void close(void) 78 { 79 if (m_handle) 80 { 81 ndb_mgm_disconnect_quiet(m_handle); 82 ndb_mgm_destroy_handle(&m_handle); 83 m_handle = NULL; 84 } 85 } 86 handle(void) const87 NdbMgmHandle handle(void) const { 88 return m_handle; 89 } 90 socket(void) const91 NDB_SOCKET_TYPE socket(void) const { 92 return _ndb_mgm_get_socket(m_handle); 93 } 94 nodeid(void) const95 NodeId nodeid(void) const { 96 return m_nodeid; 97 } 98 getConnectString() const99 const char* getConnectString() const { 100 return m_connect_str.c_str(); 101 } 102 setConnectString(const char * connect_str)103 void setConnectString(const char* connect_str) { 104 m_connect_str.assign(connect_str); 105 } 106 set_timeout(unsigned int timeout)107 bool set_timeout(unsigned int timeout) { 108 m_timeout = timeout; 109 if (m_handle && 110 ndb_mgm_set_timeout(m_handle, timeout) != 0) 111 { 112 error("set_timeout: failed to set timeout on handle"); 113 return false; 114 } 115 return true; 116 } 117 verbose(bool yes=true)118 void verbose(bool yes = true){ 119 m_verbose= yes; 120 } 121 last_error(void) const122 int last_error(void) const { 123 return ndb_mgm_get_latest_error(m_handle); 124 } 125 last_error_message(void) const126 const char* last_error_message(void) const { 127 return ndb_mgm_get_latest_error_desc(m_handle); 128 } 129 connect(const char * connect_string=NULL,int num_retries=0,int retry_delay_in_seconds=0)130 bool connect(const char* connect_string = NULL, 131 int num_retries = 0, int retry_delay_in_seconds = 0) { 132 assert(m_handle == NULL); 133 m_handle= ndb_mgm_create_handle(); 134 if (!m_handle){ 135 error("connect: ndb_mgm_create_handle failed"); 136 return false; 137 } 138 139 if (ndb_mgm_set_connectstring(m_handle, 140 connect_string ? 141 connect_string : getConnectString()) != 0){ 142 error("connect: ndb_mgm_set_connectstring failed"); 143 return false; 144 } 145 146 if (m_timeout > 0 && 147 ndb_mgm_set_timeout(m_handle, m_timeout) != 0){ 148 error("connect: ndb_mgm_set_timeout failed"); 149 return false; 150 } 151 152 if (ndb_mgm_connect(m_handle,num_retries,retry_delay_in_seconds,0) != 0){ 153 error("connect: ndb_mgm_connect failed"); 154 return false; 155 } 156 157 // Handshake with the server to make sure it's really there 158 int major, minor, build; 159 char buf[16]; 160 if (ndb_mgm_get_version(m_handle, &major, &minor, &build, 161 sizeof(buf), buf) != 1) 162 { 163 error("connect: ndb_get_version failed"); 164 return false; 165 } 166 //printf("connected to ndb_mgmd version %d.%d.%d\n", 167 // major, minor, build); 168 169 if ((m_nodeid = ndb_mgm_get_mgmd_nodeid(m_handle)) == 0){ 170 error("connect: could not get nodeid of connected mgmd"); 171 return false; 172 } 173 174 return true; 175 } 176 is_connected(void)177 bool is_connected(void) { 178 if (!m_handle){ 179 error("is_connected: no handle"); 180 return false; 181 } 182 if (!ndb_mgm_is_connected(m_handle)){ 183 error("is_connected: not connected"); 184 return false; 185 } 186 return true; 187 } 188 disconnect(void)189 bool disconnect(void) { 190 if (ndb_mgm_disconnect(m_handle) != 0){ 191 error("disconnect: ndb_mgm_disconnect failed"); 192 return false; 193 } 194 195 ndb_mgm_destroy_handle(&m_handle); 196 m_handle = NULL; 197 198 return true; 199 } 200 restart(bool abort=false)201 bool restart(bool abort = false) { 202 if (!is_connected()){ 203 error("restart: not connected"); 204 return false; 205 } 206 207 int disconnect= 0; 208 int node_list= m_nodeid; 209 int restarted= ndb_mgm_restart3(m_handle, 210 1, 211 &node_list, 212 false, /* initial */ 213 false, /* nostart */ 214 abort, 215 &disconnect); 216 217 if (restarted != 1){ 218 error("restart: failed to restart node %d, restarted: %d", 219 m_nodeid, restarted); 220 return false; 221 } 222 return true; 223 } 224 call(const char * cmd,const Properties & args,const char * cmd_reply,Properties & reply,const char * bulk=NULL,bool name_value_pairs=true)225 bool call(const char* cmd, const Properties& args, 226 const char* cmd_reply, Properties& reply, 227 const char* bulk = NULL, 228 bool name_value_pairs = true){ 229 230 if (!is_connected()){ 231 error("call: not connected"); 232 return false; 233 } 234 235 SocketOutputStream out(socket()); 236 237 if (out.println(cmd)){ 238 error("call: println failed at line %d", __LINE__); 239 return false; 240 } 241 242 Properties::Iterator iter(&args); 243 const char *name; 244 while((name = iter.next()) != NULL) { 245 PropertiesType t; 246 Uint32 val_i; 247 Uint64 val_64; 248 BaseString val_s; 249 250 args.getTypeOf(name, &t); 251 switch(t) { 252 case PropertiesType_Uint32: 253 args.get(name, &val_i); 254 if (out.println("%s: %d", name, val_i)){ 255 error("call: println failed at line %d", __LINE__); 256 return false; 257 } 258 break; 259 case PropertiesType_Uint64: 260 args.get(name, &val_64); 261 if (out.println("%s: %Ld", name, val_64)){ 262 error("call: println failed at line %d", __LINE__); 263 return false; 264 } 265 break; 266 case PropertiesType_char: 267 args.get(name, val_s); 268 if (out.println("%s: %s", name, val_s.c_str())){ 269 error("call: println failed at line %d", __LINE__); 270 return false; 271 } 272 break; 273 default: 274 case PropertiesType_Properties: 275 /* Illegal */ 276 abort(); 277 break; 278 } 279 } 280 281 // Emtpy line terminates argument list 282 if (out.print("\n")){ 283 error("call: print('\n') failed at line %d", __LINE__); 284 return false; 285 } 286 287 // Send any bulk data 288 if (bulk && out.println(bulk)){ 289 error("call: print('<bulk>') failed at line %d", __LINE__); 290 return false; 291 } 292 293 BaseString buf; 294 SocketInputStream2 in(socket()); 295 if (cmd_reply) 296 { 297 // Read the reply header and compare against "cmd_reply" 298 if (!in.gets(buf)){ 299 error("call: could not read reply command"); 300 return false; 301 } 302 303 // 1. Check correct reply header 304 if (buf != cmd_reply){ 305 error("call: unexpected reply command, expected: '%s', got '%s'", 306 cmd_reply, buf.c_str()); 307 return false; 308 } 309 } 310 311 // 2. Read lines until empty line 312 int line = 1; 313 while(in.gets(buf)){ 314 315 // empty line -> end of reply 316 if (buf == "") 317 return true; 318 319 if (name_value_pairs) 320 { 321 // 3a. Read colon separated name value pair, split 322 // the name value pair on first ':' 323 Vector<BaseString> name_value_pair; 324 if (buf.split(name_value_pair, ":", 2) != 2){ 325 error("call: illegal name value pair '%s' received", buf.c_str()); 326 return false; 327 } 328 329 reply.put(name_value_pair[0].trim(" ").c_str(), 330 name_value_pair[1].trim(" ").c_str()); 331 } 332 else 333 { 334 // 3b. Not name value pair, save the line into "reply" 335 // using unique key 336 reply.put("line", line++, buf.c_str()); 337 } 338 } 339 340 error("call: should never come here"); 341 reply.print(); 342 abort(); 343 return false; 344 } 345 346 get_config(Config & config)347 bool get_config(Config& config){ 348 349 if (!is_connected()){ 350 error("get_config: not connected"); 351 return false; 352 } 353 354 struct ndb_mgm_configuration* conf = 355 ndb_mgm_get_configuration(m_handle,0); 356 if (!conf) { 357 error("get_config: ndb_mgm_get_configuration failed"); 358 return false; 359 } 360 361 config.m_configValues= conf; 362 return true; 363 } 364 set_config(Config & config)365 bool set_config(Config& config){ 366 367 if (!is_connected()){ 368 error("set_config: not connected"); 369 return false; 370 } 371 372 if (ndb_mgm_set_configuration(m_handle, 373 config.values()) != 0) 374 { 375 error("set_config: ndb_mgm_set_configuration failed"); 376 return false; 377 } 378 return true; 379 } 380 end_session(void)381 bool end_session(void){ 382 if (!is_connected()){ 383 error("end_session: not connected"); 384 return false; 385 } 386 387 if (ndb_mgm_end_session(m_handle) != 0){ 388 error("end_session: ndb_mgm_end_session failed"); 389 return false; 390 } 391 return true; 392 } 393 394 // Pretty printer for 'ndb_mgm_node_type' 395 class NodeType { 396 BaseString m_str; 397 public: NodeType(Uint32 node_type)398 NodeType(Uint32 node_type) { 399 const char* str= NULL; 400 const char* alias= 401 ndb_mgm_get_node_type_alias_string((ndb_mgm_node_type)node_type, &str); 402 m_str.assfmt("%s(%s)", alias, str); 403 } 404 c_str()405 const char* c_str() { return m_str.c_str(); } 406 }; 407 }; 408 409 #endif 410