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