1467 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
			
		
		
	
	
			1467 lines
		
	
	
		
			44 KiB
		
	
	
	
		
			C++
		
	
	
| /*
 | |
|    Copyright (c) 2009, 2019, Oracle and/or its affiliates. All rights reserved.
 | |
| 
 | |
| 
 | |
|    This program is free software; you can redistribute it and/or modify
 | |
|    it under the terms of the GNU General Public License, version 2.0,
 | |
|    as published by the Free Software Foundation.
 | |
| 
 | |
|    This program is also distributed with certain software (including
 | |
|    but not limited to OpenSSL) that is licensed under separate terms,
 | |
|    as designated in a particular file or component or in included license
 | |
|    documentation.  The authors of MySQL hereby grant you an additional
 | |
|    permission to link the program and your derivative works with the
 | |
|    separately licensed software that they have included with MySQL.
 | |
| 
 | |
|    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, version 2.0, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301  USA
 | |
|  */
 | |
| 
 | |
| #include <NDBT.hpp>
 | |
| #include <NDBT_Test.hpp>
 | |
| #include <portlib/NdbDir.hpp>
 | |
| #include "ConfigFactory.hpp"
 | |
| #include <NdbMgmd.hpp>
 | |
| #include <NdbProcess.hpp>
 | |
| #include <NDBT_Find.hpp>
 | |
| #include <NDBT_Workingdir.hpp>
 | |
| #include <NdbEnv.h>
 | |
| 
 | |
| static const char * exe_valgrind = 0;
 | |
| static const char * arg_valgrind = 0;
 | |
| 
 | |
| static bool file_exists(const char* path, Uint32 timeout = 1)
 | |
| {
 | |
|   g_info << "File '" << path << "' ";
 | |
|   /**
 | |
|    * ndb_mgmd does currently not fsync the directory
 | |
|    *   after committing config-bin,
 | |
|    *   which means that it can be on disk, wo/ being visible
 | |
|    *   remedy this by retrying some
 | |
|    */
 | |
|   for (Uint32 i = 0; i < 10 * timeout; i++)
 | |
|   {
 | |
|     if (access(path, F_OK) == 0)
 | |
|     {
 | |
|       g_info << "exists" << endl;
 | |
|       return true;
 | |
|     }
 | |
|     if (i == 0)
 | |
|     {
 | |
|       g_info << "does not exist, retrying...";
 | |
|     }
 | |
|     NdbSleep_MilliSleep(100);
 | |
|   }
 | |
|   g_info << "does not exist" << endl;
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| // Util function that concatenate strings to form a path
 | |
| 
 | |
| static BaseString path(const char* first, ...)
 | |
| {
 | |
|   BaseString path;
 | |
|   path.assign(first);
 | |
| 
 | |
|   const char* str;
 | |
|   va_list args;
 | |
|   va_start(args, first);
 | |
|   while ((str = va_arg(args, const char*)) != NULL)
 | |
|   {
 | |
|     path.appfmt("%s%s", DIR_SEPARATOR, str);
 | |
|   }
 | |
|   va_end(args);
 | |
|   return path;
 | |
| }
 | |
| 
 | |
| class Mgmd
 | |
| {
 | |
|   NdbProcess* m_proc;
 | |
|   int m_nodeid;
 | |
|   BaseString m_name;
 | |
|   BaseString m_exe;
 | |
|   NdbMgmd m_mgmd_client;
 | |
| 
 | |
|   Mgmd(const Mgmd& other); // Not implemented
 | |
| public:
 | |
| 
 | |
|   Mgmd(int nodeid) :
 | |
|   m_proc(NULL),
 | |
|   m_nodeid(nodeid)
 | |
|   {
 | |
|     m_name.assfmt("ndb_mgmd_%d", nodeid);
 | |
| 
 | |
|     NDBT_find_ndb_mgmd(m_exe);
 | |
|   }
 | |
| 
 | |
|   ~Mgmd()
 | |
|   {
 | |
|     if (m_proc)
 | |
|     {
 | |
|       //stop the proces
 | |
|       stop();
 | |
|     }
 | |
| 
 | |
|   }
 | |
| 
 | |
|   const char* name(void) const
 | |
|   {
 | |
|     return m_name.c_str();
 | |
|   }
 | |
| 
 | |
|   const char* exe(void) const
 | |
|   {
 | |
|     return m_exe.c_str();
 | |
|   }
 | |
| 
 | |
|   bool start(const char* working_dir, NdbProcess::Args& args)
 | |
|   {
 | |
|     g_info << "Starting " << name() << " ";
 | |
|     for (unsigned i = 0; i < args.args().size(); i++)
 | |
|       g_info << args.args()[i].c_str() << " ";
 | |
|     g_info << endl;
 | |
| 
 | |
|     if (exe_valgrind == 0)
 | |
|     {
 | |
|       m_proc = NdbProcess::create(name(),
 | |
|                                   exe(),
 | |
|                                   working_dir,
 | |
|                                   args);
 | |
|     }
 | |
|     else
 | |
|     {
 | |
|       NdbProcess::Args copy;
 | |
|       if (arg_valgrind)
 | |
|       {
 | |
|         copy.add(arg_valgrind);
 | |
|       }
 | |
|       copy.add(exe());
 | |
|       copy.add(args);
 | |
|       m_proc = NdbProcess::create(name(),
 | |
|                                   BaseString(exe_valgrind),
 | |
|                                   working_dir,
 | |
|                                   copy);
 | |
|     }
 | |
|     return (m_proc != NULL);
 | |
|   }
 | |
| 
 | |
|   bool start_from_config_ini(const char* working_dir,
 | |
|                              const char* first_extra_arg = NULL, ...)
 | |
|   {
 | |
|     NdbProcess::Args args;
 | |
|     args.add("--no-defaults");
 | |
|     args.add("--configdir=.");
 | |
|     args.add("-f config.ini");
 | |
|     args.add("--ndb-nodeid=", m_nodeid);
 | |
|     args.add("--nodaemon");
 | |
|     args.add("--log-name=", name());
 | |
|     args.add("--verbose");
 | |
| 
 | |
|     if (first_extra_arg)
 | |
|     {
 | |
|       // Append any extra args
 | |
|       va_list extra_args;
 | |
|       const char* str = first_extra_arg;
 | |
|       va_start(extra_args, first_extra_arg);
 | |
|       do
 | |
|       {
 | |
|         args.add(str);
 | |
|       } while ((str = va_arg(extra_args, const char*)) != NULL);
 | |
|       va_end(extra_args);
 | |
|     }
 | |
| 
 | |
|     return start(working_dir, args);
 | |
|   }
 | |
| 
 | |
|   bool start(const char* working_dir,
 | |
|              const char* first_extra_arg = NULL, ...)
 | |
|   {
 | |
|     NdbProcess::Args args;
 | |
|     args.add("--no-defaults");
 | |
|     args.add("--configdir=.");
 | |
|     args.add("--ndb-nodeid=", m_nodeid);
 | |
|     args.add("--nodaemon");
 | |
|     args.add("--log-name=", name());
 | |
|     args.add("--verbose");
 | |
| 
 | |
|     if (first_extra_arg)
 | |
|     {
 | |
|       // Append any extra args
 | |
|       va_list extra_args;
 | |
|       const char* str = first_extra_arg;
 | |
|       va_start(extra_args, first_extra_arg);
 | |
|       do
 | |
|       {
 | |
|         args.add(str);
 | |
|       } while ((str = va_arg(extra_args, const char*)) != NULL);
 | |
|       va_end(extra_args);
 | |
|     }
 | |
| 
 | |
|     return start(working_dir, args);
 | |
|   }
 | |
| 
 | |
|   bool stop(void)
 | |
|   {
 | |
|     g_info << "Stopping " << name() << endl;
 | |
| 
 | |
|     // Diconnect and close our "builtin" client
 | |
|     m_mgmd_client.close();
 | |
| 
 | |
|     if (m_proc == 0 || !m_proc->stop())
 | |
|     {
 | |
|       fprintf(stderr, "Failed to stop process %s\n", name());
 | |
|       return false; // Can't kill with -9 -> fatal error
 | |
|     }
 | |
|     int ret;
 | |
|     if (!m_proc->wait(ret, 300))
 | |
|     {
 | |
|       fprintf(stderr, "Failed to wait for process %s\n", name());
 | |
|       return false; // Can't wait after kill with -9 -> fatal error
 | |
|     }
 | |
| 
 | |
|     if (ret != 9)
 | |
|     {
 | |
|       fprintf(stderr, "stop ret: %u\n", ret);
 | |
|       return false; // Can't wait after kill with -9 -> fatal error
 | |
|     }
 | |
| 
 | |
|     delete m_proc;
 | |
|     m_proc = 0;
 | |
| 
 | |
|     return true;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   bool wait(int& ret, int timeout = 300)
 | |
|   {
 | |
|     g_info << "Waiting for " << name() << endl;
 | |
| 
 | |
|     if (m_proc == 0 || !m_proc->wait(ret, timeout))
 | |
|     {
 | |
|       fprintf(stderr, "Failed to wait for process %s\n", name());
 | |
|       return false;
 | |
|     }
 | |
|     delete m_proc;
 | |
|     m_proc = 0;
 | |
| 
 | |
|     return true;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   const BaseString connectstring(const Properties& config)
 | |
|   {
 | |
|     const char* hostname;
 | |
|     require(get_section_string(config, m_name.c_str(),
 | |
|                                "HostName", &hostname));
 | |
| 
 | |
|     Uint32 port;
 | |
|     require(get_section_uint32(config, m_name.c_str(),
 | |
|                                "PortNumber", &port));
 | |
| 
 | |
|     BaseString constr;
 | |
|     constr.assfmt("%s:%d", hostname, port);
 | |
|     return constr;
 | |
|   }
 | |
| 
 | |
|   bool connect(const Properties& config,
 | |
|                int num_retries = 60, int retry_delay_in_seconds = 1)
 | |
|   {
 | |
|     BaseString constr = connectstring(config);
 | |
|     g_info << "Connecting to " << name() << " @ " << constr.c_str() << endl;
 | |
| 
 | |
|     return m_mgmd_client.connect(constr.c_str(),
 | |
|                                  num_retries,
 | |
|                                  retry_delay_in_seconds);
 | |
|   }
 | |
| 
 | |
|   bool wait_confirmed_config(int timeout = 30)
 | |
|   {
 | |
|     if (!m_mgmd_client.is_connected())
 | |
|     {
 | |
|       g_err << "wait_confirmed_config: not connected!" << endl;
 | |
|       return false;
 | |
|     }
 | |
| 
 | |
|     int retries = 0;
 | |
|     Config conf;
 | |
|     while (!m_mgmd_client.get_config(conf))
 | |
|     {
 | |
|       retries++;
 | |
| 
 | |
|       if (retries == timeout * 10)
 | |
|       {
 | |
|         g_err << "wait_confirmed_config: Failed to get config within "
 | |
|                 << timeout << " seconds" << endl;
 | |
|         return false;
 | |
|       }
 | |
| 
 | |
|       g_err << "Failed to get config, sleeping" << endl;
 | |
|       NdbSleep_MilliSleep(100);
 | |
| 
 | |
|     }
 | |
|     g_info << "wait_confirmed_config: ok" << endl;
 | |
|     return true;
 | |
| 
 | |
|   }
 | |
| 
 | |
|   NdbMgmHandle handle() { return m_mgmd_client.handle(); }
 | |
| 
 | |
| private:
 | |
| 
 | |
|   bool get_section_string(const Properties& config,
 | |
|                           const char* section_name,
 | |
|                           const char* key,
 | |
|                           const char** value) const
 | |
|   {
 | |
|     const Properties* section;
 | |
|     if (!config.get(section_name, §ion))
 | |
|       return false;
 | |
| 
 | |
|     if (!section->get(key, value))
 | |
|       return false;
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
|   bool get_section_uint32(const Properties& config,
 | |
|                           const char* section_name,
 | |
|                           const char* key,
 | |
|                           Uint32* value) const
 | |
|   {
 | |
|     const Properties* section;
 | |
|     if (!config.get(section_name, §ion))
 | |
|       return false;
 | |
| 
 | |
|     if (!section->get(key, value))
 | |
|       return false;
 | |
|     return true;
 | |
|   }
 | |
| 
 | |
| };
 | |
| 
 | |
| class MgmdProcessList : public Vector<Mgmd*>
 | |
| {
 | |
| public:
 | |
| 
 | |
|   ~MgmdProcessList()
 | |
|   {
 | |
|     // Delete and thus stop the mgmd(s)
 | |
|     for (unsigned i = 0; i < size(); i++)
 | |
|     {
 | |
|       Mgmd* mgmd = this->operator[](i);
 | |
|       delete mgmd;
 | |
|     }
 | |
|     //  delete this->[i];
 | |
|     clear();
 | |
|   }
 | |
| };
 | |
| 
 | |
| 
 | |
| #define CHECK(x)                                            \
 | |
|   if (!(x)) {                                               \
 | |
|     fprintf(stderr, "CHECK(" #x ") failed at line: %d\n", \
 | |
|             __LINE__);                                      \
 | |
|      return NDBT_FAILED;                                    \
 | |
|   }
 | |
| 
 | |
| int runTestBasic2Mgm(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   // Create config.ini
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
|   // Start ndb_mgmd(s)
 | |
|   MgmdProcessList mgmds;
 | |
|   for (int i = 1; i <= 2; i++)
 | |
|   {
 | |
|     Mgmd* mgmd = new Mgmd(i);
 | |
|     mgmds.push_back(mgmd);
 | |
|     CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
|   }
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   // Check binary config files created
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   // Stop the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->stop());
 | |
| 
 | |
|   // Start up the mgmd(s) again from config.bin
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path()));
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   CHECK(!file_exists(path(wd.path(),
 | |
|                           "ndb_1_config.bin.2",
 | |
|                           NULL).c_str()));
 | |
|   CHECK(!file_exists(path(wd.path(),
 | |
|                           "ndb_2_config.bin.2",
 | |
|                           NULL).c_str()));
 | |
| 
 | |
|   return NDBT_OK;
 | |
| 
 | |
| }
 | |
| 
 | |
| int runTestBug45495(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
|   // Start ndb_mgmd(s)
 | |
|   MgmdProcessList mgmds;
 | |
|   for (int i = 1; i <= 2; i++)
 | |
|   {
 | |
|     Mgmd* mgmd = new Mgmd(i);
 | |
|     mgmds.push_back(mgmd);
 | |
|     CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
|   }
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   // Check binary config files created
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Restart one ndb_mgmd at a time --reload + --initial" << endl;
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "--reload", "--initial", NULL));
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|     // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            "ndb_1_config.bin.1",
 | |
|                            NULL).c_str()));
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            "ndb_2_config.bin.1",
 | |
|                            NULL).c_str()));
 | |
| 
 | |
|     CHECK(!file_exists(path(wd.path(),
 | |
|                             "ndb_1_config.bin.2",
 | |
|                             NULL).c_str()));
 | |
|     CHECK(!file_exists(path(wd.path(),
 | |
|                             "ndb_2_config.bin.2",
 | |
|                             NULL).c_str()));
 | |
|   }
 | |
| 
 | |
|   g_err << "** Restart one ndb_mgmd at a time --initial" << endl;
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "--initial", NULL));
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|     // check ndb_X_config.bin.1 still exists but not ndb_X_config.bin.2
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            "ndb_1_config.bin.1",
 | |
|                            NULL).c_str()));
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            "ndb_2_config.bin.1",
 | |
|                            NULL).c_str()));
 | |
| 
 | |
|     CHECK(!file_exists(path(wd.path(),
 | |
|                             "ndb_1_config.bin.2",
 | |
|                             NULL).c_str()));
 | |
|     CHECK(!file_exists(path(wd.path(),
 | |
|                             "ndb_2_config.bin.2",
 | |
|                             NULL).c_str()));
 | |
|   }
 | |
| 
 | |
|   g_err << "** Create config2.ini" << endl;
 | |
|   CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config2.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Restart one ndb_mgmd at a time --initial should not work" << endl;
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|     // Start from config2.ini
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "-f config2.ini",
 | |
|                                           "--initial", NULL));
 | |
| 
 | |
|     // Wait for mgmd to exit and check return status
 | |
|     int ret;
 | |
|     CHECK(mgmds[i]->wait(ret));
 | |
|     CHECK(ret == 1);
 | |
| 
 | |
|     // check config files exist only for the still running mgmd(s)
 | |
|     for (unsigned j = 0; j < mgmds.size(); j++)
 | |
|     {
 | |
|       BaseString tmp;
 | |
|       tmp.assfmt("ndb_%d_config.bin.1", j+1);
 | |
|       CHECK(file_exists(path(wd.path(),
 | |
|                              tmp.c_str(),
 | |
|                              NULL).c_str()) == (j != i));
 | |
|     }
 | |
| 
 | |
|     // Start from config.ini again
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "--initial",
 | |
|                                           "--reload",
 | |
|                                           NULL));
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
|   }
 | |
| 
 | |
|   g_err << "** Reload from config2.ini" << endl;
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|     // Start from config2.ini
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "-f config2.ini",
 | |
|                                           "--reload", NULL));
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
|   }
 | |
| 
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   Uint32 timeout = 30;
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.2",
 | |
|                          NULL).c_str(), timeout));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.2",
 | |
|                          NULL).c_str(), timeout));
 | |
| 
 | |
|   g_err << "** Reload mgmd initial(from generation=2)" << endl;
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|     CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                           "-f config2.ini",
 | |
|                                           "--reload", "--initial", NULL));
 | |
| 
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|      // check config files exist
 | |
|     for (unsigned j = 0; j < mgmds.size(); j++)
 | |
|     {
 | |
|       BaseString tmp;
 | |
|       tmp.assfmt("ndb_%d_config.bin.1", j+1);
 | |
|       CHECK(file_exists(path(wd.path(),
 | |
|                              tmp.c_str(),
 | |
|                              NULL).c_str()) == (i < j));
 | |
| 
 | |
|       tmp.assfmt("ndb_%d_config.bin.2", j+1);
 | |
|       CHECK(file_exists(path(wd.path(),
 | |
|                              tmp.c_str(),
 | |
|                              NULL).c_str(),
 | |
|                         timeout));
 | |
|     }
 | |
|   }
 | |
| 
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| 
 | |
| int runTestBug42015(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   MgmdProcessList mgmds;
 | |
|   // Start ndb_mgmd 1 from config.ini
 | |
|   Mgmd* mgmd = new Mgmd(1);
 | |
|   mgmds.push_back(mgmd);
 | |
|   CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
| 
 | |
|   // Start ndb_mgmd 2 by fetching from first
 | |
|   Mgmd* mgmd2 = new Mgmd(2);
 | |
|   mgmds.push_back(mgmd2);
 | |
|   CHECK(mgmd2->start(wd.path(),
 | |
|                      "--ndb-connectstring",
 | |
|                      mgmd->connectstring(config).c_str(),
 | |
|                      NULL));
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   // Check binary config files created
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   return NDBT_OK;
 | |
| 
 | |
| }
 | |
| 
 | |
| /* Test for bug 53008:  --skip-config-cache */
 | |
| int runTestNoConfigCache(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
|   
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create();
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
|   
 | |
|   // Start ndb_mgmd  from config.ini
 | |
|   Mgmd* mgmd = new Mgmd(1);
 | |
|   CHECK(mgmd->start_from_config_ini(wd.path(), "--skip-config-cache", NULL));
 | |
|      
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   CHECK(mgmd->connect(config));
 | |
|   
 | |
|   // wait for confirmed config
 | |
|   CHECK(mgmd->wait_confirmed_config());
 | |
|   
 | |
|   // Check binary config files *not* created
 | |
|   bool bin_conf_file = file_exists(path(wd.path(),
 | |
|                                         "ndb_1_config.bin.1", 
 | |
|                                         NULL).c_str());
 | |
|   CHECK(bin_conf_file == false);
 | |
| 
 | |
|   mgmd->stop();
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| /* Test for BUG#13428853 */
 | |
| int runTestNoConfigCache_DontCreateConfigDir(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create();
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   g_err << "Test no configdir is created with --skip-config-cache" << endl;
 | |
|   Mgmd* mgmd = new Mgmd(1);
 | |
|   CHECK(mgmd->start_from_config_ini(wd.path(),
 | |
|                                     "--skip-config-cache",
 | |
|                                     "--config-dir=dir37",
 | |
|                                     NULL));
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   CHECK(mgmd->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   CHECK(mgmd->wait_confirmed_config());
 | |
| 
 | |
|   // Check configdir not created
 | |
|   CHECK(!file_exists(path(wd.path(), "dir37", NULL).c_str()));
 | |
| 
 | |
|   mgmd->stop();
 | |
| 
 | |
|   g_err << "Also test --initial --skip-config-cache" << endl;
 | |
|   // Also test starting ndb_mgmd --initial --skip-config-cache
 | |
|   CHECK(mgmd->start_from_config_ini(wd.path(),
 | |
|                                     "--skip-config-cache",
 | |
|                                     "--initial",
 | |
|                                     "--config-dir=dir37",
 | |
|                                     NULL));
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   CHECK(mgmd->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   CHECK(mgmd->wait_confirmed_config());
 | |
| 
 | |
|   // Check configdir not created
 | |
|   CHECK(!file_exists(path(wd.path(), "dir37", NULL).c_str()));
 | |
| 
 | |
|   mgmd->stop();
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| int runTestNoConfigCache_Fetch(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   MgmdProcessList mgmds;
 | |
|   // Start ndb_mgmd 1 from config.ini without config cache
 | |
|   Mgmd* mgmd = new Mgmd(1);
 | |
|   mgmds.push_back(mgmd);
 | |
|   CHECK(mgmd->start_from_config_ini(wd.path(),
 | |
|                                     "--skip-config-cache",
 | |
|                                     NULL));
 | |
| 
 | |
|   // Start ndb_mgmd 2 without config cache and by fetching from first
 | |
|   Mgmd* mgmd2 = new Mgmd(2);
 | |
|   mgmds.push_back(mgmd2);
 | |
|   CHECK(mgmd2->start(wd.path(),
 | |
|                      "--ndb-connectstring",
 | |
|                      mgmd->connectstring(config).c_str(),
 | |
|                      "--skip-config-cache",
 | |
|                      NULL));
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   return NDBT_OK;
 | |
| 
 | |
| }
 | |
| 
 | |
| 
 | |
| int runTestNowaitNodes(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   MgmdProcessList mgmds;
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   // Create config.ini
 | |
|   unsigned nodeids[] = { 1, 2 };
 | |
|   Properties config = ConfigFactory::create(2, 1, 1, nodeids);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
| 
 | |
|   BaseString binfile[2];
 | |
|   binfile[0].assfmt("ndb_%u_config.bin.1", nodeids[0]);
 | |
|   binfile[1].assfmt("ndb_%u_config.bin.1", nodeids[1]);
 | |
| 
 | |
|   // Start first ndb_mgmd
 | |
|   Mgmd* mgmd1 = new Mgmd(nodeids[0]);
 | |
|   {
 | |
|     mgmds.push_back(mgmd1);
 | |
|     BaseString arg;
 | |
|     arg.assfmt("--nowait-nodes=%u", nodeids[1]);
 | |
|     CHECK(mgmd1->start_from_config_ini(wd.path(),
 | |
|                                        "--initial",
 | |
|                                        arg.c_str(),
 | |
|                                        NULL));
 | |
| 
 | |
|     // Connect the ndb_mgmd
 | |
|     CHECK(mgmd1->connect(config));
 | |
| 
 | |
|     // wait for confirmed config
 | |
|     CHECK(mgmd1->wait_confirmed_config());
 | |
| 
 | |
|     // Check binary config file created
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[0].c_str(),
 | |
|                            NULL).c_str()));
 | |
|   }
 | |
| 
 | |
|   // Start second ndb_mgmd
 | |
|   {
 | |
|     Mgmd* mgmd2 = new Mgmd(nodeids[1]);
 | |
|     mgmds.push_back(mgmd2);
 | |
|     CHECK(mgmd2->start_from_config_ini(wd.path(),
 | |
|                                        "--initial",
 | |
|                                        NULL));
 | |
| 
 | |
|     // Connect the ndb_mgmd
 | |
|     CHECK(mgmd2->connect(config));
 | |
| 
 | |
|     // wait for confirmed config
 | |
|     CHECK(mgmd2->wait_confirmed_config());
 | |
| 
 | |
|     // Check binary config file created
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[1].c_str(),
 | |
|                            NULL).c_str()));
 | |
| 
 | |
|   }
 | |
| 
 | |
|   // Create new config.ini
 | |
|   g_err << "** Create config2.ini" << endl;
 | |
|   CHECK(ConfigFactory::put(config, "ndb_mgmd", nodeids[0], "ArbitrationDelay", 100));
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config2.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Reload second mgmd from config2.ini" << endl;
 | |
|   {
 | |
|     Mgmd* mgmd2 = mgmds[1];
 | |
|     CHECK(mgmd2->stop());
 | |
|     // Start from config2.ini
 | |
|     CHECK(mgmd2->start_from_config_ini(wd.path(),
 | |
|                                        "-f config2.ini",
 | |
|                                        "--reload", NULL));
 | |
|     CHECK(mgmd2->connect(config));
 | |
|     CHECK(mgmd1->wait_confirmed_config());
 | |
|     CHECK(mgmd2->wait_confirmed_config());
 | |
| 
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[0].c_str(),
 | |
|                            NULL).c_str()));
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[1].c_str(),
 | |
|                            NULL).c_str()));
 | |
| 
 | |
|     // Both ndb_mgmd(s) should have reloaded and new binary config exist
 | |
|     binfile[0].assfmt("ndb_%u_config.bin.2", nodeids[0]);
 | |
|     binfile[1].assfmt("ndb_%u_config.bin.2", nodeids[1]);
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[0].c_str(),
 | |
|                            NULL).c_str()));
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            binfile[1].c_str(),
 | |
|                            NULL).c_str()));
 | |
|   }
 | |
| 
 | |
|   // Stop the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->stop());
 | |
| 
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| 
 | |
| int runTestNowaitNodes2(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   int ret;
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   // Create config.ini
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Start mgmd1 from config.ini" << endl;
 | |
|   MgmdProcessList mgmds;
 | |
|   Mgmd* mgmd1 = new Mgmd(1);
 | |
|   mgmds.push_back(mgmd1);
 | |
|   CHECK(mgmd1->start_from_config_ini(wd.path(),
 | |
|                                      "--initial",
 | |
|                                      "--nowait-nodes=1-255",
 | |
|                                      NULL));
 | |
|   CHECK(mgmd1->connect(config));
 | |
|   CHECK(mgmd1->wait_confirmed_config());
 | |
| 
 | |
|   // check config files exist
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Create config2.ini" << endl;
 | |
|   CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config2.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Start mgmd2 from config2.ini" << endl;
 | |
|   Mgmd* mgmd2 = new Mgmd(2);
 | |
|   mgmds.push_back(mgmd2);
 | |
|   CHECK(mgmd2->start_from_config_ini(wd.path(),
 | |
|                                      "-f config2.ini",
 | |
|                                      "--initial",
 | |
|                                      "--nowait-nodes=1-255",
 | |
|                                      NULL));
 | |
|   CHECK(mgmd2->wait(ret));
 | |
|   CHECK(ret == 1);
 | |
| 
 | |
|   CHECK(mgmd1->stop());
 | |
| 
 | |
|   g_err << "** Start mgmd2 again from config2.ini" << endl;
 | |
|   CHECK(mgmd2->start_from_config_ini(wd.path(),
 | |
|                                      "-f config2.ini",
 | |
|                                      "--initial",
 | |
|                                      "--nowait-nodes=1-255",
 | |
|                                      NULL));
 | |
| 
 | |
| 
 | |
|   CHECK(mgmd2->connect(config));
 | |
|   CHECK(mgmd2->wait_confirmed_config());
 | |
| 
 | |
|   // check config files exist
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   g_err << "** Start mgmd1 from config.ini, mgmd2 should shutdown" << endl;
 | |
|   CHECK(mgmd1->start_from_config_ini(wd.path(),
 | |
|                                      "--initial",
 | |
|                                      "--nowait-nodes=1-255",
 | |
|                                      NULL));
 | |
|   CHECK(mgmd2->wait(ret));
 | |
|   CHECK(ret == 1);
 | |
| 
 | |
|   CHECK(mgmd1->stop());
 | |
| 
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| int
 | |
| runBug56844(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
|   // Start ndb_mgmd(s)
 | |
|   MgmdProcessList mgmds;
 | |
|   for (int i = 1; i <= 2; i++)
 | |
|   {
 | |
|     Mgmd* mgmd = new Mgmd(i);
 | |
|     mgmds.push_back(mgmd);
 | |
|     CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
|   }
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|   }
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
|   }
 | |
| 
 | |
|   // stop them
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->stop());
 | |
|   }
 | |
| 
 | |
|   // Check binary config files created
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_2_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   CHECK(ConfigFactory::put(config, "ndb_mgmd", 1, "ArbitrationDelay", 100));
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config2.ini",
 | |
|                                              NULL).c_str()));
 | |
|   Uint32 no = 2;
 | |
|   int loops = ctx->getNumLoops();
 | |
|   for (int l = 0; l < loops; l++, no++)
 | |
|   {
 | |
|     g_err << l << ": *** Reload from config.ini" << endl;
 | |
|     for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     {
 | |
|       // Start from config2.ini
 | |
|       CHECK(mgmds[i]->start_from_config_ini(wd.path(),
 | |
|                                             (l & 1) == 1 ?
 | |
|                                             "-f config.ini" :
 | |
|                                             "-f config2.ini",
 | |
|                                             "--reload", NULL));
 | |
|     }
 | |
|     for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     {
 | |
|       CHECK(mgmds[i]->connect(config));
 | |
|       CHECK(mgmds[i]->wait_confirmed_config());
 | |
|     }
 | |
| 
 | |
|     /**
 | |
|      * Since it will first be confirmed...
 | |
|      *   and then once connected to other ndb_nmgmd start a config
 | |
|      *   change, it can take a bit until new config exists...
 | |
|      *   allow 30s
 | |
|      */
 | |
|     Uint32 timeout = 30;
 | |
|     for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     {
 | |
|       BaseString p = path(wd.path(), "", NULL);
 | |
|       p.appfmt("ndb_%u_config.bin.%u", i+1, no);
 | |
|       g_err << "CHECK(" << p.c_str() << ")" << endl;
 | |
|       CHECK(file_exists(p.c_str(), timeout));
 | |
|     }
 | |
| 
 | |
|     for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     {
 | |
|       CHECK(mgmds[i]->stop());
 | |
|     }
 | |
|   }
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| get_status(const char* connectstring,
 | |
|            Properties& status)
 | |
| {
 | |
|   NdbMgmd ndbmgmd;
 | |
|   if (!ndbmgmd.connect(connectstring))
 | |
|     return false;
 | |
| 
 | |
|   Properties args;
 | |
|   if (!ndbmgmd.call("get status", args,
 | |
|                     "node status", status, NULL, true))
 | |
|   {
 | |
|     g_err << "fetch_mgmd_status: mgmd.call failed" << endl;
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static bool
 | |
| value_equal(Properties& status,
 | |
|             int nodeid, const char* name,
 | |
|             const char* expected_value)
 | |
| {
 | |
|   const char* value;
 | |
|   BaseString key;
 | |
|   key.assfmt("node.%d.%s", nodeid, name);
 | |
|   if (!status.get(key.c_str(), &value))
 | |
|   {
 | |
|     g_err << "value_equal: no value found for '" << name
 | |
|           << "." << nodeid << "'" << endl;
 | |
|     return false;
 | |
|   }
 | |
| 
 | |
|   if (strcmp(value, expected_value))
 | |
|   {
 | |
|     g_err << "value_equal: found unexpected value: '" << value
 | |
|           << "', expected: '" << expected_value << "'" <<endl;
 | |
|     return false;
 | |
|   }
 | |
|   g_info << "'" << value << "'=='" << expected_value << "'" << endl;
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| #include <ndb_version.h>
 | |
| 
 | |
| int runTestBug12352191(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   BaseString version;
 | |
|   version.assfmt("%u", NDB_VERSION_D);
 | |
|   BaseString mysql_version;
 | |
|   mysql_version.assfmt("%u", NDB_MYSQL_VERSION_D);
 | |
|   BaseString address("127.0.0.1");
 | |
| 
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   g_err << "** Create config.ini" << endl;
 | |
|   Properties config = ConfigFactory::create(2);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   MgmdProcessList mgmds;
 | |
|   const int nodeid1 = 1;
 | |
|   Mgmd* mgmd1 = new Mgmd(nodeid1);
 | |
|   mgmds.push_back(mgmd1);
 | |
| 
 | |
|   const int nodeid2 = 2;
 | |
|   Mgmd* mgmd2 = new Mgmd(nodeid2);
 | |
|   mgmds.push_back(mgmd2);
 | |
| 
 | |
|   // Start first mgmd
 | |
|   CHECK(mgmd1->start_from_config_ini(wd.path()));
 | |
|   CHECK(mgmd1->connect(config));
 | |
| 
 | |
|   Properties status1;
 | |
|   CHECK(get_status(mgmd1->connectstring(config).c_str(), status1));
 | |
|   //status1.print();
 | |
|   // Check status for own mgm node, always CONNECTED
 | |
|   CHECK(value_equal(status1, nodeid1, "type", "MGM"));
 | |
|   CHECK(value_equal(status1, nodeid1, "status", "CONNECTED"));
 | |
|   CHECK(value_equal(status1, nodeid1, "version", version.c_str()));
 | |
|   CHECK(value_equal(status1, nodeid1, "mysql_version", mysql_version.c_str()));
 | |
|   CHECK(value_equal(status1, nodeid1, "address", address.c_str()));
 | |
|   CHECK(value_equal(status1, nodeid1, "startphase", "0"));
 | |
|   CHECK(value_equal(status1, nodeid1, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status1, nodeid1, "node_group", "0"));
 | |
|   CHECK(value_equal(status1, nodeid1, "connect_count", "0"));
 | |
| 
 | |
|   // Check status for other mgm node
 | |
|   // not started yet -> NO_CONTACT, no address, no versions
 | |
|   CHECK(value_equal(status1, nodeid2, "type", "MGM"));
 | |
|   CHECK(value_equal(status1, nodeid2, "status", "NO_CONTACT"));
 | |
|   CHECK(value_equal(status1, nodeid2, "version", "0"));
 | |
|   CHECK(value_equal(status1, nodeid2, "mysql_version", "0"));
 | |
|   CHECK(value_equal(status1, nodeid2, "address", ""));
 | |
|   CHECK(value_equal(status1, nodeid2, "startphase", "0"));
 | |
|   CHECK(value_equal(status1, nodeid2, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status1, nodeid2, "node_group", "0"));
 | |
|   CHECK(value_equal(status1, nodeid2, "connect_count", "0"));
 | |
| 
 | |
|   // Start second mgmd
 | |
|   CHECK(mgmd2->start_from_config_ini(wd.path()));
 | |
|   CHECK(mgmd2->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   Properties status2;
 | |
|   CHECK(get_status(mgmd2->connectstring(config).c_str(), status2));
 | |
|   //status2.print();
 | |
|   // Check status for own mgm node, always CONNECTED
 | |
|   CHECK(value_equal(status2, nodeid2, "type", "MGM"));
 | |
|   CHECK(value_equal(status2, nodeid2, "status", "CONNECTED"));
 | |
|   CHECK(value_equal(status2, nodeid2, "version", version.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid2, "mysql_version", mysql_version.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid2, "address", address.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid2, "startphase", "0"));
 | |
|   CHECK(value_equal(status2, nodeid2, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status2, nodeid2, "node_group", "0"));
 | |
|   CHECK(value_equal(status2, nodeid2, "connect_count", "0"));
 | |
| 
 | |
|   // Check status for other mgm node
 | |
|   // both started now -> CONNECTED, address and versions filled in
 | |
|   CHECK(value_equal(status2, nodeid1, "type", "MGM"));
 | |
|   CHECK(value_equal(status2, nodeid1, "status", "CONNECTED"));
 | |
|   CHECK(value_equal(status2, nodeid1, "version", version.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid1, "mysql_version", mysql_version.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid1, "address", address.c_str()));
 | |
|   CHECK(value_equal(status2, nodeid1, "startphase", "0"));
 | |
|   CHECK(value_equal(status2, nodeid1, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status2, nodeid1, "node_group", "0"));
 | |
|   CHECK(value_equal(status2, nodeid1, "connect_count", "0"));
 | |
| 
 | |
|   Properties status3;
 | |
|   CHECK(get_status(mgmd1->connectstring(config).c_str(), status3));
 | |
|   //status3.print();
 | |
|   // Check status for own mgm node, always CONNECTED
 | |
|   CHECK(value_equal(status3, nodeid1, "type", "MGM"));
 | |
|   CHECK(value_equal(status3, nodeid1, "status", "CONNECTED"));
 | |
|   CHECK(value_equal(status3, nodeid1, "version", version.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid1, "mysql_version", mysql_version.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid1, "address", address.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid1, "startphase", "0"));
 | |
|   CHECK(value_equal(status3, nodeid1, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status3, nodeid1, "node_group", "0"));
 | |
|   CHECK(value_equal(status3, nodeid1, "connect_count", "0"));
 | |
| 
 | |
|   // Check status for other mgm node
 | |
|   // both started now -> CONNECTED, address and versions filled in
 | |
|   CHECK(value_equal(status3, nodeid2, "type", "MGM"));
 | |
|   CHECK(value_equal(status3, nodeid2, "status", "CONNECTED"));
 | |
|   CHECK(value_equal(status3, nodeid2, "version", version.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid2, "mysql_version", mysql_version.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid2, "address", address.c_str()));
 | |
|   CHECK(value_equal(status3, nodeid2, "startphase", "0"));
 | |
|   CHECK(value_equal(status3, nodeid2, "dynamic_id", "0"));
 | |
|   CHECK(value_equal(status3, nodeid2, "node_group", "0"));
 | |
|   CHECK(value_equal(status3, nodeid2, "connect_count", "0"));
 | |
| 
 | |
|   return NDBT_OK;
 | |
| 
 | |
| }
 | |
| 
 | |
| int
 | |
| runBug61607(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   // Create config.ini
 | |
|   const int cnt_mgmd = 1;
 | |
|   Properties config = ConfigFactory::create(cnt_mgmd);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
|   // Start ndb_mgmd(s)
 | |
|   MgmdProcessList mgmds;
 | |
|   for (int i = 1; i <= cnt_mgmd; i++)
 | |
|   {
 | |
|     Mgmd* mgmd = new Mgmd(i);
 | |
|     mgmds.push_back(mgmd);
 | |
|     CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
|   }
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   // Check binary config files created
 | |
|   CHECK(file_exists(path(wd.path(),
 | |
|                          "ndb_1_config.bin.1",
 | |
|                          NULL).c_str()));
 | |
| 
 | |
|   int no_of_nodes = 0;
 | |
|   int * node_ids = 0;
 | |
|   int initialstart = 0;
 | |
|   int nostart = 0;
 | |
|   int abort = 0;
 | |
|   int force = 0;
 | |
|   int need_disconnect = 0;
 | |
|   int res = ndb_mgm_restart4(mgmds[0]->handle(), no_of_nodes, node_ids,
 | |
|                              initialstart, nostart, abort, force,
 | |
|                              &need_disconnect);
 | |
| 
 | |
| 
 | |
|   return res == 0 ? NDBT_OK : NDBT_FAILED;
 | |
| }
 | |
| 
 | |
| int
 | |
| runStopDuringStart(NDBT_Context* ctx, NDBT_Step* step)
 | |
| {
 | |
|   MgmdProcessList mgmds;
 | |
|   NDBT_Workingdir wd("test_mgmd"); // temporary working directory
 | |
| 
 | |
|   // Create config.ini
 | |
|   unsigned nodeids[] = { 251, 252 };
 | |
|   Properties config = ConfigFactory::create(2, 1, 1, nodeids);
 | |
|   CHECK(ConfigFactory::write_config_ini(config,
 | |
|                                         path(wd.path(),
 | |
|                                              "config.ini",
 | |
|                                              NULL).c_str()));
 | |
| 
 | |
|   for (unsigned i = 0; i < NDB_ARRAY_SIZE(nodeids); i++)
 | |
|   {
 | |
|     Mgmd* mgmd = new Mgmd(nodeids[i]);
 | |
|     mgmds.push_back(mgmd);
 | |
|     CHECK(mgmd->start_from_config_ini(wd.path()));
 | |
|   }
 | |
| 
 | |
|   // Connect the ndb_mgmd(s)
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
| 
 | |
|   // wait for confirmed config
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   // Check binary config files created
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     BaseString file;
 | |
|     file.assfmt("ndb_%u_config.bin.1", nodeids[i]);
 | |
|     CHECK(file_exists(path(wd.path(),
 | |
|                            file.c_str(),
 | |
|                            NULL).c_str()));
 | |
|   }
 | |
| 
 | |
|   // stop them
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|   {
 | |
|     mgmds[i]->stop();
 | |
|     int exitCode;
 | |
|     mgmds[i]->wait(exitCode);
 | |
|   }
 | |
| 
 | |
|   // restart one with error-insert 100
 | |
|   // => it shall exit during start...
 | |
|   mgmds[0]->start(wd.path(), "--error-insert=100", NULL);
 | |
| 
 | |
|   // restart rest normally
 | |
|   for (unsigned i = 1; i < mgmds.size(); i++)
 | |
|   {
 | |
|     mgmds[i]->start(wd.path());
 | |
|   }
 | |
| 
 | |
|   // wait first one to terminate
 | |
|   int exitCode;
 | |
|   mgmds[0]->wait(exitCode);
 | |
|   NdbSleep_MilliSleep(3000);
 | |
| 
 | |
|   // check other OK
 | |
|   for (unsigned i = 1; i < mgmds.size(); i++)
 | |
|   {
 | |
|     CHECK(mgmds[i]->connect(config));
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
|   }
 | |
| 
 | |
|   // now restart without error insert
 | |
|   mgmds[0]->start(wd.path());
 | |
| 
 | |
|   // connect
 | |
|   CHECK(mgmds[0]->connect(config));
 | |
| 
 | |
|   // all should be ok
 | |
|   for (unsigned i = 0; i < mgmds.size(); i++)
 | |
|     CHECK(mgmds[i]->wait_confirmed_config());
 | |
| 
 | |
|   return NDBT_OK;
 | |
| }
 | |
| 
 | |
| NDBT_TESTSUITE(testMgmd);
 | |
| DRIVER(DummyDriver); /* turn off use of NdbApi */
 | |
| 
 | |
| TESTCASE("Basic2Mgm",
 | |
|          "Basic test with two mgmd")
 | |
| {
 | |
|   INITIALIZER(runTestBasic2Mgm);
 | |
| }
 | |
| 
 | |
| TESTCASE("Bug42015",
 | |
|          "Test that mgmd can fetch configuration from another mgmd")
 | |
| {
 | |
|   INITIALIZER(runTestBug42015);
 | |
| }
 | |
| TESTCASE("NowaitNodes",
 | |
|          "Test that one mgmd(of 2) can start alone with usage "
 | |
|          "of --nowait-nodes, then start the second mgmd and it should join")
 | |
| {
 | |
|   INITIALIZER(runTestNowaitNodes);
 | |
| }
 | |
| TESTCASE("NowaitNodes2",
 | |
|          "Test that one mgmd(of 2) can start alone with usage "
 | |
|          "of --nowait-nodes, then start the second mgmd from different "
 | |
|          "configuration and the one with lowest nodeid should shutdown")
 | |
| {
 | |
|   INITIALIZER(runTestNowaitNodes2);
 | |
| }
 | |
| 
 | |
| TESTCASE("NoCfgCache",
 | |
|          "Test that when an mgmd is started with --skip-config-cache, "
 | |
|          "no ndb_xx_config.xx.bin file is created, but you can "
 | |
|          "connect to the mgm node and retrieve the config.")
 | |
| {
 | |
|   INITIALIZER(runTestNoConfigCache);
 | |
| }
 | |
| TESTCASE("NoCfgCacheOrConfigDir",
 | |
|          "Test that when an mgmd is started with --skip-config-cache, "
 | |
|          "no ndb_xx_config.xx.bin file is created, but you can "
 | |
|          "connect to the mgm node and retrieve the config.")
 | |
| {
 | |
|   INITIALIZER(runTestNoConfigCache_DontCreateConfigDir);
 | |
| }
 | |
| TESTCASE("NoCfgCacheFetch",
 | |
|          "Test that when an mgmd is started with --skip-config-cache, "
 | |
|          "it can still fetch config from another ndb_mgmd.")
 | |
| {
 | |
|   INITIALIZER(runTestNoConfigCache_Fetch);
 | |
| }
 | |
| TESTCASE("Bug45495",
 | |
|          "Test that mgmd can be restarted in any order")
 | |
| {
 | |
|   INITIALIZER(runTestBug45495);
 | |
| }
 | |
| 
 | |
| TESTCASE("Bug56844",
 | |
|          "Test that mgmd can be reloaded in parallel")
 | |
| {
 | |
|   INITIALIZER(runBug56844);
 | |
| }
 | |
| TESTCASE("Bug12352191",
 | |
|          "Test mgmd status for other mgmd")
 | |
| {
 | |
|   INITIALIZER(runTestBug12352191);
 | |
| }
 | |
| TESTCASE("Bug61607",
 | |
|          "ndb_mgmd incorrectly reports failure when there are no ndbds to stop")
 | |
| {
 | |
|   INITIALIZER(runBug61607);
 | |
| }
 | |
| TESTCASE("StopDuringStart", "")
 | |
| {
 | |
|   INITIALIZER(runStopDuringStart);
 | |
| }
 | |
| 
 | |
| NDBT_TESTSUITE_END(testMgmd)
 | |
| 
 | |
| int main(int argc, const char** argv)
 | |
| {
 | |
|   ndb_init();
 | |
|   NDBT_TESTSUITE_INSTANCE(testMgmd);
 | |
|   testMgmd.setCreateTable(false);
 | |
|   testMgmd.setRunAllTables(true);
 | |
|   testMgmd.setConnectCluster(false);
 | |
| 
 | |
| #ifdef NDB_USE_GET_ENV
 | |
|   char buf1[255], buf2[255];
 | |
|   if (NdbEnv_GetEnv("NDB_MGMD_VALGRIND_EXE", buf1, sizeof(buf1))) {
 | |
|     exe_valgrind = buf1;
 | |
|   }
 | |
| 
 | |
|   if (NdbEnv_GetEnv("NDB_MGMD_VALGRIND_ARG", buf2, sizeof(buf2))) {
 | |
|     arg_valgrind = buf2;
 | |
|   }
 | |
| #endif
 | |
| 
 | |
|   return testMgmd.execute(argc, argv);
 | |
| }
 | |
| 
 | |
| template class Vector<Mgmd*>;
 | |
| 
 |