MySQL 5.6.14 Source Code Document
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
main.cpp
1 
2 /*
3  Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; version 2 of the License.
8 
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  GNU General Public License for more details.
13 
14  You should have received a copy of the GNU General Public License
15  along with this program; if not, write to the Free Software
16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17 */
18 
19 
20 #ifdef _WIN32
21 #define DEFAULT_PREFIX "c:/atrt"
22 #endif
23 
24 #include "atrt.hpp"
25 #include <my_sys.h>
26 #include <my_getopt.h>
27 
28 #include <NdbOut.hpp>
29 #include <NdbAutoPtr.hpp>
30 
31 #include <SysLogHandler.hpp>
32 #include <FileLogHandler.hpp>
33 
34 #include <NdbSleep.h>
35 
36 #define PATH_SEPARATOR DIR_SEPARATOR
37 
39 static const char progname[] = "ndb_atrt";
40 static const char * g_gather_progname = "atrt-gather-result.sh";
41 static const char * g_analyze_progname = "atrt-analyze-result.sh";
42 static const char * g_setup_progname = "atrt-setup.sh";
43 
44 static const char * g_log_filename = 0;
45 static const char * g_test_case_filename = 0;
46 static const char * g_report_filename = 0;
47 
48 static int g_do_setup = 0;
49 static int g_do_deploy = 0;
50 static int g_do_sshx = 0;
51 static int g_do_start = 0;
52 static int g_do_quit = 0;
53 
54 static int g_help = 0;
55 static int g_verbosity = 1;
56 static FILE * g_report_file = 0;
57 static FILE * g_test_case_file = stdin;
58 static int g_mode = 0;
59 
60 Logger g_logger;
61 atrt_config g_config;
62 const char * g_user = 0;
63 int g_baseport = 10000;
64 int g_fqpn = 0;
65 int g_fix_nodeid= 0;
66 int g_default_ports = 0;
67 int g_mt = 0;
68 int g_mt_rr = 0;
69 
70 const char * g_cwd = 0;
71 const char * g_basedir = 0;
72 const char * g_my_cnf = 0;
73 const char * g_prefix = 0;
74 const char * g_prefix1 = 0;
75 const char * g_clusters = 0;
76 BaseString g_replicate;
77 const char *save_file = 0;
78 const char *save_group_suffix = 0;
79 const char * g_dummy;
80 char * g_env_path = 0;
81 const char* g_mysqld_host = 0;
82 
83 static struct my_option g_options[] =
84 {
85  { "help", '?', "Display this help and exit.",
86  (uchar **) &g_help, (uchar **) &g_help,
87  0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0 },
88  { "version", 'V', "Output version information and exit.", 0, 0, 0,
89  GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0 },
90  { "clusters", 256, "Cluster",
91  (uchar **) &g_clusters, (uchar **) &g_clusters,
92  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
93  { "mysqld", 256, "atrt mysqld",
94  (uchar **) &g_mysqld_host, (uchar **) &g_mysqld_host,
95  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
96  { "replicate", 1024, "replicate",
97  (uchar **) &g_dummy, (uchar **) &g_dummy,
98  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
99  { "log-file", 256, "log-file",
100  (uchar **) &g_log_filename, (uchar **) &g_log_filename,
101  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
102  { "testcase-file", 'f', "testcase-file",
103  (uchar **) &g_test_case_filename, (uchar **) &g_test_case_filename,
104  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
105  { "report-file", 'r', "report-file",
106  (uchar **) &g_report_filename, (uchar **) &g_report_filename,
107  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
108  { "basedir", 256, "Base path",
109  (uchar **) &g_basedir, (uchar **) &g_basedir,
110  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
111  { "baseport", 256, "Base port",
112  (uchar **) &g_baseport, (uchar **) &g_baseport,
113  0, GET_INT, REQUIRED_ARG, g_baseport, 0, 0, 0, 0, 0},
114  { "prefix", 256, "mysql install dir",
115  (uchar **) &g_prefix, (uchar **) &g_prefix,
116  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
117  { "prefix1", 256, "mysql install dir 1",
118  (uchar **) &g_prefix1, (uchar **) &g_prefix1,
119  0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
120  { "verbose", 'v', "Verbosity",
121  (uchar **) &g_verbosity, (uchar **) &g_verbosity,
122  0, GET_INT, REQUIRED_ARG, g_verbosity, 0, 0, 0, 0, 0},
123  { "configure", 256, "configure",
124  (uchar **) &g_do_setup, (uchar **) &g_do_setup,
125  0, GET_INT, REQUIRED_ARG, g_do_setup, 0, 0, 0, 0, 0 },
126  { "deploy", 256, "deploy",
127  (uchar **) &g_do_deploy, (uchar **) &g_do_deploy,
128  0, GET_INT, REQUIRED_ARG, g_do_deploy, 0, 0, 0, 0, 0 },
129  { "sshx", 256, "sshx",
130  (uchar **) &g_do_sshx, (uchar **) &g_do_sshx,
131  0, GET_INT, REQUIRED_ARG, g_do_sshx, 0, 0, 0, 0, 0 },
132  { "start", 256, "start",
133  (uchar **) &g_do_start, (uchar **) &g_do_start,
134  0, GET_INT, REQUIRED_ARG, g_do_start, 0, 0, 0, 0, 0 },
135  { "fqpn", 256, "Fully qualified path-names ",
136  (uchar **) &g_fqpn, (uchar **) &g_fqpn,
137  0, GET_INT, REQUIRED_ARG, g_fqpn, 0, 0, 0, 0, 0 },
138  { "fix-nodeid", 256, "Fix nodeid for each started process ",
139  (uchar **) &g_fix_nodeid, (uchar **) &g_fix_nodeid,
140  0, GET_INT, REQUIRED_ARG, g_fqpn, 0, 0, 0, 0, 0 },
141  { "default-ports", 256, "Use default ports when possible",
142  (uchar **) &g_default_ports, (uchar **) &g_default_ports,
143  0, GET_INT, REQUIRED_ARG, g_default_ports, 0, 0, 0, 0, 0 },
144  { "mode", 256, "Mode 0=interactive 1=regression 2=bench",
145  (uchar **) &g_mode, (uchar **) &g_mode,
146  0, GET_INT, REQUIRED_ARG, g_mode, 0, 0, 0, 0, 0 },
147  { "quit", 256, "Quit before starting tests",
148  (uchar **) &g_do_quit, (uchar **) &g_do_quit,
149  0, GET_BOOL, NO_ARG, g_do_quit, 0, 0, 0, 0, 0 },
150  { "mt", 256, "Use ndbmtd (0 = never, 1 = round-robin, 2 = only)",
151  (uchar **) &g_mt, (uchar **) &g_mt,
152  0, GET_INT, REQUIRED_ARG, g_mt, 0, 0, 0, 0, 0 },
153  { 0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
154 };
155 
156 const int p_ndb = atrt_process::AP_NDB_MGMD | atrt_process::AP_NDBD;
157 const int p_servers = atrt_process::AP_MYSQLD;
158 const int p_clients = atrt_process::AP_CLIENT | atrt_process::AP_NDB_API;
159 
160 int
161 main(int argc, char ** argv)
162 {
163  ndb_init();
164 
165  bool restart = true;
166  int lineno = 1;
167  int test_no = 1;
168  int return_code = 1;
169 
170  g_logger.setCategory(progname);
171  g_logger.enable(Logger::LL_ALL);
172  g_logger.createConsoleHandler();
173 
174  if(!parse_args(argc, argv))
175  {
176  g_logger.critical("Failed to parse arguments");
177  goto end;
178  }
179 
180  g_logger.info("Starting...");
181  g_config.m_generated = false;
182  g_config.m_replication = g_replicate;
183  if (!setup_config(g_config, g_mysqld_host))
184  {
185  g_logger.critical("Failed to setup configuration");
186  goto end;
187  }
188 
189  if (!configure(g_config, g_do_setup))
190  {
191  g_logger.critical("Failed to configure");
192  goto end;
193  }
194 
195  g_logger.info("Setting up directories...");
196  if (!setup_directories(g_config, g_do_setup))
197  {
198  g_logger.critical("Failed to set up directories");
199  goto end;
200  }
201 
202  if (g_do_setup)
203  {
204  g_logger.info("Setting up files...");
205  if (!setup_files(g_config, g_do_setup, g_do_sshx))
206  {
207  g_logger.critical("Failed to set up files");
208  goto end;
209  }
210  }
211 
212  if (g_do_deploy)
213  {
214  if (!deploy(g_do_deploy, g_config))
215  {
216  g_logger.critical("Failed to deploy");
217  goto end;
218  }
219  }
220 
221  if (g_do_quit)
222  {
223  return_code = 0;
224  goto end;
225  }
226 
227  if(!setup_hosts(g_config))
228  {
229  g_logger.critical("Failed to setup hosts");
230  goto end;
231  }
232 
233  if (g_do_sshx)
234  {
235  g_logger.info("Starting xterm-ssh");
236  if (!sshx(g_config, g_do_sshx))
237  {
238  g_logger.critical("Failed to start xterm-ssh");
239  goto end;
240  }
241 
242  g_logger.info("Done...sleeping");
243  while(true)
244  {
245  if (!do_command(g_config))
246  {
247  g_logger.critical("Failed to do ssh command");
248  goto end;
249  }
250 
251  NdbSleep_SecSleep(1);
252  }
253  return_code = 0;
254  goto end;
255  }
256 
257  g_logger.info("Connecting to hosts...");
258  if(!connect_hosts(g_config))
259  {
260  g_logger.critical("Failed to connect to CPCD on hosts");
261  goto end;
262  }
263 
264 #ifndef _WIN32
265  if (g_do_start && !g_test_case_filename)
266  {
267  g_logger.info("Starting server processes: %x", g_do_start);
268  if (!start(g_config, g_do_start))
269  {
270  g_logger.critical("Failed to start server processes");
271  goto end;
272  }
273 
274  if (!setup_db(g_config))
275  {
276  g_logger.critical("Failed to setup database");
277  goto end;
278  }
279 
280  g_logger.info("Done...sleeping");
281  while(true)
282  {
283  if (!do_command(g_config))
284  {
285  g_logger.info("Exiting");
286  goto end;
287  }
288 
289  NdbSleep_SecSleep(1);
290  }
291  return_code = 0;
292  goto end;
293  }
294 #endif
295 
296  return_code = 0;
297 
301  g_logger.debug("Entering main loop");
302  while(!feof(g_test_case_file))
303  {
307  if(restart)
308  {
309  restart = false;
310  g_logger.info("(Re)starting server processes...");
311 
312  if(!stop_processes(g_config, ~0))
313  {
314  g_logger.critical("Failed to stop all processes");
315  goto end;
316  }
317 
318  if (!setup_directories(g_config, 2))
319  {
320  g_logger.critical("Failed to setup directories");
321  goto end;
322  }
323 
324  if (!setup_files(g_config, 2, 1))
325  {
326  g_logger.critical("Failed to setup files");
327  goto end;
328  }
329 
330  if(!setup_hosts(g_config))
331  {
332  g_logger.critical("Failed to setup hosts");
333  goto end;
334  }
335 
336  g_logger.debug("Setup complete, starting servers");
337  if (!start(g_config, p_ndb | p_servers))
338  {
339  g_logger.critical("Failed to start server processes");
340  g_logger.info("Gathering logs and saving them as test %u", test_no);
341 
342  int tmp;
343  if(!gather_result(g_config, &tmp))
344  {
345  g_logger.critical("Failed to gather results");
346  goto end;
347  }
348 
349  if(g_report_file != 0)
350  {
351  fprintf(g_report_file, "%s ; %d ; %d ; %d\n",
352  "start servers", test_no, ERR_FAILED_TO_START, 0);
353  fflush(g_report_file);
354  }
355 
356  BaseString resdir;
357  resdir.assfmt("result.%d", test_no);
358  remove_dir(resdir.c_str(), true);
359 
360  if(rename("result", resdir.c_str()) != 0)
361  {
362  g_logger.critical("Failed to rename %s as %s",
363  "result", resdir.c_str());
364  goto end;
365  }
366  goto end;
367  }
368 
369  if (!setup_db(g_config))
370  {
371  g_logger.critical("Failed to setup database");
372  goto end;
373  }
374 
375  g_logger.info("All servers start completed");
376  }
377 
378  // const int start_line = lineno;
380  if(!read_test_case(g_test_case_file, test_case, lineno))
381  goto end;
382 
383  g_logger.info("#%d - %s %s",
384  test_no,
385  test_case.m_command.c_str(), test_case.m_args.c_str());
386 
387  // Assign processes to programs
388  if(!setup_test_case(g_config, test_case))
389  {
390  g_logger.critical("Failed to setup test case");
391  goto end;
392  }
393 
394  if(!start_processes(g_config, p_clients))
395  {
396  g_logger.critical("Failed to start client processes");
397  goto end;
398  }
399 
400  int result = 0;
401 
402  const time_t start = time(0);
403  time_t now = start;
404  do
405  {
406  if(!update_status(g_config, atrt_process::AP_ALL))
407  {
408  g_logger.critical("Failed to get updated status for all processes");
409  goto end;
410  }
411 
412  if(is_running(g_config, p_ndb) != 2)
413  {
414  result = ERR_NDB_FAILED;
415  break;
416  }
417 
418  if(is_running(g_config, p_servers) != 2)
419  {
420  result = ERR_SERVERS_FAILED;
421  break;
422  }
423 
424  if(is_running(g_config, p_clients) == 0)
425  {
426  break;
427  }
428 
429  if (!do_command(g_config))
430  {
431  result = ERR_COMMAND_FAILED;
432  break;
433  }
434 
435  now = time(0);
436  if(now > (start + test_case.m_max_time))
437  {
438  g_logger.debug("Timed out");
439  result = ERR_MAX_TIME_ELAPSED;
440  g_logger.info("Timeout '%s' after %ld seconds", test_case.m_name.c_str(), test_case.m_max_time);
441  break;
442  }
443  NdbSleep_SecSleep(1);
444  } while(true);
445 
446  const time_t elapsed = time(0) - start;
447 
448  if(!stop_processes(g_config, p_clients))
449  {
450  g_logger.critical("Failed to stop client processes");
451  goto end;
452  }
453 
454  int tmp, *rp = result ? &tmp : &result;
455  if(!gather_result(g_config, rp))
456  {
457  g_logger.critical("Failed to gather result after test run");
458  goto end;
459  }
460 
461  g_logger.info("#%d %s(%d)",
462  test_no,
463  (result == 0 ? "OK" : "FAILED"), result);
464 
465  if(g_report_file != 0)
466  {
467  fprintf(g_report_file, "%s ; %d ; %d ; %ld\n",
468  test_case.m_name.c_str(), test_no, result, elapsed);
469  fflush(g_report_file);
470  }
471 
472  if(g_mode == 0 && result)
473  {
474  g_logger.info
475  ("Encountered failed test in interactive mode - terminating");
476  break;
477  }
478 
479  BaseString resdir;
480  resdir.assfmt("result.%d", test_no);
481  remove_dir(resdir.c_str(), true);
482 
483  if(test_case.m_report || g_mode == 2 || (g_mode && result))
484  {
485  if(rename("result", resdir.c_str()) != 0)
486  {
487  g_logger.critical("Failed to rename %s as %s",
488  "result", resdir.c_str());
489  goto end;
490  }
491  }
492  else
493  {
494  remove_dir("result", true);
495  }
496 
497  if (reset_config(g_config))
498  {
499  restart = true;
500  }
501 
502  if(result != 0)
503  {
504  restart = true;
505  }
506  test_no++;
507  }
508 
509  end:
510  if(g_report_file != 0){
511  fclose(g_report_file);
512  g_report_file = 0;
513  }
514 
515  if(g_test_case_file != 0 && g_test_case_file != stdin){
516  fclose(g_test_case_file);
517  g_test_case_file = 0;
518  }
519 
520  g_logger.info("Stopping all processes, result: %d", return_code);
521  stop_processes(g_config, atrt_process::AP_ALL);
522  return return_code;
523 }
524 
525 extern "C"
526 my_bool
527 get_one_option(int arg, const struct my_option * opt, char * value)
528 {
529  if (arg == 1024)
530  {
531  if (g_replicate.length())
532  g_replicate.append(";");
533  g_replicate.append(value);
534  return 0;
535  }
536  return 0;
537 }
538 
539 bool
540 parse_args(int argc, char** argv)
541 {
542  char buf[2048];
543  if (getcwd(buf, sizeof(buf)) == 0)
544  {
545  g_logger.error("Unable to get current working directory");
546  return false;
547  }
548  g_cwd = strdup(buf);
549 
550  struct stat sbuf;
551  BaseString mycnf;
552  mycnf.append(g_cwd);
553  mycnf.append(DIR_SEPARATOR);
554 
555  if (argc > 1 && lstat(argv[argc-1], &sbuf) == 0)
556  {
557  mycnf.append(argv[argc-1]);
558  }
559  else
560  {
561  mycnf.append("my.cnf");
562  if (lstat(mycnf.c_str(), &sbuf) != 0)
563  {
564  g_logger.error("Could not find out which config file to use! "
565  "Pass it as last argument to atrt: 'atrt <config file>' "
566  "(default: '%s')", mycnf.c_str());
567  return false;
568  }
569  }
570 
571  to_fwd_slashes((char*)g_cwd);
572 
573  g_logger.info("Bootstrapping using %s", mycnf.c_str());
574 
575  const char *groups[] = { "atrt", 0 };
576  int ret = load_defaults(mycnf.c_str(), groups, &argc, &argv);
577 
578  if (ret)
579  {
580  g_logger.error("Failed to load defaults, returned (%d)",ret);
581  return false;
582  }
583 
584  save_file = my_defaults_file;
585  save_group_suffix = my_defaults_group_suffix;
586 
587  if (my_defaults_extra_file)
588  {
589  g_logger.error("--defaults-extra-file(%s) is not supported...",
590  my_defaults_extra_file);
591  return false;
592  }
593 
594  ret = handle_options(&argc, &argv, g_options, get_one_option);
595  if (ret)
596  {
597  g_logger.error("handle_options failed, ret: %d, argc: %d, *argv: '%s'",
598  ret, argc, *argv);
599  return false;
600  }
601 
602  if (argc >= 2)
603  {
604  const char * arg = argv[argc-2];
605  while(* arg)
606  {
607  switch(* arg){
608  case 'c':
609  g_do_setup = (g_do_setup == 0) ? 1 : g_do_setup;
610  break;
611  case 'C':
612  g_do_setup = 2;
613  break;
614  case 'd':
615  g_do_deploy = 3;
616  break;
617  case 'D':
618  g_do_deploy = 2; // only binaries
619  break;
620  case 'x':
621  g_do_sshx = atrt_process::AP_CLIENT | atrt_process::AP_NDB_API;
622  break;
623  case 'X':
624  g_do_sshx = atrt_process::AP_ALL;
625  break;
626  case 's':
627  g_do_start = p_ndb;
628  break;
629  case 'S':
630  g_do_start = p_ndb | p_servers;
631  break;
632  case 'f':
633  g_fqpn = 1;
634  break;
635  case 'z':
636  g_fix_nodeid = 1;
637  break;
638  case 'q':
639  g_do_quit = 1;
640  break;
641  default:
642  g_logger.error("Unknown switch '%c'", *arg);
643  return false;
644  }
645  arg++;
646  }
647  }
648 
649  if(g_log_filename != 0)
650  {
651  g_logger.removeConsoleHandler();
652  g_logger.addHandler(new FileLogHandler(g_log_filename));
653  }
654 
655  {
656  int tmp = Logger::LL_WARNING - g_verbosity;
657  tmp = (tmp < Logger::LL_DEBUG ? Logger::LL_DEBUG : tmp);
658  g_logger.disable(Logger::LL_ALL);
659  g_logger.enable(Logger::LL_ON);
660  g_logger.enable((Logger::LoggerLevel)tmp, Logger::LL_ALERT);
661  }
662 
663  if(!g_basedir)
664  {
665  g_basedir = g_cwd;
666  g_logger.info("basedir not specified, using %s", g_basedir);
667  }
668  else
669  {
670  g_logger.info("basedir, %s", g_basedir);
671  }
672 
673  if (!g_prefix)
674  {
675  g_prefix = DEFAULT_PREFIX;
676  }
677 
681  {
682  BaseString tmp;
683  const char* env = getenv("PATH");
684  if (env && strlen(env))
685  {
686  tmp.assfmt("PATH=%s:%s/mysql-test/ndb",
687  env, g_prefix);
688  }
689  else
690  {
691  tmp.assfmt("PATH=%s/mysql-test/ndb", g_prefix);
692  }
693  to_native(tmp);
694  g_env_path = strdup(tmp.c_str());
695  putenv(g_env_path);
696  }
697 
698  if (g_help)
699  {
700  my_print_help(g_options);
701  my_print_variables(g_options);
702  return 0;
703  }
704 
705  if(g_test_case_filename)
706  {
707  g_test_case_file = fopen(g_test_case_filename, "r");
708  if(g_test_case_file == 0)
709  {
710  g_logger.critical("Unable to open file: %s", g_test_case_filename);
711  return false;
712  }
713  if (g_do_setup == 0)
714  g_do_setup = 2;
715 
716  if (g_do_start == 0)
717  g_do_start = p_ndb | p_servers;
718 
719  if (g_mode == 0)
720  g_mode = 1;
721 
722  if (g_do_sshx)
723  {
724  g_logger.critical("ssx specified...not possible with testfile");
725  return false;
726  }
727  }
728  else {
729  g_logger.info("No test case file given with -f <test file>, "
730  "running in interactive mode from stdin");
731  }
732 
733  if (g_do_setup == 0)
734  {
735  BaseString tmp;
736  tmp.append(g_basedir);
737  tmp.append(PATH_SEPARATOR);
738  tmp.append("my.cnf");
739  if (lstat(tmp.c_str(), &sbuf) != 0)
740  {
741  g_logger.error("Could not find a my.cnf file in the basedir '%s', "
742  "you probably need to configure it with "
743  "'atrt --configure=1 <config_file>'", g_basedir);
744  return false;
745  }
746 
747  if (!S_ISREG(sbuf.st_mode))
748  {
749  g_logger.error("%s is not a regular file", tmp.c_str());
750  return false;
751  }
752 
753  g_my_cnf = strdup(tmp.c_str());
754  g_logger.info("Using %s", tmp.c_str());
755  }
756  else
757  {
758  g_my_cnf = strdup(mycnf.c_str());
759  }
760 
761  g_logger.info("Using --prefix=\"%s\"", g_prefix);
762 
763  if (g_prefix1)
764  {
765  g_logger.info("Using --prefix1=\"%s\"", g_prefix1);
766  }
767 
768 
769 
770  if(g_report_filename)
771  {
772  g_report_file = fopen(g_report_filename, "w");
773  if(g_report_file == 0)
774  {
775  g_logger.critical("Unable to create report file: %s", g_report_filename);
776  return false;
777  }
778  }
779 
780  if (g_clusters == 0)
781  {
782  g_logger.critical("No clusters specified");
783  return false;
784  }
785 
786  /* Read username from environment, default to sakila */
787  g_user = strdup(getenv("LOGNAME"));
788  if (g_user == 0)
789  {
790  g_user = "sakila";
791  g_logger.info("No default user specified, will use 'sakila'.");
792  g_logger.info("Please set LOGNAME environment variable for other username");
793  }
794  return true;
795 }
796 
797 bool
798 connect_hosts(atrt_config& config){
799  for(size_t i = 0; i<config.m_hosts.size(); i++){
800  if(config.m_hosts[i]->m_cpcd->connect() != 0){
801  g_logger.error("Unable to connect to cpc %s:%d",
802  config.m_hosts[i]->m_cpcd->getHost(),
803  config.m_hosts[i]->m_cpcd->getPort());
804  return false;
805  }
806  g_logger.debug("Connected to %s:%d",
807  config.m_hosts[i]->m_cpcd->getHost(),
808  config.m_hosts[i]->m_cpcd->getPort());
809  }
810 
811  return true;
812 }
813 
814 bool
815 connect_ndb_mgm(atrt_process & proc){
817  if(handle == 0){
818  g_logger.critical("Unable to create mgm handle");
819  return false;
820  }
821  BaseString tmp = proc.m_host->m_hostname;
822  const char * val;
823  proc.m_options.m_loaded.get("--PortNumber=", &val);
824  tmp.appfmt(":%s", val);
825 
826  if (ndb_mgm_set_connectstring(handle,tmp.c_str()))
827  {
828  g_logger.critical("Unable to create parse connectstring");
829  return false;
830  }
831 
832  if(ndb_mgm_connect(handle, 30, 1, 0) != -1)
833  {
834  proc.m_ndb_mgm_handle = handle;
835  return true;
836  }
837 
838  g_logger.critical("Unable to connect to ndb mgm %s", tmp.c_str());
839  return false;
840 }
841 
842 bool
843 connect_ndb_mgm(atrt_config& config){
844  for(size_t i = 0; i<config.m_processes.size(); i++){
845  atrt_process & proc = *config.m_processes[i];
846  if((proc.m_type & atrt_process::AP_NDB_MGMD) != 0){
847  if(!connect_ndb_mgm(proc)){
848  return false;
849  }
850  }
851  }
852 
853  return true;
854 }
855 
856 static int remap(int i){
859  return i;
860 }
861 
862 bool
863 wait_ndb(atrt_config& config, int goal){
864 
865  goal = remap(goal);
866 
867  size_t cnt = 0;
868  for (size_t i = 0; i<config.m_clusters.size(); i++)
869  {
870  atrt_cluster* cluster = config.m_clusters[i];
871 
872  if (strcmp(cluster->m_name.c_str(), ".atrt") == 0)
873  {
877  cnt++;
878  continue;
879  }
880 
884  NdbMgmHandle handle = 0;
885  for(size_t j = 0; j<cluster->m_processes.size(); j++){
886  atrt_process & proc = *cluster->m_processes[j];
887  if((proc.m_type & atrt_process::AP_NDB_MGMD) != 0){
888  handle = proc.m_ndb_mgm_handle;
889  break;
890  }
891  }
892 
893  if(handle == 0){
894  return true;
895  }
896 
897  if(goal == NDB_MGM_NODE_STATUS_STARTED){
903  if(!wait_ndb(config, NDB_MGM_NODE_STATUS_NOT_STARTED))
904  return false;
905 
906  ndb_mgm_start(handle, 0, 0);
907  }
908 
909  struct ndb_mgm_cluster_state * state;
910 
911  time_t now = time(0);
912  time_t end = now + 360;
913  int min = remap(NDB_MGM_NODE_STATUS_NO_CONTACT);
914  int min2 = goal;
915 
916  while(now < end){
920  state = 0;
921  do {
922  state = ndb_mgm_get_status(handle);
923  if(state == 0){
924  const int err = ndb_mgm_get_latest_error(handle);
925  g_logger.error("Unable to poll db state: %d %s %s",
926  ndb_mgm_get_latest_error(handle),
929  if(err == NDB_MGM_SERVER_NOT_CONNECTED && connect_ndb_mgm(config)){
930  g_logger.error("Reconnected...");
931  continue;
932  }
933  return false;
934  }
935  } while(state == 0);
936  NdbAutoPtr<void> tmp(state);
937 
938  min2 = goal;
939  for(int j = 0; j<state->no_of_nodes; j++){
941  const int s = remap(state->node_states[j].node_status);
942  min2 = (min2 < s ? min2 : s );
943 
944  if(s < remap(NDB_MGM_NODE_STATUS_NO_CONTACT) ||
946  g_logger.critical("Strange DB status during start: %d %d",
947  j, min2);
948  return false;
949  }
950 
951  if(min2 < min){
952  g_logger.critical("wait ndb failed node: %d %d %d %d",
953  state->node_states[j].node_id, min, min2, goal);
954  }
955  }
956  }
957 
958  if(min2 < min){
959  g_logger.critical("wait ndb failed %d %d %d", min, min2, goal);
960  return false;
961  }
962 
963  if(min2 == goal){
964  cnt++;
965  goto next;
966  }
967 
968  min = min2;
969  now = time(0);
970  }
971 
972  g_logger.critical("wait ndb timed out %d %d %d", min, min2, goal);
973  break;
974 
975 next:
976  ;
977  }
978 
979  return cnt == config.m_clusters.size();
980 }
981 
982 bool
983 start_process(atrt_process & proc){
984  if(proc.m_proc.m_id != -1){
985  g_logger.critical("starting already started process: %u",
986  (unsigned)proc.m_index);
987  return false;
988  }
989 
990  BaseString tmp = g_setup_progname;
991  tmp.appfmt(" %s %s/ %s",
992  proc.m_host->m_hostname.c_str(),
993  proc.m_proc.m_cwd.c_str(),
994  proc.m_proc.m_cwd.c_str());
995 
996  g_logger.debug("system(%s)", tmp.c_str());
997  const int r1 = sh(tmp.c_str());
998  if(r1 != 0)
999  {
1000  g_logger.critical("Failed to setup process");
1001  return false;
1002  }
1003 
1004  {
1005  Properties reply;
1006  if(proc.m_host->m_cpcd->define_process(proc.m_proc, reply) != 0){
1007  BaseString msg;
1008  reply.get("errormessage", msg);
1009  g_logger.error("Unable to define process: %s", msg.c_str());
1010  return false;
1011  }
1012  }
1013  {
1014  Properties reply;
1015  if(proc.m_host->m_cpcd->start_process(proc.m_proc.m_id, reply) != 0){
1016  BaseString msg;
1017  reply.get("errormessage", msg);
1018  g_logger.error("Unable to start process: %s", msg.c_str());
1019  return false;
1020  }
1021  }
1022  return true;
1023 }
1024 
1025 bool
1026 start_processes(atrt_config& config, int types){
1027  for(size_t i = 0; i<config.m_processes.size(); i++){
1028  atrt_process & proc = *config.m_processes[i];
1029  if(IF_WIN(!(proc.m_type & atrt_process::AP_MYSQLD), 1)
1030  && (types & proc.m_type) != 0 && proc.m_proc.m_path != ""){
1031  if(!start_process(proc)){
1032  return false;
1033  }
1034  }
1035  }
1036  return true;
1037 }
1038 
1039 bool
1040 stop_process(atrt_process & proc){
1041  if(proc.m_proc.m_id == -1){
1042  return true;
1043  }
1044 
1045  {
1046  Properties reply;
1047  if(proc.m_host->m_cpcd->stop_process(proc.m_proc.m_id, reply) != 0){
1048  Uint32 status;
1049  reply.get("status", &status);
1050  if(status != 4){
1051  BaseString msg;
1052  reply.get("errormessage", msg);
1053  g_logger.error("Unable to stop process: %s(%d)", msg.c_str(), status);
1054  return false;
1055  }
1056  }
1057  }
1058  {
1059  Properties reply;
1060  if(proc.m_host->m_cpcd->undefine_process(proc.m_proc.m_id, reply) != 0){
1061  BaseString msg;
1062  reply.get("errormessage", msg);
1063  g_logger.error("Unable to undefine process: %s", msg.c_str());
1064  return false;
1065  }
1066  proc.m_proc.m_id = -1;
1067  }
1068  return true;
1069 }
1070 
1071 bool
1072 stop_processes(atrt_config& config, int types){
1073  for(size_t i = 0; i<config.m_processes.size(); i++){
1074  atrt_process & proc = *config.m_processes[i];
1075  if((types & proc.m_type) != 0){
1076  if(!stop_process(proc)){
1077  return false;
1078  }
1079  }
1080  }
1081  return true;
1082 }
1083 
1084 bool
1085 update_status(atrt_config& config, int){
1086 
1088 
1090  m_procs.fill(config.m_hosts.size(), dummy);
1091  for(size_t i = 0; i<config.m_hosts.size(); i++){
1092  Properties p;
1093  config.m_hosts[i]->m_cpcd->list_processes(m_procs[i], p);
1094  }
1095 
1096  for(size_t i = 0; i<config.m_processes.size(); i++){
1097  atrt_process & proc = *config.m_processes[i];
1098  if(proc.m_proc.m_id != -1){
1099  Vector<SimpleCpcClient::Process> &h_procs= m_procs[proc.m_host->m_index];
1100  bool found = false;
1101  for(size_t j = 0; j<h_procs.size(); j++){
1102  if(proc.m_proc.m_id == h_procs[j].m_id){
1103  found = true;
1104  proc.m_proc.m_status = h_procs[j].m_status;
1105  break;
1106  }
1107  }
1108  if(!found){
1109  g_logger.error("update_status: not found");
1110  g_logger.error("id: %d host: %s cmd: %s",
1111  proc.m_proc.m_id,
1112  proc.m_host->m_hostname.c_str(),
1113  proc.m_proc.m_path.c_str());
1114  for(size_t j = 0; j<h_procs.size(); j++){
1115  g_logger.error("found: %d %s", h_procs[j].m_id,
1116  h_procs[j].m_path.c_str());
1117  }
1118  return false;
1119  }
1120  }
1121  }
1122  return true;
1123 }
1124 
1125 int
1126 is_running(atrt_config& config, int types){
1127  int found = 0, running = 0;
1128  for(size_t i = 0; i<config.m_processes.size(); i++){
1129  atrt_process & proc = *config.m_processes[i];
1130  if((types & proc.m_type) != 0){
1131  found++;
1132  if(proc.m_proc.m_status == "running")
1133  running++;
1134  else {
1135  if(IF_WIN(proc.m_type & atrt_process::AP_MYSQLD, 0)) {
1136  running++;
1137  }
1138  }
1139  }
1140  }
1141 
1142  if(found == running)
1143  return 2;
1144  if(running == 0)
1145  return 0;
1146  return 1;
1147 }
1148 
1149 
1150 int
1151 insert(const char * pair, Properties & p){
1152  BaseString tmp(pair);
1153 
1154  tmp.trim(" \t\n\r");
1155 
1156  Vector<BaseString> split;
1157  tmp.split(split, ":=", 2);
1158 
1159  if(split.size() != 2)
1160  return -1;
1161 
1162  p.put(split[0].trim().c_str(), split[1].trim().c_str());
1163 
1164  return 0;
1165 }
1166 
1167 bool
1168 read_test_case(FILE * file, atrt_testcase& tc, int& line){
1169 
1170  Properties p;
1171  int elements = 0;
1172  char buf[1024];
1173 
1174  while(!feof(file)){
1175  if (file == stdin)
1176  printf("atrt> ");
1177  if(!fgets(buf, 1024, file))
1178  break;
1179 
1180  line++;
1181  BaseString tmp = buf;
1182 
1183  if(tmp.length() > 0 && tmp.c_str()[0] == '#')
1184  continue;
1185 
1186  if(insert(tmp.c_str(), p) != 0)
1187  break;
1188 
1189  elements++;
1190  }
1191 
1192  if(elements == 0){
1193  if(file == stdin){
1194  BaseString tmp(buf);
1195  tmp.trim(" \t\n\r");
1196  Vector<BaseString> split;
1197  tmp.split(split, " ", 2);
1198  tc.m_command = split[0];
1199  if(split.size() == 2)
1200  tc.m_args = split[1];
1201  else
1202  tc.m_args = "";
1203  tc.m_max_time = 60000;
1204  return true;
1205  }
1206  return false;
1207  }
1208 
1209  if(!p.get("cmd", tc.m_command)){
1210  g_logger.critical("Invalid test file: cmd is missing near line: %d", line);
1211  return false;
1212  }
1213 
1214  if(!p.get("args", tc.m_args))
1215  tc.m_args = "";
1216 
1217  const char * mt = 0;
1218  if(!p.get("max-time", &mt))
1219  tc.m_max_time = 60000;
1220  else
1221  tc.m_max_time = atoi(mt);
1222 
1223  if(p.get("type", &mt) && strcmp(mt, "bench") == 0)
1224  tc.m_report= true;
1225  else
1226  tc.m_report= false;
1227 
1228  if(p.get("run-all", &mt) && strcmp(mt, "yes") == 0)
1229  tc.m_run_all= true;
1230  else
1231  tc.m_run_all= false;
1232 
1233  if (!p.get("name", &mt))
1234  {
1235  tc.m_name.assfmt("%s %s",
1236  tc.m_command.c_str(),
1237  tc.m_args.c_str());
1238  }
1239  else
1240  {
1241  tc.m_name.assign(mt);
1242  }
1243 
1244  return true;
1245 }
1246 
1247 bool
1248 setup_test_case(atrt_config& config, const atrt_testcase& tc){
1249 
1250  if (!remove_dir("result", true))
1251  {
1252  g_logger.critical("setup_test_case: Failed to clear result");
1253  return false;
1254  }
1255 
1256  size_t i = 0;
1257  for(; i<config.m_processes.size(); i++)
1258  {
1259  atrt_process & proc = *config.m_processes[i];
1260  if(proc.m_type == atrt_process::AP_NDB_API ||
1261  proc.m_type == atrt_process::AP_CLIENT)
1262  {
1263  BaseString cmd;
1264  if (tc.m_command.c_str()[0] != '/')
1265  {
1266  cmd.appfmt("%s/bin/", g_prefix);
1267  }
1268  cmd.append(tc.m_command.c_str());
1269 
1270  if (0) // valgrind
1271  {
1272  proc.m_proc.m_path = "/usr/bin/valgrind";
1273  proc.m_proc.m_args.appfmt("%s %s", cmd.c_str(), tc.m_args.c_str());
1274  }
1275  else
1276  {
1277  proc.m_proc.m_path = cmd;
1278  proc.m_proc.m_args.assign(tc.m_args);
1279  }
1280  if(!tc.m_run_all)
1281  break;
1282  }
1283  }
1284  for(i++; i<config.m_processes.size(); i++){
1285  atrt_process & proc = *config.m_processes[i];
1286  if(proc.m_type == atrt_process::AP_NDB_API ||
1287  proc.m_type == atrt_process::AP_CLIENT)
1288  {
1289  proc.m_proc.m_path.assign("");
1290  proc.m_proc.m_args.assign("");
1291  }
1292  }
1293  return true;
1294 }
1295 
1296 bool
1297 gather_result(atrt_config& config, int * result){
1298  BaseString tmp = g_gather_progname;
1299 
1300  for(size_t i = 0; i<config.m_hosts.size(); i++)
1301  {
1302  tmp.appfmt(" %s:%s/*",
1303  config.m_hosts[i]->m_hostname.c_str(),
1304  config.m_hosts[i]->m_basedir.c_str());
1305  }
1306 
1307  g_logger.debug("system(%s)", tmp.c_str());
1308  const int r1 = sh(tmp.c_str());
1309  if(r1 != 0)
1310  {
1311  g_logger.critical("Failed to gather result!");
1312  return false;
1313  }
1314 
1315  g_logger.debug("system(%s)", g_analyze_progname);
1316  const int r2 = sh(g_analyze_progname);
1317 
1318  if(r2 == -1 || r2 == (127 << 8))
1319  {
1320  g_logger.critical("Failed to analyze results");
1321  return false;
1322  }
1323 
1324  * result = r2 ;
1325  return true;
1326 }
1327 
1328 bool
1329 setup_hosts(atrt_config& config){
1330  if (!remove_dir("result", true))
1331  {
1332  g_logger.critical("setup_hosts: Failed to clear result");
1333  return false;
1334  }
1335 
1336  for(size_t i = 0; i<config.m_hosts.size(); i++){
1337  BaseString tmp = g_setup_progname;
1338  tmp.appfmt(" %s %s/ %s/",
1339  config.m_hosts[i]->m_hostname.c_str(),
1340  g_basedir,
1341  config.m_hosts[i]->m_basedir.c_str());
1342 
1343  g_logger.debug("system(%s)", tmp.c_str());
1344  const int r1 = sh(tmp.c_str());
1345  if(r1 != 0){
1346  g_logger.critical("Failed to setup %s",
1347  config.m_hosts[i]->m_hostname.c_str());
1348  return false;
1349  }
1350  }
1351  return true;
1352 }
1353 
1354 static
1355 bool
1356 do_rsync(const char *dir, const char *dst)
1357 {
1358  BaseString tmp = g_setup_progname;
1359  tmp.appfmt(" %s %s/ %s", dst, dir, dir);
1360 
1361  g_logger.info("rsyncing %s to %s", dir, dst);
1362  g_logger.debug("system(%s)", tmp.c_str());
1363  const int r1 = sh(tmp.c_str());
1364  if(r1 != 0)
1365  {
1366  g_logger.critical("Failed to rsync %s to %s", dir, dst);
1367  return false;
1368  }
1369 
1370  return true;
1371 }
1372 
1373 bool
1374 deploy(int d, atrt_config & config)
1375 {
1376  for (size_t i = 0; i<config.m_hosts.size(); i++)
1377  {
1378  if (d & 1)
1379  {
1380  if (!do_rsync(g_basedir, config.m_hosts[i]->m_hostname.c_str()))
1381  return false;
1382  }
1383 
1384  if (d & 2)
1385  {
1386  if (!do_rsync(g_prefix, config.m_hosts[i]->m_hostname.c_str()))
1387  return false;
1388 
1389  if (g_prefix1 &&
1390  !do_rsync(g_prefix1, config.m_hosts[i]->m_hostname.c_str()))
1391  return false;
1392  }
1393  }
1394 
1395  return true;
1396 }
1397 
1398 bool
1399 sshx(atrt_config & config, unsigned mask)
1400 {
1401  for (size_t i = 0; i<config.m_processes.size(); i++)
1402  {
1403  atrt_process & proc = *config.m_processes[i];
1404 
1405  BaseString tmp;
1406  const char * type = 0;
1407  switch(proc.m_type){
1408  case atrt_process::AP_NDB_MGMD:
1409  type = (mask & proc.m_type) ? "ndb_mgmd" : 0;
1410  break;
1411  case atrt_process::AP_NDBD:
1412  type = (mask & proc.m_type) ? "ndbd" : 0;
1413  break;
1414  case atrt_process::AP_MYSQLD:
1415  type = (mask & proc.m_type) ? "mysqld" : 0;
1416  break;
1417  case atrt_process::AP_NDB_API:
1418  type = (mask & proc.m_type) ? "ndbapi" : 0;
1419  break;
1420  case atrt_process::AP_CLIENT:
1421  type = (mask & proc.m_type) ? "client" : 0;
1422  break;
1423  default:
1424  type = "<unknown>";
1425  }
1426 
1427  if (type == 0)
1428  continue;
1429 
1430 #ifdef _WIN32
1431 #define SYS_SSH "bash '-c echo\"%s(%s) on %s\";" \
1432  "ssh -t %s sh %s/ssh-login.sh' &"
1433 #else
1434 #define SYS_SSH "xterm -fg black -title \"%s(%s) on %s\"" \
1435  " -e 'ssh -t -X %s sh %s/ssh-login.sh' &"
1436 #endif
1437 
1438  tmp.appfmt(SYS_SSH,
1439  type,
1440  proc.m_cluster->m_name.c_str(),
1441  proc.m_host->m_hostname.c_str(),
1442  proc.m_host->m_hostname.c_str(),
1443  proc.m_proc.m_cwd.c_str());
1444 
1445  g_logger.debug("system(%s)", tmp.c_str());
1446  const int r1 = sh(tmp.c_str());
1447  if(r1 != 0)
1448  {
1449  g_logger.critical("Failed sshx (%s)",
1450  tmp.c_str());
1451  return false;
1452  }
1453  NdbSleep_MilliSleep(300); // To prevent xlock problem
1454  }
1455 
1456  return true;
1457 }
1458 
1459 bool
1460 start(atrt_config & config, unsigned proc_mask)
1461 {
1462  if (proc_mask & atrt_process::AP_NDB_MGMD)
1463  if(!start_processes(g_config, atrt_process::AP_NDB_MGMD))
1464  return false;
1465 
1466  if (proc_mask & atrt_process::AP_NDBD)
1467  {
1468  if(!connect_ndb_mgm(g_config)){
1469  return false;
1470  }
1471 
1472  if(!start_processes(g_config, atrt_process::AP_NDBD))
1473  return false;
1474 
1475  if(!wait_ndb(g_config, NDB_MGM_NODE_STATUS_NOT_STARTED))
1476  return false;
1477 
1478  for(Uint32 i = 0; i<3; i++)
1479  if(wait_ndb(g_config, NDB_MGM_NODE_STATUS_STARTED))
1480  goto started;
1481  return false;
1482  }
1483 
1484 started:
1485  if(!start_processes(g_config, p_servers & proc_mask))
1486  return false;
1487 
1488  return true;
1489 }
1490 
1491 bool
1492 reset_config(atrt_config & config)
1493 {
1494  bool changed = false;
1495  for(size_t i = 0; i<config.m_processes.size(); i++)
1496  {
1497  atrt_process & proc = *config.m_processes[i];
1498  if (proc.m_save.m_saved)
1499  {
1500  if (!stop_process(proc))
1501  return false;
1502 
1503  changed = true;
1504  proc.m_save.m_saved = false;
1505  proc.m_proc = proc.m_save.m_proc;
1506  proc.m_proc.m_id = -1;
1507  }
1508  }
1509  return changed;
1510 }
1511 
1513 template class Vector<atrt_host*>;
1514 template class Vector<atrt_cluster*>;
1515 template class Vector<atrt_process*>;