CommandInterpreter.cpp 93 KB
Newer Older
1 2 3 4
/* Copyright (C) 2003 MySQL AB

   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
unknown's avatar
unknown committed
5
   the Free Software Foundation; version 2 of the License.
6 7 8 9 10 11 12 13 14 15

   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.

   You should have received a copy of the GNU General Public License
   along with this program; if not, write to the Free Software
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

16 17 18
#include <ndb_global.h>
#include <my_sys.h>

19 20 21 22 23 24 25 26
//#define HAVE_GLOBAL_REPLICATION

#include <Vector.hpp>
#ifdef  HAVE_GLOBAL_REPLICATION
#include "../rep/repapi/repapi.h"
#endif

#include <mgmapi.h>
27
#include <util/BaseString.hpp>
28
#include <ndbd_exit_codes.h>
29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47

class MgmtSrvr;

/** 
 *  @class CommandInterpreter
 *  @brief Reads command line in management client
 *
 *  This class has one public method which reads a command line 
 *  from a stream. It then interpret that commmand line and calls a suitable 
 *  method in the MgmtSrvr class which executes the command.
 *
 *  For command syntax, see the HELP command.
 */ 
class CommandInterpreter {
public:
  /**
   *   Constructor
   *   @param mgmtSrvr: Management server to use when executing commands
   */
unknown's avatar
unknown committed
48
  CommandInterpreter(const char *, int verbose);
49 50 51 52 53 54 55 56 57
  ~CommandInterpreter();
  
  /**
   *   Reads one line from the stream, parse the line to find 
   *   a command and then calls a suitable method which executes 
   *   the command.
   *
   *   @return true until quit/bye/exit has been typed
   */
58
  int execute(const char *_line, int _try_reconnect=-1, bool interactive=1, int *error= 0);
59 60 61

private:
  void printError();
62
  int execute_impl(const char *_line, bool interactive=1);
63 64 65 66 67 68 69 70

  /**
   *   Analyse the command line, after the first token.
   *
   *   @param  processId:           DB process id to send command to or -1 if
   *                                command will be sent to all DB processes.
   *   @param  allAfterFirstToken:  What the client gave after the 
   *                                first token on the command line
71
   *   @return: 0 if analyseAfterFirstToken succeeds, otherwise -1 
72
   */
73
  int  analyseAfterFirstToken(int processId, char* allAfterFirstTokenCstr);
74

75
  int  executeCommand(Vector<BaseString> &command_list,
76 77
                      unsigned command_pos,
                      int *node_ids, int no_of_nodes);
78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
  /**
   *   Parse the block specification part of the LOG* commands,
   *   things after LOG*: [BLOCK = {ALL|<blockName>+}]
   *
   *   @param  allAfterLog: What the client gave after the second token 
   *                        (LOG*) on the command line
   *   @param  blocks, OUT: ALL or name of all the blocks
   *   @return: true if correct syntax, otherwise false
   */
  bool parseBlockSpecification(const char* allAfterLog, 
			       Vector<const char*>& blocks);
  
  /**
   *   A bunch of execute functions: Executes one of the commands
   *
   *   @param  processId:   DB process id to send command to
   *   @param  parameters:  What the client gave after the command name 
   *                        on the command line.
   *   For example if complete input from user is: "1 LOGLEVEL 22" then the
   *   parameters argument is the string with everything after LOGLEVEL, in
   *   this case "22". Each function is responsible to check the parameters
   *   argument.
   */
101 102 103
  int  executeHelp(char* parameters);
  int  executeShow(char* parameters);
  int  executePurge(char* parameters);
104
  int  executeConnect(char* parameters, bool interactive);
unknown's avatar
unknown committed
105
  int  executeShutdown(char* parameters);
106 107 108 109 110
  void executeRun(char* parameters);
  void executeInfo(char* parameters);
  void executeClusterLog(char* parameters);

public:
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128
  int  executeStop(int processId, const char* parameters, bool all);
  int  executeEnterSingleUser(char* parameters);
  int  executeExitSingleUser(char* parameters);
  int  executeStart(int processId, const char* parameters, bool all);
  int  executeRestart(int processId, const char* parameters, bool all);
  int  executeLogLevel(int processId, const char* parameters, bool all);
  int  executeError(int processId, const char* parameters, bool all);
  int  executeLog(int processId, const char* parameters, bool all);
  int  executeLogIn(int processId, const char* parameters, bool all);
  int  executeLogOut(int processId, const char* parameters, bool all);
  int  executeLogOff(int processId, const char* parameters, bool all);
  int  executeTestOn(int processId, const char* parameters, bool all);
  int  executeTestOff(int processId, const char* parameters, bool all);
  int  executeSet(int processId, const char* parameters, bool all);
  int  executeGetStat(int processId, const char* parameters, bool all);
  int  executeStatus(int processId, const char* parameters, bool all);
  int  executeEventReporting(int processId, const char* parameters, bool all);
  int  executeDumpState(int processId, const char* parameters, bool all);
129
  int  executeStartBackup(char * parameters, bool interactive);
130
  int  executeAbortBackup(char * parameters);
131
  int  executeStop(Vector<BaseString> &command_list, unsigned command_pos,
132
                   int *node_ids, int no_of_nodes);
133
  int  executeRestart(Vector<BaseString> &command_list, unsigned command_pos,
134
                      int *node_ids, int no_of_nodes);
135 136

  int  executeRep(char* parameters);
137 138 139 140

  void executeCpc(char * parameters);

public:
141
  bool connect(bool interactive);
142 143 144 145 146 147
  bool disconnect();

  /**
   * A execute function definition
   */
public:
148
  typedef int (CommandInterpreter::* ExecuteFunction)(int processId, 
149 150 151 152 153 154 155 156 157 158 159
						       const char * param, 
						       bool all);
  
  struct CommandFunctionPair {
    const char * command;
    ExecuteFunction executeFunction;
  };
private:
  /**
   * 
   */
160
  int  executeForAll(const char * cmd, 
161 162 163 164
		     ExecuteFunction fun,
		     const char * param);

  NdbMgmHandle m_mgmsrv;
unknown's avatar
unknown committed
165
  NdbMgmHandle m_mgmsrv2;
166
  const char *m_constr;
unknown's avatar
unknown committed
167
  bool m_connected;
unknown's avatar
unknown committed
168
  int m_verbose;
169
  int try_reconnect;
170
  int m_error;
171 172 173 174 175
#ifdef HAVE_GLOBAL_REPLICATION  
  NdbRepHandle m_repserver;
  const char *rep_host;
  bool rep_connected;
#endif
unknown's avatar
unknown committed
176
  struct NdbThread* m_event_thread;
177
  NdbMutex *m_print_mutex;
178 179
};

180 181 182 183 184 185
struct event_thread_param {
  NdbMgmHandle *m;
  NdbMutex **p;
};

NdbMutex* print_mutex;
186 187 188 189 190 191

/*
 * Facade object for CommandInterpreter
 */

#include "ndb_mgmclient.hpp"
192
#include "ndb_mgmclient.h"
193

unknown's avatar
unknown committed
194
Ndb_mgmclient::Ndb_mgmclient(const char *host,int verbose)
195
{
unknown's avatar
unknown committed
196
  m_cmd= new CommandInterpreter(host,verbose);
197 198 199 200 201
}
Ndb_mgmclient::~Ndb_mgmclient()
{
  delete m_cmd;
}
202
int Ndb_mgmclient::execute(const char *_line, int _try_reconnect, bool interactive, int *error)
203
{
204
  return m_cmd->execute(_line,_try_reconnect,interactive, error);
205 206 207 208 209 210 211
}
int
Ndb_mgmclient::disconnect()
{
  return m_cmd->disconnect();
}

212 213 214 215 216
extern "C" {
  Ndb_mgmclient_handle ndb_mgmclient_handle_create(const char *connect_string)
  {
    return (Ndb_mgmclient_handle) new Ndb_mgmclient(connect_string);
  }
217
  int ndb_mgmclient_execute(Ndb_mgmclient_handle h, int argc, char** argv)
218 219 220 221 222 223
  {
    return ((Ndb_mgmclient*)h)->execute(argc, argv, 1);
  }
  int ndb_mgmclient_handle_destroy(Ndb_mgmclient_handle h)
  {
    delete (Ndb_mgmclient*)h;
unknown's avatar
unknown committed
224
    return 0;
225 226
  }
}
227 228 229
/*
 * The CommandInterpreter
 */
230 231 232 233

#include <mgmapi.h>
#include <mgmapi_debug.h>
#include <version.h>
unknown's avatar
unknown committed
234
#include <NdbAutoPtr.hpp>
235 236
#include <NdbOut.hpp>
#include <NdbSleep.h>
237
#include <NdbMem.h>
238 239 240 241 242 243 244
#include <EventLogger.hpp>
#include <signaldata/SetLogLevelOrd.hpp>
#include <signaldata/GrepImpl.hpp>
#ifdef HAVE_GLOBAL_REPLICATION

#endif // HAVE_GLOBAL_REPLICATION
#include "MgmtErrorReporter.hpp"
245 246 247 248
#include <Parser.hpp>
#include <SocketServer.hpp>
#include <util/InputStream.hpp>
#include <util/OutputStream.hpp>
249

250
int Ndb_mgmclient::execute(int argc, char** argv, int _try_reconnect, bool interactive, int *error)
251 252 253 254 255 256 257 258
{
  if (argc <= 0)
    return 0;
  BaseString _line(argv[0]);
  for (int i= 1; i < argc; i++)
  {
    _line.appfmt(" %s", argv[i]);
  }
259
  return m_cmd->execute(_line.c_str(),_try_reconnect, interactive, error);
260
}
261 262 263 264 265 266 267 268 269

/*****************************************************************************
 * HELP
 *****************************************************************************/
static const char* helpText =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help\n"
"---------------------------------------------------------------------------\n"
"HELP                                   Print help text\n"
unknown's avatar
unknown committed
270
"HELP COMMAND                           Print detailed help for COMMAND(e.g. SHOW)\n"
271 272 273 274 275 276 277
#ifdef HAVE_GLOBAL_REPLICATION
"HELP REPLICATION                       Help for global replication\n"
#endif // HAVE_GLOBAL_REPLICATION
#ifdef VM_TRACE // DEBUG ONLY
"HELP DEBUG                             Help for debug compiled version\n"
#endif
"SHOW                                   Print information about cluster\n"
unknown's avatar
unknown committed
278
#if 0
279 280
"SHOW CONFIG                            Print configuration\n"
"SHOW PARAMETERS                        Print configuration parameters\n"
unknown's avatar
unknown committed
281
#endif
unknown's avatar
unknown committed
282 283
"START BACKUP [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
"                                       Start backup (default WAIT COMPLETED)\n"
284
"ABORT BACKUP <backup id>               Abort backup\n"
unknown's avatar
unknown committed
285
"SHUTDOWN                               Shutdown all processes in cluster\n"
unknown's avatar
unknown committed
286 287 288
"CLUSTERLOG ON [<severity>] ...         Enable Cluster logging\n"
"CLUSTERLOG OFF [<severity>] ...        Disable Cluster logging\n"
"CLUSTERLOG TOGGLE [<severity>] ...     Toggle severity filter on/off\n"
289
"CLUSTERLOG INFO                        Print cluster log information\n"
unknown's avatar
unknown committed
290 291 292 293
"<id> START                             Start data node (started with -n)\n"
"<id> RESTART [-n] [-i]                 Restart data or management server node\n"
"<id> STOP                              Stop data or management server node\n"
"ENTER SINGLE USER MODE <id>            Enter single user mode\n"
294 295 296
"EXIT SINGLE USER MODE                  Exit single user mode\n"
"<id> STATUS                            Print status\n"
"<id> CLUSTERLOG {<category>=<level>}+  Set log level for cluster log\n"
unknown's avatar
unknown committed
297
#ifdef HAVE_GLOBAL_REPLICATION
298
"REP CONNECT <host:port>                Connect to REP server on host:port\n"
unknown's avatar
unknown committed
299
#endif
300
"PURGE STALE SESSIONS                   Reset reserved nodeid's in the mgmt server\n"
301
"CONNECT [<connectstring>]              Connect to management server (reconnect if already connected)\n"
302 303 304 305 306 307 308
"QUIT                                   Quit management client\n"
;

static const char* helpTextShow =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for SHOW command\n"
"---------------------------------------------------------------------------\n"
unknown's avatar
unknown committed
309 310 311 312
"SHOW Print information about cluster\n\n"
"SHOW               Print information about cluster.The status reported is from\n"
"                   the perspective of the data nodes. API and Management Server nodes\n"
"                   are only reported as connected once the data nodes have started.\n" 
unknown's avatar
unknown committed
313
#if 0
314 315
"SHOW CONFIG        Print configuration (in initial config file format)\n" 
"SHOW PARAMETERS    Print information about configuration parameters\n\n"
unknown's avatar
unknown committed
316
#endif
317 318
;

unknown's avatar
unknown committed
319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400
static const char* helpTextHelp =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for HELP command\n"
"---------------------------------------------------------------------------\n"
"HELP List available commands of NDB Cluster Management Client\n\n"
"HELP               List available commands.\n"
;

static const char* helpTextBackup =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for BACKUP command\n"
"---------------------------------------------------------------------------\n"
"BACKUP  A backup is a snapshot of the database at a given time. \n"
"        The backup consists of three main parts:\n\n"
"        Metadata: the names and definitions of all database tables. \n"
"        Table records: the data actually stored in the database tables \n"
"        at the time that the backup was made.\n"
"        Transaction log: a sequential record telling how \n"
"        and when data was stored in the database.\n\n"
"        Backups are stored on each data node in the cluster that \n"
"        participates in the backup.\n\n"
"        The cluster log records backup related events (such as \n"
"        backup started, aborted, finished).\n"
;

static const char* helpTextStartBackup =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for START BACKUP command\n"
"---------------------------------------------------------------------------\n"
"START BACKUP  Start a cluster backup\n\n"
"START BACKUP [NOWAIT | WAIT STARTED | WAIT COMPLETED]\n"
"                   Start a backup for the cluster.\n"
"                   Each backup gets an ID number that is reported to the\n"
"                   user. This ID number can help you find the backup on the\n"
"                   file system, or ABORT BACKUP if you wish to cancel a \n"
"                   running backup.\n\n"
"                   NOWAIT \n"
"                     Start a cluster backup and return immediately.\n"
"                     The management client will return control directly\n"
"                     to the user without waiting for the backup\n"
"                     to have started.\n"
"                     The status of the backup is recorded in the Cluster log.\n"
"                   WAIT STARTED\n"
"                     Start a cluster backup and return until the backup has\n"
"                     started. The management client will wait for the backup \n"
"                     to have started before returning control to the user.\n"
"                   WAIT COMPLETED\n"
"                     Start a cluster backup and return until the backup has\n"
"                     completed. The management client will wait for the backup\n"
"                     to complete before returning control to the user.\n"
;

static const char* helpTextAbortBackup =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for ABORT BACKUP command\n"
"---------------------------------------------------------------------------\n"
"ABORT BACKUP  Abort a cluster backup\n\n"
"ABORT BACKUP <backup id>  \n"
"                   Abort a backup that is already in progress.\n"
"                   The backup id can be seen in the cluster log or in the\n"
"                   output of the START BACKUP command.\n"
;

static const char* helpTextShutdown =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for SHUTDOWN command\n"
"---------------------------------------------------------------------------\n"
"SHUTDOWN  Shutdown the cluster\n\n"
"SHUTDOWN           Shutdown the data nodes and management nodes.\n"
"                   MySQL Servers and NDBAPI nodes are currently not \n"
"                   shut down by issuing this command.\n"
;

static const char* helpTextClusterlogOn =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CLUSTERLOG ON command\n"
"---------------------------------------------------------------------------\n"
"CLUSTERLOG ON  Enable Cluster logging\n\n"
"CLUSTERLOG ON [<severity>] ... \n"
"                   Turn the cluster log on.\n"
"                   It tells management server which severity levels\n"
"                   messages will be logged.\n\n"
401
"                   <severity> can be any one of the following values:\n"
unknown's avatar
unknown committed
402 403 404 405 406 407 408 409 410 411 412 413
"                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
;

static const char* helpTextClusterlogOff =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CLUSTERLOG OFF command\n"
"---------------------------------------------------------------------------\n"
"CLUSTERLOG OFF  Disable Cluster logging\n\n"
"CLUSTERLOG OFF [<severity>] ...  \n"
"                   Turn the cluster log off.\n"
"                   It tells management server which serverity\n"
"                   levels logging will be disabled.\n\n"
414
"                   <severity> can be any one of the following values:\n"
unknown's avatar
unknown committed
415 416 417 418 419 420 421 422 423 424 425 426
"                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
;

static const char* helpTextClusterlogToggle =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CLUSTERLOG TOGGLE command\n"
"---------------------------------------------------------------------------\n"
"CLUSTERLOG TOGGLE  Toggle severity filter on/off\n\n"
"CLUSTERLOG TOGGLE [<severity>] ...  \n"
"                   Toggle serverity filter on/off.\n"
"                   If a serverity level is already enabled,then it will\n"
"                   be disabled after you use the command,vice versa.\n\n"
427
"                   <severity> can be any one of the following values:\n"
unknown's avatar
unknown committed
428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548
"                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
;

static const char* helpTextClusterlogInfo =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CLUSTERLOG INFO command\n"
"---------------------------------------------------------------------------\n"
"CLUSTERLOG INFO  Print cluster log information\n\n"
"CLUSTERLOG INFO    Display which severity levels have been enabled,\n"
"                   see HELP CLUSTERLOG for list of the severity levels.\n"
;

static const char* helpTextStart =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for START command\n"
"---------------------------------------------------------------------------\n"
"START  Start data node (started with -n)\n\n"
"<id> START         Start the data node identified by <id>.\n"
"                   Only starts data nodes that have not\n"
"                   yet joined the cluster. These are nodes\n"
"                   launched or restarted with the -n(--nostart)\n"
"                   option.\n\n"
"                   It does not launch the ndbd process on a remote\n"
"                   machine.\n"
;

static const char* helpTextRestart =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for RESTART command\n"
"---------------------------------------------------------------------------\n"
"RESTART  Restart data or management server node\n\n"
"<id> RESTART [-n] [-i] \n"
"                   Restart the data or management node <id>(or All data nodes).\n\n"
"                   -n (--nostart) restarts the node but does not\n"
"                   make it join the cluster. Use '<id> START' to\n"
"                   join the node to the cluster.\n\n"
"                   -i (--initial) perform initial start.\n"
"                   This cleans the file system (ndb_<id>_fs)\n"
"                   and the node will copy data from another node\n"
"                   in the same node group during start up.\n\n"
"                   Consult the documentation before using -i.\n\n" 
"                   INCORRECT USE OF -i WILL CAUSE DATA LOSS!\n"
;

static const char* helpTextStop =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for STOP command\n"
"---------------------------------------------------------------------------\n"
"STOP  Stop data or management server node\n\n"
"<id> STOP          Stop the data or management server node <id>.\n\n"
"                   ALL STOP will just stop all data nodes.\n\n"
"                   If you desire to also shut down management servers,\n"
"                   use SHUTDOWN instead.\n" 
;

static const char* helpTextEnterSingleUserMode =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for ENTER SINGLE USER MODE command\n"
"---------------------------------------------------------------------------\n"
"ENTER SINGLE USER MODE  Enter single user mode\n\n"
"ENTER SINGLE USER MODE <id> \n"
"                   Enters single-user mode, whereby only the MySQL Server or NDBAPI\n" 
"                   node identified by <id> is allowed to access the database. \n"
;

static const char* helpTextExitSingleUserMode =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for EXIT SINGLE USER MODE command\n"
"---------------------------------------------------------------------------\n"
"EXIT SINGLE USER MODE  Exit single user mode\n\n"
"EXIT SINGLE USER MODE \n"
"                   Exits single-user mode, allowing all SQL nodes \n"
"                   (that is, all running mysqld processes) to access the database. \n" 
;

static const char* helpTextStatus =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for STATUS command\n"
"---------------------------------------------------------------------------\n"
"STATUS  Print status\n\n"
"<id> STATUS        Displays status information for the data node <id>\n"
"                   or for All data nodes. \n\n"
"                   e.g.\n"
"                      ALL STATUS\n"
"                      1 STATUS\n\n"
"                   When a node is starting, the start phase will be\n"
"                   listed.\n\n"
"                   Start Phase   Meaning\n"
"                   1             Clear the cluster file system(ndb_<id>_fs). \n"
"                                 This stage occurs only when the --initial option \n"
"                                 has been specified.\n"
"                   2             This stage sets up Cluster connections, establishes \n"
"                                 inter-node communications and starts Cluster heartbeats.\n"
"                   3             The arbitrator node is elected.\n"
"                   4             Initializes a number of internal cluster variables.\n"
"                   5             For an initial start or initial node restart,\n"
"                                 the redo log files are created.\n"
"                   6             If this is an initial start, create internal system tables.\n"
"                   7             Update internal variables. \n"
"                   8             In a system restart, rebuild all indexes.\n"
"                   9             Update internal variables. \n"
"                   10            The node can be connected by APIs and can receive events.\n"
"                   11            At this point,event delivery is handed over to\n"
"                                 the node joining the cluster.\n"
"(see manual for more information)\n"
;

static const char* helpTextClusterlog =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CLUSTERLOG command\n"
"---------------------------------------------------------------------------\n"
"CLUSTERLOG  Set log level for cluster log\n\n"
" <id> CLUSTERLOG {<category>=<level>}+  \n"
"                   Logs <category> events with priority less than \n"
"                   or equal to <level> in the cluster log.\n\n"
"                   <category> can be any one of the following values:\n"
"                   STARTUP, SHUTDOWN, STATISTICS, CHECKPOINT, NODERESTART,\n"
"                   CONNECTION, ERROR, INFO, CONGESTION, DEBUG, or BACKUP. \n\n"
"                   <level> is represented by one of the numbers \n"
"                   from 1 to 15 inclusive, where 1 indicates 'most important' \n"
"                   and 15 'least important'.\n\n"
549
"                   <severity> can be any one of the following values:\n"
unknown's avatar
unknown committed
550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598
"                   ALERT, CRITICAL, ERROR, WARNING, INFO, DEBUG.\n"
;


static const char* helpTextPurgeStaleSessions =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for PURGE STALE SESSIONS command\n"
"---------------------------------------------------------------------------\n"
"PURGE STALE SESSIONS  Reset reserved nodeid's in the mgmt server\n\n"
"PURGE STALE SESSIONS \n"
"                   Running this statement forces all reserved \n"
"                   node IDs to be checked; any that are not \n"
"                   being used by nodes acutally connected to \n"
"                   the cluster are then freed.\n\n"   
"                   This command is not normally needed, but may be\n"
"                   required in some situations where failed nodes \n"
"                   cannot rejoin the cluster due to failing to\n"
"                   allocate a node id.\n" 
;

static const char* helpTextConnect =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for CONNECT command\n"
"---------------------------------------------------------------------------\n"
"CONNECT  Connect to management server (reconnect if already connected)\n\n"
"CONNECT [<connectstring>] \n"
"                   Connect to management server.\n"
"                   The optional parameter connectstring specifies the \n"
"                   connect string to user.\n\n"
"                   A connect string may be:\n"
"                       mgm-server\n"
"                       mgm-server:port\n"
"                       mgm1:port,mgm2:port\n"
"                   With multiple management servers comma separated.\n"
"                   The management client with try to connect to the \n"
"                   management servers in the order they are listed.\n\n"
"                   If no connect string is specified, the default \n"
"                   is used. \n"
;

static const char* helpTextQuit =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for QUIT command\n"
"---------------------------------------------------------------------------\n"
"QUIT  Quit management client\n\n"
"QUIT               Terminates the management client. \n"                    
;


599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655
#ifdef HAVE_GLOBAL_REPLICATION
static const char* helpTextRep =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for Global Replication\n"
"---------------------------------------------------------------------------\n"
"Commands should be executed on the standby NDB Cluster\n"
"These features are in an experimental release state.\n"
"\n"
"Simple Commands:\n"
"REP START              Start Global Replication\n" 
"REP START REQUESTOR    Start Global Replication Requestor\n" 
"REP STATUS             Show Global Replication status\n" 
"REP STOP               Stop Global Replication\n"
"REP STOP REQUESTOR     Stop Global Replication Requestor\n"
"\n" 
"Advanced Commands:\n"
"REP START <protocol>   Starts protocol\n"
"REP STOP <protocol>    Stops protocol\n"
"<protocol> = TRANSFER | APPLY | DELETE\n"
"\n"
#ifdef VM_TRACE // DEBUG ONLY
"Debugging commands:\n"
"REP DELETE             Removes epochs stored in primary and standy systems\n"
"REP DROP <tableid>     Drop a table in SS identified by table id\n"
"REP SLOWSTOP           Stop Replication (Tries to synchonize with primary)\n" 
"REP FASTSTOP           Stop Replication (Stops in consistent state)\n" 
"<component> = SUBSCRIPTION\n"
"              METALOG | METASCAN | DATALOG | DATASCAN\n"
"              REQUESTOR | TRANSFER | APPLY | DELETE\n"
#endif
;
#endif // HAVE_GLOBAL_REPLICATION

#ifdef VM_TRACE // DEBUG ONLY
static const char* helpTextDebug =
"---------------------------------------------------------------------------\n"
" NDB Cluster -- Management Client -- Help for Debugging (Internal use only)\n"
"---------------------------------------------------------------------------\n"
"SHOW PROPERTIES                       Print config properties object\n"
"<id> LOGLEVEL {<category>=<level>}+   Set log level\n"
#ifdef ERROR_INSERT
"<id> ERROR <errorNo>                  Inject error into NDB node\n"
#endif
"<id> LOG [BLOCK = {ALL|<block>+}]     Set logging on in & out signals\n"
"<id> LOGIN [BLOCK = {ALL|<block>+}]   Set logging on in signals\n"
"<id> LOGOUT [BLOCK = {ALL|<block>+}]  Set logging on out signals\n"
"<id> LOGOFF [BLOCK = {ALL|<block>+}]  Unset signal logging\n"
"<id> TESTON                           Start signal logging\n"
"<id> TESTOFF                          Stop signal logging\n"
"<id> SET <configParamName> <value>    Update configuration variable\n"
"<id> DUMP <arg>                       Dump system state to cluster.log\n"
"<id> GETSTAT                          Print statistics\n"
"\n"
"<id>       = ALL | Any database node id\n"
;
#endif

unknown's avatar
unknown committed
656
struct st_cmd_help {
unknown's avatar
unknown committed
657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693
  const char *cmd;
  const char * help;
}help_items[]={
  {"SHOW", helpTextShow},
  {"HELP", helpTextHelp},
  {"BACKUP", helpTextBackup},
  {"START BACKUP", helpTextStartBackup},
  {"START BACKUP NOWAIT", helpTextStartBackup},
  {"START BACKUP WAIT STARTED", helpTextStartBackup},
  {"START BACKUP WAIT", helpTextStartBackup},
  {"START BACKUP WAIT COMPLETED", helpTextStartBackup},
  {"ABORT BACKUP", helpTextAbortBackup},
  {"SHUTDOWN", helpTextShutdown},
  {"CLUSTERLOG ON", helpTextClusterlogOn},
  {"CLUSTERLOG OFF", helpTextClusterlogOff},
  {"CLUSTERLOG TOGGLE", helpTextClusterlogToggle},
  {"CLUSTERLOG INFO", helpTextClusterlogInfo},
  {"START", helpTextStart},
  {"RESTART", helpTextRestart},
  {"STOP", helpTextStop},
  {"ENTER SINGLE USER MODE", helpTextEnterSingleUserMode},
  {"EXIT SINGLE USER MODE", helpTextExitSingleUserMode},
  {"STATUS", helpTextStatus},
  {"CLUSTERLOG", helpTextClusterlog},
  {"PURGE STALE SESSIONS", helpTextPurgeStaleSessions},
  {"CONNECT", helpTextConnect},
  {"QUIT", helpTextQuit},
#ifdef HAVE_GLOBAL_REPLICATION
  {"REPLICATION", helpTextRep},
  {"REP", helpTextRep},
#endif // HAVE_GLOBAL_REPLICATION
#ifdef VM_TRACE // DEBUG ONLY
  {"DEBUG", helpTextDebug},
#endif //VM_TRACE
  {NULL, NULL}
};

694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718
static bool
convert(const char* s, int& val) {
  
  if (s == NULL)
    return false;

  if (strlen(s) == 0)
    return false;

  errno = 0;
  char* p;
  long v = strtol(s, &p, 10);
  if (errno != 0)
    return false;

  if (p != &s[strlen(s)])
    return false;
  
  val = v;
  return true;
}

/*
 * Constructor
 */
unknown's avatar
unknown committed
719 720
CommandInterpreter::CommandInterpreter(const char *_host,int verbose) 
  : m_verbose(verbose)
721
{
722
  m_constr= _host;
unknown's avatar
unknown committed
723
  m_connected= false;
724
  m_event_thread= NULL;
725
  try_reconnect = 0;
726
  m_print_mutex= NdbMutex_Create();
727 728 729 730 731 732 733 734 735 736 737 738
#ifdef HAVE_GLOBAL_REPLICATION
  rep_host = NULL;
  m_repserver = NULL;
  rep_connected = false;
#endif
}

/*
 * Destructor
 */
CommandInterpreter::~CommandInterpreter() 
{
unknown's avatar
unknown committed
739
  disconnect();
740
  NdbMutex_Destroy(m_print_mutex);
741 742
}

743
static bool 
744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765
emptyString(const char* s) 
{
  if (s == NULL) {
    return true;
  }

  for (unsigned int i = 0; i < strlen(s); ++i) {
    if (! isspace(s[i])) {
      return false;
    }
  }

  return true;
}

void
CommandInterpreter::printError() 
{
  ndbout_c("* %5d: %s", 
	   ndb_mgm_get_latest_error(m_mgmsrv),
	   ndb_mgm_get_latest_error_msg(m_mgmsrv));
  ndbout_c("*        %s", ndb_mgm_get_latest_error_desc(m_mgmsrv));
766 767 768 769
  if (ndb_mgm_check_connection(m_mgmsrv))
  {
    disconnect();
  }
770 771
}

772 773 774
/*
 * print log event from mgmsrv to console screen
 */
775 776 777 778 779 780
#define make_uint64(a,b) (((Uint64)(a)) + (((Uint64)(b)) << 32))
#define Q64(a) make_uint64(event->EVENT.a ## _lo, event->EVENT.a ## _hi)
#define R event->source_nodeid
#define Q(a) event->EVENT.a
#define QVERSION getMajor(Q(version)), getMinor(Q(version)), getBuild(Q(version))
#define NDB_LE_(a) NDB_LE_ ## a
781 782 783 784 785 786 787
static void
printLogEvent(struct ndb_logevent* event)
{
  switch (event->type) {
    /** 
     * NDB_MGM_EVENT_CATEGORY_BACKUP
     */
788 789 790 791 792
#undef  EVENT
#define EVENT BackupStarted
  case NDB_LE_BackupStarted:
      ndbout_c("Node %u: Backup %d started from node %d",
               R, Q(backup_id), Q(starting_node));
793
      break;
794 795
#undef  EVENT
#define EVENT BackupFailedToStart
796
    case NDB_LE_BackupFailedToStart:
797 798
      ndbout_c("Node %u: Backup request from %d failed to start. Error: %d",
               R, Q(starting_node), Q(error));
799
      break;
800 801
#undef  EVENT
#define EVENT BackupCompleted
802
    case NDB_LE_BackupCompleted:
803
      ndbout_c("Node %u: Backup %u started from node %u completed\n" 
804 805
               " StartGCP: %u StopGCP: %u\n" 
               " #Records: %u #LogRecords: %u\n" 
806 807 808 809 810
               " Data: %u bytes Log: %u bytes", R,
               Q(backup_id), Q(starting_node),
               Q(start_gci), Q(stop_gci),
               Q(n_records), Q(n_log_records),
               Q(n_bytes),   Q(n_log_bytes));
811
      break;
812 813
#undef  EVENT
#define EVENT BackupAborted
814
    case NDB_LE_BackupAborted:
815 816
      ndbout_c("Node %u: Backup %d started from %d has been aborted. Error: %d",
               R, Q(backup_id), Q(starting_node), Q(error));
817 818 819 820
      break;
    /** 
     * NDB_MGM_EVENT_CATEGORY_STARTUP
     */ 
821 822
#undef  EVENT
#define EVENT NDBStartStarted
823
    case NDB_LE_NDBStartStarted:
824 825
      ndbout_c("Node %u: Start initiated (version %d.%d.%d)",
               R, QVERSION);
826
      break;
827 828
#undef  EVENT
#define EVENT NDBStartCompleted
829
    case NDB_LE_NDBStartCompleted:
830 831
      ndbout_c("Node %u: Started (version %d.%d.%d)",
               R, QVERSION);
832
      break;
833 834
#undef  EVENT
#define EVENT NDBStopStarted
835
    case NDB_LE_NDBStopStarted:
836 837
      ndbout_c("Node %u: %s shutdown initiated", R,
               (Q(stoptype) == 1 ? "Cluster" : "Node"));
838
      break;
839 840
#undef  EVENT
#define EVENT NDBStopCompleted
841 842 843 844
    case NDB_LE_NDBStopCompleted:
      {
        BaseString action_str("");
        BaseString signum_str("");
845 846
        getRestartAction(Q(action), action_str);
        if (Q(signum))
847
          signum_str.appfmt(" Initiated by signal %d.", 
848 849 850
                            Q(signum));
        ndbout_c("Node %u: Node shutdown completed%s.%s", 
                 R, action_str.c_str(), signum_str.c_str());
851 852
      }
      break;
853 854
#undef  EVENT
#define EVENT NDBStopForced
855 856 857 858 859
    case NDB_LE_NDBStopForced:
      {
        BaseString action_str("");
        BaseString reason_str("");
        BaseString sphase_str("");
860 861 862 863 864
        int signum = Q(signum);
        int error = Q(error); 
        int sphase = Q(sphase); 
        int extra = Q(extra); 
        getRestartAction(Q(action), action_str);
865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880
        if (signum)
          reason_str.appfmt(" Initiated by signal %d.", signum);
        if (error)
        {
          ndbd_exit_classification cl;
          ndbd_exit_status st;
          const char *msg = ndbd_exit_message(error, &cl);
          const char *cl_msg = ndbd_exit_classification_message(cl, &st);
          const char *st_msg = ndbd_exit_status_message(st);
          reason_str.appfmt(" Caused by error %d: \'%s(%s). %s\'.", 
                            error, msg, cl_msg, st_msg);
          if (extra != 0)
            reason_str.appfmt(" (extra info %d)", extra);
        }
        if (sphase < 255)
          sphase_str.appfmt(" Occured during startphase %u.", sphase);
881 882
        ndbout_c("Node %u: Forced node shutdown completed%s.%s%s",
                 R, action_str.c_str(), sphase_str.c_str(), 
883 884 885
                 reason_str.c_str());
      }
      break;
886 887
#undef  EVENT
#define EVENT StopAborted
888
    case NDB_LE_NDBStopAborted:
889
      ndbout_c("Node %u: Node shutdown aborted", R);
890 891 892 893 894 895 896 897 898
      break;
    /** 
     * default nothing to print
     */ 
    default:
      break;
  }
}

899 900 901
//*****************************************************************************
//*****************************************************************************

unknown's avatar
unknown committed
902 903
static int do_event_thread;
static void*
904
event_thread_run(void* p)
unknown's avatar
unknown committed
905
{
906 907
  DBUG_ENTER("event_thread_run");

908 909 910
  struct event_thread_param param= *(struct event_thread_param*)p;
  NdbMgmHandle handle= *(param.m);
  NdbMutex* printmutex= *(param.p);
unknown's avatar
unknown committed
911

unknown's avatar
unknown committed
912 913 914
  int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP,
		   1, NDB_MGM_EVENT_CATEGORY_STARTUP,
		   0 };
915 916 917 918 919 920

  NdbLogEventHandle log_handle= NULL;
  struct ndb_logevent log_event;

  log_handle= ndb_mgm_create_logevent_handle(handle, filter);
  if (log_handle) 
unknown's avatar
unknown committed
921
  {
922
    do_event_thread= 1;
unknown's avatar
unknown committed
923
    do {
924 925 926 927
      if (ndb_logevent_get_next(log_handle, &log_event, 2000) <= 0)
        continue;
      Guard g(printmutex);
      printLogEvent(&log_event);
unknown's avatar
unknown committed
928
    } while(do_event_thread);
929
    ndb_mgm_destroy_logevent_handle(&log_handle);
unknown's avatar
unknown committed
930
  }
931 932 933 934
  else
  {
    do_event_thread= -1;
  }
unknown's avatar
unknown committed
935

936
  DBUG_RETURN(NULL);
unknown's avatar
unknown committed
937 938 939
}

bool
940
CommandInterpreter::connect(bool interactive)
941
{
942
  DBUG_ENTER("CommandInterpreter::connect");
943 944 945 946 947 948 949 950 951

  if(m_connected)
    DBUG_RETURN(m_connected);

  m_mgmsrv = ndb_mgm_create_handle();
  if(m_mgmsrv == NULL) {
    ndbout_c("Cannot create handle to management server.");
    exit(-1);
  }
952 953 954 955 956 957
  if (interactive) {
    m_mgmsrv2 = ndb_mgm_create_handle();
    if(m_mgmsrv2 == NULL) {
      ndbout_c("Cannot create 2:nd handle to management server.");
      exit(-1);
    }
958 959 960
  }

  if (ndb_mgm_set_connectstring(m_mgmsrv, m_constr))
unknown's avatar
unknown committed
961
  {
962 963 964 965 966 967 968 969 970
    printError();
    exit(-1);
  }

  if(ndb_mgm_connect(m_mgmsrv, try_reconnect-1, 5, 1))
    DBUG_RETURN(m_connected); // couldn't connect, always false

  const char *host= ndb_mgm_get_connected_host(m_mgmsrv);
  unsigned port= ndb_mgm_get_connected_port(m_mgmsrv);
971 972 973 974 975
  if (interactive) {
    BaseString constr;
    constr.assfmt("%s:%d",host,port);
    if(!ndb_mgm_set_connectstring(m_mgmsrv2, constr.c_str()) &&
       !ndb_mgm_connect(m_mgmsrv2, try_reconnect-1, 5, 1))
unknown's avatar
unknown committed
976
    {
977 978 979 980
      DBUG_PRINT("info",("2:ndb connected to Management Server ok at: %s:%d",
                         host, port));
      assert(m_event_thread == NULL);
      assert(do_event_thread == 0);
981
      do_event_thread= 0;
982 983 984 985 986 987 988 989
      struct event_thread_param p;
      p.m= &m_mgmsrv2;
      p.p= &m_print_mutex;
      m_event_thread = NdbThread_Create(event_thread_run,
                                        (void**)&p,
                                        32768,
                                        "CommandInterpreted_event_thread",
                                        NDB_THREAD_PRIO_LOW);
990
      if (m_event_thread)
991
      {
992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014
        DBUG_PRINT("info",("Thread created ok, waiting for started..."));
        int iter= 1000; // try for 30 seconds
        while(do_event_thread == 0 &&
              iter-- > 0)
          NdbSleep_MilliSleep(30);
      }
      if (m_event_thread == NULL ||
          do_event_thread == 0 ||
          do_event_thread == -1)
      {
        DBUG_PRINT("info",("Warning, event thread startup failed, "
                           "degraded printouts as result, errno=%d",
                           errno));
        printf("Warning, event thread startup failed, "
               "degraded printouts as result, errno=%d\n", errno);
        do_event_thread= 0;
        if (m_event_thread)
        {
          void *res;
          NdbThread_WaitFor(m_event_thread, &res);
          NdbThread_Destroy(&m_event_thread);
        }
        ndb_mgm_disconnect(m_mgmsrv2);
unknown's avatar
unknown committed
1015 1016
      }
    }
1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028
    else
    {
      DBUG_PRINT("warning",
                 ("Could not do 2:nd connect to mgmtserver for event listening"));
      DBUG_PRINT("info", ("code: %d, msg: %s",
                          ndb_mgm_get_latest_error(m_mgmsrv2),
                          ndb_mgm_get_latest_error_msg(m_mgmsrv2)));
      printf("Warning, event connect failed, degraded printouts as result\n");
      printf("code: %d, msg: %s\n",
             ndb_mgm_get_latest_error(m_mgmsrv2),
             ndb_mgm_get_latest_error_msg(m_mgmsrv2));
    }
1029 1030 1031 1032 1033 1034 1035 1036 1037
  }
  m_connected= true;
  DBUG_PRINT("info",("Connected to Management Server at: %s:%d", host, port));
  if (m_verbose)
  {
    printf("Connected to Management Server at: %s:%d\n",
           host, port);
  }

1038
  DBUG_RETURN(m_connected);
1039 1040 1041 1042 1043
}

bool 
CommandInterpreter::disconnect() 
{
1044
  DBUG_ENTER("CommandInterpreter::disconnect");
1045

unknown's avatar
unknown committed
1046 1047 1048 1049 1050
  if (m_event_thread) {
    void *res;
    do_event_thread= 0;
    NdbThread_WaitFor(m_event_thread, &res);
    NdbThread_Destroy(&m_event_thread);
1051
    m_event_thread= NULL;
1052
    ndb_mgm_destroy_handle(&m_mgmsrv2);
unknown's avatar
unknown committed
1053 1054 1055
  }
  if (m_connected)
  {
1056
    ndb_mgm_destroy_handle(&m_mgmsrv);
unknown's avatar
unknown committed
1057
    m_connected= false;
1058
  }
1059
  DBUG_RETURN(true);
1060 1061 1062 1063 1064
}

//*****************************************************************************
//*****************************************************************************

1065
int 
1066
CommandInterpreter::execute(const char *_line, int _try_reconnect,
1067
			    bool interactive, int *error) 
1068 1069 1070
{
  if (_try_reconnect >= 0)
    try_reconnect=_try_reconnect;
1071
  int result= execute_impl(_line, interactive);
1072 1073
  if (error)
    *error= m_error;
1074

1075 1076 1077
  return result;
}

1078 1079 1080 1081 1082 1083 1084
static void
invalid_command(const char *cmd)
{
  ndbout << "Invalid command: " << cmd << endl;
  ndbout << "Type HELP for help." << endl << endl;
}

1085
int 
1086
CommandInterpreter::execute_impl(const char *_line, bool interactive) 
1087 1088 1089 1090 1091
{
  DBUG_ENTER("CommandInterpreter::execute_impl");
  DBUG_PRINT("enter",("line=\"%s\"",_line));
  m_error= 0;

1092 1093
  char * line;
  if(_line == NULL) {
1094
    m_error = -1;
unknown's avatar
unknown committed
1095
    DBUG_RETURN(false);
1096
  }
1097 1098
  line = my_strdup(_line,MYF(MY_WME));
  My_auto_ptr<char> ptr(line);
1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118

  int do_continue;
  do {
    do_continue= 0;
    BaseString::trim(line," \t");
    if (line[0] == 0 ||
	line[0] == '#')
    {
      DBUG_RETURN(true);
    }
    // for mysql client compatability remove trailing ';'
    {
      unsigned last= strlen(line)-1;
      if (line[last] == ';')
      {
	line[last]= 0;
	do_continue= 1;
      }
    }
  } while (do_continue);
1119
  // if there is anything in the line proceed
1120 1121 1122 1123 1124 1125 1126
  Vector<BaseString> command_list;
  {
    BaseString tmp(line);
    tmp.split(command_list);
    for (unsigned i= 0; i < command_list.size();)
      command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
  }
1127 1128
  char* firstToken = strtok(line, " ");
  char* allAfterFirstToken = strtok(NULL, "");
1129

1130 1131
  if (strcasecmp(firstToken, "HELP") == 0 ||
      strcasecmp(firstToken, "?") == 0) {
1132
    m_error = executeHelp(allAfterFirstToken);
unknown's avatar
unknown committed
1133 1134
    DBUG_RETURN(true);
  }
1135
  else if (strcasecmp(firstToken, "CONNECT") == 0) {
1136
    m_error = executeConnect(allAfterFirstToken, interactive);
unknown's avatar
unknown committed
1137
    DBUG_RETURN(true);
1138
  }
1139 1140
  else if (strcasecmp(firstToken, "SLEEP") == 0) {
    if (allAfterFirstToken)
1141 1142
      if (sleep(atoi(allAfterFirstToken)) != 0 )
        m_error = -1;
1143 1144
    DBUG_RETURN(true);
  }
unknown's avatar
unknown committed
1145 1146 1147 1148 1149 1150
  else if((strcasecmp(firstToken, "QUIT") == 0 ||
	  strcasecmp(firstToken, "EXIT") == 0 ||
	  strcasecmp(firstToken, "BYE") == 0) && 
	  allAfterFirstToken == NULL){
    DBUG_RETURN(false);
  }
unknown's avatar
unknown committed
1151

1152
  if (!connect(interactive)){
1153
    m_error = -1;
unknown's avatar
unknown committed
1154
    DBUG_RETURN(true);
1155
  }
unknown's avatar
unknown committed
1156

1157 1158 1159
  if (ndb_mgm_check_connection(m_mgmsrv))
  {
    disconnect();
1160
    connect(interactive);
1161 1162
  }

1163
  if (strcasecmp(firstToken, "SHOW") == 0) {
unknown's avatar
unknown committed
1164
    Guard g(m_print_mutex);
1165
    m_error = executeShow(allAfterFirstToken);
unknown's avatar
unknown committed
1166
    DBUG_RETURN(true);
1167
  }
1168
  else if (strcasecmp(firstToken, "SHUTDOWN") == 0) {
unknown's avatar
unknown committed
1169
    m_error= executeShutdown(allAfterFirstToken);
unknown's avatar
unknown committed
1170
    DBUG_RETURN(true);
unknown's avatar
unknown committed
1171
  }
1172
  else if (strcasecmp(firstToken, "CLUSTERLOG") == 0){
1173
    executeClusterLog(allAfterFirstToken);
unknown's avatar
unknown committed
1174
    DBUG_RETURN(true);
1175
  }
1176
  else if(strcasecmp(firstToken, "START") == 0 &&
1177
	  allAfterFirstToken != NULL &&
1178
	  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1179
    m_error= executeStartBackup(allAfterFirstToken, interactive);
unknown's avatar
unknown committed
1180
    DBUG_RETURN(true);
1181
  }
1182
  else if(strcasecmp(firstToken, "ABORT") == 0 &&
1183
	  allAfterFirstToken != NULL &&
1184
	  strncasecmp(allAfterFirstToken, "BACKUP", sizeof("BACKUP") - 1) == 0){
1185
    m_error = executeAbortBackup(allAfterFirstToken);
unknown's avatar
unknown committed
1186
    DBUG_RETURN(true);
1187
  }
1188
  else if (strcasecmp(firstToken, "PURGE") == 0) {
1189
    m_error = executePurge(allAfterFirstToken);
unknown's avatar
unknown committed
1190
    DBUG_RETURN(true);
1191
  } 
1192
#ifdef HAVE_GLOBAL_REPLICATION
1193 1194
  else if(strcasecmp(firstToken, "REPLICATION") == 0 ||
	  strcasecmp(firstToken, "REP") == 0) {
1195
    m_error = executeRep(allAfterFirstToken);
unknown's avatar
unknown committed
1196
    DBUG_RETURN(true);
1197 1198
  }
#endif // HAVE_GLOBAL_REPLICATION
1199
  else if(strcasecmp(firstToken, "ENTER") == 0 &&
1200
	  allAfterFirstToken != NULL &&
1201
	  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ", 
1202
		  sizeof("SINGLE USER MODE") - 1) == 0){
1203
    m_error = executeEnterSingleUser(allAfterFirstToken);
unknown's avatar
unknown committed
1204
    DBUG_RETURN(true);
1205
  }
1206
  else if(strcasecmp(firstToken, "EXIT") == 0 &&
1207
	  allAfterFirstToken != NULL &&
1208
	  strncasecmp(allAfterFirstToken, "SINGLE USER MODE ", 
1209
		  sizeof("SINGLE USER MODE") - 1) == 0){
1210
    m_error = executeExitSingleUser(allAfterFirstToken);
unknown's avatar
unknown committed
1211
    DBUG_RETURN(true);
1212
  }
1213
  else if (strcasecmp(firstToken, "ALL") == 0) {
1214
    m_error = analyseAfterFirstToken(-1, allAfterFirstToken);
1215 1216
  } else {
    /**
1217
     * First tokens should be digits, node ID's
1218
     */
1219 1220 1221 1222 1223 1224 1225
    int node_ids[MAX_NODES];
    unsigned pos;
    for (pos= 0; pos < command_list.size(); pos++)
    {
      int node_id;
      if (convert(command_list[pos].c_str(), node_id))
      {
1226
        if (node_id <= 0 || node_id > MAX_NODES) {
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239
          ndbout << "Invalid node ID: " << command_list[pos].c_str()
                 << "." << endl;
          DBUG_RETURN(true);
        }
        node_ids[pos]= node_id;
        continue;
      }
      break;
    }
    int no_of_nodes= pos;
    if (no_of_nodes == 0)
    {
      /* No digit found */
1240
      invalid_command(_line);
1241
      m_error = -1;
unknown's avatar
unknown committed
1242
      DBUG_RETURN(true);
1243
    }
1244 1245 1246 1247
    if (pos == command_list.size())
    {
      /* No command found */
      invalid_command(_line);
1248
      m_error = -1;
unknown's avatar
unknown committed
1249
      DBUG_RETURN(true);
1250
    }
1251 1252
    if (no_of_nodes == 1)
    {
1253
      m_error = analyseAfterFirstToken(node_ids[0], allAfterFirstToken);
1254 1255
      DBUG_RETURN(true);
    }
1256
    m_error = executeCommand(command_list, pos, node_ids, no_of_nodes);
1257
    DBUG_RETURN(true);
1258
  }
unknown's avatar
unknown committed
1259
  DBUG_RETURN(true);
1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289
}


/**
 * List of commands used as second command argument
 */
static const CommandInterpreter::CommandFunctionPair commands[] = {
  { "START", &CommandInterpreter::executeStart }
  ,{ "RESTART", &CommandInterpreter::executeRestart }
  ,{ "STOP", &CommandInterpreter::executeStop }
  ,{ "STATUS", &CommandInterpreter::executeStatus }
  ,{ "LOGLEVEL", &CommandInterpreter::executeLogLevel }
  ,{ "CLUSTERLOG", &CommandInterpreter::executeEventReporting }
#ifdef ERROR_INSERT
  ,{ "ERROR", &CommandInterpreter::executeError }
#endif
  ,{ "LOG", &CommandInterpreter::executeLog }
  ,{ "LOGIN", &CommandInterpreter::executeLogIn }
  ,{ "LOGOUT", &CommandInterpreter::executeLogOut }
  ,{ "LOGOFF", &CommandInterpreter::executeLogOff }
  ,{ "TESTON", &CommandInterpreter::executeTestOn }
  ,{ "TESTOFF", &CommandInterpreter::executeTestOff }
  ,{ "SET", &CommandInterpreter::executeSet }
  ,{ "GETSTAT", &CommandInterpreter::executeGetStat }
  ,{ "DUMP", &CommandInterpreter::executeDumpState }
};


//*****************************************************************************
//*****************************************************************************
1290
int
1291 1292 1293
CommandInterpreter::analyseAfterFirstToken(int processId,
					   char* allAfterFirstToken) {
  
1294
  int retval = 0;
1295
  if (emptyString(allAfterFirstToken)) {
1296 1297
    ndbout << "Expected a command after "
	   << ((processId == -1) ? "ALL." : "node ID.") << endl;
1298
    return -1;
1299 1300 1301 1302 1303 1304 1305 1306 1307
  }
  
  char* secondToken = strtok(allAfterFirstToken, " ");
  char* allAfterSecondToken = strtok(NULL, "\0");

  const int tmpSize = sizeof(commands)/sizeof(CommandFunctionPair);
  ExecuteFunction fun = 0;
  const char * command = 0;
  for(int i = 0; i<tmpSize; i++){
1308
    if(strcasecmp(secondToken, commands[i].command) == 0){
1309 1310 1311 1312 1313 1314 1315
      fun = commands[i].executeFunction;
      command = commands[i].command;
      break;
    }
  }
  
  if(fun == 0){
1316
    invalid_command(secondToken);
1317
    return -1;
1318 1319 1320
  }
  
  if(processId == -1){
1321
    retval = executeForAll(command, fun, allAfterSecondToken);
1322
  } else {
1323
    retval = (this->*fun)(processId, allAfterSecondToken, false);
1324
  }
unknown's avatar
unknown committed
1325
  ndbout << endl;
1326
  return retval;
1327 1328
}

1329
int
1330 1331 1332 1333 1334
CommandInterpreter::executeCommand(Vector<BaseString> &command_list,
                                   unsigned command_pos,
                                   int *node_ids, int no_of_nodes)
{
  const char *cmd= command_list[command_pos].c_str();
1335 1336
  int retval = 0;

1337 1338
  if (strcasecmp("STOP", cmd) == 0)
  {
1339 1340
    retval = executeStop(command_list, command_pos+1, node_ids, no_of_nodes);
    return retval;
1341 1342 1343
  }
  if (strcasecmp("RESTART", cmd) == 0)
  {
1344 1345
    retval = executeRestart(command_list, command_pos+1, node_ids, no_of_nodes);
    return retval;
1346 1347 1348
  }
  ndbout_c("Invalid command: '%s' after multi node id list. "
           "Expected STOP or RESTART.", cmd);
1349
  return -1;
1350 1351
}

1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389
/**
 * Get next nodeid larger than the give node_id. node_id will be
 * set to the next node_id in the list. node_id should be set
 * to 0 (zero) on the first call.
 *
 * @param handle the NDB management handle
 * @param node_id last node_id retreived, 0 at first call
 * @param type type of node to look for
 * @return 1 if a node was found, 0 if no more node exist
 */
static 
int 
get_next_nodeid(struct ndb_mgm_cluster_state *cl,
		int *node_id,
		enum ndb_mgm_node_type type)
{
  int i;
  
  if(cl == NULL)
    return 0;
  
  i=0;
  while((i < cl->no_of_nodes)) {
    if((*node_id < cl->node_states[i].node_id) &&
       (cl->node_states[i].node_type == type)) {
      
      if(i >= cl->no_of_nodes)
	return 0;
      
      *node_id = cl->node_states[i].node_id;
      return 1;
    }
    i++;
  }
  
  return 0;
}

1390
int
1391 1392 1393 1394
CommandInterpreter::executeForAll(const char * cmd, ExecuteFunction fun, 
				  const char * allAfterSecondToken)
{
  int nodeId = 0;
1395 1396
  int retval = 0;

1397
  if(strcasecmp(cmd, "STOP") == 0) {
1398
    ndbout_c("Executing STOP on all nodes.");
1399
    retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1400
  } else if(strcasecmp(cmd, "RESTART") == 0) {
1401 1402
    ndbout_c("Executing RESTART on all nodes.");
    ndbout_c("Starting shutdown. This may take a while. Please wait...");
1403
    retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1404 1405 1406
    ndbout_c("Trying to start all nodes of system.");
    ndbout_c("Use ALL STATUS to see the system start-up phases.");
  } else {
1407
    Guard g(m_print_mutex);
1408
    struct ndb_mgm_cluster_state *cl= ndb_mgm_get_status(m_mgmsrv);
1409 1410 1411
    if(cl == 0){
      ndbout_c("Unable get status from management server");
      printError();
1412
      return -1;
1413
    }
1414
    NdbAutoPtr<char> ap1((char*)cl);
unknown's avatar
unknown committed
1415
    while(get_next_nodeid(cl, &nodeId, NDB_MGM_NODE_TYPE_NDB))
1416
      retval = (this->*fun)(nodeId, allAfterSecondToken, true);
1417
  }
1418
  return retval;
1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433
}

//*****************************************************************************
//*****************************************************************************
bool 
CommandInterpreter::parseBlockSpecification(const char* allAfterLog,
					    Vector<const char*>& blocks) 
{
  // Parse: [BLOCK = {ALL|<blockName>+}]

  if (emptyString(allAfterLog)) {
    return true;
  }

  // Copy allAfterLog since strtok will modify it  
1434 1435
  char* newAllAfterLog = my_strdup(allAfterLog,MYF(MY_WME));
  My_auto_ptr<char> ap1(newAllAfterLog);
1436 1437 1438 1439 1440
  char* firstTokenAfterLog = strtok(newAllAfterLog, " ");
  for (unsigned int i = 0; i < strlen(firstTokenAfterLog); ++i) {
    firstTokenAfterLog[i] = toupper(firstTokenAfterLog[i]);
  }
  
1441
  if (strcasecmp(firstTokenAfterLog, "BLOCK") != 0) {
1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453
    ndbout << "Unexpected value: " << firstTokenAfterLog 
	   << ". Expected BLOCK." << endl;
    return false;
  }

  char* allAfterFirstToken = strtok(NULL, "\0");
  if (emptyString(allAfterFirstToken)) {
    ndbout << "Expected =." << endl;
    return false;
  }

  char* secondTokenAfterLog = strtok(allAfterFirstToken, " ");
1454
  if (strcasecmp(secondTokenAfterLog, "=") != 0) {
1455 1456 1457 1458 1459 1460 1461
    ndbout << "Unexpected value: " << secondTokenAfterLog 
	   << ". Expected =." << endl;
    return false;
  }

  char* blockName = strtok(NULL, " ");
  bool all = false;
1462
  if (blockName != NULL && (strcasecmp(blockName, "ALL") == 0)) {
1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487
    all = true;
  }
  while (blockName != NULL) {
    blocks.push_back(strdup(blockName));
    blockName = strtok(NULL, " ");
  }

  if (blocks.size() == 0) {
    ndbout << "No block specified." << endl;
    return false;
  }
  if (blocks.size() > 1 && all) {
    // More than "ALL" specified
    ndbout << "Nothing expected after ALL." << endl;
    return false;
  }
  
  return true;
}



/*****************************************************************************
 * HELP
 *****************************************************************************/
1488
int
1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499
CommandInterpreter::executeHelp(char* parameters)
{
  if (emptyString(parameters)) {
    ndbout << helpText;

    ndbout << endl 
	   << "<severity> = " 
	   << "ALERT | CRITICAL | ERROR | WARNING | INFO | DEBUG"
	   << endl;

    ndbout << "<category> = ";
unknown's avatar
unknown committed
1500 1501 1502 1503 1504 1505
    for(int i = CFG_MIN_LOGLEVEL; i <= CFG_MAX_LOGLEVEL; i++){
      const char *str= ndb_mgm_get_event_category_string((ndb_mgm_event_category)i);
      if (str) {
	if (i != CFG_MIN_LOGLEVEL)
	  ndbout << " | ";
	ndbout << str;
1506 1507 1508 1509 1510 1511 1512
      }
    }
    ndbout << endl;

    ndbout << "<level>    = " << "0 - 15" << endl;
    ndbout << "<id>       = " << "ALL | Any database node id" << endl;
    ndbout << endl;
unknown's avatar
unknown committed
1513
    ndbout << "For detailed help on COMMAND, use HELP COMMAND." << endl;
1514
  } else {
unknown's avatar
unknown committed
1515 1516 1517 1518 1519 1520 1521 1522 1523
    int i = 0;
    for (i = 0; help_items[i].cmd != NULL; i++) 
    {
      if (strcasecmp(parameters, help_items[i].cmd) == 0)
      {
        ndbout << help_items[i].help;
        break;
      }     
    }
1524
    if (help_items[i].cmd == NULL){
unknown's avatar
unknown committed
1525
      ndbout << "No help for " << parameters << " available" << endl;
1526 1527
      return -1;
    }
1528
  }
1529
  return 0;
1530 1531 1532
}


unknown's avatar
unknown committed
1533 1534 1535 1536
/*****************************************************************************
 * SHUTDOWN
 *****************************************************************************/

unknown's avatar
unknown committed
1537
int
unknown's avatar
unknown committed
1538 1539 1540 1541 1542 1543
CommandInterpreter::executeShutdown(char* parameters) 
{ 
  ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
  if(state == NULL) {
    ndbout_c("Could not get status");
    printError();
unknown's avatar
unknown committed
1544
    return 1;
unknown's avatar
unknown committed
1545
  }
1546
  NdbAutoPtr<char> ap1((char*)state);
unknown's avatar
unknown committed
1547 1548

  int result = 0;
1549 1550
  int need_disconnect;
  result = ndb_mgm_stop3(m_mgmsrv, -1, 0, 0, &need_disconnect);
unknown's avatar
unknown committed
1551
  if (result < 0) {
1552
    ndbout << "Shutdown of NDB Cluster node(s) failed." << endl;
unknown's avatar
unknown committed
1553
    printError();
unknown's avatar
unknown committed
1554
    return result;
unknown's avatar
unknown committed
1555 1556
  }

1557
  ndbout << result << " NDB Cluster node(s) have shutdown." << endl;
unknown's avatar
unknown committed
1558

1559
  if(need_disconnect) {
1560
    ndbout << "Disconnecting to allow management server to shutdown."
1561
           << endl;
1562
    disconnect();
unknown's avatar
unknown committed
1563
  }
unknown's avatar
unknown committed
1564
  return 0;
unknown's avatar
unknown committed
1565 1566
}

1567 1568 1569 1570
/*****************************************************************************
 * SHOW
 *****************************************************************************/

unknown's avatar
unknown committed
1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596

static
const char *status_string(ndb_mgm_node_status status)
{
  switch(status){
  case NDB_MGM_NODE_STATUS_NO_CONTACT:
    return "not connected";
  case NDB_MGM_NODE_STATUS_NOT_STARTED:
    return "not started";
  case NDB_MGM_NODE_STATUS_STARTING:
    return "starting";
  case NDB_MGM_NODE_STATUS_STARTED:
    return "started";
  case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
    return "shutting down";
  case NDB_MGM_NODE_STATUS_RESTARTING:
    return "restarting";
  case NDB_MGM_NODE_STATUS_SINGLEUSER:
    return "single user mode";
  default:
    return "unknown state";
  }
}

static void
print_nodes(ndb_mgm_cluster_state *state, ndb_mgm_configuration_iterator *it,
1597 1598
	    const char *proc_name, int no_proc, ndb_mgm_node_type type,
	    int master_id)
unknown's avatar
unknown committed
1599 1600 1601
{ 
  int i;
  ndbout << "[" << proc_name
1602 1603
	 << "(" << ndb_mgm_get_node_type_string(type) << ")]\t"
	 << no_proc << " node(s)" << endl;
unknown's avatar
unknown committed
1604 1605 1606 1607 1608 1609 1610
  for(i=0; i < state->no_of_nodes; i++) {
    struct ndb_mgm_node_state *node_state= &(state->node_states[i]);
    if(node_state->node_type == type) {
      int node_id= node_state->node_id;
      ndbout << "id=" << node_id;
      if(node_state->version != 0) {
	const char *hostname= node_state->connect_address;
1611 1612
	if (hostname == 0
	    || strlen(hostname) == 0
1613
	    || strcasecmp(hostname,"0.0.0.0") == 0)
unknown's avatar
unknown committed
1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626
	  ndbout << " ";
	else
	  ndbout << "\t@" << hostname;
	ndbout << "  (Version: "
	       << getMajor(node_state->version) << "."
	       << getMinor(node_state->version) << "."
	       << getBuild(node_state->version);
	if (type == NDB_MGM_NODE_TYPE_NDB) {
	  if (node_state->node_status != NDB_MGM_NODE_STATUS_STARTED) {
	    ndbout << ", " << status_string(node_state->node_status);
	  }
	  if (node_state->node_group >= 0) {
	    ndbout << ", Nodegroup: " << node_state->node_group;
1627
	    if (master_id && node_state->dynamic_id == master_id)
unknown's avatar
unknown committed
1628 1629 1630 1631 1632
	      ndbout << ", Master";
	  }
	}
	ndbout << ")" << endl;
      } else {
1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643
	ndb_mgm_first(it);
	if(ndb_mgm_find(it, CFG_NODE_ID, node_id) == 0){
	  const char *config_hostname= 0;
	  ndb_mgm_get_string_parameter(it, CFG_NODE_HOST, &config_hostname);
	  if (config_hostname == 0 || config_hostname[0] == 0)
	    config_hostname= "any host";
	  ndbout_c(" (not connected, accepting connect from %s)",
		   config_hostname);
	}
	else
	{
unknown's avatar
unknown committed
1644 1645 1646 1647 1648 1649 1650 1651
	  ndbout_c("Unable to find node with id: %d", node_id);
	}
      }
    }
  }
  ndbout << endl;
}

1652
int
1653 1654 1655 1656 1657 1658 1659 1660
CommandInterpreter::executePurge(char* parameters) 
{ 
  int command_ok= 0;
  do {
    if (emptyString(parameters))
      break;
    char* firstToken = strtok(parameters, " ");
    char* nextToken = strtok(NULL, " \0");
1661
    if (strcasecmp(firstToken,"STALE") == 0 &&
1662
	nextToken &&
1663
	strcasecmp(nextToken, "SESSIONS") == 0) {
1664 1665 1666 1667 1668 1669 1670
      command_ok= 1;
      break;
    }
  } while(0);

  if (!command_ok) {
    ndbout_c("Unexpected command, expected: PURGE STALE SESSIONS");
1671
    return -1;
1672 1673 1674 1675 1676 1677
  }

  char *str;
  
  if (ndb_mgm_purge_stale_sessions(m_mgmsrv, &str)) {
    ndbout_c("Command failed");
1678
    return -1;
1679 1680 1681 1682 1683 1684 1685 1686 1687
  }
  if (str) {
    ndbout_c("Purged sessions with node id's: %s", str);
    free(str);
  }
  else
  {
    ndbout_c("No sessions purged");
  }
1688
  return 0;
1689 1690
}

1691
int
1692
CommandInterpreter::executeShow(char* parameters) 
unknown's avatar
unknown committed
1693 1694
{ 
  int i;
1695 1696 1697 1698 1699
  if (emptyString(parameters)) {
    ndb_mgm_cluster_state *state = ndb_mgm_get_status(m_mgmsrv);
    if(state == NULL) {
      ndbout_c("Could not get status");
      printError();
1700
      return -1;
1701
    }
1702
    NdbAutoPtr<char> ap1((char*)state);
1703

unknown's avatar
unknown committed
1704 1705 1706 1707
    ndb_mgm_configuration * conf = ndb_mgm_get_configuration(m_mgmsrv,0);
    if(conf == 0){
      ndbout_c("Could not get configuration");
      printError();
1708
      return -1;
unknown's avatar
unknown committed
1709 1710 1711 1712 1713 1714 1715
    }

    ndb_mgm_configuration_iterator * it;
    it = ndb_mgm_create_configuration_iterator((struct ndb_mgm_configuration *)conf, CFG_SECTION_NODE);

    if(it == 0){
      ndbout_c("Unable to create config iterator");
1716
      ndb_mgm_destroy_configuration(conf);
1717
      return -1;
unknown's avatar
unknown committed
1718 1719 1720
    }
    NdbAutoPtr<ndb_mgm_configuration_iterator> ptr(it);

1721
    int
1722 1723 1724 1725
      master_id= 0,
      ndb_nodes= 0,
      api_nodes= 0,
      mgm_nodes= 0;
1726

unknown's avatar
unknown committed
1727 1728 1729 1730 1731 1732 1733 1734
    for(i=0; i < state->no_of_nodes; i++) {
      if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB &&
	 state->node_states[i].version != 0){
	master_id= state->node_states[i].dynamic_id;
	break;
      }
    }
    
unknown's avatar
unknown committed
1735
    for(i=0; i < state->no_of_nodes; i++) {
1736 1737 1738 1739 1740
      switch(state->node_states[i].node_type) {
      case NDB_MGM_NODE_TYPE_API:
	api_nodes++;
	break;
      case NDB_MGM_NODE_TYPE_NDB:
unknown's avatar
unknown committed
1741 1742
	if (state->node_states[i].dynamic_id &&
	    state->node_states[i].dynamic_id < master_id)
1743
	  master_id= state->node_states[i].dynamic_id;
1744 1745 1746 1747 1748 1749 1750
	ndb_nodes++;
	break;
      case NDB_MGM_NODE_TYPE_MGM:
	mgm_nodes++;
	break;
      case NDB_MGM_NODE_TYPE_UNKNOWN:
        ndbout << "Error: Unknown Node Type" << endl;
1751
        return -1;
unknown's avatar
unknown committed
1752 1753
      case NDB_MGM_NODE_TYPE_REP:
	abort();
1754 1755 1756
      }
    }

1757 1758
    ndbout << "Cluster Configuration" << endl
	   << "---------------------" << endl;
unknown's avatar
unknown committed
1759 1760 1761
    print_nodes(state, it, "ndbd",     ndb_nodes, NDB_MGM_NODE_TYPE_NDB, master_id);
    print_nodes(state, it, "ndb_mgmd", mgm_nodes, NDB_MGM_NODE_TYPE_MGM, 0);
    print_nodes(state, it, "mysqld",   api_nodes, NDB_MGM_NODE_TYPE_API, 0);
1762
    //    ndbout << helpTextShow;
1763
    ndb_mgm_destroy_configuration(conf);
1764
    return 0;
1765 1766
  } else if (strcasecmp(parameters, "PROPERTIES") == 0 ||
	     strcasecmp(parameters, "PROP") == 0) {
1767 1768
    ndbout << "SHOW PROPERTIES is not yet implemented." << endl;
    //  ndbout << "_mgmtSrvr.getConfig()->print();" << endl; /* XXX */
1769 1770
  } else if (strcasecmp(parameters, "CONFIGURATION") == 0 ||
	     strcasecmp(parameters, "CONFIG") == 0){
1771 1772
    ndbout << "SHOW CONFIGURATION is not yet implemented." << endl;
    //nbout << "_mgmtSrvr.getConfig()->printConfigFile();" << endl; /* XXX */
1773 1774 1775
  } else if (strcasecmp(parameters, "PARAMETERS") == 0 ||
	     strcasecmp(parameters, "PARAMS") == 0 ||
	     strcasecmp(parameters, "PARAM") == 0) {
1776 1777 1778 1779 1780
    ndbout << "SHOW PARAMETERS is not yet implemented." << endl;
    //    ndbout << "_mgmtSrvr.getConfig()->getConfigInfo()->print();" 
    //           << endl; /* XXX */
  } else {
    ndbout << "Invalid argument." << endl;
1781
    return -1;
1782
  }
1783
  return 0;
1784 1785
}

1786
int
1787
CommandInterpreter::executeConnect(char* parameters, bool interactive) 
unknown's avatar
unknown committed
1788
{
1789 1790
  BaseString *basestring = NULL;

unknown's avatar
unknown committed
1791
  disconnect();
1792
  if (!emptyString(parameters)) {
1793 1794
    basestring= new BaseString(parameters);
    m_constr= basestring->trim().c_str();
1795
  }
1796
  if ( connect(interactive) == false ){
1797 1798
    return -1;
  }
1799 1800
  if (basestring != NULL)
    delete basestring;
1801

1802
  return 0;
unknown's avatar
unknown committed
1803
}
1804 1805 1806 1807 1808 1809

//*****************************************************************************
//*****************************************************************************
void 
CommandInterpreter::executeClusterLog(char* parameters) 
{
unknown's avatar
unknown committed
1810
  DBUG_ENTER("CommandInterpreter::executeClusterLog");
unknown's avatar
unknown committed
1811
  int i;
unknown's avatar
unknown committed
1812 1813 1814
  if (emptyString(parameters))
  {
    ndbout << "Missing argument." << endl;
1815
    m_error = -1;
unknown's avatar
unknown committed
1816 1817 1818
    DBUG_VOID_RETURN;
  }

unknown's avatar
unknown committed
1819
  enum ndb_mgm_event_severity severity = NDB_MGM_EVENT_SEVERITY_ALL;
1820
    
unknown's avatar
unknown committed
1821 1822 1823 1824 1825
  char * tmpString = my_strdup(parameters,MYF(MY_WME));
  My_auto_ptr<char> ap1(tmpString);
  char * tmpPtr = 0;
  char * item = strtok_r(tmpString, " ", &tmpPtr);
  int enable;
1826

unknown's avatar
unknown committed
1827
  const unsigned int *enabled= ndb_mgm_get_logfilter(m_mgmsrv);
unknown's avatar
unknown committed
1828 1829 1830
  if(enabled == NULL) {
    ndbout << "Couldn't get status" << endl;
    printError();
1831
    m_error = -1;
unknown's avatar
unknown committed
1832 1833
    DBUG_VOID_RETURN;
  }
1834

unknown's avatar
unknown committed
1835 1836 1837 1838 1839 1840 1841 1842
  /********************
   * CLUSTERLOG INFO
   ********************/
  if (strcasecmp(item, "INFO") == 0) {
    DBUG_PRINT("info",("INFO"));
    if(enabled[0] == 0)
    {
      ndbout << "Cluster logging is disabled." << endl;
1843
      m_error = 0;
unknown's avatar
unknown committed
1844 1845 1846 1847 1848 1849 1850
      DBUG_VOID_RETURN;
    }
#if 0 
    for(i = 0; i<7;i++)
      printf("enabled[%d] = %d\n", i, enabled[i]);
#endif
    ndbout << "Severities enabled: ";
unknown's avatar
unknown committed
1851 1852
    for(i = 1; i < (int)NDB_MGM_EVENT_SEVERITY_ALL; i++) {
      const char *str= ndb_mgm_get_event_severity_string((ndb_mgm_event_severity)i);
unknown's avatar
unknown committed
1853 1854 1855 1856
      if (str == 0)
      {
	DBUG_ASSERT(false);
	continue;
1857
      }
unknown's avatar
unknown committed
1858 1859
      if(enabled[i])
	ndbout << BaseString(str).ndb_toupper() << " ";
1860
    }
unknown's avatar
unknown committed
1861
    ndbout << endl;
1862
    m_error = 0;
unknown's avatar
unknown committed
1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878
    DBUG_VOID_RETURN;

  } 
  else if (strcasecmp(item, "FILTER") == 0 ||
	   strcasecmp(item, "TOGGLE") == 0)
  {
    DBUG_PRINT("info",("TOGGLE"));
    enable= -1;
  } 
  else if (strcasecmp(item, "OFF") == 0) 
  {
    DBUG_PRINT("info",("OFF"));
    enable= 0;
  } else if (strcasecmp(item, "ON") == 0) {
    DBUG_PRINT("info",("ON"));
    enable= 1;
1879
  } else {
unknown's avatar
unknown committed
1880
    ndbout << "Invalid argument." << endl;
1881
    m_error = -1;
unknown's avatar
unknown committed
1882
    DBUG_VOID_RETURN;
1883
  }
unknown's avatar
unknown committed
1884 1885 1886 1887

  int res_enable;
  item = strtok_r(NULL, " ", &tmpPtr);
  if (item == NULL) {
unknown's avatar
unknown committed
1888 1889 1890 1891
    res_enable=
      ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv,
					     NDB_MGM_EVENT_SEVERITY_ON,
					     enable, NULL);
unknown's avatar
unknown committed
1892 1893 1894 1895
    if (res_enable < 0)
    {
      ndbout << "Couldn't set filter" << endl;
      printError();
1896
      m_error = -1;
unknown's avatar
unknown committed
1897 1898 1899
      DBUG_VOID_RETURN;
    }
    ndbout << "Cluster logging is " << (res_enable ? "enabled.":"disabled") << endl;
1900
    m_error = 0;
unknown's avatar
unknown committed
1901 1902 1903 1904
    DBUG_VOID_RETURN;
  }

  do {
unknown's avatar
unknown committed
1905
    severity= NDB_MGM_ILLEGAL_EVENT_SEVERITY;
unknown's avatar
unknown committed
1906
    if (strcasecmp(item, "ALL") == 0) {
unknown's avatar
unknown committed
1907
      severity = NDB_MGM_EVENT_SEVERITY_ALL;	
unknown's avatar
unknown committed
1908
    } else if (strcasecmp(item, "ALERT") == 0) {
unknown's avatar
unknown committed
1909
      severity = NDB_MGM_EVENT_SEVERITY_ALERT;
unknown's avatar
unknown committed
1910
    } else if (strcasecmp(item, "CRITICAL") == 0) { 
unknown's avatar
unknown committed
1911
      severity = NDB_MGM_EVENT_SEVERITY_CRITICAL;
unknown's avatar
unknown committed
1912
    } else if (strcasecmp(item, "ERROR") == 0) {
unknown's avatar
unknown committed
1913
      severity = NDB_MGM_EVENT_SEVERITY_ERROR;
unknown's avatar
unknown committed
1914
    } else if (strcasecmp(item, "WARNING") == 0) {
unknown's avatar
unknown committed
1915
      severity = NDB_MGM_EVENT_SEVERITY_WARNING;
unknown's avatar
unknown committed
1916
    } else if (strcasecmp(item, "INFO") == 0) {
unknown's avatar
unknown committed
1917
      severity = NDB_MGM_EVENT_SEVERITY_INFO;
unknown's avatar
unknown committed
1918
    } else if (strcasecmp(item, "DEBUG") == 0) {
unknown's avatar
unknown committed
1919
      severity = NDB_MGM_EVENT_SEVERITY_DEBUG;
unknown's avatar
unknown committed
1920 1921 1922
    } else if (strcasecmp(item, "OFF") == 0 ||
	       strcasecmp(item, "ON") == 0) {
      if (enable < 0) // only makes sense with toggle
unknown's avatar
unknown committed
1923
	severity = NDB_MGM_EVENT_SEVERITY_ON;
unknown's avatar
unknown committed
1924
    }
unknown's avatar
unknown committed
1925
    if (severity == NDB_MGM_ILLEGAL_EVENT_SEVERITY) {
unknown's avatar
unknown committed
1926
      ndbout << "Invalid severity level: " << item << endl;
1927
      m_error = -1;
unknown's avatar
unknown committed
1928 1929 1930
      DBUG_VOID_RETURN;
    }

unknown's avatar
unknown committed
1931 1932
    res_enable= ndb_mgm_set_clusterlog_severity_filter(m_mgmsrv, severity,
						       enable, NULL);
unknown's avatar
unknown committed
1933 1934 1935 1936
    if (res_enable < 0)
    {
      ndbout << "Couldn't set filter" << endl;
      printError();
1937
      m_error = -1;
unknown's avatar
unknown committed
1938 1939
      DBUG_VOID_RETURN;
    }
1940
    ndbout << BaseString(item).ndb_toupper().c_str() << " " << (res_enable ? "enabled":"disabled") << endl;
unknown's avatar
unknown committed
1941 1942 1943

    item = strtok_r(NULL, " ", &tmpPtr);	
  } while(item != NULL);
1944 1945
  
  m_error = 0;
unknown's avatar
unknown committed
1946
  DBUG_VOID_RETURN;
1947 1948 1949 1950 1951
} 

//*****************************************************************************
//*****************************************************************************

1952
int
1953 1954
CommandInterpreter::executeStop(int processId, const char *parameters,
                                bool all) 
1955
{
1956
  int retval = 0;
1957

1958 1959 1960 1961 1962 1963 1964
  Vector<BaseString> command_list;
  if (parameters)
  {
    BaseString tmp(parameters);
    tmp.split(command_list);
    for (unsigned i= 0; i < command_list.size();)
      command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
unknown's avatar
unknown committed
1965
  }
1966
  if (all)
1967
    retval = executeStop(command_list, 0, 0, 0);
1968
  else
1969 1970 1971
    retval = executeStop(command_list, 0, &processId, 1);

  return retval;
1972 1973
}

1974
int
1975 1976 1977 1978
CommandInterpreter::executeStop(Vector<BaseString> &command_list,
                                unsigned command_pos,
                                int *node_ids, int no_of_nodes)
{
1979
  int need_disconnect;
1980
  int abort= 0;
1981 1982
  int retval = 0;

1983 1984 1985 1986 1987 1988 1989 1990 1991 1992
  for (; command_pos < command_list.size(); command_pos++)
  {
    const char *item= command_list[command_pos].c_str();
    if (strcasecmp(item, "-A") == 0)
    {
      abort= 1;
      continue;
    }
    ndbout_c("Invalid option: %s. Expecting -A after STOP",
             item);
1993
    return -1;
1994 1995
  }

1996 1997
  int result= ndb_mgm_stop3(m_mgmsrv, no_of_nodes, node_ids, abort,
                            &need_disconnect);
1998 1999 2000
  if (result < 0)
  {
    ndbout_c("Shutdown failed.");
2001
    printError();
2002
    retval = -1;
2003 2004 2005 2006 2007 2008
  }
  else
  {
    if (node_ids == 0)
      ndbout_c("NDB Cluster has shutdown.");
    else
2009
    {
2010 2011
      ndbout << "Node";
      for (int i= 0; i < no_of_nodes; i++)
2012
          ndbout << " " << node_ids[i];
2013
      ndbout_c(" has shutdown.");
2014
    }
2015
  }
2016 2017 2018 2019 2020 2021 2022

  if(need_disconnect)
  {
    ndbout << "Disconnecting to allow Management Server to shutdown" << endl;
    disconnect();
  }

2023
  return retval;
2024 2025
}

2026
int
2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037
CommandInterpreter::executeEnterSingleUser(char* parameters) 
{
  strtok(parameters, " ");
  struct ndb_mgm_reply reply;
  char* id = strtok(NULL, " ");
  id = strtok(NULL, " ");
  id = strtok(NULL, "\0");
  int nodeId = -1;
  if(id == 0 || sscanf(id, "%d", &nodeId) != 1){
    ndbout_c("Invalid arguments: expected <NodeId>");
    ndbout_c("Use SHOW to see what API nodes are configured");
2038
    return -1;
2039 2040 2041 2042 2043 2044
  }
  int result = ndb_mgm_enter_single_user(m_mgmsrv, nodeId, &reply);
  
  if (result != 0) {
    ndbout_c("Entering single user mode for node %d failed", nodeId);
    printError();
2045
    return -1;
2046
  } else {
2047 2048
    ndbout_c("Single user mode entered");
    ndbout_c("Access is granted for API node %d only.", nodeId);
2049
  }
2050
  return 0;
2051 2052
}

2053
int
2054 2055 2056 2057 2058 2059
CommandInterpreter::executeExitSingleUser(char* parameters) 
{
  int result = ndb_mgm_exit_single_user(m_mgmsrv, 0);
  if (result != 0) {
    ndbout_c("Exiting single user mode failed.");
    printError();
2060
    return -1;
2061 2062
  } else {
    ndbout_c("Exiting single user mode in progress.");
2063
    ndbout_c("Use ALL STATUS or SHOW to see when single user mode has been exited.");
2064
    return 0;
2065 2066 2067
  }
}

2068
int
2069 2070 2071 2072
CommandInterpreter::executeStart(int processId, const char* parameters,
				 bool all) 
{
  int result;
2073
  int retval = 0;
2074 2075 2076 2077 2078 2079 2080 2081 2082
  if(all) {
    result = ndb_mgm_start(m_mgmsrv, 0, 0);
  } else {
    result = ndb_mgm_start(m_mgmsrv, 1, &processId);
  }

  if (result <= 0) {
    ndbout << "Start failed." << endl;
    printError();
2083
    retval = -1;
2084 2085 2086 2087 2088 2089 2090
  } else
    {
      if(all)
	ndbout_c("NDB Cluster is being started.");
      else
	ndbout_c("Database node %d is being started.", processId);
    }
2091
  return retval;
2092 2093
}

2094
int
2095
CommandInterpreter::executeRestart(int processId, const char* parameters,
2096 2097 2098
				   bool all)
{
  Vector<BaseString> command_list;
2099 2100
  int retval = 0;

2101 2102 2103 2104 2105 2106 2107 2108
  if (parameters)
  {
    BaseString tmp(parameters);
    tmp.split(command_list);
    for (unsigned i= 0; i < command_list.size();)
      command_list[i].c_str()[0] ? i++ : (command_list.erase(i),0);
  }
  if (all)
2109
    retval = executeRestart(command_list, 0, 0, 0);
2110
  else
2111 2112 2113
    retval = executeRestart(command_list, 0, &processId, 1);

  return retval;
2114 2115
}

2116
int
2117 2118 2119
CommandInterpreter::executeRestart(Vector<BaseString> &command_list,
                                   unsigned command_pos,
                                   int *node_ids, int no_of_nodes)
2120 2121
{
  int result;
2122
  int retval = 0;
2123 2124 2125
  int nostart= 0;
  int initialstart= 0;
  int abort= 0;
2126
  int need_disconnect= 0;
2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144

  for (; command_pos < command_list.size(); command_pos++)
  {
    const char *item= command_list[command_pos].c_str();
    if (strcasecmp(item, "-N") == 0)
    {
      nostart= 1;
      continue;
    }
    if (strcasecmp(item, "-I") == 0)
    {
      initialstart= 1;
      continue;
    }
    if (strcasecmp(item, "-A") == 0)
    {
      abort= 1;
      continue;
2145
    }
2146 2147
    ndbout_c("Invalid option: %s. Expecting -A,-N or -I after RESTART",
             item);
2148
    return -1;
2149 2150
  }

2151 2152 2153
  if (!nostart)
    ndbout_c("Shutting down nodes with \"-n, no start\" option, to subsequently start the nodes.");

2154 2155 2156
  result= ndb_mgm_restart3(m_mgmsrv, no_of_nodes, node_ids,
                           initialstart, nostart, abort, &need_disconnect);

2157
  if (result <= 0) {
2158
    ndbout_c("Restart failed.");
2159
    printError();
2160
    retval = -1;
2161 2162 2163 2164 2165 2166
  }
  else
  {
    if (node_ids == 0)
      ndbout_c("NDB Cluster is being restarted.");
    else
2167
    {
2168 2169 2170 2171
      ndbout << "Node";
      for (int i= 0; i < no_of_nodes; i++)
        ndbout << " " << node_ids[i];
      ndbout_c(" is being restarted");
2172
    }
2173 2174
    if(need_disconnect)
      disconnect();
2175
  }
2176
  return retval;
2177 2178
}

2179
int
2180 2181 2182
CommandInterpreter::executeDumpState(int processId, const char* parameters,
				     bool all) 
{
unknown's avatar
unknown committed
2183
  if(emptyString(parameters)){
2184
    ndbout << "Expected argument" << endl;
2185
    return -1;
2186 2187 2188 2189 2190
  }

  Uint32 no = 0;
  int pars[25];
  
2191 2192
  char * tmpString = my_strdup(parameters,MYF(MY_WME));
  My_auto_ptr<char> ap1(tmpString);
2193 2194 2195 2196 2197 2198 2199 2200 2201
  char * tmpPtr = 0;
  char * item = strtok_r(tmpString, " ", &tmpPtr);
  while(item != NULL){
    if (0x0 <= strtoll(item, NULL, 0) && strtoll(item, NULL, 0) <= 0xffffffff){
      pars[no] = strtoll(item, NULL, 0); 
    } else {
      ndbout << "Illegal value in argument to signal." << endl
	     << "(Value must be between 0 and 0xffffffff.)" 
	     << endl;
2202
      return -1;
2203 2204 2205 2206 2207 2208 2209 2210 2211 2212 2213
    }
    no++;
    item = strtok_r(NULL, " ", &tmpPtr);
  }
  ndbout << "Sending dump signal with data:" << endl;
  for (Uint32 i=0; i<no; i++) {
    ndbout.setHexFormat(1) << pars[i] << " ";
    if (!(i+1 & 0x3)) ndbout << endl;
  }
  
  struct ndb_mgm_reply reply;
2214
  return ndb_mgm_dump_state(m_mgmsrv, processId, pars, no, &reply);
2215 2216
}

2217
int
2218 2219 2220 2221
CommandInterpreter::executeStatus(int processId, 
				  const char* parameters, bool all) 
{
  if (! emptyString(parameters)) {
unknown's avatar
unknown committed
2222
    ndbout_c("No parameters expected to this command.");
2223
    return -1;
2224 2225 2226 2227 2228 2229 2230 2231 2232 2233
  }

  ndb_mgm_node_status status;
  Uint32 startPhase, version;
  
  struct ndb_mgm_cluster_state *cl;
  cl = ndb_mgm_get_status(m_mgmsrv);
  if(cl == NULL) {
    ndbout_c("Cannot get status of node %d.", processId);
    printError();
2234
    return -1;
2235
  }
2236
  NdbAutoPtr<char> ap1((char*)cl);
2237 2238 2239 2240 2241 2242

  int i = 0;
  while((i < cl->no_of_nodes) && cl->node_states[i].node_id != processId)
    i++;
  if(cl->node_states[i].node_id != processId) {
    ndbout << processId << ": Node not found" << endl;
2243
    return -1;
2244
  }
2245 2246
  if (cl->node_states[i].node_type != NDB_MGM_NODE_TYPE_NDB){
    if (cl->node_states[i].version != 0){
2247
      version = cl->node_states[i].version;
2248 2249 2250 2251 2252 2253 2254 2255 2256
      ndbout << "Node "<< cl->node_states[i].node_id <<": connected" ;
      ndbout_c(" (Version %d.%d.%d)",
             getMajor(version) ,
             getMinor(version),
             getBuild(version));

    }else
     ndbout << "Node "<< cl->node_states[i].node_id <<": not connected" << endl;
    return 0;
2257
  }
2258 2259 2260 2261
  status = cl->node_states[i].node_status;
  startPhase = cl->node_states[i].start_phase;
  version = cl->node_states[i].version;

unknown's avatar
unknown committed
2262
  ndbout << "Node " << processId << ": " << status_string(status);
2263 2264
  switch(status){
  case NDB_MGM_NODE_STATUS_STARTING:
unknown's avatar
unknown committed
2265
    ndbout << " (Phase " << startPhase << ")";
2266 2267
    break;
  case NDB_MGM_NODE_STATUS_SHUTTING_DOWN:
unknown's avatar
unknown committed
2268
    ndbout << " (Phase " << startPhase << ")";
2269 2270 2271 2272 2273 2274 2275 2276 2277
    break;
  default:
    break;
  }
  if(status != NDB_MGM_NODE_STATUS_NO_CONTACT)
    ndbout_c(" (Version %d.%d.%d)", 
	     getMajor(version) ,
	     getMinor(version),
	     getBuild(version));
unknown's avatar
unknown committed
2278 2279
  else
    ndbout << endl;
2280 2281
  
  return 0;
2282 2283 2284 2285 2286 2287
}


//*****************************************************************************
//*****************************************************************************

2288
int
2289 2290 2291 2292
CommandInterpreter::executeLogLevel(int processId, const char* parameters, 
				    bool all) 
{
  (void) all;
unknown's avatar
unknown committed
2293 2294
  if (emptyString(parameters)) {
    ndbout << "Expected argument" << endl;
2295
    return -1;
unknown's avatar
unknown committed
2296
  } 
2297 2298 2299 2300 2301
  BaseString tmp(parameters);
  Vector<BaseString> spec;
  tmp.split(spec, "=");
  if(spec.size() != 2){
    ndbout << "Invalid loglevel specification: " << parameters << endl;
2302
    return -1;
2303
  }
2304

2305 2306 2307 2308 2309 2310 2311
  spec[0].trim().ndb_toupper();
  int category = ndb_mgm_match_event_category(spec[0].c_str());
  if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
    category = atoi(spec[0].c_str());
    if(category < NDB_MGM_MIN_EVENT_CATEGORY ||
       category > NDB_MGM_MAX_EVENT_CATEGORY){
      ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
2312
      return -1;
2313 2314
    }
  }
2315 2316 2317 2318
  
  int level = atoi(spec[1].c_str());
  if(level < 0 || level > 15){
    ndbout << "Invalid level: " << spec[1].c_str() << endl;
2319
    return -1;
2320 2321
  }
  
unknown's avatar
unknown committed
2322 2323
  ndbout << "Executing LOGLEVEL on node " << processId << flush;

2324 2325 2326
  struct ndb_mgm_reply reply;
  int result;
  result = ndb_mgm_set_loglevel_node(m_mgmsrv, 
2327 2328
				     processId,
				     (ndb_mgm_event_category)category,
2329 2330
				     level, 
				     &reply);
2331
  
2332
  if (result < 0) {
unknown's avatar
unknown committed
2333
    ndbout_c(" failed.");
2334
    printError();
2335
    return -1;
2336
  } else {
unknown's avatar
unknown committed
2337
    ndbout_c(" OK!");
2338
  }  
2339
  return 0;
2340 2341 2342 2343
}

//*****************************************************************************
//*****************************************************************************
2344
int CommandInterpreter::executeError(int processId, 
2345 2346
				      const char* parameters, bool /* all */) 
{
2347
  int retval = 0;
2348 2349
  if (emptyString(parameters)) {
    ndbout << "Missing error number." << endl;
2350
    return -1;
2351 2352 2353
  }

  // Copy parameters since strtok will modify it
2354 2355
  char* newpar = my_strdup(parameters,MYF(MY_WME)); 
  My_auto_ptr<char> ap1(newpar);
2356 2357 2358 2359 2360
  char* firstParameter = strtok(newpar, " ");

  int errorNo;
  if (! convert(firstParameter, errorNo)) {
    ndbout << "Expected an integer." << endl;
2361
    return -1;
2362 2363 2364 2365 2366
  }

  char* allAfterFirstParameter = strtok(NULL, "\0");
  if (! emptyString(allAfterFirstParameter)) {
    ndbout << "Nothing expected after error number." << endl;
2367
    return -1;
2368 2369
  }

2370 2371
  retval = ndb_mgm_insert_error(m_mgmsrv, processId, errorNo, NULL);
  return retval;
2372 2373 2374 2375 2376
}

//*****************************************************************************
//*****************************************************************************

2377
int
2378 2379 2380 2381 2382 2383
CommandInterpreter::executeLog(int processId,
			       const char* parameters, bool all) 
{
  struct ndb_mgm_reply reply;
  Vector<const char *> blocks;
  if (! parseBlockSpecification(parameters, blocks)) {
2384
    return -1;
2385
  }
2386
  int len=1;
unknown's avatar
unknown committed
2387 2388
  Uint32 i;
  for(i=0; i<blocks.size(); i++) {
2389
    len += strlen(blocks[i]) + 1;
2390
  }
2391 2392
  char * blockNames = (char*)my_malloc(len,MYF(MY_WME));
  My_auto_ptr<char> ap1(blockNames);
2393
  
2394
  blockNames[0] = 0;
unknown's avatar
unknown committed
2395
  for(i=0; i<blocks.size(); i++) {
2396 2397 2398 2399
    strcat(blockNames, blocks[i]);
    strcat(blockNames, "|");
  }
  
2400
  int result = ndb_mgm_log_signals(m_mgmsrv,
2401 2402 2403 2404 2405
				   processId, 
				   NDB_MGM_SIGNAL_LOG_MODE_INOUT, 
				   blockNames,
				   &reply);
  if (result != 0) {
2406 2407
    ndbout_c("Execute LOG on node %d failed.", processId);
    printError();
2408
    return -1;
2409
  }
2410
  return 0;
2411 2412 2413 2414
}

//*****************************************************************************
//*****************************************************************************
2415
int
2416 2417 2418
CommandInterpreter::executeLogIn(int /* processId */,
				 const char* parameters, bool /* all */) 
{
2419
  ndbout << "Command LOGIN not implemented." << endl;
2420
  return 0;
2421 2422 2423 2424
}

//*****************************************************************************
//*****************************************************************************
2425
int
2426 2427 2428
CommandInterpreter::executeLogOut(int /*processId*/, 
				  const char* parameters, bool /*all*/) 
{
2429
  ndbout << "Command LOGOUT not implemented." << endl;
2430
  return 0;
2431 2432 2433 2434
}

//*****************************************************************************
//*****************************************************************************
2435
int
2436 2437 2438
CommandInterpreter::executeLogOff(int /*processId*/,
				  const char* parameters, bool /*all*/) 
{
2439
  ndbout << "Command LOGOFF not implemented." << endl;
2440
  return 0;
2441 2442 2443 2444
}

//*****************************************************************************
//*****************************************************************************
2445
int
2446
CommandInterpreter::executeTestOn(int processId,
2447 2448 2449 2450
				  const char* parameters, bool /*all*/) 
{
  if (! emptyString(parameters)) {
    ndbout << "No parameters expected to this command." << endl;
2451
    return -1;
2452
  }
2453 2454
  struct ndb_mgm_reply reply;
  int result = ndb_mgm_start_signallog(m_mgmsrv, processId, &reply);
2455
  if (result != 0) {
2456 2457
    ndbout_c("Execute TESTON failed.");
    printError();
2458
    return -1;
2459
  }
2460
  return 0;
2461 2462 2463 2464
}

//*****************************************************************************
//*****************************************************************************
2465
int
2466
CommandInterpreter::executeTestOff(int processId,
2467 2468 2469 2470
				   const char* parameters, bool /*all*/) 
{
  if (! emptyString(parameters)) {
    ndbout << "No parameters expected to this command." << endl;
2471
    return -1;
2472
  }
2473 2474
  struct ndb_mgm_reply reply;
  int result = ndb_mgm_stop_signallog(m_mgmsrv, processId, &reply);
2475
  if (result != 0) {
2476 2477
    ndbout_c("Execute TESTOFF failed.");
    printError();
2478
    return -1;
2479
  }
2480
  return 0;
2481 2482 2483 2484 2485
}


//*****************************************************************************
//*****************************************************************************
2486
int 
2487 2488 2489 2490 2491
CommandInterpreter::executeSet(int /*processId*/, 
			       const char* parameters, bool /*all*/) 
{
  if (emptyString(parameters)) {
    ndbout << "Missing parameter name." << endl;
2492
    return -1;
2493 2494 2495
  }
#if 0
  // Copy parameters since strtok will modify it
2496 2497
  char* newpar = my_strdup(parameters,MYF(MY_WME));
  My_auto_ptr<char> ap1(newpar);
2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533
  char* configParameterName = strtok(newpar, " ");

  char* allAfterParameterName = strtok(NULL, "\0");
  if (emptyString(allAfterParameterName)) {
    ndbout << "Missing parameter value." << endl;
    return;
  }

  char* value = strtok(allAfterParameterName, " ");

  char* allAfterValue = strtok(NULL, "\0");
  if (! emptyString(allAfterValue)) {
    ndbout << "Nothing expected after parameter value." << endl;
    return;
  }

  bool configBackupFileUpdated;
  bool configPrimaryFileUpdated;
  
  // TODO The handling of the primary and backup config files should be 
  // analysed further.
  // How it should be handled if only the backup is possible to write.

  int result = _mgmtSrvr.updateConfigParam(processId, configParameterName, 
					   value, configBackupFileUpdated, 
					   configPrimaryFileUpdated);
  if (result == 0) {
    if (configBackupFileUpdated && configPrimaryFileUpdated) {
      ndbout << "The configuration is updated." << endl;
    }
    else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
      ndbout << "The configuration is updated but it was only possible " 
	     << "to update the backup configuration file, not the primary." 
	     << endl;
    }
    else {
unknown's avatar
unknown committed
2534
      assert(false);
2535 2536 2537
    }
  }
  else {
2538
    ndbout << get_error_text(result) << endl;
2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552
    if (configBackupFileUpdated && configPrimaryFileUpdated) {
      ndbout << "The configuration files are however updated and "
	     << "the value will be used next time the process is restarted." 
	     << endl;
    }
    else if (configBackupFileUpdated && !configPrimaryFileUpdated) {
      ndbout << "It was only possible to update the backup "
	     << "configuration file, not the primary." << endl;
    }
    else if (!configBackupFileUpdated && !configPrimaryFileUpdated) {
      ndbout << "The configuration files are not updated." << endl;
    }
    else {
      // The primary is not tried to write if the write of backup file fails
unknown's avatar
unknown committed
2553
      abort();
2554 2555
    }
  }
2556 2557
#endif 
  return 0;
2558 2559 2560 2561
}

//*****************************************************************************
//*****************************************************************************
2562
int CommandInterpreter::executeGetStat(int /*processId*/,
2563 2564 2565 2566
					const char* parameters, bool /*all*/) 
{
  if (! emptyString(parameters)) {
    ndbout << "No parameters expected to this command." << endl;
2567
    return -1;
2568 2569 2570 2571 2572 2573
  }

#if 0
  MgmtSrvr::Statistics statistics;
  int result = _mgmtSrvr.getStatistics(processId, statistics);
  if (result != 0) {
2574
    ndbout << get_error_text(result) << endl;
2575 2576 2577 2578 2579 2580 2581 2582
    return;
  }
#endif
  // Print statistic...
  /*
  ndbout << "Number of GETSTAT commands: " 
  << statistics._test1 << endl;
  */
2583
  return 0;
2584 2585 2586 2587 2588
}

//*****************************************************************************
//*****************************************************************************
				 
2589
int
2590 2591 2592 2593
CommandInterpreter::executeEventReporting(int processId,
					  const char* parameters, 
					  bool all) 
{
2594
  int retval = 0;
unknown's avatar
unknown committed
2595 2596
  if (emptyString(parameters)) {
    ndbout << "Expected argument" << endl;
2597
    return -1;
unknown's avatar
unknown committed
2598
  }
2599
  BaseString tmp(parameters);
2600 2601
  Vector<BaseString> specs;
  tmp.split(specs, " ");
2602

unknown's avatar
unknown committed
2603
  for (int i=0; i < (int) specs.size(); i++)
2604 2605 2606 2607 2608 2609
  {
    Vector<BaseString> spec;
    specs[i].split(spec, "=");
    if(spec.size() != 2){
      ndbout << "Invalid loglevel specification: " << specs[i] << endl;
      continue;
2610
    }
unknown's avatar
unknown committed
2611

2612 2613 2614 2615 2616 2617 2618 2619 2620 2621
    spec[0].trim().ndb_toupper();
    int category = ndb_mgm_match_event_category(spec[0].c_str());
    if(category == NDB_MGM_ILLEGAL_EVENT_CATEGORY){
      if(!convert(spec[0].c_str(), category) ||
	 category < NDB_MGM_MIN_EVENT_CATEGORY ||
	 category > NDB_MGM_MAX_EVENT_CATEGORY){
	ndbout << "Unknown category: \"" << spec[0].c_str() << "\"" << endl;
	continue;
      }
    }
unknown's avatar
unknown committed
2622

2623 2624 2625 2626 2627 2628
    int level;
    if (!convert(spec[1].c_str(),level))
    {
      ndbout << "Invalid level: " << spec[1].c_str() << endl;
      continue;
    }
2629

2630 2631 2632 2633 2634 2635 2636 2637 2638 2639
    ndbout << "Executing CLUSTERLOG " << spec[0] << "=" << spec[1]
	   << " on node " << processId << flush;

    struct ndb_mgm_reply reply;
    int result;
    result = ndb_mgm_set_loglevel_clusterlog(m_mgmsrv, 
					     processId,
					     (ndb_mgm_event_category)category,
					     level, 
					     &reply);
2640
  
2641 2642 2643
    if (result != 0) {
      ndbout_c(" failed."); 
      printError();
2644
      retval = -1;
2645 2646 2647 2648
    } else {
      ndbout_c(" OK!"); 
    }
  }
2649
  return retval;
2650 2651 2652 2653 2654
}

/*****************************************************************************
 * Backup
 *****************************************************************************/
2655
int
2656
CommandInterpreter::executeStartBackup(char* parameters, bool interactive)
2657 2658 2659
{
  struct ndb_mgm_reply reply;
  unsigned int backupId;
2660

unknown's avatar
unknown committed
2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672
  Vector<BaseString> args;
  {
    BaseString(parameters).split(args);
    for (unsigned i= 0; i < args.size(); i++)
      if (args[i].length() == 0)
	args.erase(i--);
      else
	args[i].ndb_toupper();
  }
  int sz= args.size();

  int result;
2673 2674
  int flags = 2;
  if (sz == 2 && args[1] == "NOWAIT")
unknown's avatar
unknown committed
2675
  {
2676
    flags = 0;
unknown's avatar
unknown committed
2677
  }
2678
  else if (sz == 1 || (sz == 3 && args[1] == "WAIT" && args[2] == "COMPLETED"))
unknown's avatar
unknown committed
2679
  {
2680
    flags = 2;
unknown's avatar
unknown committed
2681 2682
    ndbout_c("Waiting for completed, this may take several minutes");
  }
2683
  else if (sz == 3 && args[1] == "WAIT" && args[2] == "STARTED")
unknown's avatar
unknown committed
2684 2685
  {
    ndbout_c("Waiting for started, this may take several minutes");
2686
    flags = 1;
unknown's avatar
unknown committed
2687 2688 2689 2690 2691 2692 2693
  }
  else
  {
    invalid_command(parameters);
    return -1;
  }

2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708
  NdbLogEventHandle log_handle= NULL;
  struct ndb_logevent log_event;
  if (flags == 2 && !interactive)
  {
    int filter[] = { 15, NDB_MGM_EVENT_CATEGORY_BACKUP, 0, 0 };
    log_handle = ndb_mgm_create_logevent_handle(m_mgmsrv, filter);
    if (!log_handle)
    {
      ndbout << "Initializing start of backup failed" << endl;
      printError();
      return -1;
    }
  }
  result = ndb_mgm_start_backup(m_mgmsrv, flags, &backupId, &reply);

2709
  if (result != 0) {
2710
    ndbout << "Backup failed" << endl;
2711
    printError();
2712 2713 2714

    if (log_handle) 
      ndb_mgm_destroy_logevent_handle(&log_handle);
2715
    return result;
2716
  }
2717 2718 2719 2720 2721

  /**
   * If interactive, event listner thread is already running
   */
  if (log_handle && !interactive)
unknown's avatar
unknown committed
2722 2723
  {
    int count = 0;
2724
    int retry = 0;
unknown's avatar
unknown committed
2725
    do {
2726
      if (ndb_logevent_get_next(log_handle, &log_event, 60000) > 0)
unknown's avatar
unknown committed
2727
      {
2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750
        int print = 0;
        switch (log_event.type) {
          case NDB_LE_BackupStarted:
            if (log_event.BackupStarted.backup_id == backupId)
              print = 1;
            break;
          case NDB_LE_BackupCompleted:
            if (log_event.BackupCompleted.backup_id == backupId)
              print = 1;
            break;
          case NDB_LE_BackupAborted:
            if (log_event.BackupAborted.backup_id == backupId)
              print = 1;
            break;
          default:
            break;
        }
        if (print)
        {
          Guard g(m_print_mutex);
          printLogEvent(&log_event);
          count++;
        }
unknown's avatar
unknown committed
2751
      }
2752 2753 2754 2755 2756
      else
      {
        retry++;
      }
    } while(count < 2 && retry < 3);
unknown's avatar
unknown committed
2757

2758 2759 2760 2761 2762
    if (retry >= 3)
      ndbout << "get backup event failed for " << retry << " times" << endl;

    ndb_mgm_destroy_logevent_handle(&log_handle);
  }
unknown's avatar
unknown committed
2763

2764
  return 0;
2765 2766
}

2767

2768
int
2769 2770 2771
CommandInterpreter::executeAbortBackup(char* parameters) 
{
  int bid = -1;
unknown's avatar
unknown committed
2772 2773 2774 2775 2776 2777 2778 2779 2780
  struct ndb_mgm_reply reply;
  if (emptyString(parameters))
    goto executeAbortBackupError1;

  {
    strtok(parameters, " ");
    char* id = strtok(NULL, "\0");
    if(id == 0 || sscanf(id, "%d", &bid) != 1)
      goto executeAbortBackupError1;
2781
  }
unknown's avatar
unknown committed
2782 2783 2784 2785 2786
  {
    int result= ndb_mgm_abort_backup(m_mgmsrv, bid, &reply);
    if (result != 0) {
      ndbout << "Abort of backup " << bid << " failed" << endl;
      printError();
2787
      return -1;
unknown's avatar
unknown committed
2788 2789 2790
    } else {
      ndbout << "Abort of backup " << bid << " ordered" << endl;
    }
2791
  }
2792
  return 0;
unknown's avatar
unknown committed
2793 2794
 executeAbortBackupError1:
  ndbout << "Invalid arguments: expected <BackupId>" << endl;
2795
  return -1;
2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825
}

#ifdef HAVE_GLOBAL_REPLICATION
/*****************************************************************************
 * Global Replication
 *
 * For information about the different commands, see
 * GrepReq::Request in file signaldata/grepImpl.cpp.
 *
 * Below are commands as of 2003-07-05 (may change!):
 * START = 0,            ///< Start Global Replication (all phases)
 * START_METALOG = 1,    ///< Start Global Replication (all phases)
 * START_METASCAN = 2,   ///< Start Global Replication (all phases)
 * START_DATALOG = 3,    ///< Start Global Replication (all phases)
 * START_DATASCAN = 4,   ///< Start Global Replication (all phases)
 * START_REQUESTOR = 5,  ///< Start Global Replication (all phases)
 * ABORT = 6,            ///< Immediate stop (removes subscription)
 * SLOW_STOP = 7,        ///< Stop after finishing applying current GCI epoch
 * FAST_STOP = 8,        ///< Stop after finishing applying all PS GCI epochs
 * START_TRANSFER = 9,   ///< Start SS-PS transfer
 * STOP_TRANSFER = 10,   ///< Stop SS-PS transfer
 * START_APPLY = 11,     ///< Start applying GCI epochs in SS
 * STOP_APPLY = 12,      ///< Stop applying GCI epochs in SS
 * STATUS = 13,           ///< Status
 * START_SUBSCR = 14,
 * REMOVE_BUFFERS = 15,
 * DROP_TABLE = 16

 *****************************************************************************/

2826
int
2827 2828 2829 2830
CommandInterpreter::executeRep(char* parameters) 
{
  if (emptyString(parameters)) {
    ndbout << helpTextRep;
2831
    return 0;
2832 2833
  }

2834 2835
  char * line = my_strdup(parameters,MYF(MY_WME));
  My_auto_ptr<char> ap1((char*)line);
2836 2837 2838 2839 2840 2841
  char * firstToken = strtok(line, " ");
  
  struct ndb_rep_reply  reply;
  unsigned int          repId;


2842
  if (!strcasecmp(firstToken, "CONNECT")) {
2843 2844 2845 2846 2847 2848 2849 2850
    char * host = strtok(NULL, "\0");
    for (unsigned int i = 0; i < strlen(host); ++i) {
      host[i] = tolower(host[i]);
    }
    
    if(host == NULL)
    {
      ndbout_c("host:port must be specified.");
2851
      return -1;
2852 2853 2854 2855 2856 2857 2858 2859 2860 2861 2862
    }
    
    if(rep_connected) {
      if(m_repserver != NULL) {
	ndb_rep_disconnect(m_repserver);
	rep_connected = false;
      }       
    }
          
    if(m_repserver == NULL)
      m_repserver = ndb_rep_create_handle();
2863 2864 2865 2866
    if(ndb_rep_connect(m_repserver, host) < 0){
      ndbout_c("Failed to connect to %s", host);
      return -1;
    } 
2867 2868
    else
      rep_connected=true;
2869
    return 0;
2870 2871 2872
    
    if(!rep_connected) {
      ndbout_c("Not connected to REP server");
2873
      return -1;
2874 2875 2876 2877 2878 2879
    }
  }
    
  /********
   * START 
   ********/
2880
  if (!strcasecmp(firstToken, "START")) {
2881 2882 2883 2884 2885 2886
    
    unsigned int          req;
    char *startType = strtok(NULL, "\0");
    
    if (startType == NULL) {                
      req = GrepReq::START;
2887
    } else if (!strcasecmp(startType, "SUBSCRIPTION")) {  
2888
      req = GrepReq::START_SUBSCR;
2889
    } else if (!strcasecmp(startType, "METALOG")) { 
2890
      req = GrepReq::START_METALOG;
2891
    } else if (!strcasecmp(startType, "METASCAN")) {
2892
      req = GrepReq::START_METASCAN;
2893
    } else if (!strcasecmp(startType, "DATALOG")) {
2894
      req = GrepReq::START_DATALOG;
2895
    } else if (!strcasecmp(startType, "DATASCAN")) {
2896
      req = GrepReq::START_DATASCAN;
2897
    } else if (!strcasecmp(startType, "REQUESTOR")) {
2898
      req = GrepReq::START_REQUESTOR;
2899
    } else if (!strcasecmp(startType, "TRANSFER")) {
2900
      req = GrepReq::START_TRANSFER;
2901
    } else if (!strcasecmp(startType, "APPLY")) {
2902
      req = GrepReq::START_APPLY;
2903
    } else if (!strcasecmp(startType, "DELETE")) {
2904 2905 2906
      req = GrepReq::START_DELETE;
    } else {
      ndbout_c("Illegal argument to command 'REPLICATION START'");
2907
      return -1;
2908 2909 2910 2911 2912 2913
    }

    int result = ndb_rep_command(m_repserver, req, &repId, &reply);
    
    if (result != 0) {
      ndbout << "Start of Global Replication failed" << endl;
2914
      return -1;
2915 2916 2917
    } else {
      ndbout << "Start of Global Replication ordered" << endl;
    }
2918
    return 0;
2919 2920 2921 2922 2923
  }

  /********
   * STOP
   ********/
2924
  if (!strcasecmp(firstToken, "STOP")) {    
2925 2926 2927 2928 2929 2930 2931 2932 2933
    unsigned int          req;
    char *startType = strtok(NULL, " ");
    unsigned int epoch = 0;
    
    if (startType == NULL) {                 
      /**
       * Stop immediately
       */
      req = GrepReq::STOP;
2934
    } else if (!strcasecmp(startType, "EPOCH")) {  
2935 2936 2937
      char *strEpoch = strtok(NULL, "\0");
      if(strEpoch == NULL) {
	ndbout_c("Epoch expected!");
2938
	return -1;
2939 2940 2941
      }
      req = GrepReq::STOP;
      epoch=atoi(strEpoch);      
2942
    } else if (!strcasecmp(startType, "SUBSCRIPTION")) {  
2943
      req = GrepReq::STOP_SUBSCR;
2944
    } else if (!strcasecmp(startType, "METALOG")) { 
2945
      req = GrepReq::STOP_METALOG;
2946
    } else if (!strcasecmp(startType, "METASCAN")) {
2947
      req = GrepReq::STOP_METASCAN;
2948
    } else if (!strcasecmp(startType, "DATALOG")) {
2949
      req = GrepReq::STOP_DATALOG;
2950
    } else if (!strcasecmp(startType, "DATASCAN")) {
2951
      req = GrepReq::STOP_DATASCAN;
2952
    } else if (!strcasecmp(startType, "REQUESTOR")) {
2953
      req = GrepReq::STOP_REQUESTOR;
2954
    } else if (!strcasecmp(startType, "TRANSFER")) {
2955
      req = GrepReq::STOP_TRANSFER;
2956
    } else if (!strcasecmp(startType, "APPLY")) {
2957
      req = GrepReq::STOP_APPLY;
2958
    } else if (!strcasecmp(startType, "DELETE")) {
2959 2960 2961
      req = GrepReq::STOP_DELETE;
    } else {
      ndbout_c("Illegal argument to command 'REPLICATION STOP'");
2962
      return -1;
2963 2964 2965 2966 2967
    }
    int result = ndb_rep_command(m_repserver, req, &repId, &reply, epoch);
    
    if (result != 0) {
      ndbout << "Stop command failed" << endl;
2968
      return -1;
2969 2970 2971
    } else {
      ndbout << "Stop ordered" << endl;
    }
2972
    return 0;
2973 2974 2975 2976 2977
  }

  /*********
   * STATUS
   *********/
2978
  if (!strcasecmp(firstToken, "STATUS")) {
2979 2980 2981 2982 2983 2984
    struct rep_state repstate;
    int result = 
      ndb_rep_get_status(m_repserver, &repId, &reply, &repstate);
    
    if (result != 0) {
      ndbout << "Status request of Global Replication failed" << endl;
2985
      return -1;
2986 2987 2988 2989 2990 2991 2992
    } else {
      ndbout << "Status request of Global Replication ordered" << endl;
      ndbout << "See printout at one of the DB nodes" << endl;
      ndbout << "(Better status report is under development.)" << endl;
      ndbout << " SubscriptionId " << repstate.subid 
	     << " SubscriptionKey " << repstate.subkey << endl;
    }
2993
    return 0;
2994 2995 2996 2997 2998
  }

  /*********
   * QUERY (see repapi.h for querable counters)
   *********/
2999
  if (!strcasecmp(firstToken, "QUERY")) {
3000 3001 3002 3003 3004 3005 3006 3007 3008 3009 3010 3011
    char *query = strtok(NULL, "\0");
    int queryCounter=-1;
    if(query != NULL) {
      queryCounter = atoi(query);
    }
    struct rep_state repstate;
    unsigned repId = 0;
    int result = ndb_rep_query(m_repserver, (QueryCounter)queryCounter,
			       &repId, &reply, &repstate);
    
    if (result != 0) {
      ndbout << "Query repserver failed" << endl;
3012
      return -1;
3013 3014 3015 3016 3017 3018 3019 3020
    } else {
      ndbout << "Query repserver sucessful" << endl;
      ndbout_c("repstate : QueryCounter %d, f=%d l=%d"
	       " nodegroups %d" , 
	       repstate.queryCounter,
	       repstate.first[0], repstate.last[0],
	       repstate.no_of_nodegroups );
    }
3021
    return 0;
3022
  }
3023
  return 0;
3024 3025 3026
}
#endif // HAVE_GLOBAL_REPLICATION

unknown's avatar
unknown committed
3027
template class Vector<char const*>;