summaryrefslogtreecommitdiff
path: root/storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp')
-rw-r--r--storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp456
1 files changed, 456 insertions, 0 deletions
diff --git a/storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp b/storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp
new file mode 100644
index 00000000000..a0daf9529ab
--- /dev/null
+++ b/storage/ndb/src/old_files/rep/RepCommandInterpreter.cpp
@@ -0,0 +1,456 @@
+/* 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
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ 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 */
+
+#include "RepCommandInterpreter.hpp"
+
+static const char*
+helpTextRep =
+"+-------------------------------------------------------------------------+\n"
+"| MySQL Replication Server |\n"
+"| Commands should be executed on the standby Replication Server |\n"
+"+-------------------------------------------------------------------------+\n"
+"| Simple Commands |\n"
+"+-------------------------------------------------------------------------+\n"
+"| START Start replication |\n"
+"| STATUS Show replication status |\n"
+"+-------------------------------------------------------------------------+\n"
+"| Advanced Commands |\n"
+"+-------------------------------------------------------------------------+\n"
+"| STOP <epoch no> Stop replication after epoch number <epoch no> |\n"
+"| STOP IMMEDIATELY Stop replication after applying the current epoch |\n"
+"| ADD TABLE <db>/<schema>/<tablename> |\n"
+"| Note: <db>/<schema>/<tablename> is case sensitive! |\n"
+"| Use 'STATUS' to see added tables. |\n"
+"| REMOVE TABLE <db>/<schema>/<tablename> |\n"
+"| Note: <db>/<schema>/<tablename> is case sensitive! |\n"
+"| ENABLE <protocol> Starts protocol |\n"
+"| DISABLE <protocol> Stops protocol |\n"
+"| DEBUG Toggle logging of replication messages on console |\n"
+"| |\n"
+"| <protocol> ::= REQUESTOR | TRANSFER | APPLY | DELETE |\n"
+"+-------------------------------------------------------------------------+\n"
+;
+
+/**
+ * @todo
+"| <protocol> ::= SUBID | SUBSCRIPTION |\n"
+"| <protocol> ::= METALOG | METASCAN | DATALOG | DATASCAN |\n"
+"| <system> ::= PRIMARY | STANDBY | TWOWAY |\n"
+"| CONNECT <system> Connects to NDB Cluster and other replication server |\n"
+"| DELETE Removes all epochs stored in replication servers |\n"
+"| DROP <tableid> Drops table in standby system identified by table id |\n"
+"| <epoch> ::= Any integer (naming the last epoch to be applied) |\n"
+*/
+
+RepCommandInterpreter::RepCommandInterpreter(RepComponents * comps)
+{
+ m_repComponents = comps;
+ m_repState = comps->getRepState();
+}
+
+RepCommandInterpreter::~RepCommandInterpreter()
+{
+}
+
+/**
+ * Read a string, and return a pointer to it.
+ *
+ * @return NULL on EOF.
+ */
+char *
+RepCommandInterpreter::readline_gets() const
+{
+ static char *line_read = (char *)NULL;
+
+ // Disable the default file-name completion action of TAB
+ // rl_bind_key ('\t', rl_insert);
+
+ /* If the buffer has already been allocated, return the memory
+ to the free pool. */
+ if (line_read)
+ {
+ NdbMem_Free(line_read);
+ line_read = (char *)NULL;
+ }
+
+ /* Get a line from the user. */
+ line_read = readline ("REP> ");
+
+ /* If the line has any text in it, save it on the history. */
+ if (line_read && *line_read)
+ add_history (line_read);
+
+ return (line_read);
+}
+
+bool 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;
+}
+
+/**
+ * Converts a string to a Uint32 pointed value!
+ */
+bool convert(const char* s, Uint32 * 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;
+}
+
+void
+printError(GrepError::Code err)
+{
+ if (err == GrepError::NO_ERROR) { ndbout << "Ok" << endl; }
+ else { ndbout << GrepError::getErrorDesc(err) << endl; }
+}
+
+bool
+RepCommandInterpreter::readAndExecute()
+{
+ GrepError::Code err;
+
+ char* _line = readline_gets();
+ char * line;
+ if(_line == NULL) {
+ ndbout << endl;
+ return true;
+ }
+
+ line = strdup(_line);
+
+ if (emptyString(line)) {
+ return true;
+ }
+
+ /* I have to uncomment this, since otherwise <db>/<schema>/<table>
+ is converted to capitals, but it is case sensitive!
+ for (unsigned int i = 0; i < strlen(line); ++i) {
+ line[i] = toupper(line[i]);
+ }
+ */
+ // if there is anything in the line proceed
+ char* firstToken = strtok(line, " ");
+ for (unsigned int i = 0; i < strlen(firstToken); ++i) {
+ firstToken[i] = toupper(firstToken[i]);
+ }
+ char* allAfterFirstToken = strtok(NULL, "\0");
+
+ /**
+ * Commands for REP Client only
+ */
+ if (strcmp(firstToken, "ADD") == 0) {
+ if (m_repState->m_channel.getStateSub() !=
+ Channel::NO_SUBSCRIPTION_EXISTS) {
+ ndbout_c("Subscription already exists");
+ ndbout_c("Tables must be added before subscription exists");
+ return true;
+ }
+ char * secondToken = strtok(allAfterFirstToken, " ");
+ char * fullTableName = strtok(NULL, "\0");
+ if(fullTableName == NULL) {
+ ndbout_c("Table name not specified");
+ return true;
+ }
+ for (unsigned int i = 0; i < strlen(secondToken); ++i) {
+ secondToken[i] = toupper(secondToken[i]);
+ }
+
+ if (strcmp(secondToken, "TABLE") == 0) {
+ err = m_repState->protectedAddTable(fullTableName);
+ printError(err);
+ return true;
+ }
+ return true;
+ }
+ if (strcmp(firstToken, "REMOVE") == 0) {
+ if (m_repState->m_channel.getStateSub() !=
+ Channel::NO_SUBSCRIPTION_EXISTS) {
+ ndbout_c("Subscription already exists");
+ ndbout_c("Tables can not be removed after subscription is created");
+ return true;
+ }
+ char * secondToken = strtok(allAfterFirstToken, " ");
+ char * fullTableName = strtok(NULL, "\0");
+ if(fullTableName == NULL) {
+ ndbout_c("Table name not specified");
+ return true;
+ }
+ for (unsigned int i = 0; i < strlen(secondToken); ++i) {
+ secondToken[i] = toupper(secondToken[i]);
+ }
+
+ if (strcmp(secondToken, "TABLE") == 0) {
+ err = m_repState->protectedRemoveTable(fullTableName);
+ printError(err);
+ return true;
+ }
+ return true;
+ }
+ /**
+ * now, we can convert allAfterFirstToken to capitals
+ */
+ if(allAfterFirstToken != 0) {
+ for (unsigned int i = 0; i < strlen(allAfterFirstToken); ++i) {
+ allAfterFirstToken[i] = toupper(allAfterFirstToken[i]);
+ }
+ }
+ if (strcmp(firstToken, "CONNECT") == 0) {
+
+ if (strcmp(allAfterFirstToken, "PRIMARY") == 0) {
+ m_repComponents->connectPS();
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "STANDBY") == 0) {
+ m_repComponents->connectPS();
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "TWOWAY") == 0) {
+ m_repComponents->connectPS();
+ return true;
+ }
+ ndbout_c("Unknown argument: %s to command: %s",
+ allAfterFirstToken, firstToken);
+ return true;
+ }
+
+ if (strcmp(firstToken, "HELP") == 0) {
+ ndbout << helpTextRep;
+ return true;
+ }
+
+ if (strcmp(firstToken, "QUIT") == 0 ||
+ strcmp(firstToken, "BYE") == 0 ||
+ strcmp(firstToken, "EXIT") == 0) {
+ return false;
+ }
+
+ /**
+ * Commands for REP Server API
+ */
+ if (strcmp(firstToken, "STATUS") == 0 ||
+ strcmp(firstToken, "INFO") == 0 ||
+ strcmp(firstToken, "I") == 0) {
+ m_repState->protectedRequest(GrepReq::STATUS, 0);
+ return true;
+ }
+
+ if (strcmp(firstToken, "DEBUG") == 0) {
+ if (replogEnabled)
+ {
+ ndbout_c("Debugging disabled.");
+ replogEnabled = false;
+ }
+ else
+ {
+ ndbout_c("Debugging enabled.");
+ replogEnabled = true;
+ }
+ return true;
+ }
+
+ if (strcmp(firstToken, "ENABLE") == 0) {
+ if (strcmp(allAfterFirstToken, "REQUESTOR") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_REQUESTOR, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "TRANSFER") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_TRANSFER, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "APPLY") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_APPLY, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DELETE") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_DELETE, 0);
+ printError(err);
+ return true;
+ }
+ ndbout_c("Unknown argument: %s to command: %s",
+ allAfterFirstToken, firstToken);
+ return true;
+ }
+
+ if (strcmp(firstToken, "DISABLE") == 0) {
+ if (strcmp(allAfterFirstToken, "REQUESTOR") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_REQUESTOR, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "TRANSFER") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_TRANSFER, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "APPLY") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_APPLY, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DELETE") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_DELETE, 0);
+ printError(err);
+ return true;
+ }
+ ndbout_c("Unknown argument: %s to command: %s",
+ allAfterFirstToken, firstToken);
+ return true;
+ }
+
+ if (strcmp(firstToken, "START") == 0) {
+ if (allAfterFirstToken == NULL) {
+ err = m_repState->protectedRequest(GrepReq::START, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "SUBID") == 0) {
+ err = m_repState->protectedRequest(GrepReq::CREATE_SUBSCR, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "SUBSCR") == 0 ||
+ strcmp(allAfterFirstToken, "SUBSCRIPTION") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_SUBSCR, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "METALOG") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_METALOG, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "METASCAN") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_METASCAN, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DATALOG") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_DATALOG, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DATASCAN") == 0) {
+ err = m_repState->protectedRequest(GrepReq::START_DATASCAN, 0);
+ printError(err);
+ return true;
+ }
+ ndbout_c("Unknown argument: %s to command: %s",
+ allAfterFirstToken, firstToken);
+ return true;
+ }
+
+ if (strcmp(firstToken, "STOP") == 0) {
+ if (allAfterFirstToken == NULL) {
+ ndbout_c("Please use either 'STOP IMMEDIATELY' or 'STOP <epoch no>', "
+ "where\n<epoch no> is greater than or equal to "
+ "the last applied epoch.");
+ return true;
+ }
+
+ char * secondToken = strtok(allAfterFirstToken, " ");
+ char * subscription = strtok(NULL, "\0");
+ if (strcmp(secondToken, "SUBSCR") == 0 ||
+ strcmp(secondToken, "SUBSCRIPTION") == 0) {
+ char * sSubId = strtok(subscription," ");
+ char * sSubKey = strtok(NULL, "\0");
+ int subId = atoi(sSubId);
+ int subKey = atoi(sSubKey);
+ err = m_repState->protectedRequest(GrepReq::STOP_SUBSCR, subId, subKey );
+ printError(err);
+ return true;
+ }
+
+ if (strcmp(allAfterFirstToken, "SUBID") == 0) {
+ ndbout_c("Not implemented");
+ return true;
+ }
+
+
+ if (strcmp(allAfterFirstToken, "METALOG") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_METALOG, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "METASCAN") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_METASCAN, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DATALOG") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_DATALOG, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "DATASCAN") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP_DATASCAN, 0);
+ printError(err);
+ return true;
+ }
+ if (strcmp(allAfterFirstToken, "IM") == 0 ||
+ strcmp(allAfterFirstToken, "IMM") == 0 ||
+ strcmp(allAfterFirstToken, "IMMEDIATELY") == 0) {
+ err = m_repState->protectedRequest(GrepReq::STOP, 0);
+ printError(err);
+ return true;
+ }
+ Uint32 stopEpoch;
+ if (convert(allAfterFirstToken, &stopEpoch)) {
+ err = m_repState->protectedRequest(GrepReq::STOP, stopEpoch);
+ printError(err);
+ return true;
+ }
+
+ ndbout_c("Unknown argument: %s to command: %s",
+ allAfterFirstToken, firstToken);
+ return true;
+ }
+
+ ndbout_c("Unknown Command: %s", firstToken);
+ ndbout_c("Type HELP for help.");
+ ndbout << endl;
+ return true;
+}