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