List:Commits« Previous MessageNext Message »
From:Magnus Svensson Date:December 17 2008 4:18pm
Subject:bzr commit into mysql-5.1 branch (msvensson:3178)
View as plain text  
#At file:///home/msvensson/mysql/6.4/ based on revid:msvensson@stripped

 3178 Magnus Svensson	2008-12-17 [merge]
      Merge
modified:
  storage/ndb/include/kernel/signaldata/ConfigChange.hpp
  storage/ndb/src/mgmapi/mgmapi.cpp
  storage/ndb/src/mgmsrv/Config.cpp
  storage/ndb/src/mgmsrv/Config.hpp
  storage/ndb/src/mgmsrv/ConfigManager.cpp
  storage/ndb/src/mgmsrv/ConfigManager.hpp
  storage/ndb/src/mgmsrv/MgmtSrvr.cpp
  storage/ndb/test/include/NdbMgmd.hpp
  storage/ndb/test/ndbapi/testMgm.cpp

=== modified file 'storage/ndb/include/kernel/signaldata/ConfigChange.hpp'
--- a/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	2008-12-16 16:27:47 +0000
+++ b/storage/ndb/include/kernel/signaldata/ConfigChange.hpp	2008-12-17 16:09:24 +0000
@@ -74,38 +74,55 @@ class ConfigChangeRef {
     ConfigChangeOnGoing     = 1,
     NotMaster               = 2,
     NoConfigData            = 3,
-    ConfigChangeAborted     = 4,
-    ConfigNotOk             = 5,
-
-    InternalError           = 10,
-    PrepareFailed           = 11,
-    IllegalConfigChange     = 13,
-    FailedToUnpack          = 14,
-    InvalidGeneration       = 15,
-    InvalidConfigName       = 16,
-    IllegalState            = 17,
-    IllegalInitialGeneration = 18,
-    DifferentInitial        = 19,
-    NotAllStarted           = 20,
-    NotPrimaryMgmNode       = 21
-  } ;
+    ConfigNotOk             = 4,
+    InternalError           = 5,
+    PrepareFailed           = 6,
+    IllegalConfigChange     = 7,
+    FailedToUnpack          = 8,
+    InvalidGeneration       = 9,
+    InvalidConfigName       = 10,
+    IllegalInitialState     = 11,
+    IllegalInitialGeneration = 12,
+    DifferentInitial        = 13,
+    NotAllStarted           = 14,
+    NotPrimaryMgmNode       = 15
+  };
 
 public:
   STATIC_CONST( SignalLength = 1 );
 
   static const char* errorMessage(Uint32 error) {
     switch (error){
+    case ConfigChangeOnGoing:
+      return "Config change ongoing";
+    case NotMaster:
+      return "Not the config change master";
     case NoConfigData:
       return "No config data in signal";
-    case ConfigChangeAborted:
-      return "Config change was aborted";
-    case FailedToUnpack:
-      return "Failed to unpack the configuration";
-    case IllegalConfigChange:
-      return "Illegal config change";
-
+    case ConfigNotOk:
+      return "Config is not ok";
     case InternalError:
       return "ConfigChangeRef, internal error";
+    case PrepareFailed:
+      return "Prepare of config change failed";
+    case IllegalConfigChange:
+      return "Illegal configuration change";
+    case FailedToUnpack:
+      return "Failed to unpack the configuration";
+    case InvalidGeneration:
+      return "Invalid generation in configuration";
+    case InvalidConfigName:
+      return "Invalid configuration name in configuration";
+    case IllegalInitialState:
+      return "Initial config change not allowed in this state";
+    case IllegalInitialGeneration:
+      return "Initial config change with generation not 0";
+    case DifferentInitial:
+      return "Different initial config files";
+    case NotAllStarted:
+      return " Not all mgm nodes are started";
+    case NotPrimaryMgmNode:
+      return "Not primary mgm node for configuration";
 
     default:
       return "ConfigChangeRef, unknown error";
@@ -138,6 +155,7 @@ private:
   Uint32 requestType;
   Uint32 initial; // Valid when requestType = Prepare
   Uint32 length; // Length of the config data in long signal
+
 };
 
 

=== modified file 'storage/ndb/src/mgmapi/mgmapi.cpp'
--- a/storage/ndb/src/mgmapi/mgmapi.cpp	2008-12-16 16:41:33 +0000
+++ b/storage/ndb/src/mgmapi/mgmapi.cpp	2008-12-17 16:18:23 +0000
@@ -3133,7 +3133,6 @@ ndb_mgm_set_configuration(NdbMgmHandle h
   delete reply;
 
   if(strcmp(result.c_str(), "Ok") != 0) {
-    fprintf(h->errstream, "ERROR Message: %s\n", result.c_str());
     SET_ERROR(h, NDB_MGM_CONFIG_CHANGE_FAILED, result.c_str());
     return -1;
   }

=== modified file 'storage/ndb/src/mgmsrv/Config.cpp'
--- a/storage/ndb/src/mgmsrv/Config.cpp	2008-12-16 14:09:42 +0000
+++ b/storage/ndb/src/mgmsrv/Config.cpp	2008-12-17 16:18:23 +0000
@@ -233,6 +233,27 @@ Config::pack(UtilBuffer& buf) const
 }
 
 
+#include <base64.h>
+
+bool
+Config::pack64(BaseString& encoded) const
+{
+  UtilBuffer buf;
+  if (m_configValues->m_config.pack(buf) == 0)
+    return false;
+
+  // Expand the string to correct length by filling with Z
+  encoded.assfmt("%*s",
+                 base64_needed_encoded_length(buf.length()),
+                 "Z");
+
+  if (base64_encode(buf.get_data(),
+                    buf.length(),
+                    (char*)encoded.c_str()))
+    return false;
+  return true;
+}
+
 
 enum diff_types {
   DT_DIFF,            // Value differed
@@ -725,3 +746,34 @@ bool Config::illegal_change(const Config
   return illegal_change(diff_list);
 }
 
+
+void Config::getConnectString(BaseString& connectstring,
+                              const BaseString& separator) const
+{
+  bool first= true;
+  ConfigIter it(this, CFG_SECTION_NODE);
+
+  for(;it.valid(); it.next())
+  {
+    /* Get type of Node */
+    Uint32 nodeType;
+    require(it.get(CFG_TYPE_OF_SECTION, &nodeType) == 0);
+
+    if (nodeType != NODE_TYPE_MGM)
+      continue;
+
+    Uint32 port;
+    const char* hostname;
+    require(it.get(CFG_NODE_HOST, &hostname) == 0);
+    require(it.get(CFG_MGM_PORT, &port) == 0);
+
+    if (!first)
+      connectstring.append(separator);
+    first= false;
+
+    connectstring.appfmt("%s:%d", hostname, port);
+
+  }
+  ndbout << connectstring << endl;
+}
+

=== modified file 'storage/ndb/src/mgmsrv/Config.hpp'
--- a/storage/ndb/src/mgmsrv/Config.hpp	2008-12-16 11:53:18 +0000
+++ b/storage/ndb/src/mgmsrv/Config.hpp	2008-12-16 16:30:58 +0000
@@ -73,6 +73,11 @@ public:
   Uint32 pack(UtilBuffer&) const;
 
   /*
+    Pack the config as base64
+  */
+  bool pack64(BaseString&) const;
+
+  /*
     Compare against another config and return a list of
     differences in a Properties object
   */
@@ -84,6 +89,15 @@ public:
    */
   void print_diff(const Config* other) const;
 
+
+  /*
+    Get the full connectstring for this configuration. ie
+    a list of all the mgmd servers and their port separated
+    by separator.
+   */
+  void getConnectString(BaseString&,
+                        const BaseString& separator = BaseString(";")) const;
+
   /*
     Print the difference to string buffer
   */
@@ -100,6 +114,7 @@ public:
   bool equal(const Config*, const unsigned* exclude = NULL) const;
 
   struct ndb_mgm_configuration * m_configValues;
+  struct ndb_mgm_configuration * values(void) const { return m_configValues; };
 
 private:
   bool setValue(Uint32 section, Uint32 section_no,

=== modified file 'storage/ndb/src/mgmsrv/ConfigManager.cpp'
--- a/storage/ndb/src/mgmsrv/ConfigManager.cpp	2008-12-16 16:27:47 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigManager.cpp	2008-12-17 16:09:24 +0000
@@ -56,6 +56,7 @@ ConfigManager::ConfigManager(const MgmtS
   m_config_change_state(CCS_IDLE),
   m_config_state(CS_UNINITIALIZED),
   m_previous_state(CS_UNINITIALIZED),
+  m_config_change_error(ConfigChangeRef::OK),
   m_client_ref(RNIL),
   m_prepared_config(NULL),
   m_node_id(0),
@@ -722,7 +723,8 @@ ConfigManager::execCONFIG_CHANGE_IMPL_RE
         g_eventLogger->warning("Refusing to start initial "             \
                                "configuration change since this node "  \
                                "is not in INITIAL state");
-        sendConfigChangeImplRef(ss, nodeId, ConfigChangeRef::IllegalState);
+        sendConfigChangeImplRef(ss, nodeId,
+                                ConfigChangeRef::IllegalInitialState);
         return;
       }
 
@@ -769,14 +771,16 @@ ConfigManager::execCONFIG_CHANGE_IMPL_RE
     else
     {
 
-      // Check that config change was started by primary mgm node
-      Uint32 primaryMgmNode = m_config->getPrimaryMgmNode();
-      if (nodeId != primaryMgmNode)
+      // Check that new config has same primary mgm node as current
+      Uint32 curr_primary = m_config->getPrimaryMgmNode();
+      Uint32 new_primary = new_config.getPrimaryMgmNode();
+      if (new_primary != curr_primary)
       {
         g_eventLogger->warning("Refusing to start configuration change " \
-                               "requested by node %d, it's not set as " \
-                               "the primary management node %d.",
-                               nodeId, primaryMgmNode);
+                               "requested by node %d, the new config uses " \
+                               "different primary mgm node %d. "      \
+                               "Current primary mmgm node is %d.",
+                               nodeId, new_primary, curr_primary);
         sendConfigChangeImplRef(ss, nodeId,
                                 ConfigChangeRef::NotPrimaryMgmNode);
         return;
@@ -874,6 +878,10 @@ ConfigManager::execCONFIG_CHANGE_IMPL_RE
   g_eventLogger->warning("Node %d refused configuration change, error: %d",
                          nodeId, ref->errorCode);
 
+  /* Remember the original error code */
+  if (m_config_change_error == 0)
+    m_config_change_error = (ConfigChangeRef::ErrorCode)ref->errorCode;
+
   switch(m_config_change_state){
 
   case CCS_PREPARING:{
@@ -990,6 +998,7 @@ ConfigManager::execCONFIG_CHANGE_IMPL_CO
       return;
 
     require(m_client_ref != RNIL);
+    require(m_config_change_error == 0);
     if (m_client_ref == ss.getOwnRef())
     {
       g_eventLogger->info("Config change completed! New generation: %d",
@@ -1035,6 +1044,7 @@ ConfigManager::execCONFIG_CHANGE_IMPL_CO
       return;
 
     require(m_client_ref != RNIL);
+    require(m_config_change_error);
     if (m_client_ref == ss.getOwnRef())
     {
       g_eventLogger->error("Config change failed!");
@@ -1044,8 +1054,9 @@ ConfigManager::execCONFIG_CHANGE_IMPL_CO
     {
       /* Send ref to the requestor */
       sendConfigChangeRef(ss, m_client_ref,
-                          ConfigChangeRef::ConfigChangeAborted);
+                          m_config_change_error);
     }
+    m_config_change_error= ConfigChangeRef::OK;
     m_client_ref = RNIL;
     m_config_change_state = CCS_IDLE;
     break;
@@ -1174,6 +1185,7 @@ ConfigManager::execCONFIG_CHANGE_REQ(Sig
     sendConfigChangeRef(ss, from, ConfigChangeRef::ConfigChangeOnGoing);
     return;
   }
+  require(m_config_change_error == ConfigChangeRef::OK);
 
   if (sig->header.m_noOfSections != 1)
   {

=== modified file 'storage/ndb/src/mgmsrv/ConfigManager.hpp'
--- a/storage/ndb/src/mgmsrv/ConfigManager.hpp	2008-12-16 15:53:28 +0000
+++ b/storage/ndb/src/mgmsrv/ConfigManager.hpp	2008-12-17 16:09:24 +0000
@@ -58,6 +58,9 @@ class ConfigManager : public MgmtThread 
   ConfigState m_config_state;
   ConfigState m_previous_state;
 
+  /* The original error that caused config change to be aborted */
+  ConfigChangeRef::ErrorCode m_config_change_error;
+
   BlockReference m_client_ref;
   BaseString m_config_name;
   Config* m_prepared_config;

=== modified file 'storage/ndb/src/mgmsrv/MgmtSrvr.cpp'
--- a/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2008-12-17 15:40:11 +0000
+++ b/storage/ndb/src/mgmsrv/MgmtSrvr.cpp	2008-12-17 16:18:23 +0000
@@ -3932,7 +3932,7 @@ MgmtSrvr::change_config(Config& new_conf
 
     default:
       report_unknown_signal(signal);
-      return SEND_OR_RECEIVE_FAILED;
+      return false;
 
     }
   }

=== modified file 'storage/ndb/test/include/NdbMgmd.hpp'
--- a/storage/ndb/test/include/NdbMgmd.hpp	2008-11-19 13:42:48 +0000
+++ b/storage/ndb/test/include/NdbMgmd.hpp	2008-12-17 16:09:24 +0000
@@ -30,8 +30,13 @@
 class NdbMgmd {
   BaseString m_connect_str;
   NdbMgmHandle m_handle;
+  Uint32 m_nodeid;
+  bool m_verbose;
   void error(const char* msg, ...) ATTRIBUTE_FORMAT(printf, 2, 3)
   {
+    if (!m_verbose)
+      return;
+
     va_list args;
     printf("NdbMgmd::");
     va_start(args, msg);
@@ -48,7 +53,7 @@ class NdbMgmd {
   }
 public:
   NdbMgmd() :
-    m_handle(NULL)
+    m_handle(NULL), m_nodeid(0), m_verbose(true)
     {
       const char* connect_string= getenv("NDB_CONNECTSTRING");
       if (connect_string)
@@ -69,14 +74,28 @@ public:
     return m_connect_str.c_str();
   }
 
-  bool connect(void) {
+  void verbose(bool yes = true){
+    m_verbose= yes;
+  }
+
+  int last_error(void) const {
+    return ndb_mgm_get_latest_error(m_handle);
+  }
+
+  const char* last_error_message(void) const {
+    return ndb_mgm_get_latest_error_desc(m_handle);
+  }
+
+  bool connect(const char* connect_string = NULL) {
     m_handle= ndb_mgm_create_handle();
     if (!m_handle){
       error("connect: ndb_mgm_create_handle failed");
       return false;
     }
 
-    if (ndb_mgm_set_connectstring(m_handle, getConnectString()) != 0){
+    if (ndb_mgm_set_connectstring(m_handle,
+                                  connect_string ?
+                                  connect_string : getConnectString()) != 0){
       error("connect: ndb_mgm_set_connectstring failed");
       return false;
     }
@@ -85,6 +104,12 @@ public:
       error("connect: ndb_mgm_connect failed");
       return false;
     }
+
+    if ((m_nodeid = ndb_mgm_get_mgmd_nodeid(m_handle)) == 0){
+      error("connect: could not get nodeid of connected mgmd");
+      return false;
+    }
+
     return true;
   }
 
@@ -100,8 +125,34 @@ public:
     return true;
   }
 
+  bool restart(bool abort = false) {
+    if (!is_connected()){
+      error("restart: not connected");
+      return false;
+    }
+
+    int disconnect= 0;
+    int node_list= m_nodeid;
+    int restarted= ndb_mgm_restart3(m_handle,
+                                    1,
+                                    &node_list,
+                                    false, /* initial */
+                                    false, /* nostart */
+                                    abort,
+                                    &disconnect);
+
+    if (restarted != 1){
+      error("restart: failed to restart node %d, restarted: %d",
+            m_nodeid, restarted);
+      return false;
+    }
+    return true;
+  }
+
   bool call(const char* cmd, const Properties& args,
-            const char* cmd_reply, Properties& reply){
+            const char* cmd_reply, Properties& reply,
+            const char* bulk = NULL,
+            bool name_value_pairs = true){
 
     if (!is_connected()){
       error("call: not connected");
@@ -153,46 +204,68 @@ public:
 	break;
       }
     }
+
+    // Emtpy line terminates argument list
     if (out.print("\n")){
       error("call: print('\n') failed at line %d", __LINE__);
       return false;
     }
 
+    // Send any bulk data
+    if (bulk && out.println(bulk)){
+      error("call: print('<bulk>') failed at line %d", __LINE__);
+      return false;
+    }
 
-    // Read the reply
     BaseString buf;
     SocketInputStream2 in(_ndb_mgm_get_socket(m_handle));
-    if (!in.gets(buf)){
-      error("call: could not read reply command");
-      return false;
-    }
+    if (cmd_reply)
+    {
+      // Read the reply header and compare against "cmd_reply"
+      if (!in.gets(buf)){
+        error("call: could not read reply command");
+        return false;
+      }
 
-    // 1. Check correct reply header
-    if (buf != cmd_reply){
-      error("call: unexpected reply command, expected: '%s', got '%s'",
-            cmd_reply, buf.c_str());
-      return false;
+      // 1. Check correct reply header
+      if (buf != cmd_reply){
+        error("call: unexpected reply command, expected: '%s', got '%s'",
+              cmd_reply, buf.c_str());
+        return false;
+      }
     }
 
-    // 2. Read colon separated name value pairs until empty line
+    // 2. Read lines until empty line
+    int line = 1;
     while(in.gets(buf)){
 
       // empty line -> end of reply
       if (buf == "")
         return true;
 
-      // Split the name value pair on first ':'
-      Vector<BaseString> name_value_pair;
-      if (buf.split(name_value_pair, ":", 2) != 2){
-        error("call: illegal name value pair '%s' received", buf.c_str());
-        return false;
-      }
+      if (name_value_pairs)
+      {
+        // 3a. Read colon separated name value pair, split
+        // the name value pair on first ':'
+        Vector<BaseString> name_value_pair;
+        if (buf.split(name_value_pair, ":", 2) != 2){
+          error("call: illegal name value pair '%s' received", buf.c_str());
+          return false;
+        }
 
-      reply.put(name_value_pair[0].trim(" ").c_str(),
-                name_value_pair[1].trim(" ").c_str());
+        reply.put(name_value_pair[0].trim(" ").c_str(),
+                  name_value_pair[1].trim(" ").c_str());
+      }
+      else
+      {
+        // 3b. Not name value pair, save the line into "reply"
+        // using unique key
+        reply.put("line", line++, buf.c_str());
+      }
     }
 
     error("call: should never come here");
+    reply.print();
     abort();
     return false;
   }
@@ -216,6 +289,22 @@ public:
     return true;
   }
 
+  bool set_config(Config& config){
+
+    if (!is_connected()){
+      error("set_config: not connected");
+      return false;
+    }
+
+    if (ndb_mgm_set_configuration(m_handle,
+                                  config.values()) != 0)
+    {
+      error("set_config: ndb_mgm_set_configuration failed");
+      return false;
+    }
+    return true;
+  }
+
   bool end_session(void){
     if (!is_connected()){
       error("end_session: not connected");

=== modified file 'storage/ndb/test/ndbapi/testMgm.cpp'
--- a/storage/ndb/test/ndbapi/testMgm.cpp	2008-12-17 08:06:47 +0000
+++ b/storage/ndb/test/ndbapi/testMgm.cpp	2008-12-17 16:18:23 +0000
@@ -681,7 +681,6 @@ int runSetConfigUntilStopped(NDBT_Contex
   while(!ctx->isTestStopped() &&
         (result= runSetConfig(ctx, step)) == NDBT_OK)
     ;
-  ctx->stopTest();
   return result;
 }
 
@@ -712,7 +711,6 @@ int runGetConfigUntilStopped(NDBT_Contex
   while(!ctx->isTestStopped() &&
         (result= runGetConfig(ctx, step)) == NDBT_OK)
     ;
-  ctx->stopTest();
   return result;
 }
 
@@ -917,7 +915,6 @@ int runTestStatusUntilStopped(NDBT_Conte
   while(!ctx->isTestStopped() &&
         (result= runTestStatus(ctx, step)) == NDBT_OK)
     ;
-  ctx->stopTest();
   return result;
 }
 
@@ -1240,7 +1237,6 @@ int runTestGetNodeIdUntilStopped(NDBT_Co
   while(!ctx->isTestStopped() &&
         (result= runTestGetNodeId(ctx, step)) == NDBT_OK)
     ;
-  ctx->stopTest();
   return result;
 }
 
@@ -1256,6 +1252,598 @@ int runSleepAndStop(NDBT_Context* ctx, N
 }
 
 
+static bool
+get_version(NdbMgmd& mgmd,
+            Properties& reply)
+{
+  Properties args;
+  if (!mgmd.call("get version", args,
+                 "version", reply))
+  {
+    g_err << "get_version: mgmd.call failed" << endl;
+    return false;
+  }
+
+  //reply.print();
+  return true;
+}
+
+int runTestGetVersion(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  Properties reply;
+  if (!get_version(mgmd, reply))
+   return NDBT_FAILED;
+
+  return NDBT_OK;
+}
+
+int runTestGetVersionUntilStopped(NDBT_Context* ctx, NDBT_Step* step)
+{
+  int result= NDBT_OK;
+  while(!ctx->isTestStopped() &&
+        (result= runTestGetVersion(ctx, step)) == NDBT_OK)
+    ;
+  return result;
+}
+
+static bool
+show_config(NdbMgmd& mgmd,
+            const Properties& args,
+            Properties& reply)
+{
+  if (!mgmd.call("show config", args,
+                 "show config reply", reply, NULL, false))
+  {
+    g_err << "show_config: mgmd.call failed" << endl;
+    return false;
+  }
+
+  // reply.print();
+  return true;
+}
+
+
+int runCheckConfig(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  // Connect to any mgmd and get the config
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  Properties args1;
+  Properties config1;
+  if (!show_config(mgmd, args1, config1))
+    return NDBT_FAILED;
+
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return NDBT_FAILED;
+
+  // Extract list of connectstrings to each mgmd
+  BaseString connectstring;
+  conf.getConnectString(connectstring, ";");
+
+  Vector<BaseString> mgmds;
+  connectstring.split(mgmds, ";");
+
+  // Connect to each mgmd and check
+  // they all have the same config
+  for (size_t i = 0; i < mgmds.size(); i++)
+  {
+    NdbMgmd mgmd2;
+    g_info << "Connecting to " << mgmds[i].c_str() << endl;
+    if (!mgmd2.connect(mgmds[i].c_str()))
+      return NDBT_FAILED;
+
+    Properties args2;
+    Properties config2;
+    if (!show_config(mgmd, args2, config2))
+      return NDBT_FAILED;
+
+    // Compare config1 and config2 line by line
+    Uint32 line = 1;
+    const char* value1;
+    const char* value2;
+    while (true)
+    {
+      if (config1.get("line", line, &value1))
+      {
+        // config1 had line, so should config2
+        if (config2.get("line", line, &value2))
+        {
+          // both configs had line, check they are equal
+          if (strcmp(value1, value2) != 0)
+          {
+            g_err << "the value on line " << line << "didn't match!" << endl;
+            g_err << "config1, value: " << value1 << endl;
+            g_err << "config2, value: " << value2 << endl;
+            return NDBT_FAILED;
+          }
+          // g_info << line << ": " << value1 << " = " << value2 << endl;
+        }
+        else
+        {
+          g_err << "config2 didn't have line " << line << "!" << endl;
+          return NDBT_FAILED;
+        }
+      }
+      else
+      {
+        // Make sure config2 does not have this line either and end loop
+        if (config2.get("line", line, &value2))
+        {
+          g_err << "config2 had line " << line << " not in config1!" << endl;
+          return NDBT_FAILED;
+        }
+
+        // End of loop
+        g_info << "There was " << line << " lines in config" << endl;
+        break;
+      }
+      line++;
+    }
+    if (line == 0)
+    {
+      g_err << "FAIL: config should have lines!" << endl;
+      return NDBT_FAILED;
+    }
+
+    // Compare the binary config
+    Config conf2;
+    if (!mgmd.get_config(conf2))
+      return NDBT_FAILED;
+
+    if (!conf.equal(&conf2))
+    {
+      g_err << "The binary config was different! host: " << mgmds[i] << endl;
+      return NDBT_FAILED;
+    }
+
+  }
+
+  return NDBT_OK;
+}
+
+
+static bool
+reload_config(NdbMgmd& mgmd,
+              const Properties& args,
+              Properties& reply)
+{
+  if (!mgmd.call("reload config", args,
+                 "reload config reply", reply))
+  {
+    g_err << "reload config: mgmd.call failed" << endl;
+    return false;
+  }
+
+  //reply.print();
+  return true;
+}
+
+
+static bool reload_config_result_contains(NdbMgmd& mgmd,
+                                          const Properties& args,
+                                          const char* expected_result)
+{
+  Properties reply;
+  if (!reload_config(mgmd, args, reply))
+    return false;
+  return result_contains(reply, expected_result);
+}
+
+
+static bool
+check_reload_config_both_config_and_mycnf(NdbMgmd& mgmd)
+{
+  Properties args;
+  // Send reload command with both config_filename and mycnf set
+  args.put("config_filename", "some filename");
+  args.put("mycnf", 1);
+  return reload_config_result_contains(mgmd, args,
+                                       "ERROR: Both mycnf and config_filename");
+}
+
+static bool
+check_reload_config_invalid_config_filename(NdbMgmd& mgmd)
+{
+  Properties args;
+  // Send reload command with an invalid config_filename
+  args.put("config_filename", "nonexisting_file");
+  return reload_config_result_contains(mgmd, args,
+                                       "Could not load configuration "
+                                       "from 'nonexisting_file");
+}
+
+
+int runTestReloadConfig(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  int result= NDBT_FAILED;
+  if (
+      check_reload_config_both_config_and_mycnf(mgmd) &&
+      check_reload_config_invalid_config_filename(mgmd) &&
+      true)
+    result= NDBT_OK;
+
+  if (!mgmd.end_session())
+    result= NDBT_FAILED;
+
+  return result;
+}
+
+
+static bool
+set_config(NdbMgmd& mgmd,
+           const Properties& args,
+           BaseString encoded_config,
+           Properties& reply)
+{
+
+  // Fill in default values of other args
+  Properties call_args(args);
+  if (!call_args.contains("Content-Type"))
+    call_args.put("Content-Type", "ndbconfig/octet-stream");
+  if (!call_args.contains("Content-Transfer-Encoding"))
+    call_args.put("Content-Transfer-Encoding", "base64");
+  if (!call_args.contains("Content-Length"))
+    call_args.put("Content-Length",
+                  encoded_config.length() ? encoded_config.length() - 1 : 1);
+
+  if (!mgmd.call("set config", call_args,
+                 "set config reply", reply,
+                 encoded_config.c_str()))
+  {
+    g_err << "set config: mgmd.call failed" << endl;
+    return false;
+  }
+
+  //reply.print();
+  return true;
+}
+
+
+static bool set_config_result_contains(NdbMgmd& mgmd,
+                                       const Properties& args,
+                                       const BaseString& encoded_config,
+                                       const char* expected_result)
+{
+  Properties reply;
+  if (!set_config(mgmd, args, encoded_config, reply))
+    return false;
+  return result_contains(reply, expected_result);
+}
+
+
+static bool set_config_result_contains(NdbMgmd& mgmd,
+                                       const Config& conf,
+                                       const char* expected_result)
+{
+  Properties reply;
+  Properties args;
+
+  BaseString encoded_config;
+  if (!conf.pack64(encoded_config))
+    return false;
+
+  if (!set_config(mgmd, args, encoded_config, reply))
+    return false;
+  return result_contains(reply, expected_result);
+}
+
+
+static bool
+check_set_config_invalid_content_type(NdbMgmd& mgmd)
+{
+  Properties args;
+  args.put("Content-Type", "illegal type");
+  return set_config_result_contains(mgmd, args, BaseString(""),
+                                    "Unhandled content type 'illegal type'");
+}
+
+static bool
+check_set_config_invalid_content_encoding(NdbMgmd& mgmd)
+{
+  Properties args;
+  args.put("Content-Transfer-Encoding", "illegal encoding");
+  return set_config_result_contains(mgmd, args, BaseString(""),
+                                    "Unhandled content encoding "
+                                    "'illegal encoding'");
+}
+
+static bool
+check_set_config_too_large_content_length(NdbMgmd& mgmd)
+{
+  Properties args;
+  args.put("Content-Length", 1024*1024 + 1);
+  return set_config_result_contains(mgmd, args, BaseString(""),
+                                    "Illegal config length size 1048577");
+}
+
+static bool
+check_set_config_too_small_content_length(NdbMgmd& mgmd)
+{
+  Properties args;
+  args.put("Content-Length", (Uint32)0);
+  return set_config_result_contains(mgmd, args, BaseString(""),
+                                    "Illegal config length size 0");
+}
+
+static bool
+check_set_config_wrong_config_length(NdbMgmd& mgmd)
+{
+
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  BaseString encoded_config;
+  if (!conf.pack64(encoded_config))
+    return false;
+
+  Properties args;
+  args.put("Content-Length", encoded_config.length() - 20);
+  bool res = set_config_result_contains(mgmd, args, encoded_config,
+                                        "Failed to unpack config");
+
+  if (res){
+    /*
+      There are now additional 20 bytes of junk that has been
+      sent to  mgmd, send a new line and read the result to get rid of it
+    */
+    Properties args, reply;
+    if (!mgmd.call("", args,
+                   NULL, reply))
+      return false;
+  }
+  return res;
+}
+
+static bool
+check_set_config_any_node(NDBT_Context* ctx, NDBT_Step* step, NdbMgmd& mgmd)
+{
+
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  // Extract list of connectstrings to each mgmd
+  BaseString connectstring;
+  conf.getConnectString(connectstring, ";");
+
+  Vector<BaseString> mgmds;
+  connectstring.split(mgmds, ";");
+
+  // Connect to each mgmd and check
+  // they all have the same config
+  for (size_t i = 0; i < mgmds.size(); i++)
+  {
+    NdbMgmd mgmd2;
+    g_info << "Connecting to " << mgmds[i].c_str() << endl;
+    if (!mgmd2.connect(mgmds[i].c_str()))
+      return false;
+
+    // Get the binary config
+    Config conf2;
+    if (!mgmd2.get_config(conf2))
+      return false;
+
+#if 0
+    // Change one value in the config
+    if (!conf2.setValue(CFG_SECTION_NODE, 0,
+                        CFG_NODE_ARBIT_DELAY,
+#endif
+
+    // Set the modified config
+    if (!mgmd2.set_config(conf2))
+      return false;
+
+    // Check that all mgmds now have the new config
+    if (runCheckConfig(ctx, step) != NDBT_OK)
+      return false;
+
+  }
+
+  return true;
+}
+
+static bool
+check_set_config_fail_wrong_generation(NdbMgmd& mgmd)
+{
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  // Change generation
+  if (!conf.setGeneration(conf.getGeneration() + 10))
+    return false;
+
+  // Set the modified config
+  return set_config_result_contains(mgmd, conf,
+                                    "Invalid generation in");
+}
+
+static bool
+check_set_config_fail_wrong_name(NdbMgmd& mgmd)
+{
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  // Change name
+  if (!conf.setName("NEWNAME"))
+    return false;
+
+  // Set the modified config
+  return set_config_result_contains(mgmd, conf,
+                                    "Invalid configuration name");
+}
+
+static bool
+check_set_config_fail_wrong_primary(NdbMgmd& mgmd)
+{
+  // Get the binary config
+  Config conf;
+  if (!mgmd.get_config(conf))
+    return false;
+
+  // Change primary and thus make this configuration invalid
+  if (!conf.setPrimaryMgmNode(conf.getPrimaryMgmNode()+10))
+    return false;
+
+  // Set the modified config
+  return set_config_result_contains(mgmd, conf,
+                                    "Not primary mgm node");
+}
+
+int runTestSetConfig(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  int result= NDBT_FAILED;
+  if (
+      check_set_config_invalid_content_type(mgmd) &&
+      check_set_config_invalid_content_encoding(mgmd) &&
+      check_set_config_too_large_content_length(mgmd) &&
+      check_set_config_too_small_content_length(mgmd) &&
+      check_set_config_wrong_config_length(mgmd) &&
+      check_set_config_any_node(ctx, step, mgmd) &&
+      check_set_config_fail_wrong_generation(mgmd) &&
+      check_set_config_fail_wrong_name(mgmd) &&
+      check_set_config_fail_wrong_primary(mgmd) &&
+      true)
+    result= NDBT_OK;
+
+  if (!mgmd.end_session())
+    result= NDBT_FAILED;
+
+  return result;
+}
+
+int runTestSetConfigParallel(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  int result = NDBT_OK;
+  int loops = ctx->getNumLoops();
+  int sucessful = 0;
+
+  int invalid_generation = 0, config_change_ongoing = 0;
+
+  /*
+    continue looping until "loops" number of successful
+    changes have been made from this thread
+  */
+  while (sucessful < loops &&
+         !ctx->isTestStopped() &&
+         result == NDBT_OK)
+  {
+    // Get the binary config
+    Config conf;
+    if (!mgmd.get_config(conf))
+      return NDBT_FAILED;
+
+    /* Set the config and check for valid errors */
+    mgmd.verbose(false);
+    if (mgmd.set_config(conf))
+    {
+      /* Config change suceeded */
+      sucessful++;
+    }
+    else
+    {
+      /* Config change failed */
+      if (mgmd.last_error() != NDB_MGM_CONFIG_CHANGE_FAILED)
+      {
+        g_err << "Config change failed with unexpected error: "
+              << mgmd.last_error() << endl;
+        result = NDBT_FAILED;
+        continue;
+      }
+
+      BaseString error(mgmd.last_error_message());
+      if (error == "Invalid generation in configuration")
+        invalid_generation++;
+      else
+      if (error == "Config change ongoing")
+        config_change_ongoing++;
+      else
+      {
+        g_err << "Config change failed with unexpected error: '"
+              << error << "'" << endl;
+        result = NDBT_FAILED;
+
+      }
+    }
+  }
+
+  ndbout << "Thread " << step->getStepNo()
+         << ", sucess: " << sucessful
+         << ", ongoing: " << config_change_ongoing
+         << ", invalid_generation: " << invalid_generation << endl;
+  return result;
+}
+
+int runTestSetConfigParallelUntilStopped(NDBT_Context* ctx, NDBT_Step* step)
+{
+  int result= NDBT_OK;
+  while(!ctx->isTestStopped() &&
+        (result= runTestSetConfigParallel(ctx, step)) == NDBT_OK)
+    ;
+  return result;
+}
+
+
+#ifdef NOT_YET
+static bool
+check_restart_connected(NdbMgmd& mgmd)
+{
+  if (!mgmd.restart())
+    return false;
+  return true;
+ }
+
+int runTestRestartMgmd(NDBT_Context* ctx, NDBT_Step* step)
+{
+  NdbMgmd mgmd;
+
+  if (!mgmd.connect())
+    return NDBT_FAILED;
+
+  int result= NDBT_FAILED;
+  if (
+      check_restart_connected(mgmd) &&
+      true)
+    result= NDBT_OK;
+
+  if (!mgmd.end_session())
+    result= NDBT_FAILED;
+
+  return result;
+}
+#endif
+
 
 NDBT_TESTSUITE(testMgm);
 DRIVER(DummyDriver); /* turn off use of NdbApi */
@@ -1297,7 +1885,22 @@ TESTCASE("ApiMgmStructEventTimeout",
 TESTCASE("SetConfig",
 	 "Tests the ndb_mgm_set_configuration function"){
   INITIALIZER(runSetConfig);
-
+}
+TESTCASE("CheckConfig",
+	 "Connect to each ndb_mgmd and check they have the same configuration"){
+  INITIALIZER(runCheckConfig);
+}
+TESTCASE("TestReloadConfig",
+	 "Test of 'reload config'"){
+  INITIALIZER(runTestReloadConfig);
+}
+TESTCASE("TestSetConfig",
+	 "Test of 'set config'"){
+  INITIALIZER(runTestSetConfig);
+}
+TESTCASE("TestSetConfigParallel",
+	 "Test of 'set config' from 5 threads"){
+  STEPS(runTestSetConfigParallel, 5);
 }
 TESTCASE("GetConfig", "Run ndb_mgm_get_configuration in parallel"){
   STEPS(runGetConfig, 100);
@@ -1322,14 +1925,34 @@ TESTCASE("TestStatus200",
 TESTCASE("TestGetNodeId",
 	 "Test 'get nodeid'"){
   INITIALIZER(runTestGetNodeId);
+}
 
+TESTCASE("TestGetVersion",
+	 "Test 'get version'"){
+  INITIALIZER(runTestGetVersion);
+}
+#ifdef NOT_YET
+TESTCASE("TestRestartMgmd",
+        "Test restart of ndb_mgmd(s)"){
+  INITIALIZER(runTestRestartMgmd);
 }
+#endif
 TESTCASE("Stress",
 	 "Run everything while changing config"){
   STEP(runTestGetNodeIdUntilStopped);
   STEP(runSetConfigUntilStopped);
   STEPS(runGetConfigUntilStopped, 10);
   STEPS(runTestStatusUntilStopped, 10);
+//  STEPS(runTestGetVersionUntilStopped, 5);
+  STEP(runSleepAndStop);
+}
+TESTCASE("Stress2",
+	 "Run everything while changing config in parallel"){
+  STEP(runTestGetNodeIdUntilStopped);
+  STEPS(runTestSetConfigParallelUntilStopped, 5);
+  STEPS(runGetConfigUntilStopped, 10);
+  STEPS(runTestStatusUntilStopped, 10);
+//  STEPS(runTestGetVersionUntilStopped, 5);
   STEP(runSleepAndStop);
 }
 NDBT_TESTSUITE_END(testMgm);

Thread
bzr commit into mysql-5.1 branch (msvensson:3178) Magnus Svensson17 Dec