summaryrefslogtreecommitdiff
path: root/storage/ndb/test/run-test/main.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'storage/ndb/test/run-test/main.cpp')
-rw-r--r--storage/ndb/test/run-test/main.cpp1003
1 files changed, 1003 insertions, 0 deletions
diff --git a/storage/ndb/test/run-test/main.cpp b/storage/ndb/test/run-test/main.cpp
new file mode 100644
index 00000000000..0b0b7472a19
--- /dev/null
+++ b/storage/ndb/test/run-test/main.cpp
@@ -0,0 +1,1003 @@
+/* Copyright (C) 2003 MySQL AB
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
+
+
+#include <ndb_global.h>
+#include <getarg.h>
+#include <BaseString.hpp>
+#include <Parser.hpp>
+#include <NdbOut.hpp>
+#include <Properties.hpp>
+#include <NdbAutoPtr.hpp>
+
+#include "run-test.hpp"
+#include <SysLogHandler.hpp>
+#include <FileLogHandler.hpp>
+
+#include <mgmapi.h>
+#include "CpcClient.hpp"
+
+/** Global variables */
+static const char progname[] = "ndb_atrt";
+static const char * g_gather_progname = "atrt-gather-result.sh";
+static const char * g_analyze_progname = "atrt-analyze-result.sh";
+static const char * g_clear_progname = "atrt-clear-result.sh";
+static const char * g_setup_progname = "atrt-setup.sh";
+
+static const char * g_setup_path = 0;
+static const char * g_process_config_filename = "d.txt";
+static const char * g_log_filename = 0;
+static const char * g_test_case_filename = 0;
+static const char * g_report_filename = 0;
+
+static const char * g_default_user = 0;
+static const char * g_default_base_dir = 0;
+static int g_default_base_port = 0;
+static int g_mysqld_use_base = 1;
+
+static int g_report = 0;
+static int g_verbosity = 0;
+static FILE * g_report_file = 0;
+static FILE * g_test_case_file = stdin;
+
+Logger g_logger;
+atrt_config g_config;
+
+static int g_mode_bench = 0;
+static int g_mode_regression = 0;
+static int g_mode_interactive = 0;
+static int g_mode = 0;
+
+static
+struct getargs args[] = {
+ { "process-config", 0, arg_string, &g_process_config_filename, 0, 0 },
+ { "setup-path", 0, arg_string, &g_setup_path, 0, 0 },
+ { 0, 'v', arg_counter, &g_verbosity, 0, 0 },
+ { "log-file", 0, arg_string, &g_log_filename, 0, 0 },
+ { "testcase-file", 'f', arg_string, &g_test_case_filename, 0, 0 },
+ { 0, 'R', arg_flag, &g_report, 0, 0 },
+ { "report-file", 0, arg_string, &g_report_filename, 0, 0 },
+ { "interactive", 'i', arg_flag, &g_mode_interactive, 0, 0 },
+ { "regression", 'r', arg_flag, &g_mode_regression, 0, 0 },
+ { "bench", 'b', arg_flag, &g_mode_bench, 0, 0 },
+};
+
+const int arg_count = 10;
+
+int
+main(int argc, const char ** argv){
+ ndb_init();
+
+ bool restart = true;
+ int lineno = 1;
+ int test_no = 1;
+
+ const int p_ndb = atrt_process::NDB_MGM | atrt_process::NDB_DB;
+ const int p_servers = atrt_process::MYSQL_SERVER | atrt_process::NDB_REP;
+ const int p_clients = atrt_process::MYSQL_CLIENT | atrt_process::NDB_API;
+
+ g_logger.setCategory(progname);
+ g_logger.enable(Logger::LL_ALL);
+ g_logger.createConsoleHandler();
+
+ if(!parse_args(argc, argv))
+ goto end;
+
+ g_logger.info("Starting...");
+ if(!setup_config(g_config))
+ goto end;
+
+ g_logger.info("Connecting to hosts");
+ if(!connect_hosts(g_config))
+ goto end;
+
+ if(!setup_hosts(g_config))
+ goto end;
+
+ /**
+ * Main loop
+ */
+ while(!feof(g_test_case_file)){
+ /**
+ * Do we need to restart ndb
+ */
+ if(restart){
+ g_logger.info("(Re)starting ndb processes");
+ if(!stop_processes(g_config, ~0))
+ goto end;
+
+ if(!start_processes(g_config, atrt_process::NDB_MGM))
+ goto end;
+
+ if(!connect_ndb_mgm(g_config)){
+ goto end;
+ }
+
+ if(!start_processes(g_config, atrt_process::NDB_DB))
+ goto end;
+
+ if(!wait_ndb(g_config, NDB_MGM_NODE_STATUS_NOT_STARTED))
+ goto end;
+
+ for(Uint32 i = 0; i<3; i++)
+ if(wait_ndb(g_config, NDB_MGM_NODE_STATUS_STARTED))
+ goto started;
+
+ goto end;
+
+ started:
+ if(!start_processes(g_config, p_servers))
+ goto end;
+
+ g_logger.info("Ndb start completed");
+ }
+
+ const int start_line = lineno;
+ atrt_testcase test_case;
+ if(!read_test_case(g_test_case_file, test_case, lineno))
+ goto end;
+
+ g_logger.info("#%d - %s %s",
+ test_no,
+ test_case.m_command.c_str(), test_case.m_args.c_str());
+
+ // Assign processes to programs
+ if(!setup_test_case(g_config, test_case))
+ goto end;
+
+ if(!start_processes(g_config, p_clients))
+ goto end;
+
+ int result = 0;
+
+ const time_t start = time(0);
+ time_t now = start;
+ do {
+ if(!update_status(g_config, atrt_process::ALL))
+ goto end;
+
+ int count = 0;
+
+ if((count = is_running(g_config, p_ndb)) != 2){
+ result = ERR_NDB_FAILED;
+ break;
+ }
+
+ if((count = is_running(g_config, p_servers)) != 2){
+ result = ERR_SERVERS_FAILED;
+ break;
+ }
+
+ if((count = is_running(g_config, p_clients)) == 0){
+ break;
+ }
+
+ now = time(0);
+ if(now > (start + test_case.m_max_time)){
+ result = ERR_MAX_TIME_ELAPSED;
+ break;
+ }
+ sleep(1);
+ } while(true);
+
+ const time_t elapsed = time(0) - start;
+
+ if(!stop_processes(g_config, p_clients))
+ goto end;
+
+ if(!gather_result(g_config, &result))
+ goto end;
+
+ g_logger.info("#%d %s(%d)",
+ test_no,
+ (result == 0 ? "OK" : "FAILED"), result);
+
+ if(g_report_file != 0){
+ fprintf(g_report_file, "%s %s ; %d ; %d ; %ld\n",
+ test_case.m_command.c_str(),
+ test_case.m_args.c_str(),
+ test_no, result, elapsed);
+ fflush(g_report_file);
+ }
+
+ if(test_case.m_report || g_mode_bench || (g_mode_regression && result)){
+ BaseString tmp;
+ tmp.assfmt("result.%d", test_no);
+ if(rename("result", tmp.c_str()) != 0){
+ g_logger.critical("Failed to rename %s as %s",
+ "result", tmp.c_str());
+ goto end;
+ }
+ }
+
+ if(g_mode_interactive && result){
+ g_logger.info
+ ("Encountered failed test in interactive mode - terminating");
+ break;
+ }
+
+ if(result != 0){
+ restart = true;
+ } else {
+ restart = false;
+ }
+ test_no++;
+ }
+
+ end:
+ if(g_report_file != 0){
+ fclose(g_report_file);
+ g_report_file = 0;
+ }
+
+ if(g_test_case_file != 0 && g_test_case_file != stdin){
+ fclose(g_test_case_file);
+ g_test_case_file = 0;
+ }
+
+ stop_processes(g_config, atrt_process::ALL);
+ return 0;
+}
+
+bool
+parse_args(int argc, const char** argv){
+ int optind = 0;
+ if(getarg(args, arg_count, argc, argv, &optind)) {
+ arg_printusage(args, arg_count, progname, "");
+ return false;
+ }
+
+ if(g_log_filename != 0){
+ g_logger.removeConsoleHandler();
+ g_logger.addHandler(new FileLogHandler(g_log_filename));
+ }
+
+ {
+ int tmp = Logger::LL_WARNING - g_verbosity;
+ tmp = (tmp < Logger::LL_DEBUG ? Logger::LL_DEBUG : tmp);
+ g_logger.disable(Logger::LL_ALL);
+ g_logger.enable(Logger::LL_ON);
+ g_logger.enable((Logger::LoggerLevel)tmp, Logger::LL_ALERT);
+ }
+
+
+
+ if(!g_process_config_filename){
+ g_logger.critical("Process config not specified!");
+ return false;
+ }
+
+ if(!g_setup_path){
+ char buf[1024];
+ if(getcwd(buf, sizeof(buf))){
+ g_setup_path = strdup(buf);
+ g_logger.info("Setup path not specified, using %s", buf);
+ } else {
+ g_logger.critical("Setup path not specified!\n");
+ return false;
+ }
+ }
+
+ if(g_report & !g_report_filename){
+ g_report_filename = "report.txt";
+ }
+
+ if(g_report_filename){
+ g_report_file = fopen(g_report_filename, "w");
+ if(g_report_file == 0){
+ g_logger.critical("Unable to create report file: %s", g_report_filename);
+ return false;
+ }
+ }
+
+ if(g_test_case_filename){
+ g_test_case_file = fopen(g_test_case_filename, "r");
+ if(g_test_case_file == 0){
+ g_logger.critical("Unable to open file: %s", g_test_case_filename);
+ return false;
+ }
+ }
+
+ int sum = g_mode_interactive + g_mode_regression + g_mode_bench;
+ if(sum == 0){
+ g_mode_interactive = 1;
+ }
+
+ if(sum > 1){
+ g_logger.critical
+ ("Only one of bench/regression/interactive can be specified");
+ return false;
+ }
+
+ g_default_user = strdup(getenv("LOGNAME"));
+
+ return true;
+}
+
+
+static
+atrt_host *
+find(const BaseString& host, Vector<atrt_host> & hosts){
+ for(size_t i = 0; i<hosts.size(); i++){
+ if(hosts[i].m_hostname == host){
+ return &hosts[i];
+ }
+ }
+ return 0;
+}
+
+bool
+setup_config(atrt_config& config){
+
+ FILE * f = fopen(g_process_config_filename, "r");
+ if(!f){
+ g_logger.critical("Failed to open process config file: %s",
+ g_process_config_filename);
+ return false;
+ }
+ bool result = true;
+
+ int lineno = 0;
+ char buf[2048];
+ BaseString connect_string;
+ int mysql_port_offset = 0;
+ while(fgets(buf, 2048, f)){
+ lineno++;
+
+ BaseString tmp(buf);
+ tmp.trim(" \t\n\r");
+
+ if(tmp.length() == 0 || tmp == "" || tmp.c_str()[0] == '#')
+ continue;
+
+ Vector<BaseString> split1;
+ if(tmp.split(split1, ":", 2) != 2){
+ g_logger.warning("Invalid line %d in %s - ignoring",
+ lineno, g_process_config_filename);
+ continue;
+ }
+
+ if(split1[0].trim() == "basedir"){
+ g_default_base_dir = strdup(split1[1].trim().c_str());
+ continue;
+ }
+
+ if(split1[0].trim() == "baseport"){
+ g_default_base_port = atoi(split1[1].trim().c_str());
+ continue;
+ }
+
+ if(split1[0].trim() == "user"){
+ g_default_user = strdup(split1[1].trim().c_str());
+ continue;
+ }
+
+ if(split1[0].trim() == "mysqld-use-base" && split1[1].trim() == "no"){
+ g_mysqld_use_base = 0;
+ continue;
+ }
+
+ Vector<BaseString> hosts;
+ if(split1[1].trim().split(hosts) <= 0){
+ g_logger.warning("Invalid line %d in %s - ignoring",
+ lineno, g_process_config_filename);
+ }
+
+ // 1 - Check hosts
+ for(size_t i = 0; i<hosts.size(); i++){
+ Vector<BaseString> tmp;
+ hosts[i].split(tmp, ":");
+ BaseString hostname = tmp[0].trim();
+ BaseString base_dir;
+ if(tmp.size() >= 2)
+ base_dir = tmp[1];
+ else if(g_default_base_dir == 0){
+ g_logger.critical("Basedir not specified...");
+ return false;
+ }
+
+ atrt_host * host_ptr;
+ if((host_ptr = find(hostname, config.m_hosts)) == 0){
+ atrt_host host;
+ host.m_index = config.m_hosts.size();
+ host.m_cpcd = new SimpleCpcClient(hostname.c_str(), 1234);
+ host.m_base_dir = (base_dir.empty() ? g_default_base_dir : base_dir);
+ host.m_user = g_default_user;
+ host.m_hostname = hostname.c_str();
+ config.m_hosts.push_back(host);
+ } else {
+ if(!base_dir.empty() && (base_dir == host_ptr->m_base_dir)){
+ g_logger.critical("Inconsistent base dir definition for host %s"
+ ", \"%s\" != \"%s\"", hostname.c_str(),
+ base_dir.c_str(), host_ptr->m_base_dir.c_str());
+ return false;
+ }
+ }
+ }
+
+ for(size_t i = 0; i<hosts.size(); i++){
+ BaseString & tmp = hosts[i];
+ atrt_host * host = find(tmp, config.m_hosts);
+ BaseString & dir = host->m_base_dir;
+
+ const int index = config.m_processes.size() + 1;
+
+ atrt_process proc;
+ proc.m_index = index;
+ proc.m_host = host;
+ proc.m_proc.m_id = -1;
+ proc.m_proc.m_type = "temporary";
+ proc.m_proc.m_owner = "atrt";
+ proc.m_proc.m_group = "group";
+ proc.m_proc.m_cwd.assign(dir).append("/run/");
+ proc.m_proc.m_stdout = "log.out";
+ proc.m_proc.m_stderr = "2>&1";
+ proc.m_proc.m_runas = proc.m_host->m_user;
+ proc.m_proc.m_ulimit = "c:unlimited";
+ proc.m_proc.m_env.assfmt("MYSQL_BASE_DIR=%s", dir.c_str());
+ proc.m_proc.m_shutdown_options = "";
+ proc.m_hostname = proc.m_host->m_hostname;
+ proc.m_ndb_mgm_port = g_default_base_port;
+ if(split1[0] == "mgm"){
+ proc.m_type = atrt_process::NDB_MGM;
+ proc.m_proc.m_name.assfmt("%d-%s", index, "ndb_mgmd");
+ proc.m_proc.m_path.assign(dir).append("/libexec/ndb_mgmd");
+ proc.m_proc.m_args = "--nodaemon -f config.ini";
+ proc.m_proc.m_cwd.appfmt("%d.ndb_mgmd", index);
+ connect_string.appfmt("host=%s:%d;",
+ proc.m_hostname.c_str(), proc.m_ndb_mgm_port);
+ } else if(split1[0] == "ndb"){
+ proc.m_type = atrt_process::NDB_DB;
+ proc.m_proc.m_name.assfmt("%d-%s", index, "ndbd");
+ proc.m_proc.m_path.assign(dir).append("/libexec/ndbd");
+ proc.m_proc.m_args = "--initial --nodaemon -n";
+ proc.m_proc.m_cwd.appfmt("%d.ndbd", index);
+ } else if(split1[0] == "mysqld"){
+ proc.m_type = atrt_process::MYSQL_SERVER;
+ proc.m_proc.m_name.assfmt("%d-%s", index, "mysqld");
+ proc.m_proc.m_path.assign(dir).append("/libexec/mysqld");
+ proc.m_proc.m_args = "--core-file --ndbcluster";
+ proc.m_proc.m_cwd.appfmt("%d.mysqld", index);
+ proc.m_proc.m_shutdown_options = "SIGKILL"; // not nice
+ } else if(split1[0] == "api"){
+ proc.m_type = atrt_process::NDB_API;
+ proc.m_proc.m_name.assfmt("%d-%s", index, "ndb_api");
+ proc.m_proc.m_path = "";
+ proc.m_proc.m_args = "";
+ proc.m_proc.m_cwd.appfmt("%d.ndb_api", index);
+ } else if(split1[0] == "mysql"){
+ proc.m_type = atrt_process::MYSQL_CLIENT;
+ proc.m_proc.m_name.assfmt("%d-%s", index, "mysql");
+ proc.m_proc.m_path = "";
+ proc.m_proc.m_args = "";
+ proc.m_proc.m_cwd.appfmt("%d.mysql", index);
+ } else {
+ g_logger.critical("%s:%d: Unhandled process type: %s",
+ g_process_config_filename, lineno,
+ split1[0].c_str());
+ result = false;
+ goto end;
+ }
+ config.m_processes.push_back(proc);
+ }
+ }
+
+ // Setup connect string
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ config.m_processes[i].m_proc.m_env.appfmt(" NDB_CONNECTSTRING=%s",
+ connect_string.c_str());
+ }
+
+ end:
+ fclose(f);
+ return result;
+}
+
+bool
+connect_hosts(atrt_config& config){
+ for(size_t i = 0; i<config.m_hosts.size(); i++){
+ if(config.m_hosts[i].m_cpcd->connect() != 0){
+ g_logger.error("Unable to connect to cpc %s:%d",
+ config.m_hosts[i].m_cpcd->getHost(),
+ config.m_hosts[i].m_cpcd->getPort());
+ return false;
+ }
+ g_logger.debug("Connected to %s:%d",
+ config.m_hosts[i].m_cpcd->getHost(),
+ config.m_hosts[i].m_cpcd->getPort());
+ }
+
+ return true;
+}
+
+bool
+connect_ndb_mgm(atrt_process & proc){
+ NdbMgmHandle handle = ndb_mgm_create_handle();
+ if(handle == 0){
+ g_logger.critical("Unable to create mgm handle");
+ return false;
+ }
+ BaseString tmp = proc.m_hostname;
+ tmp.appfmt(":%d", proc.m_ndb_mgm_port);
+
+ if (ndb_mgm_set_connectstring(handle,tmp.c_str()))
+ {
+ g_logger.critical("Unable to create parse connectstring");
+ return false;
+ }
+
+ if(ndb_mgm_connect(handle, 30, 1, 0) != -1)
+ {
+ proc.m_ndb_mgm_handle = handle;
+ return true;
+ }
+
+ g_logger.critical("Unable to connect to ndb mgm %s", tmp.c_str());
+ return false;
+}
+
+bool
+connect_ndb_mgm(atrt_config& config){
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if((proc.m_type & atrt_process::NDB_MGM) != 0){
+ if(!connect_ndb_mgm(proc)){
+ return false;
+ }
+ }
+ }
+
+ return true;
+}
+
+static int remap(int i){
+ if(i == NDB_MGM_NODE_STATUS_NO_CONTACT) return NDB_MGM_NODE_STATUS_UNKNOWN;
+ if(i == NDB_MGM_NODE_STATUS_UNKNOWN) return NDB_MGM_NODE_STATUS_NO_CONTACT;
+ return i;
+}
+
+bool
+wait_ndb(atrt_config& config, int goal){
+
+ goal = remap(goal);
+
+
+ /**
+ * Get mgm handle for cluster
+ */
+ NdbMgmHandle handle = 0;
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if((proc.m_type & atrt_process::NDB_MGM) != 0){
+ handle = proc.m_ndb_mgm_handle;
+ break;
+ }
+ }
+ if(handle == 0){
+ g_logger.critical("Unable to find mgm handle");
+ return false;
+ }
+
+ if(goal == NDB_MGM_NODE_STATUS_STARTED){
+ /**
+ * 1) wait NOT_STARTED
+ * 2) send start
+ * 3) wait STARTED
+ */
+ if(!wait_ndb(config, NDB_MGM_NODE_STATUS_NOT_STARTED))
+ return false;
+
+ ndb_mgm_start(handle, 0, 0);
+ }
+
+ struct ndb_mgm_cluster_state * state;
+
+ time_t now = time(0);
+ time_t end = now + 360;
+ int min = remap(NDB_MGM_NODE_STATUS_NO_CONTACT);
+ int min2 = goal;
+
+ while(now < end){
+ /**
+ * 1) retreive current state
+ */
+ state = 0;
+ do {
+ state = ndb_mgm_get_status(handle);
+ if(state == 0){
+ const int err = ndb_mgm_get_latest_error(handle);
+ g_logger.error("Unable to poll db state: %d %s %s",
+ ndb_mgm_get_latest_error(handle),
+ ndb_mgm_get_latest_error_msg(handle),
+ ndb_mgm_get_latest_error_desc(handle));
+ if(err == NDB_MGM_SERVER_NOT_CONNECTED && connect_ndb_mgm(config)){
+ g_logger.error("Reconnected...");
+ continue;
+ }
+ return false;
+ }
+ } while(state == 0);
+ NdbAutoPtr<void> tmp(state);
+
+ min2 = goal;
+ for(int i = 0; i<state->no_of_nodes; i++){
+ if(state->node_states[i].node_type == NDB_MGM_NODE_TYPE_NDB){
+ const int s = remap(state->node_states[i].node_status);
+ min2 = (min2 < s ? min2 : s );
+
+ if(s < remap(NDB_MGM_NODE_STATUS_NO_CONTACT) ||
+ s > NDB_MGM_NODE_STATUS_STARTED){
+ g_logger.critical("Strange DB status during start: %d %d", i, min2);
+ return false;
+ }
+
+ if(min2 < min){
+ g_logger.critical("wait ndb failed node: %d %d %d %d",
+ state->node_states[i].node_id, min, min2, goal);
+ }
+ }
+ }
+
+ if(min2 < min){
+ g_logger.critical("wait ndb failed %d %d %d", min, min2, goal);
+ return false;
+ }
+
+ if(min2 == goal){
+ return true;
+ break;
+ }
+
+ min = min2;
+ now = time(0);
+ }
+
+ g_logger.critical("wait ndb timed out %d %d %d", min, min2, goal);
+
+ return false;
+}
+
+bool
+start_process(atrt_process & proc){
+ if(proc.m_proc.m_id != -1){
+ g_logger.critical("starting already started process: %d", proc.m_index);
+ return false;
+ }
+
+ BaseString path = proc.m_proc.m_cwd.substr(proc.m_host->m_base_dir.length()+BaseString("/run").length());
+
+ BaseString tmp = g_setup_progname;
+ tmp.appfmt(" %s %s/%s/ %s",
+ proc.m_host->m_hostname.c_str(),
+ g_setup_path,
+ path.c_str(),
+ proc.m_proc.m_cwd.c_str());
+
+ const int r1 = system(tmp.c_str());
+ if(r1 != 0){
+ g_logger.critical("Failed to setup process");
+ return false;
+ }
+
+ {
+ Properties reply;
+ if(proc.m_host->m_cpcd->define_process(proc.m_proc, reply) != 0){
+ BaseString msg;
+ reply.get("errormessage", msg);
+ g_logger.error("Unable to define process: %s", msg.c_str());
+ return false;
+ }
+ }
+ {
+ Properties reply;
+ if(proc.m_host->m_cpcd->start_process(proc.m_proc.m_id, reply) != 0){
+ BaseString msg;
+ reply.get("errormessage", msg);
+ g_logger.error("Unable to start process: %s", msg.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+bool
+start_processes(atrt_config& config, int types){
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if((types & proc.m_type) != 0 && proc.m_proc.m_path != ""){
+ if(!start_process(proc)){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+stop_process(atrt_process & proc){
+ if(proc.m_proc.m_id == -1){
+ return true;
+ }
+
+ {
+ Properties reply;
+ if(proc.m_host->m_cpcd->stop_process(proc.m_proc.m_id, reply) != 0){
+ Uint32 status;
+ reply.get("status", &status);
+ if(status != 4){
+ BaseString msg;
+ reply.get("errormessage", msg);
+ g_logger.error("Unable to stop process: %s(%d)", msg.c_str(), status);
+ return false;
+ }
+ }
+ }
+ {
+ Properties reply;
+ if(proc.m_host->m_cpcd->undefine_process(proc.m_proc.m_id, reply) != 0){
+ BaseString msg;
+ reply.get("errormessage", msg);
+ g_logger.error("Unable to undefine process: %s", msg.c_str());
+ return false;
+ }
+ proc.m_proc.m_id = -1;
+ }
+ return true;
+}
+
+bool
+stop_processes(atrt_config& config, int types){
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if((types & proc.m_type) != 0){
+ if(!stop_process(proc)){
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool
+update_status(atrt_config& config, int){
+
+ Vector<Vector<SimpleCpcClient::Process> > m_procs;
+
+ Vector<SimpleCpcClient::Process> dummy;
+ m_procs.fill(config.m_hosts.size(), dummy);
+ for(size_t i = 0; i<config.m_hosts.size(); i++){
+ Properties p;
+ config.m_hosts[i].m_cpcd->list_processes(m_procs[i], p);
+ }
+
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if(proc.m_proc.m_id != -1){
+ Vector<SimpleCpcClient::Process> &h_procs= m_procs[proc.m_host->m_index];
+ bool found = false;
+ for(size_t j = 0; j<h_procs.size(); j++){
+ if(proc.m_proc.m_id == h_procs[j].m_id){
+ found = true;
+ proc.m_proc.m_status = h_procs[j].m_status;
+ break;
+ }
+ }
+ if(!found){
+ g_logger.error("update_status: not found");
+ g_logger.error("id: %d host: %s cmd: %s",
+ proc.m_proc.m_id,
+ proc.m_hostname.c_str(),
+ proc.m_proc.m_path.c_str());
+ for(size_t j = 0; j<h_procs.size(); j++){
+ g_logger.error("found: %d %s", h_procs[j].m_id,
+ h_procs[j].m_path.c_str());
+ }
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+int
+is_running(atrt_config& config, int types){
+ int found = 0, running = 0;
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if((types & proc.m_type) != 0){
+ found++;
+ if(proc.m_proc.m_status == "running")
+ running++;
+ }
+ }
+
+ if(found == running)
+ return 2;
+ if(running == 0)
+ return 0;
+ return 1;
+}
+
+
+int
+insert(const char * pair, Properties & p){
+ BaseString tmp(pair);
+
+ tmp.trim(" \t\n\r");
+
+ Vector<BaseString> split;
+ tmp.split(split, ":=", 2);
+
+ if(split.size() != 2)
+ return -1;
+
+ p.put(split[0].trim().c_str(), split[1].trim().c_str());
+
+ return 0;
+}
+
+bool
+read_test_case(FILE * file, atrt_testcase& tc, int& line){
+
+ Properties p;
+ int elements = 0;
+ char buf[1024];
+ while(!feof(file)){
+ if(!fgets(buf, 1024, file))
+ break;
+
+ line++;
+ BaseString tmp = buf;
+
+ if(tmp.length() > 0 && tmp.c_str()[0] == '#')
+ continue;
+
+ if(insert(tmp.c_str(), p) != 0)
+ break;
+
+ elements++;
+ }
+
+ if(elements == 0){
+ if(file == stdin){
+ BaseString tmp(buf);
+ tmp.trim(" \t\n\r");
+ Vector<BaseString> split;
+ tmp.split(split, " ", 2);
+ tc.m_command = split[0];
+ if(split.size() == 2)
+ tc.m_args = split[1];
+ else
+ tc.m_args = "";
+ tc.m_max_time = 60000;
+ return true;
+ }
+ return false;
+ }
+
+ if(!p.get("cmd", tc.m_command)){
+ g_logger.critical("Invalid test file: cmd is missing near line: %d", line);
+ return false;
+ }
+
+ if(!p.get("args", tc.m_args))
+ tc.m_args = "";
+
+ const char * mt = 0;
+ if(!p.get("max-time", &mt))
+ tc.m_max_time = 60000;
+ else
+ tc.m_max_time = atoi(mt);
+
+ if(p.get("type", &mt) && strcmp(mt, "bench") == 0)
+ tc.m_report= true;
+ else
+ tc.m_report= false;
+
+ if(p.get("run-all", &mt) && strcmp(mt, "yes") == 0)
+ tc.m_run_all= true;
+ else
+ tc.m_run_all= false;
+
+ return true;
+}
+
+bool
+setup_test_case(atrt_config& config, const atrt_testcase& tc){
+ const int r1 = system(g_clear_progname);
+ if(r1 != 0){
+ g_logger.critical("Failed to clear result");
+ return false;
+ }
+
+ size_t i = 0;
+ for(; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if(proc.m_type == atrt_process::NDB_API || proc.m_type == atrt_process::MYSQL_CLIENT){
+ proc.m_proc.m_path.assfmt("%s/bin/%s", proc.m_host->m_base_dir.c_str(),
+ tc.m_command.c_str());
+ proc.m_proc.m_args.assign(tc.m_args);
+ if(!tc.m_run_all)
+ break;
+ }
+ }
+ for(i++; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if(proc.m_type == atrt_process::NDB_API || proc.m_type == atrt_process::MYSQL_CLIENT){
+ proc.m_proc.m_path.assign("");
+ proc.m_proc.m_args.assign("");
+ }
+ }
+ return true;
+}
+
+bool
+gather_result(atrt_config& config, int * result){
+ BaseString tmp = g_gather_progname;
+ for(size_t i = 0; i<config.m_processes.size(); i++){
+ atrt_process & proc = config.m_processes[i];
+ if(proc.m_proc.m_path != ""){
+ tmp.appfmt(" %s:%s",
+ proc.m_hostname.c_str(),
+ proc.m_proc.m_cwd.c_str());
+ }
+ }
+
+ const int r1 = system(tmp.c_str());
+ if(r1 != 0){
+ g_logger.critical("Failed to gather result");
+ return false;
+ }
+
+ const int r2 = system(g_analyze_progname);
+
+ if(r2 == -1 || r2 == (127 << 8)){
+ g_logger.critical("Failed to analyze results");
+ return false;
+ }
+
+ * result = r2 ;
+ return true;
+}
+
+bool
+setup_hosts(atrt_config& config){
+ const int r1 = system(g_clear_progname);
+ if(r1 != 0){
+ g_logger.critical("Failed to clear result");
+ return false;
+ }
+
+ for(size_t i = 0; i<config.m_hosts.size(); i++){
+ BaseString tmp = g_setup_progname;
+ tmp.appfmt(" %s %s/ %s/run",
+ config.m_hosts[i].m_hostname.c_str(),
+ g_setup_path,
+ config.m_hosts[i].m_base_dir.c_str());
+
+ const int r1 = system(tmp.c_str());
+ if(r1 != 0){
+ g_logger.critical("Failed to setup %s",
+ config.m_hosts[i].m_hostname.c_str());
+ return false;
+ }
+ }
+ return true;
+}
+
+template class Vector<Vector<SimpleCpcClient::Process> >;
+template class Vector<atrt_host>;
+template class Vector<atrt_process>;