RepCommandInterpreter.cpp
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:14k
源码类别:

MySQL数据库

开发平台:

Visual C++

  1. /* Copyright (C) 2003 MySQL AB
  2.    This program is free software; you can redistribute it and/or modify
  3.    it under the terms of the GNU General Public License as published by
  4.    the Free Software Foundation; either version 2 of the License, or
  5.    (at your option) any later version.
  6.    This program is distributed in the hope that it will be useful,
  7.    but WITHOUT ANY WARRANTY; without even the implied warranty of
  8.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  9.    GNU General Public License for more details.
  10.    You should have received a copy of the GNU General Public License
  11.    along with this program; if not, write to the Free Software
  12.    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
  13. #include "RepCommandInterpreter.hpp"
  14. static const char* 
  15. helpTextRep =
  16. "+-------------------------------------------------------------------------+n"
  17. "|                        MySQL Replication Server                         |n"
  18. "|      Commands should be executed on the standby Replication Server      |n"
  19. "+-------------------------------------------------------------------------+n"
  20. "|                             Simple Commands                             |n"
  21. "+-------------------------------------------------------------------------+n"
  22. "| START              Start replication                                    |n"
  23. "| STATUS             Show replication status                              |n"
  24. "+-------------------------------------------------------------------------+n"
  25. "|                            Advanced Commands                            |n"
  26. "+-------------------------------------------------------------------------+n"
  27. "| STOP <epoch no>    Stop replication after epoch number <epoch no>       |n"
  28. "| STOP IMMEDIATELY   Stop replication after applying the current epoch    |n"
  29. "| ADD TABLE <db>/<schema>/<tablename>                                     |n"
  30. "|                    Note: <db>/<schema>/<tablename> is case sensitive!   |n"
  31. "|                    Use 'STATUS' to see added tables.                    |n"
  32. "| REMOVE TABLE <db>/<schema>/<tablename>                                  |n"
  33. "|                    Note: <db>/<schema>/<tablename> is case sensitive!   |n"
  34. "| ENABLE <protocol>  Starts protocol                                      |n"
  35. "| DISABLE <protocol> Stops protocol                                       |n"
  36. "| DEBUG              Toggle logging of replication messages on console    |n"
  37. "|                                                                         |n"
  38. "| <protocol>  ::=    REQUESTOR | TRANSFER | APPLY | DELETE                |n"
  39. "+-------------------------------------------------------------------------+n"
  40. ;
  41. /**
  42.  * @todo
  43. "| <protocol>  ::=    SUBID | SUBSCRIPTION                                 |n"
  44. "| <protocol>  ::=    METALOG | METASCAN | DATALOG | DATASCAN              |n"
  45. "| <system>    ::=    PRIMARY | STANDBY | TWOWAY                           |n"
  46. "| CONNECT <system>   Connects to NDB Cluster and other replication server |n"
  47. "| DELETE             Removes all epochs stored in replication servers     |n"
  48. "| DROP <tableid>     Drops table in standby system identified by table id |n"
  49. "| <epoch>     ::=    Any integer (naming the last epoch to be applied)    |n"
  50. */
  51. RepCommandInterpreter::RepCommandInterpreter(RepComponents * comps)
  52. {
  53.   m_repComponents = comps;
  54.   m_repState = comps->getRepState();
  55. }
  56. RepCommandInterpreter::~RepCommandInterpreter()
  57. {
  58. }
  59. /**
  60.  *   Read a string, and return a pointer to it.  
  61.  *
  62.  *   @return NULL on EOF. 
  63.  */
  64. char *
  65. RepCommandInterpreter::readline_gets() const
  66. {
  67.   static char *line_read = (char *)NULL;
  68.   
  69.   // Disable the default file-name completion action of TAB
  70.   // rl_bind_key ('t', rl_insert);
  71.   
  72.   /* If the buffer has already been allocated, return the memory
  73.      to the free pool. */
  74.   if (line_read)
  75.   {
  76.     NdbMem_Free(line_read);
  77.     line_read = (char *)NULL;
  78.   }
  79.   
  80.   /* Get a line from the user. */
  81.   line_read = readline ("REP> ");
  82.   
  83.   /* If the line has any text in it, save it on the history. */
  84.   if (line_read && *line_read)
  85.     add_history (line_read);
  86.   
  87.   return (line_read);
  88. }
  89. bool emptyString(const char* s) 
  90. {
  91.   if (s == NULL) {
  92.     return true;
  93.   }
  94.   for (unsigned int i = 0; i < strlen(s); ++i) {
  95.     if (! isspace(s[i])) {
  96.       return false;
  97.     }
  98.   }
  99.   return true;
  100. }
  101. /**
  102.  * Converts a string to a Uint32 pointed value!
  103.  */
  104. bool convert(const char* s, Uint32 * val) 
  105. {
  106.   if (s == NULL) {
  107.     return false;
  108.   }
  109.   if (strlen(s) == 0) {
  110.     return false;
  111.   }
  112.   errno = 0;
  113.   char* p;
  114.   long v = strtol(s, &p, 10);
  115.   if (errno != 0) {
  116.     return false;
  117.   }
  118.   if (p != &s[strlen(s)]) {
  119.     return false;
  120.   }
  121.   *val = v;
  122.   return true;
  123. }
  124. void
  125. printError(GrepError::Code err) 
  126. {
  127.   if (err == GrepError::NO_ERROR) { ndbout << "Ok" << endl; } 
  128.   else { ndbout << GrepError::getErrorDesc(err) << endl; }
  129. }
  130. bool
  131. RepCommandInterpreter::readAndExecute() 
  132. {
  133.   GrepError::Code err;
  134.   char* _line = readline_gets(); 
  135.   char * line;
  136.   if(_line == NULL) {
  137.     ndbout << endl;
  138.     return true;
  139.   }
  140.   
  141.   line = strdup(_line);
  142.   
  143.   if (emptyString(line)) {
  144.     return true;
  145.   }
  146.   
  147.   /* I have to uncomment this, since otherwise <db>/<schema>/<table>
  148.      is converted to capitals, but it is case sensitive!
  149.   for (unsigned int i = 0; i < strlen(line); ++i) {
  150.     line[i] = toupper(line[i]);
  151.   }
  152.   */
  153.   // if there is anything in the line proceed
  154.   char* firstToken = strtok(line, " ");
  155.   for (unsigned int i = 0; i < strlen(firstToken); ++i) {
  156.     firstToken[i] = toupper(firstToken[i]);
  157.   }
  158.   char* allAfterFirstToken = strtok(NULL, "");
  159.   
  160.   /**
  161.    * Commands for REP Client only
  162.    */
  163.   if (strcmp(firstToken, "ADD") == 0) {    
  164.     if (m_repState->m_channel.getStateSub() != 
  165. Channel::NO_SUBSCRIPTION_EXISTS) {
  166.       ndbout_c("Subscription already exists");
  167.       ndbout_c("Tables must be added before subscription exists");
  168.       return true;
  169.     }
  170.     char * secondToken = strtok(allAfterFirstToken, " ");
  171.     char * fullTableName = strtok(NULL, "");
  172.     if(fullTableName == NULL) {
  173.       ndbout_c("Table name not specified");
  174.       return true;
  175.     }
  176.     for (unsigned int i = 0; i < strlen(secondToken); ++i) {
  177.       secondToken[i] = toupper(secondToken[i]);
  178.     }
  179.     
  180.     if (strcmp(secondToken, "TABLE") == 0) {
  181.       err = m_repState->protectedAddTable(fullTableName);
  182.       printError(err);
  183.       return true;
  184.     }
  185.     return true;
  186.   }
  187.   if (strcmp(firstToken, "REMOVE") == 0) { 
  188.     if (m_repState->m_channel.getStateSub() != 
  189. Channel::NO_SUBSCRIPTION_EXISTS) {
  190.       ndbout_c("Subscription already exists");
  191.       ndbout_c("Tables can not be removed after subscription is created");
  192.       return true;
  193.     }
  194.     char * secondToken = strtok(allAfterFirstToken, " ");
  195.     char * fullTableName = strtok(NULL, "");
  196.     if(fullTableName == NULL) {
  197.       ndbout_c("Table name not specified");
  198.       return true;
  199.     }
  200.     for (unsigned int i = 0; i < strlen(secondToken); ++i) {
  201.       secondToken[i] = toupper(secondToken[i]);
  202.     }
  203.     
  204.     if (strcmp(secondToken, "TABLE") == 0) {
  205.       err = m_repState->protectedRemoveTable(fullTableName);
  206.       printError(err);
  207.       return true;
  208.     }
  209.     return true;
  210.   }
  211.   /**
  212.    * now, we can convert allAfterFirstToken to capitals
  213.    */
  214.   if(allAfterFirstToken != 0) {
  215.     for (unsigned int i = 0; i < strlen(allAfterFirstToken); ++i) {
  216.       allAfterFirstToken[i] = toupper(allAfterFirstToken[i]);
  217.     }
  218.   }
  219.   if (strcmp(firstToken, "CONNECT") == 0) {
  220.     if (strcmp(allAfterFirstToken, "PRIMARY") == 0) {
  221.       m_repComponents->connectPS();
  222.       return true;
  223.     }
  224.     if (strcmp(allAfterFirstToken, "STANDBY") == 0) {
  225.       m_repComponents->connectPS();
  226.       return true;
  227.     }
  228.     if (strcmp(allAfterFirstToken, "TWOWAY") == 0) {
  229.       m_repComponents->connectPS();
  230.       return true;
  231.     }
  232.     ndbout_c("Unknown argument: %s to command: %s", 
  233.      allAfterFirstToken, firstToken);
  234.     return true;
  235.   }
  236.   if (strcmp(firstToken, "HELP") == 0) {
  237.     ndbout << helpTextRep;
  238.     return true;
  239.   }
  240.   if (strcmp(firstToken, "QUIT") == 0 || 
  241.       strcmp(firstToken, "BYE") == 0 || 
  242.       strcmp(firstToken, "EXIT") == 0) {
  243.     return false;
  244.   }
  245.   /**
  246.    * Commands for REP Server API
  247.    */
  248.   if (strcmp(firstToken, "STATUS") == 0 ||
  249.       strcmp(firstToken, "INFO") == 0 ||
  250.       strcmp(firstToken, "I") == 0) {
  251.     m_repState->protectedRequest(GrepReq::STATUS, 0);
  252.     return true;
  253.   }
  254.   if (strcmp(firstToken, "DEBUG") == 0) {
  255.     if (replogEnabled) 
  256.     {
  257.       ndbout_c("Debugging disabled.");
  258.       replogEnabled = false; 
  259.     }
  260.     else 
  261.     {
  262.       ndbout_c("Debugging enabled.");
  263.       replogEnabled = true;
  264.     }
  265.     return true;
  266.   }
  267.   if (strcmp(firstToken, "ENABLE") == 0) {
  268.     if (strcmp(allAfterFirstToken, "REQUESTOR") == 0) {
  269.       err = m_repState->protectedRequest(GrepReq::START_REQUESTOR, 0);
  270.       printError(err);
  271.       return true;
  272.     }
  273.     if (strcmp(allAfterFirstToken, "TRANSFER") == 0) {
  274.       err = m_repState->protectedRequest(GrepReq::START_TRANSFER, 0);
  275.       printError(err);
  276.       return true;
  277.     }
  278.     if (strcmp(allAfterFirstToken, "APPLY") == 0) {
  279.       err = m_repState->protectedRequest(GrepReq::START_APPLY, 0);
  280.       printError(err);
  281.       return true;
  282.     }
  283.     if (strcmp(allAfterFirstToken, "DELETE") == 0) {
  284.       err = m_repState->protectedRequest(GrepReq::START_DELETE, 0);
  285.       printError(err);
  286.       return true;
  287.     }
  288.     ndbout_c("Unknown argument: %s to command: %s", 
  289.      allAfterFirstToken, firstToken);
  290.     return true;
  291.   }
  292.   if (strcmp(firstToken, "DISABLE") == 0) {
  293.     if (strcmp(allAfterFirstToken, "REQUESTOR") == 0) {
  294.       err = m_repState->protectedRequest(GrepReq::STOP_REQUESTOR, 0);
  295.       printError(err);
  296.       return true;
  297.     }
  298.     if (strcmp(allAfterFirstToken, "TRANSFER") == 0) {
  299.       err = m_repState->protectedRequest(GrepReq::STOP_TRANSFER, 0);
  300.       printError(err);
  301.       return true;
  302.     }
  303.     if (strcmp(allAfterFirstToken, "APPLY") == 0) {
  304.       err = m_repState->protectedRequest(GrepReq::STOP_APPLY, 0);
  305.       printError(err);
  306.       return true;
  307.     }
  308.     if (strcmp(allAfterFirstToken, "DELETE") == 0) {
  309.       err = m_repState->protectedRequest(GrepReq::STOP_DELETE, 0);
  310.       printError(err);
  311.       return true;
  312.     }
  313.     ndbout_c("Unknown argument: %s to command: %s", 
  314.      allAfterFirstToken, firstToken);
  315.     return true;
  316.   }
  317.   if (strcmp(firstToken, "START") == 0) {
  318.     if (allAfterFirstToken == NULL) {
  319.       err = m_repState->protectedRequest(GrepReq::START, 0);
  320.       printError(err);
  321.       return true;
  322.     }
  323.     if (strcmp(allAfterFirstToken, "SUBID") == 0) {
  324.       err = m_repState->protectedRequest(GrepReq::CREATE_SUBSCR, 0);
  325.       printError(err);
  326.       return true;
  327.     }
  328.     if (strcmp(allAfterFirstToken, "SUBSCR") == 0 ||
  329.         strcmp(allAfterFirstToken, "SUBSCRIPTION") == 0) {
  330.       err = m_repState->protectedRequest(GrepReq::START_SUBSCR, 0);
  331.       printError(err);
  332.       return true;
  333.     }
  334.     if (strcmp(allAfterFirstToken, "METALOG") == 0) {
  335.       err = m_repState->protectedRequest(GrepReq::START_METALOG, 0);
  336.       printError(err);
  337.       return true;
  338.     }
  339.     if (strcmp(allAfterFirstToken, "METASCAN") == 0) {
  340.       err = m_repState->protectedRequest(GrepReq::START_METASCAN, 0);
  341.       printError(err);
  342.       return true;
  343.     }
  344.     if (strcmp(allAfterFirstToken, "DATALOG") == 0) {
  345.       err = m_repState->protectedRequest(GrepReq::START_DATALOG, 0);
  346.       printError(err);
  347.       return true;
  348.     }
  349.     if (strcmp(allAfterFirstToken, "DATASCAN") == 0) {
  350.       err = m_repState->protectedRequest(GrepReq::START_DATASCAN, 0);
  351.       printError(err);
  352.       return true;
  353.     }
  354.     ndbout_c("Unknown argument: %s to command: %s", 
  355.      allAfterFirstToken, firstToken);
  356.     return true;
  357.   }
  358.   if (strcmp(firstToken, "STOP") == 0) {
  359.     if (allAfterFirstToken == NULL) {
  360.       ndbout_c("Please use either 'STOP IMMEDIATELY' or 'STOP <epoch no>', "
  361.        "wheren<epoch no> is greater than or equal to "
  362.        "the last applied epoch.");
  363.       return true;
  364.     }
  365.     
  366.     char * secondToken = strtok(allAfterFirstToken, " ");
  367.     char * subscription = strtok(NULL, "");
  368.     if (strcmp(secondToken, "SUBSCR") == 0 ||
  369.         strcmp(secondToken, "SUBSCRIPTION") == 0) {
  370.       char * sSubId  = strtok(subscription," ");
  371.       char * sSubKey = strtok(NULL, "");
  372.       int subId = atoi(sSubId);
  373.       int subKey = atoi(sSubKey);
  374.       err = m_repState->protectedRequest(GrepReq::STOP_SUBSCR, subId, subKey );
  375.       printError(err);
  376.       return true;
  377.     }
  378.     if (strcmp(allAfterFirstToken, "SUBID") == 0) {
  379.       ndbout_c("Not implemented");
  380.       return true;
  381.     }
  382.     
  383.     
  384.     if (strcmp(allAfterFirstToken, "METALOG") == 0) {
  385.       err = m_repState->protectedRequest(GrepReq::STOP_METALOG, 0);
  386.       printError(err);
  387.       return true;
  388.     }
  389.     if (strcmp(allAfterFirstToken, "METASCAN") == 0) {
  390.       err = m_repState->protectedRequest(GrepReq::STOP_METASCAN, 0);
  391.       printError(err);
  392.       return true;
  393.     }
  394.     if (strcmp(allAfterFirstToken, "DATALOG") == 0) {
  395.       err = m_repState->protectedRequest(GrepReq::STOP_DATALOG, 0);
  396.       printError(err);
  397.       return true;
  398.     }
  399.     if (strcmp(allAfterFirstToken, "DATASCAN") == 0) {
  400.       err = m_repState->protectedRequest(GrepReq::STOP_DATASCAN, 0);
  401.       printError(err);
  402.       return true;
  403.     }
  404.     if (strcmp(allAfterFirstToken, "IM") == 0 ||
  405. strcmp(allAfterFirstToken, "IMM") == 0 ||
  406. strcmp(allAfterFirstToken, "IMMEDIATELY") == 0) {
  407.       err = m_repState->protectedRequest(GrepReq::STOP, 0);
  408.       printError(err);
  409.       return true;
  410.     }
  411.     Uint32 stopEpoch;
  412.     if (convert(allAfterFirstToken, &stopEpoch)) {
  413.       err = m_repState->protectedRequest(GrepReq::STOP, stopEpoch);
  414.       printError(err);
  415.       return true;
  416.     }
  417.     ndbout_c("Unknown argument: %s to command: %s", 
  418.      allAfterFirstToken, firstToken);
  419.     return true;
  420.   }
  421.   ndbout_c("Unknown Command: %s", firstToken);
  422.   ndbout_c("Type HELP for help.");
  423.   ndbout << endl;
  424.   return true;
  425. }