MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
CommandInterpreter.cpp
1 /*
2  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
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 as published by
6  the Free Software Foundation; version 2 of the License.
7 
8  This program is distributed in the hope that it will be useful,
9  but WITHOUT ANY WARRANTY; without even the implied warranty of
10  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11  GNU General Public License for more details.
12 
13  You should have received a copy of the GNU General Public License
14  along with this program; if not, write to the Free Software
15  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17 
18 #include <ndb_global.h>
19 
20 #include <mgmapi.h>
21 #include <ndbd_exit_codes.h>
22 
23 #include <util/BaseString.hpp>
24 #include <util/Vector.hpp>
25 #include <kernel/BlockNumbers.h>
26 
34 public:
39  CommandInterpreter(const char *, int verbose);
41 
49  bool execute(const char *line, int try_reconnect = -1,
50  bool interactive = true, int *error = NULL);
51 
52 private:
53  void printError();
54  bool execute_impl(const char *line, bool interactive);
55 
65  int analyseAfterFirstToken(int processId, char* allAfterFirstTokenCstr);
66 
67  int executeCommand(Vector<BaseString> &command_list,
68  unsigned command_pos,
69  int *node_ids, int no_of_nodes);
79  bool parseBlockSpecification(const char* allAfterLog,
80  Vector<BaseString>& blocks);
81 
93  int executeHelp(char* parameters);
94  int executeShow(char* parameters);
95  int executePurge(char* parameters);
96  int executeConnect(char* parameters, bool interactive);
97  int executeShutdown(char* parameters);
98  void executeClusterLog(char* parameters);
99 
100 public:
101  int executeStop(int processId, const char* parameters, bool all);
102  int executeEnterSingleUser(char* parameters);
103  int executeExitSingleUser(char* parameters);
104  int executeStart(int processId, const char* parameters, bool all);
105  int executeRestart(int processId, const char* parameters, bool all);
106  int executeLogLevel(int processId, const char* parameters, bool all);
107  int executeError(int processId, const char* parameters, bool all);
108  int executeLog(int processId, const char* parameters, bool all);
109  int executeTestOn(int processId, const char* parameters, bool all);
110  int executeTestOff(int processId, const char* parameters, bool all);
111  int executeStatus(int processId, const char* parameters, bool all);
112  int executeEventReporting(int processId, const char* parameters, bool all);
113  int executeDumpState(int processId, const char* parameters, bool all);
114  int executeReport(int processId, const char* parameters, bool all);
115  int executeStartBackup(char * parameters, bool interactive);
116  int executeAbortBackup(char * parameters);
117  int executeStop(Vector<BaseString> &command_list, unsigned command_pos,
118  int *node_ids, int no_of_nodes);
119  int executeRestart(Vector<BaseString> &command_list, unsigned command_pos,
120  int *node_ids, int no_of_nodes);
121  int executeStart(Vector<BaseString> &command_list, unsigned command_pos,
122  int *node_ids, int no_of_nodes);
123  int executeCreateNodeGroup(char* parameters);
124  int executeDropNodeGroup(char* parameters);
125 public:
126  bool connect(bool interactive);
127  void disconnect(void);
128 
132 public:
133  typedef int (CommandInterpreter::* ExecuteFunction)(int processId,
134  const char * param,
135  bool all);
136 
138  const char * command;
139  ExecuteFunction executeFunction;
140  };
141 private:
145  int executeForAll(const char * cmd,
146  ExecuteFunction fun,
147  const char * param);
148 
149  NdbMgmHandle m_mgmsrv;
150  NdbMgmHandle m_mgmsrv2;
151  const char *m_constr;
152  bool m_connected;
153  int m_verbose;
154  int m_try_reconnect;
155  int m_error;
156  struct NdbThread* m_event_thread;
157  NdbMutex *m_print_mutex;
158 };
159 
160 NdbMutex* print_mutex;
161 
162 /*
163  * Facade object for CommandInterpreter
164  */
165 
166 #include "ndb_mgmclient.hpp"
167 
168 Ndb_mgmclient::Ndb_mgmclient(const char *host,int verbose)
169 {
170  m_cmd= new CommandInterpreter(host,verbose);
171 }
172 Ndb_mgmclient::~Ndb_mgmclient()
173 {
174  delete m_cmd;
175 }
176 bool Ndb_mgmclient::execute(const char *line, int try_reconnect,
177  bool interactive, int *error)
178 {
179  return m_cmd->execute(line, try_reconnect, interactive, error);
180 }
181 
182 /*
183  * The CommandInterpreter
184  */
185 
186 #include <mgmapi_debug.h>
187 
188 #include <util/version.h>
189 #include <util/NdbAutoPtr.hpp>
190 #include <util/NdbOut.hpp>
191 
192 #include <portlib/NdbSleep.h>
193 #include <portlib/NdbThread.h>
194 
195 #include <debugger/EventLogger.hpp>
196 #include <signaldata/SetLogLevelOrd.hpp>
197 
198 /*****************************************************************************
199  * HELP
200  *****************************************************************************/
201 static const char* helpText =
202 "---------------------------------------------------------------------------\n"
203 " NDB Cluster -- Management Client -- Help\n"
204 "---------------------------------------------------------------------------\n"
205 "HELP Print help text\n"
206 "HELP COMMAND Print detailed help for COMMAND(e.g. SHOW)\n"
207 #ifdef VM_TRACE // DEBUG ONLY
208 "HELP DEBUG Help for debug compiled version\n"
209 #endif
210 "SHOW Print information about cluster\n"
211 "CREATE NODEGROUP <id>,<id>... Add a Nodegroup containing nodes\n"
212 "DROP NODEGROUP <NG> Drop nodegroup with id NG\n"
213 "START BACKUP [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
214 "START BACKUP [<backup id>] [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
215 "START BACKUP [<backup id>] [SNAPSHOTSTART | SNAPSHOTEND] [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
216 " Start backup (default WAIT COMPLETED,SNAPSHOTEND)\n"
217 "ABORT BACKUP <backup id> Abort backup\n"
218 "SHUTDOWN Shutdown all processes in cluster\n"
219 "CLUSTERLOG ON [<severity>] ... Enable Cluster logging\n"
220 "CLUSTERLOG OFF [<severity>] ... Disable Cluster logging\n"
221 "CLUSTERLOG TOGGLE [<severity>] ... Toggle severity filter on/off\n"
222 "CLUSTERLOG INFO Print cluster log information\n"
223 "<id> START Start data node (started with -n)\n"
224 "<id> RESTART [-n] [-i] [-a] [-f] Restart data or management server node\n"
225 "<id> STOP [-a] [-f] Stop data or management server node\n"
226 "ENTER SINGLE USER MODE <id> Enter single user mode\n"
227 "EXIT SINGLE USER MODE Exit single user mode\n"
228 "<id> STATUS Print status\n"
229 "<id> CLUSTERLOG {<category>=<level>}+ Set log level for cluster log\n"
230 "PURGE STALE SESSIONS Reset reserved nodeid's in the mgmt server\n"
231 "CONNECT [<connectstring>] Connect to management server (reconnect if already connected)\n"
232 "<id> REPORT <report-type> Display report for <report-type>\n"
233 "QUIT Quit management client\n"
234 ;
235 
236 static const char* helpTextShow =
237 "---------------------------------------------------------------------------\n"
238 " NDB Cluster -- Management Client -- Help for SHOW command\n"
239 "---------------------------------------------------------------------------\n"
240 "SHOW Print information about cluster\n\n"
241 "SHOW Print information about cluster.The status reported is from\n"
242 " the perspective of the data nodes. API and Management Server nodes\n"
243 " are only reported as connected once the data nodes have started.\n"
244 ;
245 
246 static const char* helpTextHelp =
247 "---------------------------------------------------------------------------\n"
248 " NDB Cluster -- Management Client -- Help for HELP command\n"
249 "---------------------------------------------------------------------------\n"
250 "HELP List available commands of NDB Cluster Management Client\n\n"
251 "HELP List available commands.\n"
252 ;
253 
254 static const char* helpTextBackup =
255 "---------------------------------------------------------------------------\n"
256 " NDB Cluster -- Management Client -- Help for BACKUP command\n"
257 "---------------------------------------------------------------------------\n"
258 "BACKUP A backup is a snapshot of the database at a given time. \n"
259 " The backup consists of three main parts:\n\n"
260 " Metadata: the names and definitions of all database tables. \n"
261 " Table records: the data actually stored in the database tables \n"
262 " at the time that the backup was made.\n"
263 " Transaction log: a sequential record telling how \n"
264 " and when data was stored in the database.\n\n"
265 " Backups are stored on each data node in the cluster that \n"
266 " participates in the backup.\n\n"
267 " The cluster log records backup related events (such as \n"
268 " backup started, aborted, finished).\n"
269 ;
270 
271 static const char* helpTextStartBackup =
272 "---------------------------------------------------------------------------\n"
273 " NDB Cluster -- Management Client -- Help for START BACKUP command\n"
274 "---------------------------------------------------------------------------\n"
275 "START BACKUP Start a cluster backup\n\n"
276 "START BACKUP [<backup id>] [SNAPSHOTSTART | SNAPSHOTEND] [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
277 " Start a backup for the cluster.\n"
278 " Each backup gets an ID number that is reported to the\n"
279 " user. This ID number can help you find the backup on the\n"
280 " file system, or ABORT BACKUP if you wish to cancel a \n"
281 " running backup.\n"
282 " You can also start specified backup using START BACKUP <backup id> \n\n"
283 " <backup id> \n"
284 " Start a specified backup using <backup id> as bakcup ID number.\n"
285 " SNAPSHOTSTART \n"
286 " Backup snapshot is taken around the time the backup is started.\n"
287 " SNAPSHOTEND \n"
288 " Backup snapshot is taken around the time the backup is completed.\n"
289 " NOWAIT \n"
290 " Start a cluster backup and return immediately.\n"
291 " The management client will return control directly\n"
292 " to the user without waiting for the backup\n"
293 " to have started.\n"
294 " The status of the backup is recorded in the Cluster log.\n"
295 " WAIT STARTED\n"
296 " Start a cluster backup and return until the backup has\n"
297 " started. The management client will wait for the backup \n"
298 " to have started before returning control to the user.\n"
299 " WAIT COMPLETED\n"
300 " Start a cluster backup and return until the backup has\n"
301 " completed. The management client will wait for the backup\n"
302 " to complete before returning control to the user.\n"
303 ;
304 
305 static const char* helpTextAbortBackup =
306 "---------------------------------------------------------------------------\n"
307 " NDB Cluster -- Management Client -- Help for ABORT BACKUP command\n"
308 "---------------------------------------------------------------------------\n"
309 "ABORT BACKUP Abort a cluster backup\n\n"
310 "ABORT BACKUP <backup id> \n"
311 " Abort a backup that is already in progress.\n"
312 " The backup id can be seen in the cluster log or in the\n"
313 " output of the START BACKUP command.\n"
314 ;
315 
316 static const char* helpTextShutdown =
317 "---------------------------------------------------------------------------\n"
318 " NDB Cluster -- Management Client -- Help for SHUTDOWN command\n"
319 "---------------------------------------------------------------------------\n"
320 "SHUTDOWN Shutdown the cluster\n\n"
321 "SHUTDOWN Shutdown the data nodes and management nodes.\n"
322 " MySQL Servers and NDBAPI nodes are currently not \n"
323 " shut down by issuing this command.\n"
324 ;
325 
326 static const char* helpTextClusterlogOn =
327 "---------------------------------------------------------------------------\n"
328 " NDB Cluster -- Management Client -- Help for CLUSTERLOG ON command\n"
329 "---------------------------------------------------------------------------\n"
330 "CLUSTERLOG ON Enable Cluster logging\n\n"
331 "CLUSTERLOG ON [<severity>] ... \n"
332 " Turn the cluster log on.\n"
333 " It tells management server which severity levels\n"
334 " messages will be logged.\n\n"
335 " <severity> can be any one of the following values:\n"
336 " ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
337 ;
338 
339 static const char* helpTextClusterlogOff =
340 "---------------------------------------------------------------------------\n"
341 " NDB Cluster -- Management Client -- Help for CLUSTERLOG OFF command\n"
342 "---------------------------------------------------------------------------\n"
343 "CLUSTERLOG OFF Disable Cluster logging\n\n"
344 "CLUSTERLOG OFF [<severity>] ... \n"
345 " Turn the cluster log off.\n"
346 " It tells management server which serverity\n"
347 " levels logging will be disabled.\n\n"
348 " <severity> can be any one of the following values:\n"
349 " ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
350 ;
351 
352 static const char* helpTextClusterlogToggle =
353 "---------------------------------------------------------------------------\n"
354 " NDB Cluster -- Management Client -- Help for CLUSTERLOG TOGGLE command\n"
355 "---------------------------------------------------------------------------\n"
356 "CLUSTERLOG TOGGLE Toggle severity filter on/off\n\n"
357 "CLUSTERLOG TOGGLE [<severity>] ... \n"
358 " Toggle serverity filter on/off.\n"
359 " If a serverity level is already enabled,then it will\n"
360 " be disabled after you use the command,vice versa.\n\n"
361 " <severity> can be any one of the following values:\n"
362 " ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
363 ;
364 
365 static const char* helpTextClusterlogInfo =
366 "---------------------------------------------------------------------------\n"
367 " NDB Cluster -- Management Client -- Help for CLUSTERLOG INFO command\n"
368 "---------------------------------------------------------------------------\n"
369 "CLUSTERLOG INFO Print cluster log information\n\n"
370 "CLUSTERLOG INFO Display which severity levels have been enabled,\n"
371 " see HELP CLUSTERLOG for list of the severity levels.\n"
372 ;
373 
374 static const char* helpTextStart =
375 "---------------------------------------------------------------------------\n"
376 " NDB Cluster -- Management Client -- Help for START command\n"
377 "---------------------------------------------------------------------------\n"
378 "START Start data node (started with -n)\n\n"
379 "<id> START Start the data node identified by <id>.\n"
380 " Only starts data nodes that have not\n"
381 " yet joined the cluster. These are nodes\n"
382 " launched or restarted with the -n(--nostart)\n"
383 " option.\n\n"
384 " It does not launch the ndbd process on a remote\n"
385 " machine.\n"
386 ;
387 
388 static const char* helpTextRestart =
389 "---------------------------------------------------------------------------\n"
390 " NDB Cluster -- Management Client -- Help for RESTART command\n"
391 "---------------------------------------------------------------------------\n"
392 "RESTART Restart data or management server node\n\n"
393 "<id> RESTART [-n] [-i] [-a] [-f]\n"
394 " Restart the data or management node <id>(or All data nodes).\n\n"
395 " -n (--nostart) restarts the node but does not\n"
396 " make it join the cluster. Use '<id> START' to\n"
397 " join the node to the cluster.\n\n"
398 " -i (--initial) perform initial start.\n"
399 " This cleans the file system (ndb_<id>_fs)\n"
400 " and the node will copy data from another node\n"
401 " in the same node group during start up.\n\n"
402 " Consult the documentation before using -i.\n\n"
403 " INCORRECT USE OF -i WILL CAUSE DATA LOSS!\n\n"
404 " -a Aborts the node, not syncing GCP.\n\n"
405 " -f Force restart even if that would mean the\n"
406 " whole cluster would need to be restarted\n"
407 ;
408 
409 static const char* helpTextStop =
410 "---------------------------------------------------------------------------\n"
411 " NDB Cluster -- Management Client -- Help for STOP command\n"
412 "---------------------------------------------------------------------------\n"
413 "STOP Stop data or management server node\n\n"
414 "<id> STOP [-a] [-f]\n"
415 " Stop the data or management server node <id>.\n\n"
416 " ALL STOP will just stop all data nodes.\n\n"
417 " If you desire to also shut down management servers,\n"
418 " use SHUTDOWN instead.\n\n"
419 " -a Aborts the node, not syncing GCP.\n\n"
420 " -f Force stop even if that would mean the\n"
421 " whole cluster would need to be stopped\n"
422 ;
423 
424 static const char* helpTextEnterSingleUserMode =
425 "---------------------------------------------------------------------------\n"
426 " NDB Cluster -- Management Client -- Help for ENTER SINGLE USER MODE command\n"
427 "---------------------------------------------------------------------------\n"
428 "ENTER SINGLE USER MODE Enter single user mode\n\n"
429 "ENTER SINGLE USER MODE <id> \n"
430 " Enters single-user mode, whereby only the MySQL Server or NDBAPI\n"
431 " node identified by <id> is allowed to access the database. \n"
432 ;
433 
434 static const char* helpTextExitSingleUserMode =
435 "---------------------------------------------------------------------------\n"
436 " NDB Cluster -- Management Client -- Help for EXIT SINGLE USER MODE command\n"
437 "---------------------------------------------------------------------------\n"
438 "EXIT SINGLE USER MODE Exit single user mode\n\n"
439 "EXIT SINGLE USER MODE \n"
440 " Exits single-user mode, allowing all SQL nodes \n"
441 " (that is, all running mysqld processes) to access the database. \n"
442 ;
443 
444 static const char* helpTextStatus =
445 "---------------------------------------------------------------------------\n"
446 " NDB Cluster -- Management Client -- Help for STATUS command\n"
447 "---------------------------------------------------------------------------\n"
448 "STATUS Print status\n\n"
449 "<id> STATUS Displays status information for the data node <id>\n"
450 " or for All data nodes. \n\n"
451 " e.g.\n"
452 " ALL STATUS\n"
453 " 1 STATUS\n\n"
454 " When a node is starting, the start phase will be\n"
455 " listed.\n\n"
456 " Start Phase Meaning\n"
457 " 1 Clear the cluster file system(ndb_<id>_fs). \n"
458 " This stage occurs only when the --initial option \n"
459 " has been specified.\n"
460 " 2 This stage sets up Cluster connections, establishes \n"
461 " inter-node communications and starts Cluster heartbeats.\n"
462 " 3 The arbitrator node is elected.\n"
463 " 4 Initializes a number of internal cluster variables.\n"
464 " 5 For an initial start or initial node restart,\n"
465 " the redo log files are created.\n"
466 " 6 If this is an initial start, create internal system tables.\n"
467 " 7 Update internal variables. \n"
468 " 8 In a system restart, rebuild all indexes.\n"
469 " 9 Update internal variables. \n"
470 " 10 The node can be connected by APIs and can receive events.\n"
471 " 11 At this point,event delivery is handed over to\n"
472 " the node joining the cluster.\n"
473 "(see manual for more information)\n"
474 ;
475 
476 static const char* helpTextClusterlog =
477 "---------------------------------------------------------------------------\n"
478 " NDB Cluster -- Management Client -- Help for CLUSTERLOG command\n"
479 "---------------------------------------------------------------------------\n"
480 "CLUSTERLOG Set log level for cluster log\n\n"
481 " <id> CLUSTERLOG {<category>=<level>}+ \n"
482 " Logs <category> events with priority less than \n"
483 " or equal to <level> in the cluster log.\n\n"
484 " <category> can be any one of the following values:\n"
485 " STARTUP, SHUTDOWN, STATISTICS, CHECKPOINT, NODERESTART,\n"
486 " CONNECTION, ERROR, INFO, CONGESTION, DEBUG, or BACKUP. \n\n"
487 " <level> is represented by one of the numbers \n"
488 " from 1 to 15 inclusive, where 1 indicates 'most important' \n"
489 " and 15 'least important'.\n\n"
490 " <severity> can be any one of the following values:\n"
491 " ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
492 ;
493 
494 
495 static const char* helpTextPurgeStaleSessions =
496 "---------------------------------------------------------------------------\n"
497 " NDB Cluster -- Management Client -- Help for PURGE STALE SESSIONS command\n"
498 "---------------------------------------------------------------------------\n"
499 "PURGE STALE SESSIONS Reset reserved nodeid's in the mgmt server\n\n"
500 "PURGE STALE SESSIONS \n"
501 " Running this statement forces all reserved \n"
502 " node IDs to be checked; any that are not \n"
503 " being used by nodes acutally connected to \n"
504 " the cluster are then freed.\n\n"
505 " This command is not normally needed, but may be\n"
506 " required in some situations where failed nodes \n"
507 " cannot rejoin the cluster due to failing to\n"
508 " allocate a node id.\n"
509 ;
510 
511 static const char* helpTextConnect =
512 "---------------------------------------------------------------------------\n"
513 " NDB Cluster -- Management Client -- Help for CONNECT command\n"
514 "---------------------------------------------------------------------------\n"
515 "CONNECT Connect to management server (reconnect if already connected)\n\n"
516 "CONNECT [<connectstring>] \n"
517 " Connect to management server.\n"
518 " The optional parameter connectstring specifies the \n"
519 " connect string to user.\n\n"
520 " A connect string may be:\n"
521 " mgm-server\n"
522 " mgm-server:port\n"
523 " mgm1:port,mgm2:port\n"
524 " With multiple management servers comma separated.\n"
525 " The management client with try to connect to the \n"
526 " management servers in the order they are listed.\n\n"
527 " If no connect string is specified, the default \n"
528 " is used. \n"
529 ;
530 
531 static const char* helpTextReport =
532 "---------------------------------------------------------------------------\n"
533 " NDB Cluster -- Management Client -- Help for REPORT command\n"
534 "---------------------------------------------------------------------------\n"
535 "REPORT Displays a report of type <report-type> for the specified data \n"
536 " node, or for all data nodes using ALL\n"
537 ;
538 static void helpTextReportFn();
539 
540 static const char* helpTextQuit =
541 "---------------------------------------------------------------------------\n"
542 " NDB Cluster -- Management Client -- Help for QUIT command\n"
543 "---------------------------------------------------------------------------\n"
544 "QUIT Quit management client\n\n"
545 "QUIT Terminates the management client. \n"
546 ;
547 
548 
549 #ifdef VM_TRACE // DEBUG ONLY
550 static const char* helpTextDebug =
551 "---------------------------------------------------------------------------\n"
552 " NDB Cluster -- Management Client -- Help for Debugging (Internal use only)\n"
553 "---------------------------------------------------------------------------\n"
554 "SHOW PROPERTIES Print config properties object\n"
555 "<id> LOGLEVEL {<category>=<level>}+ Set log level\n"
556 #ifdef ERROR_INSERT
557 "<id> ERROR <errorNo> Inject error into NDB node\n"
558 #endif
559 "<id> LOG [BLOCK = {ALL|<block>+}] Set logging on in & out signals\n"
560 "<id> TESTON Start signal logging\n"
561 "<id> TESTOFF Stop signal logging\n"
562 "<id> DUMP <arg> Dump system state to cluster.log\n"
563 "\n"
564 "<id> = ALL | Any database node id\n"
565 ;
566 #endif
567 
568 struct st_cmd_help {
569  const char *cmd;
570  const char * help;
571  void (* help_fn)();
572 }help_items[]={
573  {"SHOW", helpTextShow, NULL},
574  {"HELP", helpTextHelp, NULL},
575  {"BACKUP", helpTextBackup, NULL},
576  {"START BACKUP", helpTextStartBackup, NULL},
577  {"START BACKUP NOWAIT", helpTextStartBackup, NULL},
578  {"START BACKUP WAIT STARTED", helpTextStartBackup, NULL},
579  {"START BACKUP WAIT", helpTextStartBackup, NULL},
580  {"START BACKUP WAIT COMPLETED", helpTextStartBackup, NULL},
581  {"ABORT BACKUP", helpTextAbortBackup, NULL},
582  {"SHUTDOWN", helpTextShutdown, NULL},
583  {"CLUSTERLOG ON", helpTextClusterlogOn, NULL},
584  {"CLUSTERLOG OFF", helpTextClusterlogOff, NULL},
585  {"CLUSTERLOG TOGGLE", helpTextClusterlogToggle, NULL},
586  {"CLUSTERLOG INFO", helpTextClusterlogInfo, NULL},
587  {"START", helpTextStart, NULL},
588  {"RESTART", helpTextRestart, NULL},
589  {"STOP", helpTextStop, NULL},
590  {"ENTER SINGLE USER MODE", helpTextEnterSingleUserMode, NULL},
591  {"EXIT SINGLE USER MODE", helpTextExitSingleUserMode, NULL},
592  {"STATUS", helpTextStatus, NULL},
593  {"CLUSTERLOG", helpTextClusterlog, NULL},
594  {"PURGE STALE SESSIONS", helpTextPurgeStaleSessions, NULL},
595  {"CONNECT", helpTextConnect, NULL},
596  {"REPORT", helpTextReport, helpTextReportFn},
597  {"QUIT", helpTextQuit, NULL},
598 #ifdef VM_TRACE // DEBUG ONLY
599  {"DEBUG", helpTextDebug, NULL},
600 #endif //VM_TRACE
601  {NULL, NULL, NULL}
602 };
603 
604 static bool
605 convert(const char* s, int& val) {
606 
607  if (s == NULL)
608  return false;
609 
610  if (strlen(s) == 0)
611  return false;
612 
613  errno = 0;
614  char* p;
615  long v = strtol(s, &p, 10);
616  if (errno != 0)
617  return false;
618 
619  if (p != &s[strlen(s)])
620  return false;
621 
622  val = v;
623  return true;
624 }
625 
626 /*
627  * Constructor
628  */
629 CommandInterpreter::CommandInterpreter(const char *host,int verbose) :
630  m_constr(host),
631  m_connected(false),
632  m_verbose(verbose),
633  m_try_reconnect(0),
634  m_error(-1),
635  m_event_thread(NULL)
636 {
637  m_print_mutex= NdbMutex_Create();
638 }
639 
640 /*
641  * Destructor
642  */
643 CommandInterpreter::~CommandInterpreter()
644 {
645  disconnect();
646  NdbMutex_Destroy(m_print_mutex);
647 }
648 
649 static bool
650 emptyString(const char* s)
651 {
652  if (s == NULL) {
653  return true;
654  }
655 
656  for (unsigned int i = 0; i < strlen(s); ++i) {
657  if (! isspace(s[i])) {
658  return false;
659  }
660  }
661 
662  return true;
663 }
664 
665 void
666 CommandInterpreter::printError()
667 {
668  if (m_mgmsrv)
669  {
670  ndbout_c("* %5d: %s",
671  ndb_mgm_get_latest_error(m_mgmsrv),
672  ndb_mgm_get_latest_error_msg(m_mgmsrv));
673  ndbout_c("* %s", ndb_mgm_get_latest_error_desc(m_mgmsrv));
674  if (ndb_mgm_check_connection(m_mgmsrv))
675  {
676  disconnect();
677  }
678  }
679 }
680 
681 /*
682  * print log event from mgmsrv to console screen
683  */
684 #define make_uint64(a,b) (((Uint64)(a)) + (((Uint64)(b)) << 32))
685 #define Q64(a) make_uint64(event->EVENT.a ## _lo, event->EVENT.a ## _hi)
686 #define R event->source_nodeid
687 #define Q(a) event->EVENT.a
688 #define QVERSION getMajor(Q(version)), getMinor(Q(version)), getBuild(Q(version))
689 #define NDB_LE_(a) NDB_LE_ ## a
690 static void
691 printLogEvent(struct ndb_logevent* event)
692 {
693  switch (event->type) {
697 #undef EVENT
698 #define EVENT BackupStarted
700  ndbout_c("Node %u: Backup %u started from node %d",
701  R, Q(backup_id), Q(starting_node));
702  break;
703 #undef EVENT
704 #define EVENT BackupStatus
705  case NDB_LE_BackupStatus:
706  if (Q(starting_node))
707  ndbout_c("Node %u: Local backup status: backup %u started from node %u\n"
708  " #Records: %llu #LogRecords: %llu\n"
709  " Data: %llu bytes Log: %llu bytes", R,
710  Q(backup_id),
711  Q(starting_node),
712  Q64(n_records),
713  Q64(n_log_records),
714  Q64(n_bytes),
715  Q64(n_log_bytes));
716  else
717  ndbout_c("Node %u: Backup not started", R);
718  break;
719 #undef EVENT
720 #define EVENT BackupFailedToStart
722  ndbout_c("Node %u: Backup request from %d failed to start. Error: %d",
723  R, Q(starting_node), Q(error));
724  break;
725 #undef EVENT
726 #define EVENT BackupCompleted
728  ndbout_c("Node %u: Backup %u started from node %u completed\n"
729  " StartGCP: %u StopGCP: %u\n"
730  " #Records: %u #LogRecords: %u\n"
731  " Data: %u bytes Log: %u bytes", R,
732  Q(backup_id), Q(starting_node),
733  Q(start_gci), Q(stop_gci),
734  Q(n_records), Q(n_log_records),
735  Q(n_bytes), Q(n_log_bytes));
736  break;
737 #undef EVENT
738 #define EVENT BackupAborted
740  ndbout_c("Node %u: Backup %u started from %d has been aborted. Error: %d",
741  R, Q(backup_id), Q(starting_node), Q(error));
742  break;
746 #undef EVENT
747 #define EVENT NDBStartStarted
749  ndbout_c("Node %u: Start initiated (version %d.%d.%d)",
750  R, QVERSION);
751  break;
752 #undef EVENT
753 #define EVENT NDBStartCompleted
755  ndbout_c("Node %u: Started (version %d.%d.%d)",
756  R, QVERSION);
757  break;
758 #undef EVENT
759 #define EVENT NDBStopStarted
761  ndbout_c("Node %u: %s shutdown initiated", R,
762  (Q(stoptype) == 1 ? "Cluster" : "Node"));
763  break;
764 #undef EVENT
765 #define EVENT NDBStopCompleted
767  {
768  BaseString action_str("");
769  BaseString signum_str("");
770  getRestartAction(Q(action), action_str);
771  if (Q(signum))
772  signum_str.appfmt(" Initiated by signal %d.",
773  Q(signum));
774  ndbout_c("Node %u: Node shutdown completed%s.%s",
775  R, action_str.c_str(), signum_str.c_str());
776  }
777  break;
778 #undef EVENT
779 #define EVENT NDBStopForced
781  {
782  BaseString action_str("");
783  BaseString reason_str("");
784  BaseString sphase_str("");
785  int signum = Q(signum);
786  int error = Q(error);
787  int sphase = Q(sphase);
788  int extra = Q(extra);
789  getRestartAction(Q(action), action_str);
790  if (signum)
791  reason_str.appfmt(" Initiated by signal %d.", signum);
792  if (error)
793  {
794  ndbd_exit_classification cl;
795  ndbd_exit_status st;
796  const char *msg = ndbd_exit_message(error, &cl);
797  const char *cl_msg = ndbd_exit_classification_message(cl, &st);
798  const char *st_msg = ndbd_exit_status_message(st);
799  reason_str.appfmt(" Caused by error %d: \'%s(%s). %s\'.",
800  error, msg, cl_msg, st_msg);
801  if (extra != 0)
802  reason_str.appfmt(" (extra info %d)", extra);
803  }
804  if (sphase < 255)
805  sphase_str.appfmt(" Occured during startphase %u.", sphase);
806  ndbout_c("Node %u: Forced node shutdown completed%s.%s%s",
807  R, action_str.c_str(), sphase_str.c_str(),
808  reason_str.c_str());
809  }
810  break;
811 #undef EVENT
812 #define EVENT StopAborted
814  ndbout_c("Node %u: Node shutdown aborted", R);
815  break;
819 #undef EVENT
820 #define EVENT MemoryUsage
821  case NDB_LE_MemoryUsage:
822  {
823 
824  if (Q(gth) == 0)
825  {
826  // Only print MemoryUsage report for increased/decreased
827  break;
828  }
829 
830  const int percent = Q(pages_total) ? (Q(pages_used)*100)/Q(pages_total) : 0;
831  ndbout_c("Node %u: %s usage %s %d%s(%d %dK pages of total %d)", R,
832  (Q(block) == DBACC ? "Index" : (Q(block) == DBTUP ?"Data":"<unknown>")),
833  (Q(gth) > 0 ? "increased to" : "decreased to"),
834  percent, "%",
835  Q(pages_used), Q(page_size_kb)/1024, Q(pages_total));
836  break;
837  }
841  default:
842  break;
843  }
844 }
845 
846 //*****************************************************************************
847 //*****************************************************************************
848 
850  NdbMgmHandle *m;
851  NdbMutex **p;
852 };
853 
854 static int do_event_thread = 0;
855 
856 static void*
857 event_thread_run(void* p)
858 {
859  DBUG_ENTER("event_thread_run");
860 
861  struct event_thread_param param= *(struct event_thread_param*)p;
862  NdbMgmHandle handle= *(param.m);
863  NdbMutex* printmutex= *(param.p);
864 
865  int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
868  0 };
869 
870  NdbLogEventHandle log_handle= NULL;
871  struct ndb_logevent log_event;
872 
873  log_handle= ndb_mgm_create_logevent_handle(handle, filter);
874  if (log_handle)
875  {
876  do_event_thread= 1;
877  do {
878  int res= ndb_logevent_get_next(log_handle, &log_event, 2000);
879  if (res > 0)
880  {
881  Guard g(printmutex);
882  printLogEvent(&log_event);
883  }
884  else if (res < 0)
885  break;
886  } while(do_event_thread);
887  ndb_mgm_destroy_logevent_handle(&log_handle);
888  }
889  else
890  {
891  do_event_thread= 0;
892  }
893 
894  DBUG_RETURN(NULL);
895 }
896 
897 bool
898 CommandInterpreter::connect(bool interactive)
899 {
900  DBUG_ENTER("CommandInterpreter::connect");
901 
902  if(m_connected)
903  DBUG_RETURN(m_connected);
904 
905  m_mgmsrv = ndb_mgm_create_handle();
906  if(m_mgmsrv == NULL) {
907  ndbout_c("Can't create handle to management server.");
908  exit(-1);
909  }
910 
911  if (interactive) {
912  m_mgmsrv2 = ndb_mgm_create_handle();
913  if(m_mgmsrv2 == NULL) {
914  ndbout_c("Can't create 2:nd handle to management server.");
915  exit(-1);
916  }
917  }
918 
919  if (ndb_mgm_set_connectstring(m_mgmsrv, m_constr))
920  {
921  printError();
922  exit(-1);
923  }
924 
925  if(ndb_mgm_connect(m_mgmsrv, m_try_reconnect-1, 5, 1))
926  DBUG_RETURN(m_connected); // couldn't connect, always false
927 
928  const char *host= ndb_mgm_get_connected_host(m_mgmsrv);
929  unsigned port= ndb_mgm_get_connected_port(m_mgmsrv);
930  if (interactive) {
931  BaseString constr;
932  constr.assfmt("%s:%d",host,port);
933  if(!ndb_mgm_set_connectstring(m_mgmsrv2, constr.c_str()) &&
934  !ndb_mgm_connect(m_mgmsrv2, m_try_reconnect-1, 5, 1))
935  {
936  DBUG_PRINT("info",("2:ndb connected to Management Server ok at: %s:%d",
937  host, port));
938  assert(m_event_thread == NULL);
939  assert(do_event_thread == 0);
940  do_event_thread= 0;
941  struct event_thread_param p;
942  p.m= &m_mgmsrv2;
943  p.p= &m_print_mutex;
944  m_event_thread = NdbThread_Create(event_thread_run,
945  (void**)&p,
946  0, // default stack size
947  "CommandInterpreted_event_thread",
948  NDB_THREAD_PRIO_LOW);
949  if (m_event_thread)
950  {
951  DBUG_PRINT("info",("Thread created ok, waiting for started..."));
952  int iter= 1000; // try for 30 seconds
953  while(do_event_thread == 0 &&
954  iter-- > 0)
955  NdbSleep_MilliSleep(30);
956  }
957  if (m_event_thread == NULL ||
958  do_event_thread == 0 ||
959  do_event_thread == -1)
960  {
961  DBUG_PRINT("info",("Warning, event thread startup failed, "
962  "degraded printouts as result, errno=%d",
963  errno));
964  printf("Warning, event thread startup failed, "
965  "degraded printouts as result, errno=%d\n", errno);
966  do_event_thread= 0;
967  if (m_event_thread)
968  {
969  void *res;
970  NdbThread_WaitFor(m_event_thread, &res);
971  NdbThread_Destroy(&m_event_thread);
972  }
973  ndb_mgm_disconnect(m_mgmsrv2);
974  }
975  }
976  else
977  {
978  DBUG_PRINT("warning",
979  ("Could not do 2:nd connect to mgmtserver for event listening"));
980  DBUG_PRINT("info", ("code: %d, msg: %s",
981  ndb_mgm_get_latest_error(m_mgmsrv2),
982  ndb_mgm_get_latest_error_msg(m_mgmsrv2)));
983  printf("Warning, event connect failed, degraded printouts as result\n");
984  printf("code: %d, msg: %s\n",
985  ndb_mgm_get_latest_error(m_mgmsrv2),
986  ndb_mgm_get_latest_error_msg(m_mgmsrv2));
987  }
988  }
989  m_connected= true;
990  DBUG_PRINT("info",("Connected to Management Server at: %s:%d", host, port));
991  if (m_verbose)
992  {
993  printf("Connected to Management Server at: %s:%d\n",
994  host, port);
995  }
996 
997  DBUG_RETURN(m_connected);
998 }
999 
1000 void
1001 CommandInterpreter::disconnect(void)
1002 {
1003  DBUG_ENTER("CommandInterpreter::disconnect");
1004 
1005  if (m_event_thread) {
1006  void *res;
1007  do_event_thread= 0;
1008  NdbThread_WaitFor(m_event_thread, &res);
1009  NdbThread_Destroy(&m_event_thread);
1010  m_event_thread= NULL;
1011  ndb_mgm_destroy_handle(&m_mgmsrv2);
1012  }
1013  if (m_connected)
1014  {
1015  ndb_mgm_destroy_handle(&m_mgmsrv);
1016  m_connected= false;
1017  }
1018  DBUG_VOID_RETURN;
1019 }
1020 
1021 //*****************************************************************************
1022 //*****************************************************************************
1023 
1024 bool
1025 CommandInterpreter::execute(const char *_line, int try_reconnect,
1026  bool interactive, int *error)
1027 {
1028  if (try_reconnect >= 0)
1029  m_try_reconnect = try_reconnect;
1030  bool result= execute_impl(_line, interactive);
1031  if (error)
1032  *error= m_error;
1033 
1034  return result;
1035 }
1036 
1037 static void
1038 invalid_command(const char *cmd)
1039 {
1040  ndbout << "Invalid command: " << cmd << endl;
1041  ndbout << "Type HELP for help." << endl << endl;
1042 }
1043 
1044 
1045 // Utility class for easier checking of args
1046 // given to the commands
1048  ndb_mgm_cluster_state* m_status;
1049 
1050 public:
1051  ClusterInfo() :
1052  m_status(NULL) {};
1053 
1054  ~ClusterInfo() {
1055  if (m_status)
1056  free(m_status);
1057  }
1058 
1059  bool fetch(NdbMgmHandle handle, bool all_nodes = false) {
1060 
1061  const ndb_mgm_node_type types[2] = {
1063  NDB_MGM_NODE_TYPE_UNKNOWN
1064  };
1065  m_status = ndb_mgm_get_status2(handle,
1066  !all_nodes ? types : 0);
1067  if (m_status == NULL)
1068  {
1069  ndbout_c("ERROR: couldn't fetch cluster status");
1070  return false;
1071  }
1072  return true;
1073  }
1074 
1075  bool is_valid_ndb_nodeid(int nodeid) const {
1076  // Check valid NDB nodeid
1077  if (nodeid < 1 || nodeid >= MAX_NDB_NODES)
1078  {
1079  ndbout_c("ERROR: illegal nodeid %d!", nodeid);
1080  return false;
1081  }
1082  return true;
1083  }
1084 
1085  bool is_ndb_node(int nodeid) const {
1086 
1087  if (!is_valid_ndb_nodeid(nodeid))
1088  return false;
1089 
1090  bool found = false;
1091  for (int i = 0; i < m_status->no_of_nodes; i++)
1092  {
1093  if (m_status->node_states[i].node_id == nodeid &&
1095  found = true;
1096  }
1097 
1098  if (!found)
1099  ndbout_c("ERROR: node %d is not a NDB node!", nodeid);
1100 
1101  return found;
1102  }
1103 };
1104 
1105 
1106 
1107 static void
1108 split_args(const char* line, Vector<BaseString>& args)
1109 {
1110  // Split the command line on space
1111  BaseString tmp(line);
1112  tmp.split(args);
1113 
1114  // Remove any empty args which come from double
1115  // spaces in the command line
1116  // ie. "hello<space><space>world" becomes ("hello, "", "world")
1117  //
1118  for (unsigned i= 0; i < args.size(); i++)
1119  if (args[i].length() == 0)
1120  args.erase(i--);
1121 }
1122 
1123 
1124 bool
1125 CommandInterpreter::execute_impl(const char *_line, bool interactive)
1126 {
1127  DBUG_ENTER("CommandInterpreter::execute_impl");
1128  DBUG_PRINT("enter",("line='%s'", _line));
1129  m_error= 0;
1130 
1131  if(_line == NULL) {
1132  ndbout_c("ERROR: Internal error at %s:%d.", __FILE__, __LINE__);
1133  m_error = -1;
1134  DBUG_RETURN(false); // Terminate gracefully
1135  }
1136 
1137  char* line = strdup(_line);
1138  if (line == NULL)
1139  {
1140  ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1141  m_error = -1;
1142  DBUG_RETURN(false); // Terminate gracefully
1143  }
1144  NdbAutoPtr<char> ap(line);
1145 
1146  int do_continue;
1147  do {
1148  do_continue= 0;
1149  BaseString::trim(line," \t");
1150  if (line[0] == 0 ||
1151  line[0] == '#')
1152  {
1153  DBUG_RETURN(true);
1154  }
1155  // for mysql client compatability remove trailing ';'
1156  {
1157  unsigned last= strlen(line)-1;
1158  if (line[last] == ';')
1159  {
1160  line[last]= 0;
1161  do_continue= 1;
1162  }
1163  }
1164  } while (do_continue);
1165 
1166  // if there is anything in the line proceed
1167  Vector<BaseString> command_list;
1168  split_args(line, command_list);
1169 
1170  char* firstToken = strtok(line, " ");
1171  char* allAfterFirstToken = strtok(NULL, "");
1172 
1173  if (strcasecmp(firstToken, "HELP") == 0 ||
1174  strcasecmp(firstToken, "?") == 0) {
1175  m_error = executeHelp(allAfterFirstToken);
1176  DBUG_RETURN(true);
1177  }
1178  else if (strcasecmp(firstToken, "CONNECT") == 0) {
1179  m_error = executeConnect(allAfterFirstToken, interactive);
1180  DBUG_RETURN(true);
1181  }
1182  else if (strcasecmp(firstToken, "SLEEP") == 0) {
1183  if (allAfterFirstToken)
1184  NdbSleep_SecSleep(atoi(allAfterFirstToken));
1185  DBUG_RETURN(true);
1186  }
1187  else if((strcasecmp(firstToken, "QUIT") == 0 ||
1188  strcasecmp(firstToken, "EXIT") == 0 ||
1189  strcasecmp(firstToken, "BYE") == 0) &&
1190  allAfterFirstToken == NULL){
1191  DBUG_RETURN(false);
1192  }
1193 
1194  if (!connect(interactive)){
1195  m_error = -1;
1196  DBUG_RETURN(true);
1197  }
1198 
1199  if (ndb_mgm_check_connection(m_mgmsrv))
1200  {
1201  disconnect();
1202  connect(interactive);
1203  }
1204 
1205  if (strcasecmp(firstToken, "SHOW") == 0) {
1206  Guard g(m_print_mutex);
1207  m_error = executeShow(allAfterFirstToken);
1208  DBUG_RETURN(true);
1209  }
1210  else if (strcasecmp(firstToken, "SHUTDOWN") == 0) {
1211  m_error= executeShutdown(allAfterFirstToken);
1212  DBUG_RETURN(true);
1213  }
1214  else if (strcasecmp(firstToken, "CLUSTERLOG") == 0){
1215  executeClusterLog(allAfterFirstToken);
1216  DBUG_RETURN(true);
1217  }
1218  else if(strcasecmp(firstToken, "START") == 0 &&
1219  allAfterFirstToken != NULL &&
1220  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1221  m_error= executeStartBackup(allAfterFirstToken, interactive);
1222  DBUG_RETURN(true);
1223  }
1224  else if(strcasecmp(firstToken, "ABORT") == 0 &&
1225  allAfterFirstToken != NULL &&
1226  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1227  m_error = executeAbortBackup(allAfterFirstToken);
1228  DBUG_RETURN(true);
1229  }
1230  else if (strcasecmp(firstToken, "PURGE") == 0) {
1231  m_error = executePurge(allAfterFirstToken);
1232  DBUG_RETURN(true);
1233  }
1234  else if(strcasecmp(firstToken, "ENTER") == 0 &&
1235  allAfterFirstToken != NULL &&
1236  allAfterFirstToken != NULL &&
1237  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1238  sizeof("SINGLE USER MODE") - 1) == 0){
1239  m_error = executeEnterSingleUser(allAfterFirstToken);
1240  DBUG_RETURN(true);
1241  }
1242  else if(strcasecmp(firstToken, "EXIT") == 0 &&
1243  allAfterFirstToken != NULL &&
1244  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1245  sizeof("SINGLE USER MODE") - 1) == 0){
1246  m_error = executeExitSingleUser(allAfterFirstToken);
1247  DBUG_RETURN(true);
1248  }
1249  else if(strcasecmp(firstToken, "CREATE") == 0 &&
1250  allAfterFirstToken != NULL &&
1251  strncasecmp(allAfterFirstToken, "NODEGROUP",
1252  sizeof("NODEGROUP") - 1) == 0){
1253  m_error = executeCreateNodeGroup(allAfterFirstToken);
1254  DBUG_RETURN(true);
1255  }
1256  else if(strcasecmp(firstToken, "DROP") == 0 &&
1257  allAfterFirstToken != NULL &&
1258  strncasecmp(allAfterFirstToken, "NODEGROUP",
1259  sizeof("NODEGROUP") - 1) == 0){
1260  m_error = executeDropNodeGroup(allAfterFirstToken);
1261  DBUG_RETURN(true);
1262  }
1263  else if (strcasecmp(firstToken, "ALL") == 0) {
1264  m_error = analyseAfterFirstToken(-1, allAfterFirstToken);
1265  } else {
1269  int node_ids[MAX_NODES];
1270  unsigned pos;
1271  for (pos= 0; pos < command_list.size(); pos++)
1272  {
1273  int node_id;
1274  if (convert(command_list[pos].c_str(), node_id))
1275  {
1276  if (node_id <= 0 || node_id > MAX_NODES) {
1277  ndbout << "Invalid node ID: " << command_list[pos].c_str()
1278  << "." << endl;
1279  DBUG_RETURN(true);
1280  }
1281  node_ids[pos]= node_id;
1282  continue;
1283  }
1284  break;
1285  }
1286  int no_of_nodes= pos;
1287  if (no_of_nodes == 0)
1288  {
1289  /* No digit found */
1290  invalid_command(_line);
1291  m_error = -1;
1292  DBUG_RETURN(true);
1293  }
1294  if (pos == command_list.size())
1295  {
1296  /* No command found */
1297  invalid_command(_line);
1298  m_error = -1;
1299  DBUG_RETURN(true);
1300  }
1301  if (no_of_nodes == 1)
1302  {
1303  m_error = analyseAfterFirstToken(node_ids[0], allAfterFirstToken);
1304  DBUG_RETURN(true);
1305  }
1306  m_error = executeCommand(command_list, pos, node_ids, no_of_nodes);
1307  DBUG_RETURN(true);
1308  }
1309  DBUG_RETURN(true);
1310 }
1311 
1312 
1316 static const CommandInterpreter::CommandFunctionPair commands[] = {
1317  { "START", &CommandInterpreter::executeStart }
1318  ,{ "RESTART", &CommandInterpreter::executeRestart }
1319  ,{ "STOP", &CommandInterpreter::executeStop }
1320  ,{ "STATUS", &CommandInterpreter::executeStatus }
1321  ,{ "LOGLEVEL", &CommandInterpreter::executeLogLevel }
1322  ,{ "CLUSTERLOG", &CommandInterpreter::executeEventReporting }
1323 #ifdef ERROR_INSERT
1324  ,{ "ERROR", &CommandInterpreter::executeError }
1325 #endif
1326  ,{ "LOG", &CommandInterpreter::executeLog }
1327  ,{ "TESTON", &CommandInterpreter::executeTestOn }
1328  ,{ "TESTOFF", &CommandInterpreter::executeTestOff }
1329  ,{ "DUMP", &CommandInterpreter::executeDumpState }
1330  ,{ "REPORT", &CommandInterpreter::executeReport }
1331 };
1332 
1333 
1334 //*****************************************************************************
1335 //*****************************************************************************
1336 int
1337 CommandInterpreter::analyseAfterFirstToken(int processId,
1338  char* allAfterFirstToken) {
1339 
1340  int retval = 0;
1341  if (emptyString(allAfterFirstToken)) {
1342  ndbout << "Expected a command after "
1343  << ((processId == -1) ? "ALL." : "node ID.") << endl;
1344  return -1;
1345  }
1346 
1347  char* secondToken = strtok(allAfterFirstToken, " ");
1348  char* allAfterSecondToken = strtok(NULL, "\0");
1349 
1350  const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
1351  ExecuteFunction fun = 0;
1352  const char * command = 0;
1353  for(int i = 0; i<tmpSize; i++){
1354  if(strcasecmp(secondToken, commands[i].command) == 0){
1355  fun = commands[i].executeFunction;
1356  command = commands[i].command;
1357  break;
1358  }
1359  }
1360 
1361  if(fun == 0){
1362  invalid_command(secondToken);
1363  return -1;
1364  }
1365 
1366  if(processId == -1){
1367  retval = executeForAll(command, fun, allAfterSecondToken);
1368  } else {
1369  retval = (this->*fun)(processId, allAfterSecondToken, false);
1370  }
1371  ndbout << endl;
1372  return retval;
1373 }
1374 
1375 int
1376 CommandInterpreter::executeCommand(Vector<BaseString> &command_list,
1377  unsigned command_pos,
1378  int *node_ids, int no_of_nodes)
1379 {
1380  const char *cmd= command_list[command_pos].c_str();
1381  int retval = 0;
1382 
1383  if (strcasecmp("STOP", cmd) == 0)
1384  {
1385  retval = executeStop(command_list, command_pos+1, node_ids, no_of_nodes);
1386  return retval;
1387  }
1388  if (strcasecmp("RESTART", cmd) == 0)
1389  {
1390  retval = executeRestart(command_list, command_pos+1, node_ids, no_of_nodes);
1391  return retval;
1392  }
1393  if (strcasecmp("START", cmd) == 0)
1394  {
1395  retval = executeStart(command_list, command_pos+1, node_ids, no_of_nodes);
1396  return retval;
1397  }
1398  ndbout_c("Invalid command: '%s' after multi node id list. "
1399  "Expected STOP, START, or RESTART.", cmd);
1400  return -1;
1401 }
1402 
1413 static
1414 int
1415 get_next_nodeid(struct ndb_mgm_cluster_state *cl,
1416  int *node_id,
1417  enum ndb_mgm_node_type type)
1418 {
1419  int i;
1420 
1421  if(cl == NULL)
1422  return 0;
1423 
1424  i=0;
1425  while((i < cl->no_of_nodes)) {
1426  if((*node_id < cl->node_states[i].node_id) &&
1427  (cl->node_states[i].node_type == type)) {
1428 
1429  if(i >= cl->no_of_nodes)
1430  return 0;
1431 
1432  *node_id = cl->node_states[i].node_id;
1433  return 1;
1434  }
1435  i++;
1436  }
1437 
1438  return 0;
1439 }
1440 
1441 int
1442 CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun,
1443  const char * allAfterSecondToken)
1444 {
1445  int nodeId = 0;
1446  int retval = 0;
1447 
1448  if(strcasecmp(cmd, "STOP") == 0) {
1449  ndbout_c("Executing STOP on all nodes.");
1450  retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1451  } else if(strcasecmp(cmd, "RESTART") == 0) {
1452  retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1453  } else if (strcasecmp(cmd, "STATUS") == 0) {
1454  (this->*fun)(nodeId, allAfterSecondToken, true);
1455  } else if (strcasecmp(cmd, "REPORT") == 0) {
1456  Guard g(m_print_mutex);
1457  retval = executeReport(nodeId, allAfterSecondToken, true);
1458  } else {
1459  Guard g(m_print_mutex);
1460  struct ndb_mgm_cluster_state *cl= ndb_mgm_get_status(m_mgmsrv);
1461  if(cl == 0){
1462  ndbout_c("Unable get status from management server");
1463  printError();
1464  return -1;
1465  }
1466  NdbAutoPtr<char> ap1((char*)cl);
1467  while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB))
1468  retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1469  }
1470  return retval;
1471 }
1472 
1473 //*****************************************************************************
1474 //*****************************************************************************
1475 bool
1476 CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
1477  Vector<BaseString>& blocks)
1478 {
1479  // Parse: [BLOCK = {ALL|<blockName>+}]
1480 
1481  if (emptyString(allAfterLog)) {
1482  return true;
1483  }
1484 
1485  // Copy allAfterLog since strtok will modify it
1486  char* newAllAfterLog = strdup(allAfterLog);
1487  if (newAllAfterLog == NULL)
1488  {
1489  ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1490  return false; // Error parsing
1491  }
1492 
1493  NdbAutoPtr<char> ap1(newAllAfterLog);
1494  char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
1495  for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
1496  firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
1497  }
1498 
1499  if (strcasecmp(firstTokenAfterLog, "BLOCK") != 0) {
1500  ndbout << "Unexpected value: " << firstTokenAfterLog
1501  << ". Expected BLOCK." << endl;
1502  return false;
1503  }
1504 
1505  char* allAfterFirstToken = strtok(NULL, "\0");
1506  if (emptyString(allAfterFirstToken)) {
1507  ndbout << "Expected =." << endl;
1508  return false;
1509  }
1510 
1511  char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
1512  if (strcasecmp(secondTokenAfterLog, "=") != 0) {
1513  ndbout << "Unexpected value: " << secondTokenAfterLog
1514  << ". Expected =." << endl;
1515  return false;
1516  }
1517 
1518  char* blockName = strtok(NULL, " ");
1519  bool all = false;
1520  if (blockName != NULL && (strcasecmp(blockName, "ALL") == 0)) {
1521  all = true;
1522  }
1523  while (blockName != NULL) {
1524  blocks.push_back(blockName);
1525  blockName = strtok(NULL, " ");
1526  }
1527 
1528  if (blocks.size() == 0) {
1529  ndbout << "No block specified." << endl;
1530  return false;
1531  }
1532  if (blocks.size() > 1 && all) {
1533  // More than "ALL" specified
1534  ndbout << "Nothing expected after ALL." << endl;
1535  return false;
1536  }
1537 
1538  return true;
1539 }
1540 
1541 
1542 
1543 /*****************************************************************************
1544  * HELP
1545  *****************************************************************************/
1546 int
1547 CommandInterpreter::executeHelp(char* parameters)
1548 {
1549  if (emptyString(parameters)) {
1550  ndbout << helpText;
1551 
1552  ndbout << endl
1553  << "<severity> = "
1554  << "ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG"
1555  << endl;
1556 
1557  ndbout << "<category> = ";
1558  for(int i = CFG_MIN_LOGLEVEL; i <= CFG_MAX_LOGLEVEL; i++){
1559  const char *str= ndb_mgm_get_event_category_string((ndb_mgm_event_category)i);
1560  if (str) {
1561  if (i != CFG_MIN_LOGLEVEL)
1562  ndbout << " | ";
1563  ndbout << str;
1564  }
1565  }
1566  ndbout << endl;
1567 
1568  ndbout << "<level> = " << "0 - 15" << endl;
1569  ndbout << "<id> = " << "ALL | Any database node id" << endl;
1570  ndbout << endl;
1571  ndbout << "For detailed help on COMMAND, use HELP COMMAND." << endl;
1572  } else {
1573  int i = 0;
1574  for (i = 0; help_items[i].cmd != NULL; i++)
1575  {
1576  if (strcasecmp(parameters, help_items[i].cmd) == 0)
1577  {
1578  if (help_items[i].help)
1579  ndbout << help_items[i].help;
1580  if (help_items[i].help_fn)
1581  (*help_items[i].help_fn)();
1582  break;
1583  }
1584  }
1585  if (help_items[i].cmd == NULL){
1586  ndbout << "No help for " << parameters << " available" << endl;
1587  return -1;
1588  }
1589  }
1590  return 0;
1591 }
1592 
1593 
1594 /*****************************************************************************
1595  * SHUTDOWN
1596  *****************************************************************************/
1597 
1598 int
1599 CommandInterpreter::executeShutdown(char* parameters)
1600 {
1601  ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1602  if(state == NULL) {
1603  ndbout_c("Could not get status");
1604  printError();
1605  return 1;
1606  }
1607  NdbAutoPtr<char> ap1((char*)state);
1608 
1609  int result = 0;
1610  int need_disconnect;
1611  result = ndb_mgm_stop3(m_mgmsrv, -1, 0, 0, &need_disconnect);
1612  if (result < 0) {
1613  ndbout << "Shutdown of NDB Cluster node(s) failed." << endl;
1614  printError();
1615  return result;
1616  }
1617 
1618  ndbout << result << " NDB Cluster node(s) have shutdown." << endl;
1619 
1620  if(need_disconnect) {
1621  ndbout << "Disconnecting to allow management server to shutdown."
1622  << endl;
1623  disconnect();
1624  }
1625  return 0;
1626 }
1627 
1628 /*****************************************************************************
1629  * SHOW
1630  *****************************************************************************/
1631 
1632 
1633 static
1634 const char *status_string(ndb_mgm_node_status status)
1635 {
1636  switch(status){
1638  return "not connected";
1640  return "not started";
1642  return "starting";
1644  return "started";
1646  return "shutting down";
1648  return "restarting";
1650  return "single user mode";
1651  default:
1652  return "unknown state";
1653  }
1654 }
1655 
1656 static void
1658  const char *proc_name, int no_proc, ndb_mgm_node_type type,
1659  int master_id)
1660 {
1661  int i;
1662  ndbout << "[" << proc_name
1663  << "(" << ndb_mgm_get_node_type_string(type) << ")]\t"
1664  << no_proc << " node(s)" << endl;
1665  for(i=0; i < state->no_of_nodes; i++) {
1666  struct ndb_mgm_node_state *node_state= &(state->node_states[i]);
1667  if(node_state->node_type == type) {
1668  int node_id= node_state->node_id;
1669  ndbout << "id=" << node_id;
1670  if(node_state->version != 0) {
1671  const char *hostname= node_state->connect_address;
1672  if (hostname == 0
1673  || strlen(hostname) == 0
1674  || strcasecmp(hostname,"0.0.0.0") == 0)
1675  ndbout << " ";
1676  else
1677  ndbout << "\t@" << hostname;
1678 
1679  char tmp[100];
1680  ndbout << " (" << ndbGetVersionString(node_state->version,
1681  node_state->mysql_version,
1682  0,
1683  tmp, sizeof(tmp));
1684  if (type == NDB_MGM_NODE_TYPE_NDB) {
1685  if (node_state->node_status != NDB_MGM_NODE_STATUS_STARTED) {
1686  ndbout << ", " << status_string(node_state->node_status);
1687  }
1688  if (node_state->node_group >= 0 && node_state->node_group != (int)RNIL) {
1689  ndbout << ", Nodegroup: " << node_state->node_group;
1690  }
1691  else if (node_state->node_group == (int)RNIL)
1692  {
1693  ndbout << ", no nodegroup";
1694  }
1695  if (node_state->node_group >= 0 || node_state->node_group == (int)RNIL)
1696  if (master_id && node_state->dynamic_id == master_id)
1697  ndbout << ", Master";
1698  }
1699  ndbout << ")" << endl;
1700  } else {
1701  ndb_mgm_first(it);
1702  if(ndb_mgm_find(it, CFG_NODE_ID, node_id) == 0){
1703  const char *config_hostname= 0;
1704  ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &config_hostname);
1705  if (config_hostname == 0 || config_hostname[0] == 0)
1706  config_hostname= "any host";
1707  ndbout_c(" (not connected, accepting connect from %s)",
1708  config_hostname);
1709  }
1710  else
1711  {
1712  ndbout_c("Unable to find node with id: %d", node_id);
1713  }
1714  }
1715  }
1716  }
1717  ndbout << endl;
1718 }
1719 
1720 int
1721 CommandInterpreter::executePurge(char* parameters)
1722 {
1723  int command_ok= 0;
1724  do {
1725  if (emptyString(parameters))
1726  break;
1727  char* firstToken = strtok(parameters, " ");
1728  char* nextToken = strtok(NULL, " \0");
1729  if (strcasecmp(firstToken,"STALE") == 0 &&
1730  nextToken &&
1731  strcasecmp(nextToken, "SESSIONS") == 0) {
1732  command_ok= 1;
1733  break;
1734  }
1735  } while(0);
1736 
1737  if (!command_ok) {
1738  ndbout_c("Unexpected command, expected: PURGE STALE SESSIONS");
1739  return -1;
1740  }
1741 
1742  char *str;
1743 
1744  if (ndb_mgm_purge_stale_sessions(m_mgmsrv, &str)) {
1745  ndbout_c("Command failed");
1746  return -1;
1747  }
1748  if (str) {
1749  ndbout_c("Purged sessions with node id's: %s", str);
1750  free(str);
1751  }
1752  else
1753  {
1754  ndbout_c("No sessions purged");
1755  }
1756  return 0;
1757 }
1758 
1759 int
1760 CommandInterpreter::executeShow(char* parameters)
1761 {
1762  int i;
1763  if (emptyString(parameters)) {
1764  ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1765  if(state == NULL) {
1766  ndbout_c("Could not get status");
1767  printError();
1768  return -1;
1769  }
1770  NdbAutoPtr<char> ap1((char*)state);
1771 
1772  ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_mgmsrv,0);
1773  if(conf == 0){
1774  ndbout_c("Could not get configuration");
1775  printError();
1776  return -1;
1777  }
1778 
1780  it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE);
1781 
1782  if(it == 0){
1783  ndbout_c("Unable to create config iterator");
1784  ndb_mgm_destroy_configuration(conf);
1785  return -1;
1786  }
1788 
1789  int
1790  master_id= 0,
1791  ndb_nodes= 0,
1792  api_nodes= 0,
1793  mgm_nodes= 0;
1794 
1795  for(i=0; i < state->no_of_nodes; i++) {
1796  if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB &&
1797  state->node_states[i].version != 0){
1798  master_id= state->node_states[i].dynamic_id;
1799  break;
1800  }
1801  }
1802 
1803  for(i=0; i < state->no_of_nodes; i++) {
1804  switch(state->node_states[i].node_type) {
1805  case NDB_MGM_NODE_TYPE_API:
1806  api_nodes++;
1807  break;
1808  case NDB_MGM_NODE_TYPE_NDB:
1809  if (state->node_states[i].dynamic_id &&
1810  state->node_states[i].dynamic_id < master_id)
1811  master_id= state->node_states[i].dynamic_id;
1812  ndb_nodes++;
1813  break;
1814  case NDB_MGM_NODE_TYPE_MGM:
1815  mgm_nodes++;
1816  break;
1817  case NDB_MGM_NODE_TYPE_UNKNOWN:
1818  ndbout << "Error: Unknown Node Type" << endl;
1819  return -1;
1820  case NDB_MGM_NODE_TYPE_MAX:
1821  break; /* purify: deadcode */
1822  }
1823  }
1824 
1825  ndbout << "Cluster Configuration" << endl
1826  << "---------------------" << endl;
1827  print_nodes(state, it, "ndbd", ndb_nodes, NDB_MGM_NODE_TYPE_NDB, master_id);
1828  print_nodes(state, it, "ndb_mgmd", mgm_nodes, NDB_MGM_NODE_TYPE_MGM, 0);
1829  print_nodes(state, it, "mysqld", api_nodes, NDB_MGM_NODE_TYPE_API, 0);
1830  ndb_mgm_destroy_configuration(conf);
1831  return 0;
1832  } else {
1833  ndbout << "Invalid argument: '" << parameters << "'" << endl;
1834  return -1;
1835  }
1836  return 0;
1837 }
1838 
1839 int
1840 CommandInterpreter::executeConnect(char* parameters, bool interactive)
1841 {
1842  BaseString *basestring = NULL;
1843 
1844  disconnect();
1845  if (!emptyString(parameters)) {
1846  basestring= new BaseString(parameters);
1847  m_constr= basestring->trim().c_str();
1848  }
1849  if ( connect(interactive) == false ){
1850  return -1;
1851  }
1852  if (basestring != NULL)
1853  delete basestring;
1854 
1855  return 0;
1856 }
1857 
1858 //*****************************************************************************
1859 //*****************************************************************************
1860 void
1861 CommandInterpreter::executeClusterLog(char* parameters)
1862 {
1863  DBUG_ENTER("CommandInterpreter::executeClusterLog");
1864  int i;
1865  if (emptyString(parameters))
1866  {
1867  ndbout_c("ERROR: Missing argument(s).");
1868  m_error = -1;
1869  DBUG_VOID_RETURN;
1870  }
1871 
1873 
1874  char * tmpString = strdup(parameters);
1875  if (tmpString == NULL)
1876  {
1877  ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1878  m_error = -1;
1879  DBUG_VOID_RETURN;
1880  }
1881 
1882  NdbAutoPtr<char> ap1(tmpString);
1883  char * tmpPtr = 0;
1884  char * item = strtok_r(tmpString, " ", &tmpPtr);
1885  int enable;
1886 
1896  if(enabled == NULL) {
1897  ndbout << "Couldn't get status" << endl;
1898  printError();
1899  m_error = -1;
1900  DBUG_VOID_RETURN;
1901  }
1902 
1903  /********************
1904  * CLUSTERLOG INFO
1905  ********************/
1906  if (strcasecmp(item, "INFO") == 0) {
1907  DBUG_PRINT("info",("INFO"));
1908  if(enabled[0].value == 0)
1909  {
1910  ndbout << "Cluster logging is disabled." << endl;
1911  m_error = 0;
1912  DBUG_VOID_RETURN;
1913  }
1914 #if 0
1915  for(i = 0; i<DB_MGM_EVENT_SEVERITY_ALL;i++)
1916  printf("enabled[%d] = %d\n", i, enabled[i].value);
1917 #endif
1918  ndbout << "Severities enabled: ";
1919  for(i = 1; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
1920  const char *str= ndb_mgm_get_event_severity_string(enabled[i].category);
1921  if (str == 0)
1922  {
1923  DBUG_ASSERT(false);
1924  continue;
1925  }
1926  if(enabled[i].value)
1927  ndbout << BaseString(str).ndb_toupper() << " ";
1928  }
1929  ndbout << endl;
1930  m_error = 0;
1931  DBUG_VOID_RETURN;
1932 
1933  }
1934  else if (strcasecmp(item, "FILTER") == 0 ||
1935  strcasecmp(item, "TOGGLE") == 0)
1936  {
1937  DBUG_PRINT("info",("TOGGLE"));
1938  enable= -1;
1939  }
1940  else if (strcasecmp(item, "OFF") == 0)
1941  {
1942  DBUG_PRINT("info",("OFF"));
1943  enable= 0;
1944  } else if (strcasecmp(item, "ON") == 0) {
1945  DBUG_PRINT("info",("ON"));
1946  enable= 1;
1947  } else {
1948  ndbout << "Invalid argument." << endl;
1949  m_error = -1;
1950  DBUG_VOID_RETURN;
1951  }
1952 
1953  int res_enable;
1954  item = strtok_r(NULL, " ", &tmpPtr);
1955  if (item == NULL) {
1956  res_enable=
1959  enable, NULL);
1960  if (res_enable < 0)
1961  {
1962  ndbout << "Couldn't set filter" << endl;
1963  printError();
1964  m_error = -1;
1965  DBUG_VOID_RETURN;
1966  }
1967  ndbout << "Cluster logging is " << (res_enable ? "enabled.":"disabled") << endl;
1968  m_error = 0;
1969  DBUG_VOID_RETURN;
1970  }
1971 
1972  do {
1973  severity= NDB_MGM_ILLEGAL_EVENT_SEVERITY;
1974  if (strcasecmp(item, "ALL") == 0) {
1975  severity = NDB_MGM_EVENT_SEVERITY_ALL;
1976  } else if (strcasecmp(item, "ALERT") == 0) {
1977  severity = NDB_MGM_EVENT_SEVERITY_ALERT;
1978  } else if (strcasecmp(item, "CRITICAL") == 0) {
1980  } else if (strcasecmp(item, "ERROR") == 0) {
1981  severity = NDB_MGM_EVENT_SEVERITY_ERROR;
1982  } else if (strcasecmp(item, "WARNING") == 0) {
1983  severity = NDB_MGM_EVENT_SEVERITY_WARNING;
1984  } else if (strcasecmp(item, "INFO") == 0) {
1985  severity = NDB_MGM_EVENT_SEVERITY_INFO;
1986  } else if (strcasecmp(item, "DEBUG") == 0) {
1987  severity = NDB_MGM_EVENT_SEVERITY_DEBUG;
1988  } else if (strcasecmp(item, "OFF") == 0 ||
1989  strcasecmp(item, "ON") == 0) {
1990  if (enable < 0) // only makes sense with toggle
1991  severity = NDB_MGM_EVENT_SEVERITY_ON;
1992  }
1993  if (severity == NDB_MGM_ILLEGAL_EVENT_SEVERITY) {
1994  ndbout << "Invalid severity level: " << item << endl;
1995  m_error = -1;
1996  DBUG_VOID_RETURN;
1997  }
1998 
1999  res_enable= ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv, severity,
2000  enable, NULL);
2001  if (res_enable < 0)
2002  {
2003  ndbout << "Couldn't set filter" << endl;
2004  printError();
2005  m_error = -1;
2006  DBUG_VOID_RETURN;
2007  }
2008  ndbout << BaseString(item).ndb_toupper().c_str() << " " << (res_enable ? "enabled":"disabled") << endl;
2009 
2010  item = strtok_r(NULL, " ", &tmpPtr);
2011  } while(item != NULL);
2012 
2013  m_error = 0;
2014  DBUG_VOID_RETURN;
2015 }
2016 
2017 //*****************************************************************************
2018 //*****************************************************************************
2019 
2020 int
2021 CommandInterpreter::executeStop(int processId, const char *parameters,
2022  bool all)
2023 {
2024  Vector<BaseString> command_list;
2025  if (parameters)
2026  split_args(parameters, command_list);
2027 
2028  int retval;
2029  if (all)
2030  retval = executeStop(command_list, 0, 0, 0);
2031  else
2032  retval = executeStop(command_list, 0, &processId, 1);
2033 
2034  return retval;
2035 }
2036 
2037 int
2038 CommandInterpreter::executeStop(Vector<BaseString> &command_list,
2039  unsigned command_pos,
2040  int *node_ids, int no_of_nodes)
2041 {
2042  int need_disconnect;
2043  int abort= 0;
2044  int retval = 0;
2045  int force = 0;
2046 
2047  for (; command_pos < command_list.size(); command_pos++)
2048  {
2049  const char *item= command_list[command_pos].c_str();
2050  if (strcasecmp(item, "-A") == 0)
2051  {
2052  abort= 1;
2053  continue;
2054  }
2055  if (strcasecmp(item, "-F") == 0)
2056  {
2057  force = 1;
2058  continue;
2059  }
2060  ndbout_c("Invalid option: %s. Expecting -A or -F after STOP",
2061  item);
2062  return -1;
2063  }
2064 
2065  int result= ndb_mgm_stop4(m_mgmsrv, no_of_nodes, node_ids, abort,
2066  force, &need_disconnect);
2067  if (result < 0)
2068  {
2069  ndbout_c("Shutdown failed.");
2070  printError();
2071  retval = -1;
2072  }
2073  else
2074  {
2075  if (node_ids == 0)
2076  ndbout_c("NDB Cluster has shutdown.");
2077  else
2078  {
2079  ndbout << "Node";
2080  for (int i= 0; i < no_of_nodes; i++)
2081  ndbout << " " << node_ids[i];
2082  ndbout_c(" has shutdown.");
2083  }
2084  }
2085 
2086  if(need_disconnect)
2087  {
2088  ndbout << "Disconnecting to allow Management Server to shutdown" << endl;
2089  disconnect();
2090  }
2091 
2092  return retval;
2093 }
2094 
2095 int
2096 CommandInterpreter::executeEnterSingleUser(char* parameters)
2097 {
2098  strtok(parameters, " ");
2099  struct ndb_mgm_reply reply;
2100  char* id = strtok(NULL, " ");
2101  id = strtok(NULL, " ");
2102  id = strtok(NULL, "\0");
2103  int nodeId = -1;
2104  if(id == 0 || sscanf(id, "%d", &nodeId) != 1){
2105  ndbout_c("Invalid arguments: expected <NodeId>");
2106  ndbout_c("Use SHOW to see what API nodes are configured");
2107  return -1;
2108  }
2109  int result = ndb_mgm_enter_single_user(m_mgmsrv, nodeId, &reply);
2110 
2111  if (result != 0) {
2112  ndbout_c("Entering single user mode for node %d failed", nodeId);
2113  printError();
2114  return -1;
2115  } else {
2116  ndbout_c("Single user mode entered");
2117  ndbout_c("Access is granted for API node %d only.", nodeId);
2118  }
2119  return 0;
2120 }
2121 
2122 int
2123 CommandInterpreter::executeExitSingleUser(char* parameters)
2124 {
2125  int result = ndb_mgm_exit_single_user(m_mgmsrv, 0);
2126  if (result != 0) {
2127  ndbout_c("Exiting single user mode failed.");
2128  printError();
2129  return -1;
2130  } else {
2131  ndbout_c("Exiting single user mode in progress.");
2132  ndbout_c("Use ALL STATUS or SHOW to see when single user mode has been exited.");
2133  return 0;
2134  }
2135 }
2136 
2137 int
2138 CommandInterpreter::executeStart(int processId, const char* parameters,
2139  bool all)
2140 {
2141  int result;
2142  int retval = 0;
2143  if(all) {
2144  result = ndb_mgm_start(m_mgmsrv, 0, 0);
2145  } else {
2146  result = ndb_mgm_start(m_mgmsrv, 1, &processId);
2147  }
2148 
2149  if (result <= 0) {
2150  ndbout << "Start failed." << endl;
2151  printError();
2152  retval = -1;
2153  } else
2154  {
2155  if(all)
2156  ndbout_c("NDB Cluster is being started.");
2157  else
2158  ndbout_c("Database node %d is being started.", processId);
2159  }
2160  return retval;
2161 }
2162 
2163 int
2164 CommandInterpreter::executeStart(Vector<BaseString> &command_list,
2165  unsigned command_pos,
2166  int *node_ids, int no_of_nodes)
2167 {
2168  int result;
2169  result= ndb_mgm_start(m_mgmsrv, no_of_nodes, node_ids);
2170 
2171  if (result <= 0) {
2172  ndbout_c("Start failed.");
2173  printError();
2174  return -1;
2175  }
2176  else
2177  {
2178  ndbout << "Node";
2179  for (int i= 0; i < no_of_nodes; i++)
2180  ndbout << " " << node_ids[i];
2181  ndbout_c(" is being started");
2182  }
2183  return 0;
2184 }
2185 
2186 int
2187 CommandInterpreter::executeRestart(int processId, const char* parameters,
2188  bool all)
2189 {
2190  Vector<BaseString> command_list;
2191  if (parameters)
2192  split_args(parameters, command_list);
2193 
2194  int retval;
2195  if (all)
2196  retval = executeRestart(command_list, 0, 0, 0);
2197  else
2198  retval = executeRestart(command_list, 0, &processId, 1);
2199 
2200  return retval;
2201 }
2202 
2203 int
2204 CommandInterpreter::executeRestart(Vector<BaseString> &command_list,
2205  unsigned command_pos,
2206  int *node_ids, int no_of_nodes)
2207 {
2208  int result;
2209  int retval = 0;
2210  int nostart= 0;
2211  int initialstart= 0;
2212  int abort= 0;
2213  int need_disconnect= 0;
2214  int force = 0;
2215 
2216  for (; command_pos < command_list.size(); command_pos++)
2217  {
2218  const char *item= command_list[command_pos].c_str();
2219  if (strcasecmp(item, "-N") == 0)
2220  {
2221  nostart= 1;
2222  continue;
2223  }
2224  if (strcasecmp(item, "-I") == 0)
2225  {
2226  initialstart= 1;
2227  continue;
2228  }
2229  if (strcasecmp(item, "-A") == 0)
2230  {
2231  abort= 1;
2232  continue;
2233  }
2234  if (strcasecmp(item, "-F") == 0)
2235  {
2236  force = 1;
2237  continue;
2238  }
2239  ndbout_c("Invalid option: %s. Expecting -A,-N,-I or -F after RESTART",
2240  item);
2241  return -1;
2242  }
2243 
2244  struct ndb_mgm_cluster_state *cl = ndb_mgm_get_status(m_mgmsrv);
2245  if(cl == NULL)
2246  {
2247  ndbout_c("Could not get status");
2248  printError();
2249  return -1;
2250  }
2251  NdbAutoPtr<char> ap1((char*)cl);
2252 
2253  // We allow 'all restart' in single user mode
2254  if(node_ids != 0) {
2255  for (int i = 0; i<cl->no_of_nodes; i++) {
2256  if((cl->node_states+i)->node_status == NDB_MGM_NODE_STATUS_SINGLEUSER)
2257  {
2258  ndbout_c("Cannot restart nodes: single user mode");
2259  return -1;
2260  }
2261  }
2262  }
2263 
2264  if (node_ids == 0) {
2265  ndbout_c("Executing RESTART on all nodes.");
2266  ndbout_c("Starting shutdown. This may take a while. Please wait...");
2267  }
2268 
2269  for (int i= 0; i < no_of_nodes; i++)
2270  {
2271  int j = 0;
2272  while((j < cl->no_of_nodes) && cl->node_states[j].node_id != node_ids[i])
2273  j++;
2274 
2275  if(cl->node_states[j].node_id != node_ids[i])
2276  {
2277  ndbout << node_ids[i] << ": Node not found" << endl;
2278  return -1;
2279  }
2280 
2282  {
2283  ndbout << "Shutting down MGM node"
2284  << " " << node_ids[i] << " for restart" << endl;
2285  }
2286  }
2287 
2288  result= ndb_mgm_restart4(m_mgmsrv, no_of_nodes, node_ids,
2289  initialstart, nostart, abort, force,
2290  &need_disconnect);
2291 
2292  if (result <= 0) {
2293  ndbout_c("Restart failed.");
2294  printError();
2295  retval = -1;
2296  }
2297  else
2298  {
2299  if (node_ids == 0)
2300  ndbout_c("All DB nodes are being restarted.");
2301  else
2302  {
2303  ndbout << "Node";
2304  for (int i= 0; i < no_of_nodes; i++)
2305  ndbout << " " << node_ids[i];
2306  ndbout_c(" is being restarted");
2307  }
2308  if(need_disconnect)
2309  disconnect();
2310  }
2311  return retval;
2312 }
2313 
2317 static
2318 void
2319 print_status(const ndb_mgm_node_state * state)
2320 {
2321  Uint32 version = state->version;
2322  if (state->node_type != NDB_MGM_NODE_TYPE_NDB)
2323  {
2324  if (version != 0)
2325  {
2326  ndbout << "Node " << state->node_id <<": connected" ;
2327  ndbout_c(" (Version %d.%d.%d)",
2328  getMajor(version) ,
2329  getMinor(version),
2330  getBuild(version));
2331 
2332  }
2333  else
2334  {
2335  ndbout << "Node " << state->node_id << ": not connected" << endl;
2336  }
2337  return;
2338  }
2339 
2340  ndbout << "Node " << state->node_id
2341  << ": " << status_string(state->node_status);
2342  switch(state->node_status){
2344  ndbout << " (Last completed phase " << state->start_phase << ")";
2345  break;
2347  ndbout << " (Last completed phase " << state->start_phase << ")";
2348  break;
2349  default:
2350  break;
2351  }
2352 
2354  {
2355  char tmp[100];
2356  ndbout_c(" (%s)", ndbGetVersionString(version,
2357  state->mysql_version, 0,
2358  tmp, sizeof(tmp)));
2359  }
2360  else
2361  {
2362  ndbout << endl;
2363  }
2364 }
2365 
2366 int
2367 CommandInterpreter::executeStatus(int processId,
2368  const char* parameters, bool all)
2369 {
2370  if (! emptyString(parameters)) {
2371  ndbout_c("No parameters expected to this command.");
2372  return -1;
2373  }
2374 
2375  ndb_mgm_node_type types[2] = {
2377  NDB_MGM_NODE_TYPE_UNKNOWN
2378  };
2379  struct ndb_mgm_cluster_state *cl;
2380  cl = ndb_mgm_get_status2(m_mgmsrv, all ? types : 0);
2381  if(cl == NULL)
2382  {
2383  ndbout_c("Can't get status of node %d.", processId);
2384  printError();
2385  return -1;
2386  }
2387  NdbAutoPtr<char> ap1((char*)cl);
2388 
2389  if (all)
2390  {
2391  for (int i = 0; i<cl->no_of_nodes; i++)
2392  print_status(cl->node_states+i);
2393  return 0;
2394  }
2395  else
2396  {
2397  for (int i = 0; i<cl->no_of_nodes; i++)
2398  {
2399  if (cl->node_states[i].node_id == processId)
2400  {
2401  print_status(cl->node_states + i);
2402  return 0;
2403  }
2404  }
2405  ndbout << processId << ": Node not found" << endl;
2406  return -1;
2407  }
2408  return 0;
2409 } //
2410 
2411 int
2412 CommandInterpreter::executeDumpState(int processId, const char* parameters,
2413  bool all)
2414 {
2415  if(emptyString(parameters))
2416  {
2417  ndbout_c("ERROR: Expected argument!");
2418  return -1;
2419  }
2420 
2421  int params[25];
2422  int num_params = 0;
2423  const size_t max_params = sizeof(params)/sizeof(params[0]);
2424 
2425  Vector<BaseString> args;
2426  split_args(parameters, args);
2427 
2428  if (args.size() > max_params)
2429  {
2430  ndbout_c("ERROR: Too many arguments, max %d allowed", (int)max_params);
2431  return -1;
2432  }
2433 
2434  for (size_t i = 0; i < args.size(); i++)
2435  {
2436  const char* arg = args[i].c_str();
2437 
2438  if (strtoll(arg, NULL, 0) < 0 ||
2439  strtoll(arg, NULL, 0) > 0xffffffff)
2440  {
2441  ndbout_c("ERROR: Illegal value '%s' in argument to signal.\n"
2442  "(Value must be between 0 and 0xffffffff.)", arg);
2443  return -1;
2444  }
2445  assert(num_params < (int)max_params);
2446  params[num_params] = (int)strtoll(arg, NULL, 0);
2447  num_params++;
2448  }
2449 
2450  ndbout << "Sending dump signal with data:" << endl;
2451  for (int i = 0; i < num_params; i++)
2452  {
2453  ndbout.setHexFormat(1) << params[i] << " ";
2454  if (!((i+1) & 0x3)) ndbout << endl;
2455  }
2456  ndbout << endl;
2457 
2458  struct ndb_mgm_reply reply;
2459  return ndb_mgm_dump_state(m_mgmsrv, processId, params, num_params, &reply);
2460 }
2461 
2462 static void
2463 report_memoryusage(const ndb_logevent& event)
2464 {
2465  const ndb_logevent_MemoryUsage& usage = event.MemoryUsage;
2466  const Uint32 block = usage.block;
2467  const Uint32 total = usage.pages_total;
2468  const Uint32 used = usage.pages_used;
2469  assert(event.type == NDB_LE_MemoryUsage);
2470 
2471  ndbout_c("Node %u: %s usage is %d%%(%d %dK pages of total %d)",
2472  event.source_nodeid,
2473  (block == DBACC ? "Index" : (block == DBTUP ? "Data" : "<unknown>")),
2474  (total ? (used * 100 / total) : 0),
2475  used,
2476  usage.page_size_kb/1024,
2477  total);
2478 }
2479 
2480 
2481 static void
2482 report_backupstatus(const ndb_logevent& event)
2483 {
2484  const ndb_logevent_BackupStatus& status = event.BackupStatus;
2485  assert(event.type == NDB_LE_BackupStatus);
2486 
2487 
2488  if (status.starting_node)
2489  ndbout_c("Node %u: Local backup status: backup %u started from node %u\n"
2490  " #Records: %llu #LogRecords: %llu\n"
2491  " Data: %llu bytes Log: %llu bytes",
2492  event.source_nodeid,
2493  status.backup_id,
2494  refToNode(status.starting_node),
2495  make_uint64(status.n_records_lo, status.n_records_hi),
2496  make_uint64(status.n_log_records_lo, status.n_log_records_hi),
2497  make_uint64(status.n_bytes_lo, status.n_bytes_hi),
2498  make_uint64(status.n_log_bytes_lo, status.n_log_bytes_hi));
2499  else
2500  ndbout_c("Node %u: Backup not started",
2501  event.source_nodeid);
2502 }
2503 
2504 static
2505 void
2506 report_events(const ndb_logevent& event)
2507 {
2508  Uint32 threshold = 0;
2509  Logger::LoggerLevel severity = Logger::LL_WARNING;
2510  LogLevel::EventCategory cat= LogLevel::llInvalid;
2512 
2513  const EventReport * real_event = (const EventReport*)event.SavedEvent.data;
2514  Uint32 type = real_event->getEventType();
2515 
2516  if (EventLoggerBase::event_lookup(type,cat,threshold,severity,textF))
2517  return;
2518 
2519  char out[1024];
2520  Uint32 pos = 0;
2521  if (event.source_nodeid != 0)
2522  {
2523  BaseString::snprintf(out, sizeof(out), "Node %u: ", event.source_nodeid);
2524  pos= (Uint32)strlen(out);
2525  }
2526  textF(out+pos, sizeof(out)-pos, event.SavedEvent.data, event.SavedEvent.len);
2527 
2528  time_t t = event.SavedEvent.time;
2529  struct tm * tm_now = localtime(&t);
2530  ndbout_c("%d-%.2d-%.2d %.2d:%.2d:%.2d %s",
2531  tm_now->tm_year + 1900,
2532  tm_now->tm_mon + 1, //month is [0,11]. +1 -> [1,12]
2533  tm_now->tm_mday,
2534  tm_now->tm_hour,
2535  tm_now->tm_min,
2536  tm_now->tm_sec,
2537  out);
2538 }
2539 
2540 static int
2541 sort_log(const void *_a, const void *_b)
2542 {
2543  const ndb_logevent * a = (const ndb_logevent*)_a;
2544  const ndb_logevent * b = (const ndb_logevent*)_b;
2545 
2546  if (a->source_nodeid == b->source_nodeid)
2547  {
2548  return a->SavedEvent.seq - b->SavedEvent.seq;
2549  }
2550 
2551  if (a->SavedEvent.time < b->SavedEvent.time)
2552  return -1;
2553  if (a->SavedEvent.time > b->SavedEvent.time)
2554  return 1;
2555 
2556  if (a->SavedEvent.seq < b->SavedEvent.seq)
2557  return -1;
2558  if (a->SavedEvent.seq > b->SavedEvent.seq)
2559  return 1;
2560 
2561  return (a->source_nodeid - b->source_nodeid);
2562 }
2563 
2564 static const
2565 struct st_report_cmd {
2566  const char *name;
2567  const char *help;
2569  void (*print_event_fn)(const ndb_logevent&);
2570  int (* sort_fn)(const void *_a, const void *_b);
2571 } report_cmds[] = {
2572 
2573  { "BackupStatus",
2574  "Report backup status of respective node",
2576  report_backupstatus, 0 },
2577 
2578  { "MemoryUsage",
2579  "Report memory usage of respective node",
2581  report_memoryusage, 0 },
2582 
2583  { "EventLog",
2584  "Report events in datanodes circular event log buffer",
2585  NDB_LE_SavedEvent,
2586  report_events, sort_log },
2587 
2588  { 0, 0, NDB_LE_ILLEGAL_TYPE, 0, 0 }
2589 };
2590 
2591 
2592 int
2593 CommandInterpreter::executeReport(int nodeid, const char* parameters,
2594  bool all)
2595 {
2596  if (emptyString(parameters))
2597  {
2598  ndbout_c("ERROR: missing report type specifier!");
2599  return -1;
2600  }
2601 
2602  Vector<BaseString> args;
2603  split_args(parameters, args);
2604 
2605  const st_report_cmd* report_cmd = report_cmds;
2606  for (; report_cmd->name; report_cmd++)
2607  {
2608  if (strncasecmp(report_cmd->name, args[0].c_str(),
2609  args[0].length()) == 0)
2610  break;
2611  }
2612 
2613  if (!report_cmd->name)
2614  {
2615  ndbout_c("ERROR: '%s' - report type specifier unknown!", args[0].c_str());
2616  return -1;
2617  }
2618 
2619  if (!all)
2620  {
2621  ClusterInfo info;
2622  if (!info.fetch(m_mgmsrv))
2623  {
2624  printError();
2625  return -1;
2626  }
2627 
2628  // Check that given nodeid is a NDB node
2629  if (!info.is_ndb_node(nodeid))
2630  return -1;
2631  }
2632 
2633  struct ndb_mgm_events* events =
2634  ndb_mgm_dump_events(m_mgmsrv, report_cmd->type,
2635  all ? 0 : 1, &nodeid);
2636  if (!events)
2637  {
2638  ndbout_c("ERROR: failed to fetch report!");
2639  printError();
2640  return -1;
2641  }
2642 
2643  if (report_cmd->sort_fn)
2644  {
2645  qsort(events->events, events->no_of_events,
2646  sizeof(events->events[0]), report_cmd->sort_fn);
2647  }
2648 
2649  for (int i = 0; i < events->no_of_events; i++)
2650  {
2651  const ndb_logevent& event = events->events[i];
2652  report_cmd->print_event_fn(event);
2653  }
2654 
2655  free(events);
2656  return 0;
2657 }
2658 
2659 
2660 static void
2661 helpTextReportFn()
2662 {
2663  ndbout_c(" <report-type> =");
2664  const st_report_cmd* report_cmd = report_cmds;
2665  for (; report_cmd->name; report_cmd++)
2666  ndbout_c(" %s\t- %s", report_cmd->name, report_cmd->help);
2667 }
2668 
2669 
2670 //*****************************************************************************
2671 //*****************************************************************************
2672 
2673 int
2674 CommandInterpreter::executeLogLevel(int processId, const char* parameters,
2675  bool all)
2676 {
2677  (void) all;
2678  if (emptyString(parameters)) {
2679  ndbout << "Expected argument" << endl;
2680  return -1;
2681  }
2682  BaseString tmp(parameters);
2683  Vector<BaseString> spec;
2684  tmp.split(spec, "=");
2685  if(spec.size() != 2){
2686  ndbout << "Invalid loglevel specification: " << parameters << endl;
2687  return -1;
2688  }
2689 
2690  spec[0].trim().ndb_toupper();
2691  int category = ndb_mgm_match_event_category(spec[0].c_str());
2692  if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2693  category = atoi(spec[0].c_str());
2694  if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
2695  category > NDB_MGM_MAX_EVENT_CATEGORY){
2696  ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2697  return -1;
2698  }
2699  }
2700 
2701  int level = atoi(spec[1].c_str());
2702  if(level < 0 || level > 15){
2703  ndbout << "Invalid level: " << spec[1].c_str() << endl;
2704  return -1;
2705  }
2706 
2707  ndbout << "Executing LOGLEVEL on node " << processId << flush;
2708 
2709  struct ndb_mgm_reply reply;
2710  int result;
2711  result = ndb_mgm_set_loglevel_node(m_mgmsrv,
2712  processId,
2713  (ndb_mgm_event_category)category,
2714  level,
2715  &reply);
2716 
2717  if (result < 0) {
2718  ndbout_c(" failed.");
2719  printError();
2720  return -1;
2721  } else {
2722  ndbout_c(" OK!");
2723  }
2724  return 0;
2725 }
2726 
2727 //*****************************************************************************
2728 //*****************************************************************************
2729 int CommandInterpreter::executeError(int processId,
2730  const char* parameters, bool /* all */)
2731 {
2732  if (emptyString(parameters))
2733  {
2734  ndbout_c("ERROR: Missing error number.");
2735  return -1;
2736  }
2737 
2738  Vector<BaseString> args;
2739  split_args(parameters, args);
2740 
2741  if (args.size() >= 2)
2742  {
2743  ndbout << "ERROR: Too many arguments." << endl;
2744  return -1;
2745  }
2746 
2747  int errorNo;
2748  if (! convert(args[0].c_str(), errorNo)) {
2749  ndbout << "ERROR: Expected an integer." << endl;
2750  return -1;
2751  }
2752 
2753  return ndb_mgm_insert_error(m_mgmsrv, processId, errorNo, NULL);
2754 }
2755 
2756 //*****************************************************************************
2757 //*****************************************************************************
2758 
2759 int
2760 CommandInterpreter::executeLog(int processId,
2761  const char* parameters, bool all)
2762 {
2763  struct ndb_mgm_reply reply;
2764  Vector<BaseString> blocks;
2765  if (! parseBlockSpecification(parameters, blocks)) {
2766  return -1;
2767  }
2768 
2769  BaseString block_names;
2770  for (unsigned i = 0; i<blocks.size(); i++)
2771  block_names.appfmt("%s|", blocks[i].c_str());
2772 
2773  int result = ndb_mgm_log_signals(m_mgmsrv,
2774  processId,
2776  block_names.c_str(),
2777  &reply);
2778  if (result != 0) {
2779  ndbout_c("Execute LOG on node %d failed.", processId);
2780  printError();
2781  return -1;
2782  }
2783  return 0;
2784 }
2785 
2786 
2787 //*****************************************************************************
2788 //*****************************************************************************
2789 int
2790 CommandInterpreter::executeTestOn(int processId,
2791  const char* parameters, bool /*all*/)
2792 {
2793  if (! emptyString(parameters)) {
2794  ndbout << "No parameters expected to this command." << endl;
2795  return -1;
2796  }
2797  struct ndb_mgm_reply reply;
2798  int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply);
2799  if (result != 0) {
2800  ndbout_c("Execute TESTON failed.");
2801  printError();
2802  return -1;
2803  }
2804  return 0;
2805 }
2806 
2807 //*****************************************************************************
2808 //*****************************************************************************
2809 int
2810 CommandInterpreter::executeTestOff(int processId,
2811  const char* parameters, bool /*all*/)
2812 {
2813  if (! emptyString(parameters)) {
2814  ndbout << "No parameters expected to this command." << endl;
2815  return -1;
2816  }
2817  struct ndb_mgm_reply reply;
2818  int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply);
2819  if (result != 0) {
2820  ndbout_c("Execute TESTOFF failed.");
2821  printError();
2822  return -1;
2823  }
2824  return 0;
2825 }
2826 
2827 
2828 //*****************************************************************************
2829 //*****************************************************************************
2830 
2831 int
2832 CommandInterpreter::executeEventReporting(int processId,
2833  const char* parameters,
2834  bool all)
2835 {
2836  int retval = 0;
2837  if (emptyString(parameters)) {
2838  ndbout << "Expected argument" << endl;
2839  return -1;
2840  }
2841 
2842  Vector<BaseString> specs;
2843  split_args(parameters, specs);
2844 
2845  for (int i=0; i < (int) specs.size(); i++)
2846  {
2847  Vector<BaseString> spec;
2848  specs[i].split(spec, "=");
2849  if(spec.size() != 2){
2850  ndbout << "Invalid loglevel specification: " << specs[i] << endl;
2851  continue;
2852  }
2853 
2854  spec[0].trim().ndb_toupper();
2855  int category = ndb_mgm_match_event_category(spec[0].c_str());
2856  if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2857  if(!convert(spec[0].c_str(), category) ||
2858  category < NDB_MGM_MIN_EVENT_CATEGORY ||
2859  category > NDB_MGM_MAX_EVENT_CATEGORY){
2860  ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2861  continue;
2862  }
2863  }
2864 
2865  int level;
2866  if (!convert(spec[1].c_str(),level))
2867  {
2868  ndbout << "Invalid level: " << spec[1].c_str() << endl;
2869  continue;
2870  }
2871 
2872  ndbout << "Executing CLUSTERLOG " << spec[0] << "=" << spec[1]
2873  << " on node " << processId << flush;
2874 
2875  struct ndb_mgm_reply reply;
2876  int result;
2877  result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv,
2878  processId,
2879  (ndb_mgm_event_category)category,
2880  level,
2881  &reply);
2882 
2883  if (result != 0) {
2884  ndbout_c(" failed.");
2885  printError();
2886  retval = -1;
2887  } else {
2888  ndbout_c(" OK!");
2889  }
2890  }
2891  return retval;
2892 }
2893 
2894 
2895 /*****************************************************************************
2896  * Backup
2897  *****************************************************************************/
2898 int
2899 CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
2900 {
2901  struct ndb_mgm_reply reply;
2902  unsigned int backupId;
2903  unsigned int input_backupId = 0;
2904 
2905  Vector<BaseString> args;
2906  if (parameters)
2907  split_args(parameters, args);
2908 
2909  for (unsigned i= 0; i < args.size(); i++)
2910  args[i].ndb_toupper();
2911 
2912  int sz= args.size();
2913 
2914  int result;
2915  int flags = 2;
2916  //1,snapshot at start time. 0 snapshot at end time
2917  unsigned int backuppoint = 0;
2918  bool b_log = false;
2919  bool b_nowait = false;
2920  bool b_wait_completed = false;
2921  bool b_wait_started = false;
2922 
2923  /*
2924  All the commands list as follow:
2925  start backup <backupid> nowait | start backup <backupid> snapshotstart/snapshotend nowati | start backup <backupid> nowait snapshotstart/snapshotend
2926  start backup <backupid> | start backup <backupid> wait completed | start backup <backupid> snapshotstart/snapshotend
2927  start backup <backupid> snapshotstart/snapshotend wait completed | start backup <backupid> wait completed snapshotstart/snapshotend
2928  start backup <backupid> wait started | start backup <backupid> snapshotstart/snapshotend wait started
2929  start backup <backupid> wait started snapshotstart/snapshotend
2930  */
2931  for (int i= 1; i < sz; i++)
2932  {
2933  if (i == 1 && sscanf(args[1].c_str(), "%u", &input_backupId) == 1) {
2934  if (input_backupId > 0 && input_backupId < MAX_BACKUPS)
2935  continue;
2936  else {
2937  invalid_command(parameters);
2938  return -1;
2939  }
2940  }
2941 
2942  if (args[i] == "SNAPSHOTEND") {
2943  if (b_log ==true) {
2944  invalid_command(parameters);
2945  return -1;
2946  }
2947  b_log = true;
2948  backuppoint = 0;
2949  continue;
2950  }
2951  if (args[i] == "SNAPSHOTSTART") {
2952  if (b_log ==true) {
2953  invalid_command(parameters);
2954  return -1;
2955  }
2956  b_log = true;
2957  backuppoint = 1;
2958  continue;
2959  }
2960  if (args[i] == "NOWAIT") {
2961  if (b_nowait == true || b_wait_completed == true || b_wait_started ==true) {
2962  invalid_command(parameters);
2963  return -1;
2964  }
2965  b_nowait = true;
2966  flags = 0;
2967  continue;
2968  }
2969  if (args[i] == "WAIT") {
2970  if (b_nowait == true || b_wait_completed == true || b_wait_started ==true) {
2971  invalid_command(parameters);
2972  return -1;
2973  }
2974  if (i+1 < sz) {
2975  if (args[i+1] == "COMPLETED") {
2976  b_wait_completed = true;
2977  flags = 2;
2978  i++;
2979  }
2980  else if (args[i+1] == "STARTED") {
2981  b_wait_started = true;
2982  flags = 1;
2983  i++;
2984  }
2985  else {
2986  invalid_command(parameters);
2987  return -1;
2988  }
2989  }
2990  else {
2991  invalid_command(parameters);
2992  return -1;
2993  }
2994  continue;
2995  }
2996  invalid_command(parameters);
2997  return -1;
2998  }
2999 
3000  //print message
3001  if (flags == 2)
3002  ndbout_c("Waiting for completed, this may take several minutes");
3003  if (flags == 1)
3004  ndbout_c("Waiting for started, this may take several minutes");
3005 
3006  NdbLogEventHandle log_handle= NULL;
3007  struct ndb_logevent log_event;
3008  if (flags > 0 && !interactive)
3009  {
3010  int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0, 0 };
3011  log_handle = ndb_mgm_create_logevent_handle(m_mgmsrv, filter);
3012  if (!log_handle)
3013  {
3014  ndbout << "Initializing start of backup failed" << endl;
3015  printError();
3016  return -1;
3017  }
3018  }
3019 
3020  //start backup N | start backup snapshotstart/snapshotend
3021  if (input_backupId > 0 || b_log == true)
3022  result = ndb_mgm_start_backup3(m_mgmsrv, flags, &backupId, &reply, input_backupId, backuppoint);
3023  //start backup
3024  else
3025  result = ndb_mgm_start_backup(m_mgmsrv, flags, &backupId, &reply);
3026 
3027  if (result != 0) {
3028  ndbout << "Backup failed" << endl;
3029  printError();
3030 
3031  if (log_handle)
3032  ndb_mgm_destroy_logevent_handle(&log_handle);
3033  return result;
3034  }
3035 
3039  if (log_handle && !interactive)
3040  {
3041  int count = 0;
3042  int retry = 0;
3043  int res;
3044  do {
3045  if ((res= ndb_logevent_get_next(log_handle, &log_event, 60000)) > 0)
3046  {
3047  int print = 0;
3048  switch (log_event.type) {
3049  case NDB_LE_BackupStarted:
3050  if (log_event.BackupStarted.backup_id == backupId)
3051  print = 1;
3052  break;
3054  if (log_event.BackupCompleted.backup_id == backupId)
3055  print = 1;
3056  break;
3057  case NDB_LE_BackupAborted:
3058  if (log_event.BackupAborted.backup_id == backupId)
3059  print = 1;
3060  break;
3061  default:
3062  break;
3063  }
3064  if (print)
3065  {
3066  Guard g(m_print_mutex);
3067  printLogEvent(&log_event);
3068  count++;
3069  }
3070  }
3071  else
3072  {
3073  retry++;
3074  }
3075  } while(res >= 0 && count < 2 && retry < 3);
3076 
3077  if (retry >= 3)
3078  ndbout << "get backup event failed for " << retry << " times" << endl;
3079 
3080  ndb_mgm_destroy_logevent_handle(&log_handle);
3081  }
3082 
3083  return 0;
3084 }
3085 
3086 int
3087 CommandInterpreter::executeAbortBackup(char* parameters)
3088 {
3089  int bid = -1;
3090  struct ndb_mgm_reply reply;
3091  if (emptyString(parameters))
3092  goto executeAbortBackupError1;
3093 
3094  {
3095  strtok(parameters, " ");
3096  char* id = strtok(NULL, "\0");
3097  if(id == 0 || sscanf(id, "%d", &bid) != 1)
3098  goto executeAbortBackupError1;
3099  }
3100  {
3101  int result= ndb_mgm_abort_backup(m_mgmsrv, bid, &reply);
3102  if (result != 0) {
3103  ndbout << "Abort of backup " << bid << " failed" << endl;
3104  printError();
3105  return -1;
3106  } else {
3107  ndbout << "Abort of backup " << bid << " ordered" << endl;
3108  }
3109  }
3110  return 0;
3111  executeAbortBackupError1:
3112  ndbout << "Invalid arguments: expected <BackupId>" << endl;
3113  return -1;
3114 }
3115 
3116 int
3117 CommandInterpreter::executeCreateNodeGroup(char* parameters)
3118 {
3119  int result;
3120  int ng;
3121  struct ndb_mgm_reply reply;
3122  char *id= strchr(parameters, ' ');
3123  if (emptyString(id))
3124  goto err;
3125 
3126  {
3127  Vector<int> nodes;
3128  BaseString args(id);
3129  Vector<BaseString> nodelist;
3130  args.split(nodelist, ",");
3131 
3132  for (Uint32 i = 0; i<nodelist.size(); i++)
3133  {
3134  nodes.push_back(atoi(nodelist[i].c_str()));
3135  }
3136  nodes.push_back(0);
3137 
3138  result= ndb_mgm_create_nodegroup(m_mgmsrv, nodes.getBase(), &ng, &reply);
3139 
3140  if (result != 0) {
3141  printError();
3142  return -1;
3143  } else {
3144  ndbout << "Nodegroup " << ng << " created" << endl;
3145  }
3146 
3147  }
3148 
3149  return 0;
3150 err:
3151  ndbout << "Invalid arguments: expected <id>,<id>..." << endl;
3152  return -1;
3153 }
3154 
3155 int
3156 CommandInterpreter::executeDropNodeGroup(char* parameters)
3157 {
3158  int ng = -1;
3159  struct ndb_mgm_reply reply;
3160  if (emptyString(parameters))
3161  goto err;
3162 
3163  {
3164  char* id = strchr(parameters, ' ');
3165  if(id == 0 || sscanf(id, "%d", &ng) != 1)
3166  goto err;
3167  }
3168 
3169  {
3170  int result= ndb_mgm_drop_nodegroup(m_mgmsrv, ng, &reply);
3171  if (result != 0) {
3172  printError();
3173  return -1;
3174  } else {
3175  ndbout << "Drop Node Group " << ng << " done" << endl;
3176  }
3177  }
3178  return 0;
3179 err:
3180  ndbout << "Invalid arguments: expected <NG>" << endl;
3181  return -1;
3182 }