1 /*
2 Copyright (c) 2003, 2015, 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 static void helpTextReportTypeOptionFn();
547
548
549 static const char* helpTextQuit =
550 "---------------------------------------------------------------------------\n"
551 " NDB Cluster -- Management Client -- Help for QUIT command\n"
552 "---------------------------------------------------------------------------\n"
553 "QUIT Quit management client\n\n"
554 "QUIT Terminates the management client. \n"
555 ;
556
557
558 #ifdef VM_TRACE // DEBUG ONLY
559 static const char* helpTextDebug =
560 "---------------------------------------------------------------------------\n"
561 " NDB Cluster -- Management Client -- Help for Debugging (Internal use only)\n"
562 "---------------------------------------------------------------------------\n"
563 "SHOW PROPERTIES Print config properties object\n"
564 "<id> LOGLEVEL {<category>=<level>}+ Set log level\n"
565 #ifdef ERROR_INSERT
566 "<id> ERROR <errorNo> Inject error into NDB node\n"
567 #endif
568 "<id> LOG [BLOCK = {ALL|<block>+}] Set logging on in & out signals\n"
569 "<id> TESTON Start signal logging\n"
570 "<id> TESTOFF Stop signal logging\n"
571 "<id> DUMP <arg> Dump system state to cluster.log\n"
572 "\n"
573 "<id> = ALL | Any database node id\n"
574 ;
575 #endif
576
577 struct st_cmd_help {
578 const char *cmd;
579 const char * help;
580 void (* help_fn)();
581 }help_items[]={
582 {"SHOW", helpTextShow, NULL},
583 {"HELP", helpTextHelp, NULL},
584 {"BACKUP", helpTextBackup, NULL},
585 {"START BACKUP", helpTextStartBackup, NULL},
586 {"START BACKUP NOWAIT", helpTextStartBackup, NULL},
587 {"START BACKUP WAIT STARTED", helpTextStartBackup, NULL},
588 {"START BACKUP WAIT", helpTextStartBackup, NULL},
589 {"START BACKUP WAIT COMPLETED", helpTextStartBackup, NULL},
590 {"ABORT BACKUP", helpTextAbortBackup, NULL},
591 {"SHUTDOWN", helpTextShutdown, NULL},
592 {"CLUSTERLOG ON", helpTextClusterlogOn, NULL},
593 {"CLUSTERLOG OFF", helpTextClusterlogOff, NULL},
594 {"CLUSTERLOG TOGGLE", helpTextClusterlogToggle, NULL},
595 {"CLUSTERLOG INFO", helpTextClusterlogInfo, NULL},
596 {"START", helpTextStart, NULL},
597 {"RESTART", helpTextRestart, NULL},
598 {"STOP", helpTextStop, NULL},
599 {"ENTER SINGLE USER MODE", helpTextEnterSingleUserMode, NULL},
600 {"EXIT SINGLE USER MODE", helpTextExitSingleUserMode, NULL},
601 {"STATUS", helpTextStatus, NULL},
602 {"CLUSTERLOG", helpTextClusterlog, NULL},
603 {"PURGE STALE SESSIONS", helpTextPurgeStaleSessions, NULL},
604 {"CONNECT", helpTextConnect, NULL},
605 {"REPORT", helpTextReport, helpTextReportFn},
606 {"QUIT", helpTextQuit, NULL},
607 #ifdef VM_TRACE // DEBUG ONLY
608 {"DEBUG", helpTextDebug, NULL},
609 #endif //VM_TRACE
610 {NULL, NULL, NULL}
611 };
612
613 static bool
convert(const char * s,int & val)614 convert(const char* s, int& val) {
615
616 if (s == NULL)
617 return false;
618
619 if (strlen(s) == 0)
620 return false;
621
622 errno = 0;
623 char* p;
624 long v = strtol(s, &p, 10);
625 if (errno != 0)
626 return false;
627
628 if (p != &s[strlen(s)])
629 return false;
630
631 val = v;
632 return true;
633 }
634
635 /*
636 * Constructor
637 */
CommandInterpreter(const char * host,int verbose)638 CommandInterpreter::CommandInterpreter(const char *host,int verbose) :
639 m_constr(host),
640 m_connected(false),
641 m_verbose(verbose),
642 m_try_reconnect(0),
643 m_error(-1),
644 m_event_thread(NULL)
645 {
646 m_print_mutex= NdbMutex_Create();
647 }
648
649 /*
650 * Destructor
651 */
~CommandInterpreter()652 CommandInterpreter::~CommandInterpreter()
653 {
654 disconnect();
655 NdbMutex_Destroy(m_print_mutex);
656 }
657
658 static bool
emptyString(const char * s)659 emptyString(const char* s)
660 {
661 if (s == NULL) {
662 return true;
663 }
664
665 for (unsigned int i = 0; i < strlen(s); ++i) {
666 if (! isspace(s[i])) {
667 return false;
668 }
669 }
670
671 return true;
672 }
673
674 void
printError()675 CommandInterpreter::printError()
676 {
677 if (m_mgmsrv)
678 {
679 ndbout_c("* %5d: %s",
680 ndb_mgm_get_latest_error(m_mgmsrv),
681 ndb_mgm_get_latest_error_msg(m_mgmsrv));
682 ndbout_c("* %s", ndb_mgm_get_latest_error_desc(m_mgmsrv));
683 if (ndb_mgm_check_connection(m_mgmsrv))
684 {
685 disconnect();
686 }
687 }
688 }
689
690 /*
691 * print log event from mgmsrv to console screen
692 */
693 #define make_uint64(a,b) (((Uint64)(a)) + (((Uint64)(b)) << 32))
694 #define Q64(a) make_uint64(event->EVENT.a ## _lo, event->EVENT.a ## _hi)
695 #define R event->source_nodeid
696 #define Q(a) event->EVENT.a
697 #define QVERSION getMajor(Q(version)), getMinor(Q(version)), getBuild(Q(version))
698 #define NDB_LE_(a) NDB_LE_ ## a
699 static void
printLogEvent(struct ndb_logevent * event)700 printLogEvent(struct ndb_logevent* event)
701 {
702 switch (event->type) {
703 /**
704 * NDB_MGM_EVENT_CATEGORY_BACKUP
705 */
706 #undef EVENT
707 #define EVENT BackupStarted
708 case NDB_LE_BackupStarted:
709 ndbout_c("Node %u: Backup %u started from node %d",
710 R, Q(backup_id), Q(starting_node));
711 break;
712 #undef EVENT
713 #define EVENT BackupStatus
714 case NDB_LE_BackupStatus:
715 if (Q(starting_node))
716 ndbout_c("Node %u: Local backup status: backup %u started from node %u\n"
717 " #Records: %llu #LogRecords: %llu\n"
718 " Data: %llu bytes Log: %llu bytes", R,
719 Q(backup_id),
720 Q(starting_node),
721 Q64(n_records),
722 Q64(n_log_records),
723 Q64(n_bytes),
724 Q64(n_log_bytes));
725 else
726 ndbout_c("Node %u: Backup not started", R);
727 break;
728 #undef EVENT
729 #define EVENT BackupFailedToStart
730 case NDB_LE_BackupFailedToStart:
731 ndbout_c("Node %u: Backup request from %d failed to start. Error: %d",
732 R, Q(starting_node), Q(error));
733 break;
734 #undef EVENT
735 #define EVENT BackupCompleted
736 case NDB_LE_BackupCompleted:
737 ndbout_c("Node %u: Backup %u started from node %u completed\n"
738 " StartGCP: %u StopGCP: %u\n"
739 " #Records: %u #LogRecords: %u\n"
740 " Data: %u bytes Log: %u bytes", R,
741 Q(backup_id), Q(starting_node),
742 Q(start_gci), Q(stop_gci),
743 Q(n_records), Q(n_log_records),
744 Q(n_bytes), Q(n_log_bytes));
745 break;
746 #undef EVENT
747 #define EVENT BackupAborted
748 case NDB_LE_BackupAborted:
749 ndbout_c("Node %u: Backup %u started from %d has been aborted. Error: %d",
750 R, Q(backup_id), Q(starting_node), Q(error));
751 break;
752 /**
753 * NDB_MGM_EVENT_CATEGORY_STARTUP
754 */
755 #undef EVENT
756 #define EVENT NDBStartStarted
757 case NDB_LE_NDBStartStarted:
758 ndbout_c("Node %u: Start initiated (version %d.%d.%d)",
759 R, QVERSION);
760 break;
761 #undef EVENT
762 #define EVENT NDBStartCompleted
763 case NDB_LE_NDBStartCompleted:
764 ndbout_c("Node %u: Started (version %d.%d.%d)",
765 R, QVERSION);
766 break;
767 #undef EVENT
768 #define EVENT NDBStopStarted
769 case NDB_LE_NDBStopStarted:
770 ndbout_c("Node %u: %s shutdown initiated", R,
771 (Q(stoptype) == 1 ? "Cluster" : "Node"));
772 break;
773 #undef EVENT
774 #define EVENT NDBStopCompleted
775 case NDB_LE_NDBStopCompleted:
776 {
777 BaseString action_str("");
778 BaseString signum_str("");
779 getRestartAction(Q(action), action_str);
780 if (Q(signum))
781 signum_str.appfmt(" Initiated by signal %d.",
782 Q(signum));
783 ndbout_c("Node %u: Node shutdown completed%s.%s",
784 R, action_str.c_str(), signum_str.c_str());
785 }
786 break;
787 #undef EVENT
788 #define EVENT NDBStopForced
789 case NDB_LE_NDBStopForced:
790 {
791 BaseString action_str("");
792 BaseString reason_str("");
793 BaseString sphase_str("");
794 int signum = Q(signum);
795 int error = Q(error);
796 int sphase = Q(sphase);
797 int extra = Q(extra);
798 getRestartAction(Q(action), action_str);
799 if (signum)
800 reason_str.appfmt(" Initiated by signal %d.", signum);
801 if (error)
802 {
803 ndbd_exit_classification cl;
804 ndbd_exit_status st;
805 const char *msg = ndbd_exit_message(error, &cl);
806 const char *cl_msg = ndbd_exit_classification_message(cl, &st);
807 const char *st_msg = ndbd_exit_status_message(st);
808 reason_str.appfmt(" Caused by error %d: \'%s(%s). %s\'.",
809 error, msg, cl_msg, st_msg);
810 if (extra != 0)
811 reason_str.appfmt(" (extra info %d)", extra);
812 }
813 if (sphase < 255)
814 sphase_str.appfmt(" Occured during startphase %u.", sphase);
815 ndbout_c("Node %u: Forced node shutdown completed%s.%s%s",
816 R, action_str.c_str(), sphase_str.c_str(),
817 reason_str.c_str());
818 }
819 break;
820 #undef EVENT
821 #define EVENT StopAborted
822 case NDB_LE_NDBStopAborted:
823 ndbout_c("Node %u: Node shutdown aborted", R);
824 break;
825 /**
826 * NDB_MGM_EVENT_CATEGORY_STATISTIC
827 */
828 #undef EVENT
829 #define EVENT MemoryUsage
830 case NDB_LE_MemoryUsage:
831 {
832
833 if (Q(gth) == 0)
834 {
835 // Only print MemoryUsage report for increased/decreased
836 break;
837 }
838
839 const int percent = Q(pages_total) ? (Q(pages_used)*100)/Q(pages_total) : 0;
840 ndbout_c("Node %u: %s usage %s %d%s(%d %dK pages of total %d)", R,
841 (Q(block) == DBACC ? "Index" : (Q(block) == DBTUP ?"Data":"<unknown>")),
842 (Q(gth) > 0 ? "increased to" : "decreased to"),
843 percent, "%",
844 Q(pages_used), Q(page_size_kb)/1024, Q(pages_total));
845 break;
846 }
847 /**
848 * default nothing to print
849 */
850 default:
851 break;
852 }
853 }
854
855 //*****************************************************************************
856 //*****************************************************************************
857
858 struct event_thread_param {
859 NdbMgmHandle *m;
860 NdbMutex **p;
861 };
862
863 static int do_event_thread = 0;
864
865 static void*
event_thread_run(void * p)866 event_thread_run(void* p)
867 {
868 DBUG_ENTER("event_thread_run");
869
870 struct event_thread_param param= *(struct event_thread_param*)p;
871 NdbMgmHandle handle= *(param.m);
872 NdbMutex* printmutex= *(param.p);
873
874 int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
875 1, NDB_MGM_EVENT_CATEGORY_STARTUP,
876 5, NDB_MGM_EVENT_CATEGORY_STATISTIC,
877 0 };
878
879 NdbLogEventHandle log_handle= NULL;
880 struct ndb_logevent log_event;
881
882 log_handle= ndb_mgm_create_logevent_handle(handle, filter);
883 if (log_handle)
884 {
885 do_event_thread= 1;
886 do {
887 int res= ndb_logevent_get_next(log_handle, &log_event, 2000);
888 if (res > 0)
889 {
890 Guard g(printmutex);
891 printLogEvent(&log_event);
892 }
893 else if (res < 0)
894 break;
895 } while(do_event_thread);
896 ndb_mgm_destroy_logevent_handle(&log_handle);
897 }
898 else
899 {
900 do_event_thread= 0;
901 }
902
903 DBUG_RETURN(NULL);
904 }
905
906 bool
connect(bool interactive)907 CommandInterpreter::connect(bool interactive)
908 {
909 DBUG_ENTER("CommandInterpreter::connect");
910
911 if(m_connected)
912 DBUG_RETURN(m_connected);
913
914 m_mgmsrv = ndb_mgm_create_handle();
915 if(m_mgmsrv == NULL) {
916 ndbout_c("Can't create handle to management server.");
917 exit(-1);
918 }
919
920 if (interactive) {
921 m_mgmsrv2 = ndb_mgm_create_handle();
922 if(m_mgmsrv2 == NULL) {
923 ndbout_c("Can't create 2:nd handle to management server.");
924 exit(-1);
925 }
926 }
927
928 if (ndb_mgm_set_connectstring(m_mgmsrv, m_constr))
929 {
930 printError();
931 exit(-1);
932 }
933
934 if(ndb_mgm_connect(m_mgmsrv, m_try_reconnect-1, 5, 1))
935 DBUG_RETURN(m_connected); // couldn't connect, always false
936
937 const char *host= ndb_mgm_get_connected_host(m_mgmsrv);
938 unsigned port= ndb_mgm_get_connected_port(m_mgmsrv);
939 if (interactive) {
940 BaseString constr;
941 constr.assfmt("%s:%d",host,port);
942 if(!ndb_mgm_set_connectstring(m_mgmsrv2, constr.c_str()) &&
943 !ndb_mgm_connect(m_mgmsrv2, m_try_reconnect-1, 5, 1))
944 {
945 DBUG_PRINT("info",("2:ndb connected to Management Server ok at: %s:%d",
946 host, port));
947 assert(m_event_thread == NULL);
948 assert(do_event_thread == 0);
949 do_event_thread= 0;
950 struct event_thread_param p;
951 p.m= &m_mgmsrv2;
952 p.p= &m_print_mutex;
953 m_event_thread = NdbThread_Create(event_thread_run,
954 (void**)&p,
955 0, // default stack size
956 "CommandInterpreted_event_thread",
957 NDB_THREAD_PRIO_LOW);
958 if (m_event_thread)
959 {
960 DBUG_PRINT("info",("Thread created ok, waiting for started..."));
961 int iter= 1000; // try for 30 seconds
962 while(do_event_thread == 0 &&
963 iter-- > 0)
964 NdbSleep_MilliSleep(30);
965 }
966 if (m_event_thread == NULL ||
967 do_event_thread == 0 ||
968 do_event_thread == -1)
969 {
970 DBUG_PRINT("info",("Warning, event thread startup failed, "
971 "degraded printouts as result, errno=%d",
972 errno));
973 printf("Warning, event thread startup failed, "
974 "degraded printouts as result, errno=%d\n", errno);
975 do_event_thread= 0;
976 if (m_event_thread)
977 {
978 void *res;
979 NdbThread_WaitFor(m_event_thread, &res);
980 NdbThread_Destroy(&m_event_thread);
981 }
982 ndb_mgm_disconnect(m_mgmsrv2);
983 }
984 }
985 else
986 {
987 DBUG_PRINT("warning",
988 ("Could not do 2:nd connect to mgmtserver for event listening"));
989 DBUG_PRINT("info", ("code: %d, msg: %s",
990 ndb_mgm_get_latest_error(m_mgmsrv2),
991 ndb_mgm_get_latest_error_msg(m_mgmsrv2)));
992 printf("Warning, event connect failed, degraded printouts as result\n");
993 printf("code: %d, msg: %s\n",
994 ndb_mgm_get_latest_error(m_mgmsrv2),
995 ndb_mgm_get_latest_error_msg(m_mgmsrv2));
996 }
997 }
998 m_connected= true;
999 DBUG_PRINT("info",("Connected to Management Server at: %s:%d", host, port));
1000 if (m_verbose)
1001 {
1002 printf("Connected to Management Server at: %s:%d\n",
1003 host, port);
1004 }
1005
1006 DBUG_RETURN(m_connected);
1007 }
1008
1009 void
disconnect(void)1010 CommandInterpreter::disconnect(void)
1011 {
1012 DBUG_ENTER("CommandInterpreter::disconnect");
1013
1014 if (m_event_thread) {
1015 void *res;
1016 do_event_thread= 0;
1017 NdbThread_WaitFor(m_event_thread, &res);
1018 NdbThread_Destroy(&m_event_thread);
1019 m_event_thread= NULL;
1020 ndb_mgm_destroy_handle(&m_mgmsrv2);
1021 }
1022 if (m_connected)
1023 {
1024 ndb_mgm_destroy_handle(&m_mgmsrv);
1025 m_connected= false;
1026 }
1027 DBUG_VOID_RETURN;
1028 }
1029
1030 //*****************************************************************************
1031 //*****************************************************************************
1032
1033 bool
execute(const char * _line,int try_reconnect,bool interactive,int * error)1034 CommandInterpreter::execute(const char *_line, int try_reconnect,
1035 bool interactive, int *error)
1036 {
1037 if (try_reconnect >= 0)
1038 m_try_reconnect = try_reconnect;
1039 bool result= execute_impl(_line, interactive);
1040 if (error)
1041 *error= m_error;
1042
1043 return result;
1044 }
1045
1046 static void
invalid_command(const char * cmd,const char * msg=0)1047 invalid_command(const char *cmd, const char *msg=0)
1048 {
1049 ndbout << "Invalid command: " << cmd << endl;
1050 if(msg)
1051 ndbout << msg << endl;
1052 ndbout << "Type HELP for help." << endl << endl;
1053 }
1054
1055
1056 // Utility class for easier checking of args
1057 // given to the commands
1058 class ClusterInfo {
1059 ndb_mgm_cluster_state* m_status;
1060
1061 public:
ClusterInfo()1062 ClusterInfo() :
1063 m_status(NULL) {};
1064
~ClusterInfo()1065 ~ClusterInfo() {
1066 if (m_status)
1067 free(m_status);
1068 }
1069
fetch(NdbMgmHandle handle,bool all_nodes=false)1070 bool fetch(NdbMgmHandle handle, bool all_nodes = false) {
1071
1072 const ndb_mgm_node_type types[2] = {
1073 NDB_MGM_NODE_TYPE_NDB,
1074 NDB_MGM_NODE_TYPE_UNKNOWN
1075 };
1076 m_status = ndb_mgm_get_status2(handle,
1077 !all_nodes ? types : 0);
1078 if (m_status == NULL)
1079 {
1080 ndbout_c("ERROR: couldn't fetch cluster status");
1081 return false;
1082 }
1083 return true;
1084 }
1085
is_valid_ndb_nodeid(int nodeid) const1086 bool is_valid_ndb_nodeid(int nodeid) const {
1087 // Check valid NDB nodeid
1088 if (nodeid < 1 || nodeid >= MAX_NDB_NODES)
1089 {
1090 ndbout_c("ERROR: illegal nodeid %d!", nodeid);
1091 return false;
1092 }
1093 return true;
1094 }
1095
is_ndb_node(int nodeid) const1096 bool is_ndb_node(int nodeid) const {
1097
1098 if (!is_valid_ndb_nodeid(nodeid))
1099 return false;
1100
1101 bool found = false;
1102 for (int i = 0; i < m_status->no_of_nodes; i++)
1103 {
1104 if (m_status->node_states[i].node_id == nodeid &&
1105 m_status->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB)
1106 {
1107 found = true;
1108 break;
1109 }
1110 }
1111
1112 if (!found)
1113 ndbout_c("ERROR: node %d is not a NDB node!", nodeid);
1114
1115 return found;
1116 }
1117 };
1118
1119
1120
1121 static void
split_args(const char * line,Vector<BaseString> & args)1122 split_args(const char* line, Vector<BaseString>& args)
1123 {
1124 // Split the command line on space
1125 BaseString tmp(line);
1126 tmp.split(args);
1127
1128 // Remove any empty args which come from double
1129 // spaces in the command line
1130 // ie. "hello<space><space>world" becomes ("hello, "", "world")
1131 //
1132 for (unsigned i= 0; i < args.size(); i++)
1133 if (args[i].length() == 0)
1134 args.erase(i--);
1135 }
1136
1137
1138 bool
execute_impl(const char * _line,bool interactive)1139 CommandInterpreter::execute_impl(const char *_line, bool interactive)
1140 {
1141 DBUG_ENTER("CommandInterpreter::execute_impl");
1142 DBUG_PRINT("enter",("line='%s'", _line));
1143 m_error= 0;
1144
1145 if(_line == NULL)
1146 {
1147 // Pressing Ctrl-C on some platforms will cause 'readline' to
1148 // to return NULL, handle it as graceful exit of ndb_mgm
1149 m_error = -1;
1150 DBUG_RETURN(false); // Terminate gracefully
1151 }
1152
1153 char* line = strdup(_line);
1154 if (line == NULL)
1155 {
1156 ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1157 m_error = -1;
1158 DBUG_RETURN(false); // Terminate gracefully
1159 }
1160 NdbAutoPtr<char> ap(line);
1161
1162 int do_continue;
1163 do {
1164 do_continue= 0;
1165 BaseString::trim(line," \t");
1166 if (line[0] == 0 ||
1167 line[0] == '#')
1168 {
1169 DBUG_RETURN(true);
1170 }
1171 // for mysql client compatability remove trailing ';'
1172 {
1173 unsigned last= (unsigned)(strlen(line)-1);
1174 if (line[last] == ';')
1175 {
1176 line[last]= 0;
1177 do_continue= 1;
1178 }
1179 }
1180 } while (do_continue);
1181
1182 // if there is anything in the line proceed
1183 Vector<BaseString> command_list;
1184 split_args(line, command_list);
1185
1186 char* firstToken = strtok(line, " ");
1187 char* allAfterFirstToken = strtok(NULL, "");
1188
1189 if (native_strcasecmp(firstToken, "HELP") == 0 ||
1190 native_strcasecmp(firstToken, "?") == 0) {
1191 m_error = executeHelp(allAfterFirstToken);
1192 DBUG_RETURN(true);
1193 }
1194 else if (native_strcasecmp(firstToken, "CONNECT") == 0) {
1195 m_error = executeConnect(allAfterFirstToken, interactive);
1196 DBUG_RETURN(true);
1197 }
1198 else if (native_strcasecmp(firstToken, "SLEEP") == 0) {
1199 if (allAfterFirstToken)
1200 NdbSleep_SecSleep(atoi(allAfterFirstToken));
1201 DBUG_RETURN(true);
1202 }
1203 else if((native_strcasecmp(firstToken, "QUIT") == 0 ||
1204 native_strcasecmp(firstToken, "EXIT") == 0 ||
1205 native_strcasecmp(firstToken, "BYE") == 0) &&
1206 allAfterFirstToken == NULL){
1207 DBUG_RETURN(false);
1208 }
1209
1210 if (!connect(interactive)){
1211 m_error = -1;
1212 DBUG_RETURN(true);
1213 }
1214
1215 if (ndb_mgm_check_connection(m_mgmsrv))
1216 {
1217 disconnect();
1218 connect(interactive);
1219 }
1220
1221 if (native_strcasecmp(firstToken, "SHOW") == 0) {
1222 Guard g(m_print_mutex);
1223 m_error = executeShow(allAfterFirstToken);
1224 DBUG_RETURN(true);
1225 }
1226 else if (native_strcasecmp(firstToken, "SHUTDOWN") == 0) {
1227 m_error= executeShutdown(allAfterFirstToken);
1228 DBUG_RETURN(true);
1229 }
1230 else if (native_strcasecmp(firstToken, "CLUSTERLOG") == 0){
1231 executeClusterLog(allAfterFirstToken);
1232 DBUG_RETURN(true);
1233 }
1234 else if(native_strcasecmp(firstToken, "START") == 0 &&
1235 allAfterFirstToken != NULL &&
1236 native_strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1237 m_error= executeStartBackup(allAfterFirstToken, interactive);
1238 DBUG_RETURN(true);
1239 }
1240 else if(native_strcasecmp(firstToken, "ABORT") == 0 &&
1241 allAfterFirstToken != NULL &&
1242 native_strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1243 m_error = executeAbortBackup(allAfterFirstToken);
1244 DBUG_RETURN(true);
1245 }
1246 else if (native_strcasecmp(firstToken, "PURGE") == 0) {
1247 m_error = executePurge(allAfterFirstToken);
1248 DBUG_RETURN(true);
1249 }
1250 else if(native_strcasecmp(firstToken, "ENTER") == 0 &&
1251 allAfterFirstToken != NULL &&
1252 allAfterFirstToken != NULL &&
1253 native_strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1254 sizeof("SINGLE USER MODE") - 1) == 0){
1255 m_error = executeEnterSingleUser(allAfterFirstToken);
1256 DBUG_RETURN(true);
1257 }
1258 else if(native_strcasecmp(firstToken, "EXIT") == 0 &&
1259 allAfterFirstToken != NULL &&
1260 native_strncasecmp(allAfterFirstToken, "SINGLE USER MODE ",
1261 sizeof("SINGLE USER MODE") - 1) == 0){
1262 m_error = executeExitSingleUser(allAfterFirstToken);
1263 DBUG_RETURN(true);
1264 }
1265 else if(native_strcasecmp(firstToken, "CREATE") == 0 &&
1266 allAfterFirstToken != NULL &&
1267 native_strncasecmp(allAfterFirstToken, "NODEGROUP",
1268 sizeof("NODEGROUP") - 1) == 0){
1269 m_error = executeCreateNodeGroup(allAfterFirstToken);
1270 DBUG_RETURN(true);
1271 }
1272 else if(native_strcasecmp(firstToken, "DROP") == 0 &&
1273 allAfterFirstToken != NULL &&
1274 native_strncasecmp(allAfterFirstToken, "NODEGROUP",
1275 sizeof("NODEGROUP") - 1) == 0){
1276 m_error = executeDropNodeGroup(allAfterFirstToken);
1277 DBUG_RETURN(true);
1278 }
1279 else if (native_strcasecmp(firstToken, "ALL") == 0) {
1280 m_error = analyseAfterFirstToken(-1, allAfterFirstToken);
1281 } else {
1282 /**
1283 * First tokens should be digits, node ID's
1284 */
1285 int node_ids[MAX_NODES];
1286 unsigned pos;
1287 for (pos= 0; pos < command_list.size(); pos++)
1288 {
1289 int node_id;
1290 if (convert(command_list[pos].c_str(), node_id))
1291 {
1292 if (node_id <= 0 || node_id > MAX_NODES) {
1293 ndbout << "Invalid node ID: " << command_list[pos].c_str()
1294 << "." << endl;
1295 DBUG_RETURN(true);
1296 }
1297 node_ids[pos]= node_id;
1298 continue;
1299 }
1300 break;
1301 }
1302 int no_of_nodes= pos;
1303 if (no_of_nodes == 0)
1304 {
1305 /* No digit found */
1306 invalid_command(_line);
1307 m_error = -1;
1308 DBUG_RETURN(true);
1309 }
1310 if (pos == command_list.size())
1311 {
1312 /* No command found */
1313 invalid_command(_line);
1314 m_error = -1;
1315 DBUG_RETURN(true);
1316 }
1317 if (no_of_nodes == 1)
1318 {
1319 m_error = analyseAfterFirstToken(node_ids[0], allAfterFirstToken);
1320 DBUG_RETURN(true);
1321 }
1322 m_error = executeCommand(command_list, pos, node_ids, no_of_nodes);
1323 DBUG_RETURN(true);
1324 }
1325 DBUG_RETURN(true);
1326 }
1327
1328
1329 /**
1330 * List of commands used as second command argument
1331 */
1332 static const CommandInterpreter::CommandFunctionPair commands[] = {
1333 { "START", &CommandInterpreter::executeStart }
1334 ,{ "RESTART", &CommandInterpreter::executeRestart }
1335 ,{ "STOP", &CommandInterpreter::executeStop }
1336 ,{ "STATUS", &CommandInterpreter::executeStatus }
1337 ,{ "LOGLEVEL", &CommandInterpreter::executeLogLevel }
1338 ,{ "CLUSTERLOG", &CommandInterpreter::executeEventReporting }
1339 #ifdef ERROR_INSERT
1340 ,{ "ERROR", &CommandInterpreter::executeError }
1341 #endif
1342 ,{ "LOG", &CommandInterpreter::executeLog }
1343 ,{ "TESTON", &CommandInterpreter::executeTestOn }
1344 ,{ "TESTOFF", &CommandInterpreter::executeTestOff }
1345 ,{ "DUMP", &CommandInterpreter::executeDumpState }
1346 ,{ "REPORT", &CommandInterpreter::executeReport }
1347 };
1348
1349
1350 //*****************************************************************************
1351 //*****************************************************************************
1352 int
analyseAfterFirstToken(int processId,char * allAfterFirstToken)1353 CommandInterpreter::analyseAfterFirstToken(int processId,
1354 char* allAfterFirstToken) {
1355
1356 int retval = 0;
1357 if (emptyString(allAfterFirstToken)) {
1358 ndbout << "Expected a command after "
1359 << ((processId == -1) ? "ALL." : "node ID.") << endl;
1360 return -1;
1361 }
1362
1363 char* secondToken = strtok(allAfterFirstToken, " ");
1364 char* allAfterSecondToken = strtok(NULL, "\0");
1365
1366 const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
1367 ExecuteFunction fun = 0;
1368 const char * command = 0;
1369 for(int i = 0; i<tmpSize; i++){
1370 if(native_strcasecmp(secondToken, commands[i].command) == 0){
1371 fun = commands[i].executeFunction;
1372 command = commands[i].command;
1373 break;
1374 }
1375 }
1376
1377 if(fun == 0){
1378 invalid_command(secondToken);
1379 return -1;
1380 }
1381
1382 if(processId == -1){
1383 retval = executeForAll(command, fun, allAfterSecondToken);
1384 } else {
1385 retval = (this->*fun)(processId, allAfterSecondToken, false);
1386 }
1387 ndbout << endl;
1388 return retval;
1389 }
1390
1391 int
executeCommand(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)1392 CommandInterpreter::executeCommand(Vector<BaseString> &command_list,
1393 unsigned command_pos,
1394 int *node_ids, int no_of_nodes)
1395 {
1396 const char *cmd= command_list[command_pos].c_str();
1397 int retval = 0;
1398
1399 if (native_strcasecmp("STOP", cmd) == 0)
1400 {
1401 retval = executeStop(command_list, command_pos+1, node_ids, no_of_nodes);
1402 return retval;
1403 }
1404 if (native_strcasecmp("RESTART", cmd) == 0)
1405 {
1406 retval = executeRestart(command_list, command_pos+1, node_ids, no_of_nodes);
1407 return retval;
1408 }
1409 if (native_strcasecmp("START", cmd) == 0)
1410 {
1411 retval = executeStart(command_list, command_pos+1, node_ids, no_of_nodes);
1412 return retval;
1413 }
1414 ndbout_c("Invalid command: '%s' after multi node id list. "
1415 "Expected STOP, START, or RESTART.", cmd);
1416 return -1;
1417 }
1418
1419 /**
1420 * Get next nodeid larger than the give node_id. node_id will be
1421 * set to the next node_id in the list. node_id should be set
1422 * to 0 (zero) on the first call.
1423 *
1424 * @param handle the NDB management handle
1425 * @param node_id last node_id retreived, 0 at first call
1426 * @param type type of node to look for
1427 * @return 1 if a node was found, 0 if no more node exist
1428 */
1429 static
1430 int
get_next_nodeid(struct ndb_mgm_cluster_state * cl,int * node_id,enum ndb_mgm_node_type type)1431 get_next_nodeid(struct ndb_mgm_cluster_state *cl,
1432 int *node_id,
1433 enum ndb_mgm_node_type type)
1434 {
1435 int i;
1436
1437 if(cl == NULL)
1438 return 0;
1439
1440 i=0;
1441 while((i < cl->no_of_nodes)) {
1442 if((*node_id < cl->node_states[i].node_id) &&
1443 (cl->node_states[i].node_type == type)) {
1444
1445 if(i >= cl->no_of_nodes)
1446 return 0;
1447
1448 *node_id = cl->node_states[i].node_id;
1449 return 1;
1450 }
1451 i++;
1452 }
1453
1454 return 0;
1455 }
1456
1457 int
executeForAll(const char * cmd,ExecuteFunction fun,const char * allAfterSecondToken)1458 CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun,
1459 const char * allAfterSecondToken)
1460 {
1461 int nodeId = 0;
1462 int retval = 0;
1463
1464 if(native_strcasecmp(cmd, "STOP") == 0) {
1465 ndbout_c("Executing STOP on all nodes.");
1466 retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1467 } else if(native_strcasecmp(cmd, "RESTART") == 0) {
1468 retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1469 } else if (native_strcasecmp(cmd, "STATUS") == 0) {
1470 (this->*fun)(nodeId, allAfterSecondToken, true);
1471 } else if (native_strcasecmp(cmd, "REPORT") == 0) {
1472 Guard g(m_print_mutex);
1473 retval = executeReport(nodeId, allAfterSecondToken, true);
1474 } else {
1475 Guard g(m_print_mutex);
1476 struct ndb_mgm_cluster_state *cl= ndb_mgm_get_status(m_mgmsrv);
1477 if(cl == 0){
1478 ndbout_c("Unable get status from management server");
1479 printError();
1480 return -1;
1481 }
1482 NdbAutoPtr<char> ap1((char*)cl);
1483 while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB))
1484 retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1485 }
1486 return retval;
1487 }
1488
1489 //*****************************************************************************
1490 //*****************************************************************************
1491 bool
parseBlockSpecification(const char * allAfterLog,Vector<BaseString> & blocks)1492 CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
1493 Vector<BaseString>& blocks)
1494 {
1495 // Parse: [BLOCK = {ALL|<blockName>+}]
1496
1497 if (emptyString(allAfterLog)) {
1498 return true;
1499 }
1500
1501 // Copy allAfterLog since strtok will modify it
1502 char* newAllAfterLog = strdup(allAfterLog);
1503 if (newAllAfterLog == NULL)
1504 {
1505 ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1506 return false; // Error parsing
1507 }
1508
1509 NdbAutoPtr<char> ap1(newAllAfterLog);
1510 char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
1511 for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
1512 firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
1513 }
1514
1515 if (native_strcasecmp(firstTokenAfterLog, "BLOCK") != 0) {
1516 ndbout << "Unexpected value: " << firstTokenAfterLog
1517 << ". Expected BLOCK." << endl;
1518 return false;
1519 }
1520
1521 char* allAfterFirstToken = strtok(NULL, "\0");
1522 if (emptyString(allAfterFirstToken)) {
1523 ndbout << "Expected =." << endl;
1524 return false;
1525 }
1526
1527 char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
1528 if (native_strcasecmp(secondTokenAfterLog, "=") != 0) {
1529 ndbout << "Unexpected value: " << secondTokenAfterLog
1530 << ". Expected =." << endl;
1531 return false;
1532 }
1533
1534 char* blockName = strtok(NULL, " ");
1535 bool all = false;
1536 if (blockName != NULL && (native_strcasecmp(blockName, "ALL") == 0)) {
1537 all = true;
1538 }
1539 while (blockName != NULL) {
1540 blocks.push_back(blockName);
1541 blockName = strtok(NULL, " ");
1542 }
1543
1544 if (blocks.size() == 0) {
1545 ndbout << "No block specified." << endl;
1546 return false;
1547 }
1548 if (blocks.size() > 1 && all) {
1549 // More than "ALL" specified
1550 ndbout << "Nothing expected after ALL." << endl;
1551 return false;
1552 }
1553
1554 return true;
1555 }
1556
1557
1558
1559 /*****************************************************************************
1560 * HELP
1561 *****************************************************************************/
1562 int
executeHelp(char * parameters)1563 CommandInterpreter::executeHelp(char* parameters)
1564 {
1565 if (emptyString(parameters)) {
1566 ndbout << helpText;
1567
1568 ndbout << endl
1569 << "<severity> = "
1570 << "ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG"
1571 << endl;
1572
1573 ndbout << "<category> = ";
1574 for(int i = CFG_MIN_LOGLEVEL; i <= CFG_MAX_LOGLEVEL; i++){
1575 const char *str= ndb_mgm_get_event_category_string((ndb_mgm_event_category)i);
1576 if (str) {
1577 if (i != CFG_MIN_LOGLEVEL)
1578 ndbout << " | ";
1579 ndbout << str;
1580 }
1581 }
1582 ndbout << endl;
1583
1584 helpTextReportTypeOptionFn();
1585
1586 ndbout << "<level> = " << "0 - 15" << endl;
1587 ndbout << "<id> = " << "ALL | Any database node id" << endl;
1588 ndbout << endl;
1589 ndbout << "For detailed help on COMMAND, use HELP COMMAND." << endl;
1590 } else {
1591 int i = 0;
1592 for (i = 0; help_items[i].cmd != NULL; i++)
1593 {
1594 if (native_strcasecmp(parameters, help_items[i].cmd) == 0)
1595 {
1596 if (help_items[i].help)
1597 ndbout << help_items[i].help;
1598 if (help_items[i].help_fn)
1599 (*help_items[i].help_fn)();
1600 break;
1601 }
1602 }
1603 if (help_items[i].cmd == NULL){
1604 ndbout << "No help for " << parameters << " available" << endl;
1605 return -1;
1606 }
1607 }
1608 return 0;
1609 }
1610
1611
1612 /*****************************************************************************
1613 * SHUTDOWN
1614 *****************************************************************************/
1615
1616 int
executeShutdown(char * parameters)1617 CommandInterpreter::executeShutdown(char* parameters)
1618 {
1619 ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1620 if(state == NULL) {
1621 ndbout_c("Could not get status");
1622 printError();
1623 return 1;
1624 }
1625 NdbAutoPtr<char> ap1((char*)state);
1626
1627 int result = 0;
1628 int need_disconnect;
1629 result = ndb_mgm_stop3(m_mgmsrv, -1, 0, 0, &need_disconnect);
1630 if (result < 0) {
1631 ndbout << "Shutdown of NDB Cluster node(s) failed." << endl;
1632 printError();
1633 return result;
1634 }
1635
1636 ndbout << result << " NDB Cluster node(s) have shutdown." << endl;
1637
1638 if(need_disconnect) {
1639 ndbout << "Disconnecting to allow management server to shutdown."
1640 << endl;
1641 disconnect();
1642 }
1643 return 0;
1644 }
1645
1646 /*****************************************************************************
1647 * SHOW
1648 *****************************************************************************/
1649
1650
1651 static
status_string(ndb_mgm_node_status status)1652 const char *status_string(ndb_mgm_node_status status)
1653 {
1654 switch(status){
1655 case NDB_MGM_NODE_STATUS_NO_CONTACT:
1656 return "not connected";
1657 case NDB_MGM_NODE_STATUS_NOT_STARTED:
1658 return "not started";
1659 case NDB_MGM_NODE_STATUS_STARTING:
1660 return "starting";
1661 case NDB_MGM_NODE_STATUS_STARTED:
1662 return "started";
1663 case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
1664 return "shutting down";
1665 case NDB_MGM_NODE_STATUS_RESTARTING:
1666 return "restarting";
1667 case NDB_MGM_NODE_STATUS_SINGLEUSER:
1668 return "single user mode";
1669 default:
1670 return "unknown state";
1671 }
1672 }
1673
1674 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)1675 print_nodes(ndb_mgm_cluster_state *state, ndb_mgm_configuration_iterator *it,
1676 const char *proc_name, int no_proc, ndb_mgm_node_type type,
1677 int master_id)
1678 {
1679 int i;
1680 ndbout << "[" << proc_name
1681 << "(" << ndb_mgm_get_node_type_string(type) << ")]\t"
1682 << no_proc << " node(s)" << endl;
1683 for(i=0; i < state->no_of_nodes; i++) {
1684 struct ndb_mgm_node_state *node_state= &(state->node_states[i]);
1685 if(node_state->node_type == type) {
1686 int node_id= node_state->node_id;
1687 ndbout << "id=" << node_id;
1688 if(node_state->version != 0) {
1689 const char *hostname= node_state->connect_address;
1690 if (hostname == 0
1691 || strlen(hostname) == 0
1692 || native_strcasecmp(hostname,"0.0.0.0") == 0)
1693 ndbout << " ";
1694 else
1695 ndbout << "\t@" << hostname;
1696
1697 char tmp[100];
1698 ndbout << " (" << ndbGetVersionString(node_state->version,
1699 node_state->mysql_version,
1700 0,
1701 tmp, sizeof(tmp));
1702 if (type == NDB_MGM_NODE_TYPE_NDB) {
1703 if (node_state->node_status != NDB_MGM_NODE_STATUS_STARTED) {
1704 ndbout << ", " << status_string(node_state->node_status);
1705 }
1706 if (node_state->node_group >= 0 && node_state->node_group != (int)RNIL) {
1707 ndbout << ", Nodegroup: " << node_state->node_group;
1708 }
1709 else if (node_state->node_group == (int)RNIL)
1710 {
1711 ndbout << ", no nodegroup";
1712 }
1713 if (node_state->node_group >= 0 || node_state->node_group == (int)RNIL)
1714 if (master_id && node_state->dynamic_id == master_id)
1715 ndbout << ", *";
1716 }
1717 ndbout << ")" << endl;
1718 } else {
1719 ndb_mgm_first(it);
1720 if(ndb_mgm_find(it, CFG_NODE_ID, node_id) == 0){
1721 const char *config_hostname= 0;
1722 ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &config_hostname);
1723 if (config_hostname == 0 || config_hostname[0] == 0)
1724 config_hostname= "any host";
1725 ndbout_c(" (not connected, accepting connect from %s)",
1726 config_hostname);
1727 }
1728 else
1729 {
1730 ndbout_c("Unable to find node with id: %d", node_id);
1731 }
1732 }
1733 }
1734 }
1735 ndbout << endl;
1736 }
1737
1738 int
executePurge(char * parameters)1739 CommandInterpreter::executePurge(char* parameters)
1740 {
1741 int command_ok= 0;
1742 do {
1743 if (emptyString(parameters))
1744 break;
1745 char* firstToken = strtok(parameters, " ");
1746 char* nextToken = strtok(NULL, " \0");
1747 if (native_strcasecmp(firstToken,"STALE") == 0 &&
1748 nextToken &&
1749 native_strcasecmp(nextToken, "SESSIONS") == 0) {
1750 command_ok= 1;
1751 break;
1752 }
1753 } while(0);
1754
1755 if (!command_ok) {
1756 ndbout_c("Unexpected command, expected: PURGE STALE SESSIONS");
1757 return -1;
1758 }
1759
1760 char *str;
1761
1762 if (ndb_mgm_purge_stale_sessions(m_mgmsrv, &str)) {
1763 ndbout_c("Command failed");
1764 return -1;
1765 }
1766 if (str) {
1767 ndbout_c("Purged sessions with node id's: %s", str);
1768 free(str);
1769 }
1770 else
1771 {
1772 ndbout_c("No sessions purged");
1773 }
1774 return 0;
1775 }
1776
1777 int
executeShow(char * parameters)1778 CommandInterpreter::executeShow(char* parameters)
1779 {
1780 int i;
1781 if (emptyString(parameters)) {
1782 ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
1783 if(state == NULL) {
1784 ndbout_c("Could not get status");
1785 printError();
1786 return -1;
1787 }
1788 NdbAutoPtr<char> ap1((char*)state);
1789
1790 ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_mgmsrv,0);
1791 if(conf == 0){
1792 ndbout_c("Could not get configuration");
1793 printError();
1794 return -1;
1795 }
1796
1797 ndb_mgm_configuration_iterator * it;
1798 it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE);
1799
1800 if(it == 0){
1801 ndbout_c("Unable to create config iterator");
1802 ndb_mgm_destroy_configuration(conf);
1803 return -1;
1804 }
1805 NdbAutoPtr<ndb_mgm_configuration_iterator> ptr(it);
1806
1807 int
1808 master_id= 0,
1809 ndb_nodes= 0,
1810 api_nodes= 0,
1811 mgm_nodes= 0;
1812
1813 for(i=0; i < state->no_of_nodes; i++) {
1814 if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB &&
1815 state->node_states[i].version != 0){
1816 master_id= state->node_states[i].dynamic_id;
1817 break;
1818 }
1819 }
1820
1821 for(i=0; i < state->no_of_nodes; i++) {
1822 switch(state->node_states[i].node_type) {
1823 case NDB_MGM_NODE_TYPE_API:
1824 api_nodes++;
1825 break;
1826 case NDB_MGM_NODE_TYPE_NDB:
1827 if (state->node_states[i].dynamic_id &&
1828 state->node_states[i].dynamic_id < master_id)
1829 master_id= state->node_states[i].dynamic_id;
1830 ndb_nodes++;
1831 break;
1832 case NDB_MGM_NODE_TYPE_MGM:
1833 mgm_nodes++;
1834 break;
1835 case NDB_MGM_NODE_TYPE_UNKNOWN:
1836 ndbout << "Error: Unknown Node Type" << endl;
1837 return -1;
1838 case NDB_MGM_NODE_TYPE_MAX:
1839 break; /* purify: deadcode */
1840 }
1841 }
1842
1843 ndbout << "Cluster Configuration" << endl
1844 << "---------------------" << endl;
1845 print_nodes(state, it, "ndbd", ndb_nodes, NDB_MGM_NODE_TYPE_NDB, master_id);
1846 print_nodes(state, it, "ndb_mgmd", mgm_nodes, NDB_MGM_NODE_TYPE_MGM, 0);
1847 print_nodes(state, it, "mysqld", api_nodes, NDB_MGM_NODE_TYPE_API, 0);
1848 ndb_mgm_destroy_configuration(conf);
1849 return 0;
1850 } else {
1851 ndbout << "Invalid argument: '" << parameters << "'" << endl;
1852 return -1;
1853 }
1854 return 0;
1855 }
1856
1857 int
executeConnect(char * parameters,bool interactive)1858 CommandInterpreter::executeConnect(char* parameters, bool interactive)
1859 {
1860 BaseString *basestring = NULL;
1861
1862 disconnect();
1863 if (!emptyString(parameters)) {
1864 basestring= new BaseString(parameters);
1865 m_constr= basestring->trim().c_str();
1866 }
1867 if ( connect(interactive) == false ){
1868 return -1;
1869 }
1870 if (basestring != NULL)
1871 delete basestring;
1872
1873 return 0;
1874 }
1875
1876 //*****************************************************************************
1877 //*****************************************************************************
1878 void
executeClusterLog(char * parameters)1879 CommandInterpreter::executeClusterLog(char* parameters)
1880 {
1881 DBUG_ENTER("CommandInterpreter::executeClusterLog");
1882 int i;
1883 if (emptyString(parameters))
1884 {
1885 ndbout_c("ERROR: Missing argument(s).");
1886 m_error = -1;
1887 DBUG_VOID_RETURN;
1888 }
1889
1890 enum ndb_mgm_event_severity severity = NDB_MGM_EVENT_SEVERITY_ALL;
1891
1892 char * tmpString = strdup(parameters);
1893 if (tmpString == NULL)
1894 {
1895 ndbout_c("ERROR: Memory allocation error at %s:%d.", __FILE__, __LINE__);
1896 m_error = -1;
1897 DBUG_VOID_RETURN;
1898 }
1899
1900 NdbAutoPtr<char> ap1(tmpString);
1901 char * tmpPtr = 0;
1902 char * item = my_strtok_r(tmpString, " ", &tmpPtr);
1903 int enable;
1904
1905 ndb_mgm_severity enabled[NDB_MGM_EVENT_SEVERITY_ALL] =
1906 {{NDB_MGM_EVENT_SEVERITY_ON,0},
1907 {NDB_MGM_EVENT_SEVERITY_DEBUG,0},
1908 {NDB_MGM_EVENT_SEVERITY_INFO,0},
1909 {NDB_MGM_EVENT_SEVERITY_WARNING,0},
1910 {NDB_MGM_EVENT_SEVERITY_ERROR,0},
1911 {NDB_MGM_EVENT_SEVERITY_CRITICAL,0},
1912 {NDB_MGM_EVENT_SEVERITY_ALERT,0}};
1913 int returned = ndb_mgm_get_clusterlog_severity_filter(m_mgmsrv,
1914 &enabled[0],
1915 NDB_MGM_EVENT_SEVERITY_ALL);
1916 if(returned != NDB_MGM_EVENT_SEVERITY_ALL) {
1917 ndbout << "Couldn't get status" << endl;
1918 printError();
1919 m_error = -1;
1920 DBUG_VOID_RETURN;
1921 }
1922
1923 /********************
1924 * CLUSTERLOG INFO
1925 ********************/
1926 if (native_strcasecmp(item, "INFO") == 0) {
1927 DBUG_PRINT("info",("INFO"));
1928 if(enabled[0].value == 0)
1929 {
1930 ndbout << "Cluster logging is disabled." << endl;
1931 m_error = 0;
1932 DBUG_VOID_RETURN;
1933 }
1934 #if 0
1935 for(i = 0; i<DB_MGM_EVENT_SEVERITY_ALL;i++)
1936 printf("enabled[%d] = %d\n", i, enabled[i].value);
1937 #endif
1938 ndbout << "Severities enabled: ";
1939 for(i = 1; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
1940 const char *str= ndb_mgm_get_event_severity_string(enabled[i].category);
1941 if (str == 0)
1942 {
1943 DBUG_ASSERT(false);
1944 continue;
1945 }
1946 if(enabled[i].value)
1947 ndbout << BaseString(str).ndb_toupper() << " ";
1948 }
1949 ndbout << endl;
1950 m_error = 0;
1951 DBUG_VOID_RETURN;
1952
1953 }
1954 else if (native_strcasecmp(item, "FILTER") == 0 ||
1955 native_strcasecmp(item, "TOGGLE") == 0)
1956 {
1957 DBUG_PRINT("info",("TOGGLE"));
1958 enable= -1;
1959 }
1960 else if (native_strcasecmp(item, "OFF") == 0)
1961 {
1962 DBUG_PRINT("info",("OFF"));
1963 enable= 0;
1964 } else if (native_strcasecmp(item, "ON") == 0) {
1965 DBUG_PRINT("info",("ON"));
1966 enable= 1;
1967 } else {
1968 ndbout << "Invalid argument." << endl;
1969 m_error = -1;
1970 DBUG_VOID_RETURN;
1971 }
1972
1973 int res_enable;
1974 item = my_strtok_r(NULL, " ", &tmpPtr);
1975 if (item == NULL) {
1976 res_enable=
1977 ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv,
1978 NDB_MGM_EVENT_SEVERITY_ON,
1979 enable, NULL);
1980 if (res_enable < 0)
1981 {
1982 ndbout << "Couldn't set filter" << endl;
1983 printError();
1984 m_error = -1;
1985 DBUG_VOID_RETURN;
1986 }
1987 ndbout << "Cluster logging is " << (res_enable ? "enabled.":"disabled") << endl;
1988 m_error = 0;
1989 DBUG_VOID_RETURN;
1990 }
1991
1992 do {
1993 severity= NDB_MGM_ILLEGAL_EVENT_SEVERITY;
1994 if (native_strcasecmp(item, "ALL") == 0) {
1995 severity = NDB_MGM_EVENT_SEVERITY_ALL;
1996 } else if (native_strcasecmp(item, "ALERT") == 0) {
1997 severity = NDB_MGM_EVENT_SEVERITY_ALERT;
1998 } else if (native_strcasecmp(item, "CRITICAL") == 0) {
1999 severity = NDB_MGM_EVENT_SEVERITY_CRITICAL;
2000 } else if (native_strcasecmp(item, "ERROR") == 0) {
2001 severity = NDB_MGM_EVENT_SEVERITY_ERROR;
2002 } else if (native_strcasecmp(item, "WARNING") == 0) {
2003 severity = NDB_MGM_EVENT_SEVERITY_WARNING;
2004 } else if (native_strcasecmp(item, "INFO") == 0) {
2005 severity = NDB_MGM_EVENT_SEVERITY_INFO;
2006 } else if (native_strcasecmp(item, "DEBUG") == 0) {
2007 severity = NDB_MGM_EVENT_SEVERITY_DEBUG;
2008 } else if (native_strcasecmp(item, "OFF") == 0 ||
2009 native_strcasecmp(item, "ON") == 0) {
2010 if (enable < 0) // only makes sense with toggle
2011 severity = NDB_MGM_EVENT_SEVERITY_ON;
2012 }
2013 if (severity == NDB_MGM_ILLEGAL_EVENT_SEVERITY) {
2014 ndbout << "Invalid severity level: " << item << endl;
2015 m_error = -1;
2016 DBUG_VOID_RETURN;
2017 }
2018
2019 res_enable= ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv, severity,
2020 enable, NULL);
2021 if (res_enable < 0)
2022 {
2023 ndbout << "Couldn't set filter" << endl;
2024 printError();
2025 m_error = -1;
2026 DBUG_VOID_RETURN;
2027 }
2028 ndbout << BaseString(item).ndb_toupper().c_str() << " " << (res_enable ? "enabled":"disabled") << endl;
2029
2030 item = my_strtok_r(NULL, " ", &tmpPtr);
2031 } while(item != NULL);
2032
2033 m_error = 0;
2034 DBUG_VOID_RETURN;
2035 }
2036
2037 //*****************************************************************************
2038 //*****************************************************************************
2039
2040 int
executeStop(int processId,const char * parameters,bool all)2041 CommandInterpreter::executeStop(int processId, const char *parameters,
2042 bool all)
2043 {
2044 Vector<BaseString> command_list;
2045 if (parameters)
2046 split_args(parameters, command_list);
2047
2048 int retval;
2049 if (all)
2050 retval = executeStop(command_list, 0, 0, 0);
2051 else
2052 retval = executeStop(command_list, 0, &processId, 1);
2053
2054 return retval;
2055 }
2056
2057 int
executeStop(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)2058 CommandInterpreter::executeStop(Vector<BaseString> &command_list,
2059 unsigned command_pos,
2060 int *node_ids, int no_of_nodes)
2061 {
2062 int need_disconnect;
2063 int abort= 0;
2064 int retval = 0;
2065 int force = 0;
2066
2067 for (; command_pos < command_list.size(); command_pos++)
2068 {
2069 const char *item= command_list[command_pos].c_str();
2070 if (native_strcasecmp(item, "-A") == 0)
2071 {
2072 abort= 1;
2073 continue;
2074 }
2075 if (native_strcasecmp(item, "-F") == 0)
2076 {
2077 force = 1;
2078 continue;
2079 }
2080 ndbout_c("Invalid option: %s. Expecting -A or -F after STOP",
2081 item);
2082 return -1;
2083 }
2084
2085 int result= ndb_mgm_stop4(m_mgmsrv, no_of_nodes, node_ids, abort,
2086 force, &need_disconnect);
2087 if (result < 0)
2088 {
2089 ndbout_c("Shutdown failed.");
2090 printError();
2091 retval = -1;
2092 }
2093 else
2094 {
2095 if (node_ids == 0)
2096 ndbout_c("NDB Cluster has shutdown.");
2097 else
2098 {
2099 ndbout << "Node";
2100 for (int i= 0; i < no_of_nodes; i++)
2101 ndbout << " " << node_ids[i];
2102 ndbout_c(" has shutdown.");
2103 }
2104 }
2105
2106 if(need_disconnect)
2107 {
2108 ndbout << "Disconnecting to allow Management Server to shutdown" << endl;
2109 disconnect();
2110 }
2111
2112 return retval;
2113 }
2114
2115 int
executeEnterSingleUser(char * parameters)2116 CommandInterpreter::executeEnterSingleUser(char* parameters)
2117 {
2118 strtok(parameters, " ");
2119 struct ndb_mgm_reply reply;
2120 char* id = strtok(NULL, " ");
2121 id = strtok(NULL, " ");
2122 id = strtok(NULL, "\0");
2123 int nodeId = -1;
2124 if(id == 0 || sscanf(id, "%d", &nodeId) != 1){
2125 ndbout_c("Invalid arguments: expected <NodeId>");
2126 ndbout_c("Use SHOW to see what API nodes are configured");
2127 return -1;
2128 }
2129 int result = ndb_mgm_enter_single_user(m_mgmsrv, nodeId, &reply);
2130
2131 if (result != 0) {
2132 ndbout_c("Entering single user mode for node %d failed", nodeId);
2133 printError();
2134 return -1;
2135 } else {
2136 ndbout_c("Single user mode entered");
2137 ndbout_c("Access is granted for API node %d only.", nodeId);
2138 }
2139 return 0;
2140 }
2141
2142 int
executeExitSingleUser(char * parameters)2143 CommandInterpreter::executeExitSingleUser(char* parameters)
2144 {
2145 int result = ndb_mgm_exit_single_user(m_mgmsrv, 0);
2146 if (result != 0) {
2147 ndbout_c("Exiting single user mode failed.");
2148 printError();
2149 return -1;
2150 } else {
2151 ndbout_c("Exiting single user mode in progress.");
2152 ndbout_c("Use ALL STATUS or SHOW to see when single user mode has been exited.");
2153 return 0;
2154 }
2155 }
2156
2157 int
executeStart(int processId,const char * parameters,bool all)2158 CommandInterpreter::executeStart(int processId, const char* parameters,
2159 bool all)
2160 {
2161 int result;
2162 int retval = 0;
2163 if(all) {
2164 result = ndb_mgm_start(m_mgmsrv, 0, 0);
2165 } else {
2166 result = ndb_mgm_start(m_mgmsrv, 1, &processId);
2167 }
2168
2169 if (result <= 0) {
2170 ndbout << "Start failed." << endl;
2171 printError();
2172 retval = -1;
2173 } else
2174 {
2175 if(all)
2176 ndbout_c("NDB Cluster is being started.");
2177 else
2178 ndbout_c("Database node %d is being started.", processId);
2179 }
2180 return retval;
2181 }
2182
2183 int
executeStart(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)2184 CommandInterpreter::executeStart(Vector<BaseString> &command_list,
2185 unsigned command_pos,
2186 int *node_ids, int no_of_nodes)
2187 {
2188 int result;
2189 result= ndb_mgm_start(m_mgmsrv, no_of_nodes, node_ids);
2190
2191 if (result <= 0) {
2192 ndbout_c("Start failed.");
2193 printError();
2194 return -1;
2195 }
2196 else
2197 {
2198 ndbout << "Node";
2199 for (int i= 0; i < no_of_nodes; i++)
2200 ndbout << " " << node_ids[i];
2201 ndbout_c(" is being started");
2202 }
2203 return 0;
2204 }
2205
2206 int
executeRestart(int processId,const char * parameters,bool all)2207 CommandInterpreter::executeRestart(int processId, const char* parameters,
2208 bool all)
2209 {
2210 Vector<BaseString> command_list;
2211 if (parameters)
2212 split_args(parameters, command_list);
2213
2214 int retval;
2215 if (all)
2216 retval = executeRestart(command_list, 0, 0, 0);
2217 else
2218 retval = executeRestart(command_list, 0, &processId, 1);
2219
2220 return retval;
2221 }
2222
2223 int
executeRestart(Vector<BaseString> & command_list,unsigned command_pos,int * node_ids,int no_of_nodes)2224 CommandInterpreter::executeRestart(Vector<BaseString> &command_list,
2225 unsigned command_pos,
2226 int *node_ids, int no_of_nodes)
2227 {
2228 int result;
2229 int retval = 0;
2230 int nostart= 0;
2231 int initialstart= 0;
2232 int abort= 0;
2233 int need_disconnect= 0;
2234 int force = 0;
2235
2236 for (; command_pos < command_list.size(); command_pos++)
2237 {
2238 const char *item= command_list[command_pos].c_str();
2239 if (native_strcasecmp(item, "-N") == 0)
2240 {
2241 nostart= 1;
2242 continue;
2243 }
2244 if (native_strcasecmp(item, "-I") == 0)
2245 {
2246 initialstart= 1;
2247 continue;
2248 }
2249 if (native_strcasecmp(item, "-A") == 0)
2250 {
2251 abort= 1;
2252 continue;
2253 }
2254 if (native_strcasecmp(item, "-F") == 0)
2255 {
2256 force = 1;
2257 continue;
2258 }
2259 ndbout_c("Invalid option: %s. Expecting -A,-N,-I or -F after RESTART",
2260 item);
2261 return -1;
2262 }
2263
2264 struct ndb_mgm_cluster_state *cl = ndb_mgm_get_status(m_mgmsrv);
2265 if(cl == NULL)
2266 {
2267 ndbout_c("Could not get status");
2268 printError();
2269 return -1;
2270 }
2271 NdbAutoPtr<char> ap1((char*)cl);
2272
2273 // We allow 'all restart' in single user mode
2274 if(node_ids != 0) {
2275 for (int i = 0; i<cl->no_of_nodes; i++) {
2276 if((cl->node_states+i)->node_status == NDB_MGM_NODE_STATUS_SINGLEUSER)
2277 {
2278 ndbout_c("Cannot restart nodes: single user mode");
2279 return -1;
2280 }
2281 }
2282 }
2283
2284 if (node_ids == 0) {
2285 ndbout_c("Executing RESTART on all nodes.");
2286 ndbout_c("Starting shutdown. This may take a while. Please wait...");
2287 }
2288
2289 for (int i= 0; i < no_of_nodes; i++)
2290 {
2291 int j = 0;
2292 while((j < cl->no_of_nodes) && cl->node_states[j].node_id != node_ids[i])
2293 j++;
2294
2295 if(cl->node_states[j].node_id != node_ids[i])
2296 {
2297 ndbout << node_ids[i] << ": Node not found" << endl;
2298 return -1;
2299 }
2300
2301 if(cl->node_states[j].node_type == NDB_MGM_NODE_TYPE_MGM)
2302 {
2303 ndbout << "Shutting down MGM node"
2304 << " " << node_ids[i] << " for restart" << endl;
2305 }
2306 }
2307
2308 result= ndb_mgm_restart4(m_mgmsrv, no_of_nodes, node_ids,
2309 initialstart, nostart, abort, force,
2310 &need_disconnect);
2311
2312 if (result <= 0) {
2313 ndbout_c("Restart failed.");
2314 printError();
2315 retval = -1;
2316 }
2317 else
2318 {
2319 if (node_ids == 0)
2320 ndbout_c("All DB nodes are being restarted.");
2321 else
2322 {
2323 ndbout << "Node";
2324 for (int i= 0; i < no_of_nodes; i++)
2325 ndbout << " " << node_ids[i];
2326 ndbout_c(" is being restarted");
2327 }
2328 if(need_disconnect)
2329 disconnect();
2330 }
2331 return retval;
2332 }
2333
2334 /**
2335 * print status of one node
2336 */
2337 static
2338 void
print_status(const ndb_mgm_node_state * state)2339 print_status(const ndb_mgm_node_state * state)
2340 {
2341 Uint32 version = state->version;
2342 if (state->node_type != NDB_MGM_NODE_TYPE_NDB)
2343 {
2344 if (version != 0)
2345 {
2346 ndbout << "Node " << state->node_id <<": connected" ;
2347 ndbout_c(" (Version %d.%d.%d)",
2348 getMajor(version) ,
2349 getMinor(version),
2350 getBuild(version));
2351
2352 }
2353 else
2354 {
2355 ndbout << "Node " << state->node_id << ": not connected" << endl;
2356 }
2357 return;
2358 }
2359
2360 ndbout << "Node " << state->node_id
2361 << ": " << status_string(state->node_status);
2362 switch(state->node_status){
2363 case NDB_MGM_NODE_STATUS_STARTING:
2364 ndbout << " (Last completed phase " << state->start_phase << ")";
2365 break;
2366 case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
2367 ndbout << " (Last completed phase " << state->start_phase << ")";
2368 break;
2369 default:
2370 break;
2371 }
2372
2373 if(state->node_status != NDB_MGM_NODE_STATUS_NO_CONTACT)
2374 {
2375 char tmp[100];
2376 ndbout_c(" (%s)", ndbGetVersionString(version,
2377 state->mysql_version, 0,
2378 tmp, sizeof(tmp)));
2379 }
2380 else
2381 {
2382 ndbout << endl;
2383 }
2384 }
2385
2386 int
executeStatus(int processId,const char * parameters,bool all)2387 CommandInterpreter::executeStatus(int processId,
2388 const char* parameters, bool all)
2389 {
2390 if (! emptyString(parameters)) {
2391 ndbout_c("No parameters expected to this command.");
2392 return -1;
2393 }
2394
2395 ndb_mgm_node_type types[2] = {
2396 NDB_MGM_NODE_TYPE_NDB,
2397 NDB_MGM_NODE_TYPE_UNKNOWN
2398 };
2399 struct ndb_mgm_cluster_state *cl;
2400 cl = ndb_mgm_get_status2(m_mgmsrv, all ? types : 0);
2401 if(cl == NULL)
2402 {
2403 ndbout_c("Can't get status of node %d.", processId);
2404 printError();
2405 return -1;
2406 }
2407 NdbAutoPtr<char> ap1((char*)cl);
2408
2409 if (all)
2410 {
2411 for (int i = 0; i<cl->no_of_nodes; i++)
2412 print_status(cl->node_states+i);
2413 return 0;
2414 }
2415 else
2416 {
2417 for (int i = 0; i<cl->no_of_nodes; i++)
2418 {
2419 if (cl->node_states[i].node_id == processId)
2420 {
2421 print_status(cl->node_states + i);
2422 return 0;
2423 }
2424 }
2425 ndbout << processId << ": Node not found" << endl;
2426 return -1;
2427 }
2428 return 0;
2429 } //
2430
2431 int
executeDumpState(int processId,const char * parameters,bool all)2432 CommandInterpreter::executeDumpState(int processId, const char* parameters,
2433 bool all)
2434 {
2435 if(emptyString(parameters))
2436 {
2437 ndbout_c("ERROR: Expected argument!");
2438 return -1;
2439 }
2440
2441 int params[25];
2442 int num_params = 0;
2443 const size_t max_params = sizeof(params)/sizeof(params[0]);
2444
2445 Vector<BaseString> args;
2446 split_args(parameters, args);
2447
2448 if (args.size() > max_params)
2449 {
2450 ndbout_c("ERROR: Too many arguments, max %d allowed", (int)max_params);
2451 return -1;
2452 }
2453
2454 for (unsigned i = 0; i < args.size(); i++)
2455 {
2456 const char* arg = args[i].c_str();
2457
2458 if (my_strtoll(arg, NULL, 0) < 0 ||
2459 my_strtoll(arg, NULL, 0) > 0xffffffff)
2460 {
2461 ndbout_c("ERROR: Illegal value '%s' in argument to signal.\n"
2462 "(Value must be between 0 and 0xffffffff.)", arg);
2463 return -1;
2464 }
2465 assert(num_params < (int)max_params);
2466 params[num_params] = (int)my_strtoll(arg, NULL, 0);
2467 num_params++;
2468 }
2469
2470 ndbout << "Sending dump signal with data:" << endl;
2471 for (int i = 0; i < num_params; i++)
2472 {
2473 ndbout.setHexFormat(1) << params[i] << " ";
2474 if (!((i+1) & 0x3)) ndbout << endl;
2475 }
2476 ndbout << endl;
2477
2478 struct ndb_mgm_reply reply;
2479 return ndb_mgm_dump_state(m_mgmsrv, processId, params, num_params, &reply);
2480 }
2481
2482 static void
report_memoryusage(const ndb_logevent & event)2483 report_memoryusage(const ndb_logevent& event)
2484 {
2485 const ndb_logevent_MemoryUsage& usage = event.MemoryUsage;
2486 const Uint32 block = usage.block;
2487 const Uint32 total = usage.pages_total;
2488 const Uint32 used = usage.pages_used;
2489 assert(event.type == NDB_LE_MemoryUsage);
2490
2491 ndbout_c("Node %u: %s usage is %d%%(%d %dK pages of total %d)",
2492 event.source_nodeid,
2493 (block == DBACC ? "Index" : (block == DBTUP ? "Data" : "<unknown>")),
2494 (total ? (used * 100 / total) : 0),
2495 used,
2496 usage.page_size_kb/1024,
2497 total);
2498 }
2499
2500
2501 static void
report_backupstatus(const ndb_logevent & event)2502 report_backupstatus(const ndb_logevent& event)
2503 {
2504 const ndb_logevent_BackupStatus& status = event.BackupStatus;
2505 assert(event.type == NDB_LE_BackupStatus);
2506
2507
2508 if (status.starting_node)
2509 ndbout_c("Node %u: Local backup status: backup %u started from node %u\n"
2510 " #Records: %llu #LogRecords: %llu\n"
2511 " Data: %llu bytes Log: %llu bytes",
2512 event.source_nodeid,
2513 status.backup_id,
2514 refToNode(status.starting_node),
2515 make_uint64(status.n_records_lo, status.n_records_hi),
2516 make_uint64(status.n_log_records_lo, status.n_log_records_hi),
2517 make_uint64(status.n_bytes_lo, status.n_bytes_hi),
2518 make_uint64(status.n_log_bytes_lo, status.n_log_bytes_hi));
2519 else
2520 ndbout_c("Node %u: Backup not started",
2521 event.source_nodeid);
2522 }
2523
2524 static
2525 void
report_events(const ndb_logevent & event)2526 report_events(const ndb_logevent& event)
2527 {
2528 Uint32 threshold = 0;
2529 Logger::LoggerLevel severity = Logger::LL_WARNING;
2530 LogLevel::EventCategory cat= LogLevel::llInvalid;
2531 EventLogger::EventTextFunction textF;
2532
2533 const EventReport * real_event = (const EventReport*)event.SavedEvent.data;
2534 Uint32 type = real_event->getEventType();
2535
2536 if (EventLoggerBase::event_lookup(type,cat,threshold,severity,textF))
2537 return;
2538
2539 char out[1024];
2540 Uint32 pos = 0;
2541 if (event.source_nodeid != 0)
2542 {
2543 BaseString::snprintf(out, sizeof(out), "Node %u: ", event.source_nodeid);
2544 pos= (Uint32)strlen(out);
2545 }
2546 textF(out+pos, sizeof(out)-pos, event.SavedEvent.data, event.SavedEvent.len);
2547
2548 char timestamp_str[64];
2549 Logger::format_timestamp(event.SavedEvent.time, timestamp_str, sizeof(timestamp_str));
2550
2551 ndbout_c("%s %s", timestamp_str, out);
2552 }
2553
2554 static int
sort_log(const void * _a,const void * _b)2555 sort_log(const void *_a, const void *_b)
2556 {
2557 const ndb_logevent * a = (const ndb_logevent*)_a;
2558 const ndb_logevent * b = (const ndb_logevent*)_b;
2559
2560 if (a->source_nodeid == b->source_nodeid)
2561 {
2562 return a->SavedEvent.seq - b->SavedEvent.seq;
2563 }
2564
2565 if (a->SavedEvent.time < b->SavedEvent.time)
2566 return -1;
2567 if (a->SavedEvent.time > b->SavedEvent.time)
2568 return 1;
2569
2570 if (a->SavedEvent.seq < b->SavedEvent.seq)
2571 return -1;
2572 if (a->SavedEvent.seq > b->SavedEvent.seq)
2573 return 1;
2574
2575 return (a->source_nodeid - b->source_nodeid);
2576 }
2577
2578 static const
2579 struct st_report_cmd {
2580 const char *name;
2581 const char *help;
2582 Ndb_logevent_type type;
2583 void (*print_event_fn)(const ndb_logevent&);
2584 int (* sort_fn)(const void *_a, const void *_b);
2585 } report_cmds[] = {
2586
2587 { "BackupStatus",
2588 "Report backup status of respective node",
2589 NDB_LE_BackupStatus,
2590 report_backupstatus, 0 },
2591
2592 { "MemoryUsage",
2593 "Report memory usage of respective node",
2594 NDB_LE_MemoryUsage,
2595 report_memoryusage, 0 },
2596
2597 { "EventLog",
2598 "Report events in datanodes circular event log buffer",
2599 NDB_LE_SavedEvent,
2600 report_events, sort_log },
2601
2602 { 0, 0, NDB_LE_ILLEGAL_TYPE, 0, 0 }
2603 };
2604
2605
2606 int
executeReport(int nodeid,const char * parameters,bool all)2607 CommandInterpreter::executeReport(int nodeid, const char* parameters,
2608 bool all)
2609 {
2610 if (emptyString(parameters))
2611 {
2612 ndbout_c("ERROR: missing report type specifier!");
2613 return -1;
2614 }
2615
2616 Vector<BaseString> args;
2617 split_args(parameters, args);
2618
2619 const st_report_cmd* report_cmd = report_cmds;
2620 for (; report_cmd->name; report_cmd++)
2621 {
2622 if (native_strncasecmp(report_cmd->name, args[0].c_str(),
2623 args[0].length()) == 0)
2624 break;
2625 }
2626
2627 if (!report_cmd->name)
2628 {
2629 ndbout_c("ERROR: '%s' - report type specifier unknown!", args[0].c_str());
2630 return -1;
2631 }
2632
2633 if (!all)
2634 {
2635 ClusterInfo info;
2636 if (!info.fetch(m_mgmsrv))
2637 {
2638 printError();
2639 return -1;
2640 }
2641
2642 // Check that given nodeid is a NDB node
2643 if (!info.is_ndb_node(nodeid))
2644 return -1;
2645 }
2646
2647 struct ndb_mgm_events* events =
2648 ndb_mgm_dump_events(m_mgmsrv, report_cmd->type,
2649 all ? 0 : 1, &nodeid);
2650 if (!events)
2651 {
2652 ndbout_c("ERROR: failed to fetch report!");
2653 printError();
2654 return -1;
2655 }
2656
2657 if (report_cmd->sort_fn)
2658 {
2659 qsort(events->events, events->no_of_events,
2660 sizeof(events->events[0]), report_cmd->sort_fn);
2661 }
2662
2663 for (int i = 0; i < events->no_of_events; i++)
2664 {
2665 const ndb_logevent& event = events->events[i];
2666 report_cmd->print_event_fn(event);
2667 }
2668
2669 free(events);
2670 return 0;
2671 }
2672
2673
2674 static void
helpTextReportFn()2675 helpTextReportFn()
2676 {
2677 ndbout_c(" <report-type> =");
2678 const st_report_cmd* report_cmd = report_cmds;
2679 for (; report_cmd->name; report_cmd++)
2680 ndbout_c(" %s\t- %s", report_cmd->name, report_cmd->help);
2681 }
2682
2683 static void
helpTextReportTypeOptionFn()2684 helpTextReportTypeOptionFn()
2685 {
2686 ndbout << "<report-type> = ";
2687 const st_report_cmd* report_cmd = report_cmds;
2688 for (; report_cmd->name; report_cmd++){
2689 if (report_cmd != report_cmds)
2690 ndbout << " | ";
2691 ndbout << BaseString(report_cmd->name).ndb_toupper().c_str();
2692 }
2693 ndbout << endl;
2694 }
2695
2696 //*****************************************************************************
2697 //*****************************************************************************
2698
2699 int
executeLogLevel(int processId,const char * parameters,bool all)2700 CommandInterpreter::executeLogLevel(int processId, const char* parameters,
2701 bool all)
2702 {
2703 (void) all;
2704 if (emptyString(parameters)) {
2705 ndbout << "Expected argument" << endl;
2706 return -1;
2707 }
2708 BaseString tmp(parameters);
2709 Vector<BaseString> spec;
2710 tmp.split(spec, "=");
2711 if(spec.size() != 2){
2712 ndbout << "Invalid loglevel specification: " << parameters << endl;
2713 return -1;
2714 }
2715
2716 spec[0].trim().ndb_toupper();
2717 int category = ndb_mgm_match_event_category(spec[0].c_str());
2718 if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2719 category = atoi(spec[0].c_str());
2720 if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
2721 category > NDB_MGM_MAX_EVENT_CATEGORY){
2722 ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2723 return -1;
2724 }
2725 }
2726
2727 int level = atoi(spec[1].c_str());
2728 if(level < 0 || level > 15){
2729 ndbout << "Invalid level: " << spec[1].c_str() << endl;
2730 return -1;
2731 }
2732
2733 ndbout << "Executing LOGLEVEL on node " << processId << flush;
2734
2735 struct ndb_mgm_reply reply;
2736 int result;
2737 result = ndb_mgm_set_loglevel_node(m_mgmsrv,
2738 processId,
2739 (ndb_mgm_event_category)category,
2740 level,
2741 &reply);
2742
2743 if (result < 0) {
2744 ndbout_c(" failed.");
2745 printError();
2746 return -1;
2747 } else {
2748 ndbout_c(" OK!");
2749 }
2750 return 0;
2751 }
2752
2753 //*****************************************************************************
2754 //*****************************************************************************
executeError(int processId,const char * parameters,bool)2755 int CommandInterpreter::executeError(int processId,
2756 const char* parameters, bool /* all */)
2757 {
2758 if (emptyString(parameters))
2759 {
2760 ndbout_c("ERROR: Missing error number.");
2761 return -1;
2762 }
2763
2764 Vector<BaseString> args;
2765 split_args(parameters, args);
2766
2767 if (args.size() >= 2)
2768 {
2769 ndbout << "ERROR: Too many arguments." << endl;
2770 return -1;
2771 }
2772
2773 int errorNo;
2774 if (! convert(args[0].c_str(), errorNo)) {
2775 ndbout << "ERROR: Expected an integer." << endl;
2776 return -1;
2777 }
2778
2779 return ndb_mgm_insert_error(m_mgmsrv, processId, errorNo, NULL);
2780 }
2781
2782 //*****************************************************************************
2783 //*****************************************************************************
2784
2785 int
executeLog(int processId,const char * parameters,bool all)2786 CommandInterpreter::executeLog(int processId,
2787 const char* parameters, bool all)
2788 {
2789 struct ndb_mgm_reply reply;
2790 Vector<BaseString> blocks;
2791 if (! parseBlockSpecification(parameters, blocks)) {
2792 return -1;
2793 }
2794
2795 BaseString block_names;
2796 for (unsigned i = 0; i<blocks.size(); i++)
2797 block_names.appfmt("%s|", blocks[i].c_str());
2798
2799 int result = ndb_mgm_log_signals(m_mgmsrv,
2800 processId,
2801 NDB_MGM_SIGNAL_LOG_MODE_INOUT,
2802 block_names.c_str(),
2803 &reply);
2804 if (result != 0) {
2805 ndbout_c("Execute LOG on node %d failed.", processId);
2806 printError();
2807 return -1;
2808 }
2809 return 0;
2810 }
2811
2812
2813 //*****************************************************************************
2814 //*****************************************************************************
2815 int
executeTestOn(int processId,const char * parameters,bool)2816 CommandInterpreter::executeTestOn(int processId,
2817 const char* parameters, bool /*all*/)
2818 {
2819 if (! emptyString(parameters)) {
2820 ndbout << "No parameters expected to this command." << endl;
2821 return -1;
2822 }
2823 struct ndb_mgm_reply reply;
2824 int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply);
2825 if (result != 0) {
2826 ndbout_c("Execute TESTON failed.");
2827 printError();
2828 return -1;
2829 }
2830 return 0;
2831 }
2832
2833 //*****************************************************************************
2834 //*****************************************************************************
2835 int
executeTestOff(int processId,const char * parameters,bool)2836 CommandInterpreter::executeTestOff(int processId,
2837 const char* parameters, bool /*all*/)
2838 {
2839 if (! emptyString(parameters)) {
2840 ndbout << "No parameters expected to this command." << endl;
2841 return -1;
2842 }
2843 struct ndb_mgm_reply reply;
2844 int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply);
2845 if (result != 0) {
2846 ndbout_c("Execute TESTOFF failed.");
2847 printError();
2848 return -1;
2849 }
2850 return 0;
2851 }
2852
2853
2854 //*****************************************************************************
2855 //*****************************************************************************
2856
2857 int
executeEventReporting(int processId,const char * parameters,bool all)2858 CommandInterpreter::executeEventReporting(int processId,
2859 const char* parameters,
2860 bool all)
2861 {
2862 int retval = 0;
2863 if (emptyString(parameters)) {
2864 ndbout << "Expected argument" << endl;
2865 return -1;
2866 }
2867
2868 Vector<BaseString> specs;
2869 split_args(parameters, specs);
2870
2871 for (int i=0; i < (int) specs.size(); i++)
2872 {
2873 Vector<BaseString> spec;
2874 specs[i].split(spec, "=");
2875 if(spec.size() != 2){
2876 ndbout << "Invalid loglevel specification: " << specs[i] << endl;
2877 continue;
2878 }
2879
2880 spec[0].trim().ndb_toupper();
2881 int category = ndb_mgm_match_event_category(spec[0].c_str());
2882 if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
2883 if(!convert(spec[0].c_str(), category) ||
2884 category < NDB_MGM_MIN_EVENT_CATEGORY ||
2885 category > NDB_MGM_MAX_EVENT_CATEGORY){
2886 ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2887 continue;
2888 }
2889 }
2890
2891 int level;
2892 if (!convert(spec[1].c_str(),level))
2893 {
2894 ndbout << "Invalid level: " << spec[1].c_str() << endl;
2895 continue;
2896 }
2897
2898 ndbout << "Executing CLUSTERLOG " << spec[0] << "=" << spec[1]
2899 << " on node " << processId << flush;
2900
2901 struct ndb_mgm_reply reply;
2902 int result;
2903 result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv,
2904 processId,
2905 (ndb_mgm_event_category)category,
2906 level,
2907 &reply);
2908
2909 if (result != 0) {
2910 ndbout_c(" failed.");
2911 printError();
2912 retval = -1;
2913 } else {
2914 ndbout_c(" OK!");
2915 }
2916 }
2917 return retval;
2918 }
2919
2920
2921 /*****************************************************************************
2922 * Backup
2923 *****************************************************************************/
2924 int
executeStartBackup(char * parameters,bool interactive)2925 CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
2926 {
2927 struct ndb_mgm_reply reply;
2928 unsigned int backupId;
2929 unsigned int input_backupId = 0;
2930 unsigned long long int tmp_backupId = 0;
2931
2932 Vector<BaseString> args;
2933 if (parameters)
2934 split_args(parameters, args);
2935
2936 for (unsigned i= 0; i < args.size(); i++)
2937 args[i].ndb_toupper();
2938
2939 int sz= args.size();
2940
2941 int result;
2942 int flags = 2;
2943 //1,snapshot at start time. 0 snapshot at end time
2944 unsigned int backuppoint = 0;
2945 bool b_log = false;
2946 bool b_nowait = false;
2947 bool b_wait_completed = false;
2948 bool b_wait_started = false;
2949
2950 /*
2951 All the commands list as follow:
2952 start backup <backupid> nowait | start backup <backupid> snapshotstart/snapshotend nowati | start backup <backupid> nowait snapshotstart/snapshotend
2953 start backup <backupid> | start backup <backupid> wait completed | start backup <backupid> snapshotstart/snapshotend
2954 start backup <backupid> snapshotstart/snapshotend wait completed | start backup <backupid> wait completed snapshotstart/snapshotend
2955 start backup <backupid> wait started | start backup <backupid> snapshotstart/snapshotend wait started
2956 start backup <backupid> wait started snapshotstart/snapshotend
2957 */
2958 for (int i= 1; i < sz; i++)
2959 {
2960 if (i == 1 && sscanf(args[1].c_str(), "%llu", &tmp_backupId) == 1) {
2961 char out[1024];
2962 BaseString::snprintf(out, sizeof(out), "%u: ", MAX_BACKUPS);
2963 // to detect wraparound due to overflow, check if number of digits in
2964 // input backup ID <= number of digits in max backup ID
2965 if (tmp_backupId > 0 && tmp_backupId < MAX_BACKUPS && args[1].length() <= strlen(out)) {
2966 input_backupId = static_cast<unsigned>(tmp_backupId);
2967 continue;
2968 } else {
2969 BaseString::snprintf(out, sizeof(out), "Backup ID out of range [1 - %u]", MAX_BACKUPS-1);
2970 invalid_command(parameters, out);
2971 return -1;
2972 }
2973 }
2974
2975 if (args[i] == "SNAPSHOTEND") {
2976 if (b_log ==true) {
2977 invalid_command(parameters);
2978 return -1;
2979 }
2980 b_log = true;
2981 backuppoint = 0;
2982 continue;
2983 }
2984 if (args[i] == "SNAPSHOTSTART") {
2985 if (b_log ==true) {
2986 invalid_command(parameters);
2987 return -1;
2988 }
2989 b_log = true;
2990 backuppoint = 1;
2991 continue;
2992 }
2993 if (args[i] == "NOWAIT") {
2994 if (b_nowait == true || b_wait_completed == true || b_wait_started ==true) {
2995 invalid_command(parameters);
2996 return -1;
2997 }
2998 b_nowait = true;
2999 flags = 0;
3000 continue;
3001 }
3002 if (args[i] == "WAIT") {
3003 if (b_nowait == true || b_wait_completed == true || b_wait_started ==true) {
3004 invalid_command(parameters);
3005 return -1;
3006 }
3007 if (i+1 < sz) {
3008 if (args[i+1] == "COMPLETED") {
3009 b_wait_completed = true;
3010 flags = 2;
3011 i++;
3012 }
3013 else if (args[i+1] == "STARTED") {
3014 b_wait_started = true;
3015 flags = 1;
3016 i++;
3017 }
3018 else {
3019 invalid_command(parameters);
3020 return -1;
3021 }
3022 }
3023 else {
3024 invalid_command(parameters);
3025 return -1;
3026 }
3027 continue;
3028 }
3029 invalid_command(parameters);
3030 return -1;
3031 }
3032
3033 //print message
3034 if (flags == 2)
3035 ndbout_c("Waiting for completed, this may take several minutes");
3036 if (flags == 1)
3037 ndbout_c("Waiting for started, this may take several minutes");
3038
3039 NdbLogEventHandle log_handle= NULL;
3040 struct ndb_logevent log_event;
3041 if (flags > 0 && !interactive)
3042 {
3043 int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0, 0 };
3044 log_handle = ndb_mgm_create_logevent_handle(m_mgmsrv, filter);
3045 if (!log_handle)
3046 {
3047 ndbout << "Initializing start of backup failed" << endl;
3048 printError();
3049 return -1;
3050 }
3051 }
3052
3053 //start backup N | start backup snapshotstart/snapshotend
3054 if (input_backupId > 0 || b_log == true)
3055 result = ndb_mgm_start_backup3(m_mgmsrv, flags, &backupId, &reply, input_backupId, backuppoint);
3056 //start backup
3057 else
3058 result = ndb_mgm_start_backup(m_mgmsrv, flags, &backupId, &reply);
3059
3060 if (result != 0) {
3061 ndbout << "Backup failed" << endl;
3062 printError();
3063
3064 if (log_handle)
3065 ndb_mgm_destroy_logevent_handle(&log_handle);
3066 return result;
3067 }
3068
3069 /**
3070 * If interactive, event listner thread is already running
3071 */
3072 if (log_handle && !interactive)
3073 {
3074 int count = 0;
3075 int retry = 0;
3076 int res;
3077 do {
3078 if ((res= ndb_logevent_get_next(log_handle, &log_event, 60000)) > 0)
3079 {
3080 int print = 0;
3081 switch (log_event.type) {
3082 case NDB_LE_BackupStarted:
3083 if (log_event.BackupStarted.backup_id == backupId)
3084 print = 1;
3085 break;
3086 case NDB_LE_BackupCompleted:
3087 if (log_event.BackupCompleted.backup_id == backupId)
3088 print = 1;
3089 break;
3090 case NDB_LE_BackupAborted:
3091 if (log_event.BackupAborted.backup_id == backupId)
3092 print = 1;
3093 break;
3094 default:
3095 break;
3096 }
3097 if (print)
3098 {
3099 Guard g(m_print_mutex);
3100 printLogEvent(&log_event);
3101 count++;
3102 // for WAIT STARTED, exit after printing "Backup started" logevent
3103 if(flags == 1 && log_event.type == NDB_LE_BackupStarted)
3104 {
3105 ndb_mgm_destroy_logevent_handle(&log_handle);
3106 return 0;
3107 }
3108 }
3109 }
3110 else
3111 {
3112 retry++;
3113 }
3114 } while(res >= 0 && count < 2 && retry < 3);
3115
3116 if (retry >= 3)
3117 ndbout << "get backup event failed for " << retry << " times" << endl;
3118
3119 ndb_mgm_destroy_logevent_handle(&log_handle);
3120 }
3121
3122 return 0;
3123 }
3124
3125 int
executeAbortBackup(char * parameters)3126 CommandInterpreter::executeAbortBackup(char* parameters)
3127 {
3128 unsigned int bid = 0;
3129 unsigned long long int tmp_bid = 0;
3130 struct ndb_mgm_reply reply;
3131 if (emptyString(parameters))
3132 goto executeAbortBackupError1;
3133
3134 {
3135 strtok(parameters, " ");
3136 char* id = strtok(NULL, "\0");
3137 if(id == 0 || sscanf(id, "%llu", &tmp_bid) != 1)
3138 goto executeAbortBackupError1;
3139
3140 // to detect wraparound due to overflow, check if number of digits in
3141 // input backup ID > number of digits in max backup ID
3142 char out[1024];
3143 BaseString::snprintf(out, sizeof(out), "%u", MAX_BACKUPS);
3144 if(tmp_bid <= 0 || tmp_bid >= MAX_BACKUPS || strlen(id) > strlen(out))
3145 goto executeAbortBackupError2;
3146 else
3147 bid = static_cast<unsigned>(tmp_bid);
3148 }
3149 {
3150 int result= ndb_mgm_abort_backup(m_mgmsrv, bid, &reply);
3151 if (result != 0) {
3152 ndbout << "Abort of backup " << bid << " failed" << endl;
3153 printError();
3154 return -1;
3155 } else {
3156 ndbout << "Abort of backup " << bid << " ordered" << endl;
3157 }
3158 }
3159 return 0;
3160 executeAbortBackupError1:
3161 ndbout << "Invalid arguments: expected <BackupId>" << endl;
3162 return -1;
3163 executeAbortBackupError2:
3164 ndbout << "Invalid arguments: <BackupId> out of range [1-" << MAX_BACKUPS-1 << "]" << endl;
3165 return -1;
3166 }
3167
3168 int
executeCreateNodeGroup(char * parameters)3169 CommandInterpreter::executeCreateNodeGroup(char* parameters)
3170 {
3171 char *id= strchr(parameters, ' ');
3172 if (emptyString(id))
3173 goto err;
3174
3175 {
3176 Vector<int> nodes;
3177 BaseString args(id);
3178 Vector<BaseString> nodelist;
3179 args.split(nodelist, ",");
3180
3181 for (Uint32 i = 0; i<nodelist.size(); i++)
3182 {
3183 nodes.push_back(atoi(nodelist[i].c_str()));
3184 }
3185 nodes.push_back(0);
3186
3187 int ng;
3188 struct ndb_mgm_reply reply;
3189 const int result= ndb_mgm_create_nodegroup(m_mgmsrv, nodes.getBase(),
3190 &ng, &reply);
3191 if (result != 0) {
3192 printError();
3193 return -1;
3194 } else {
3195 ndbout << "Nodegroup " << ng << " created" << endl;
3196 }
3197
3198 }
3199
3200 return 0;
3201 err:
3202 ndbout << "Invalid arguments: expected <id>,<id>..." << endl;
3203 return -1;
3204 }
3205
3206 int
executeDropNodeGroup(char * parameters)3207 CommandInterpreter::executeDropNodeGroup(char* parameters)
3208 {
3209 int ng = -1;
3210 if (emptyString(parameters))
3211 goto err;
3212
3213 {
3214 char* id = strchr(parameters, ' ');
3215 if(id == 0 || sscanf(id, "%d", &ng) != 1)
3216 goto err;
3217 }
3218
3219 {
3220 struct ndb_mgm_reply reply;
3221 const int result= ndb_mgm_drop_nodegroup(m_mgmsrv, ng, &reply);
3222 if (result != 0) {
3223 printError();
3224 return -1;
3225 } else {
3226 ndbout << "Drop Node Group " << ng << " done" << endl;
3227 }
3228 }
3229 return 0;
3230 err:
3231 ndbout << "Invalid arguments: expected <NG>" << endl;
3232 return -1;
3233 }
3234