Drizzled Public API Documentation

drizzleslap.cc
1 /* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2  * vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
3  *
4  * Copyright (C) 2010 Vijay Samuel
5  * Copyright (C) 2008 MySQL
6  *
7  * This program is free software; you can redistribute it and/or modify
8  * it under the terms of the GNU General Public License as published by
9  * the Free Software Foundation; either version 2 of the License, or
10  * (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20  */
21 
22 
23 /*
24  Drizzle Slap
25 
26  A simple program designed to work as if multiple clients querying the database,
27  then reporting the timing of each stage.
28 
29  Drizzle slap runs three stages:
30  1) Create schema,table, and optionally any SP or data you want to beign
31  the test with. (single client)
32  2) Load test (many clients)
33  3) Cleanup (disconnection, drop table if specified, single client)
34 
35  Examples:
36 
37  Supply your own create and query SQL statements, with 50 clients
38  querying (200 selects for each):
39 
40  drizzleslap --delimiter=";" \
41  --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
42  --query="SELECT * FROM A" --concurrency=50 --iterations=200
43 
44  Let the program build the query SQL statement with a table of two int
45  columns, three varchar columns, five clients querying (20 times each),
46  don't create the table or insert the data (using the previous test's
47  schema and data):
48 
49  drizzleslap --concurrency=5 --iterations=20 \
50  --number-int-cols=2 --number-char-cols=3 \
51  --auto-generate-sql
52 
53  Tell the program to load the create, insert and query SQL statements from
54  the specified files, where the create.sql file has multiple table creation
55  statements delimited by ';' and multiple insert statements delimited by ';'.
56  The --query file will have multiple queries delimited by ';', run all the
57  load statements, and then run all the queries in the query file
58  with five clients (five times each):
59 
60  drizzleslap --concurrency=5 \
61  --iterations=5 --query=query.sql --create=create.sql \
62  --delimiter=";"
63 
64  @todo
65  Add language for better tests
66  String length for files and those put on the command line are not
67  setup to handle binary data.
68  More stats
69  Break up tests and run them on multiple hosts at once.
70  Allow output to be fed into a database directly.
71 
72 */
73 
74 #include <config.h>
75 #include "client/client_priv.h"
76 
77 #include "client/option_string.h"
78 #include "client/stats.h"
79 #include "client/thread_context.h"
80 #include "client/conclusions.h"
81 #include "client/wakeup.h"
82 
83 #include <signal.h>
84 #include <stdarg.h>
85 #include <sys/types.h>
86 #include <sys/wait.h>
87 #ifdef HAVE_SYS_STAT_H
88 # include <sys/stat.h>
89 #endif
90 #include <fcntl.h>
91 #include <math.h>
92 #include <cassert>
93 #include <cstdlib>
94 #include <string>
95 #include <iostream>
96 #include <fstream>
97 #include <drizzled/configmake.h>
98 #include <memory>
99 
100 /* Added this for string translation. */
101 #include <drizzled/gettext.h>
102 
103 #include <boost/algorithm/string.hpp>
104 #include <boost/thread.hpp>
105 #include <boost/thread/mutex.hpp>
106 #include <boost/thread/condition_variable.hpp>
107 #include <boost/program_options.hpp>
108 #include <boost/scoped_ptr.hpp>
109 #include <drizzled/atomics.h>
110 
111 #define SLAP_NAME "drizzleslap"
112 #define SLAP_VERSION "1.5"
113 
114 #define HUGE_STRING_LENGTH 8196
115 #define RAND_STRING_SIZE 126
116 #define DEFAULT_BLOB_SIZE 1024
117 
118 using namespace std;
119 using namespace drizzled;
120 namespace po= boost::program_options;
121 
122 #ifdef HAVE_SMEM
123 static char *shared_memory_base_name=0;
124 #endif
125 
126 client::Wakeup master_wakeup;
127 
128 /* Global Thread timer */
129 static bool timer_alarm= false;
130 boost::mutex timer_alarm_mutex;
131 boost::condition_variable_any timer_alarm_threshold;
132 
133 std::vector < std::string > primary_keys;
134 
135 drizzled::atomic<size_t> connection_count;
136 drizzled::atomic<uint64_t> failed_update_for_transaction;
137 
138 static string host,
139  opt_password,
140  user,
141  user_supplied_query,
142  user_supplied_pre_statements,
143  user_supplied_post_statements,
144  default_engine,
145  pre_system,
146  post_system;
147 
148 static vector<string> user_supplied_queries;
149 static string opt_verbose;
150 std::string opt_protocol;
151 string delimiter;
152 
153 string create_schema_string;
154 
155 static bool use_drizzle_protocol= false;
156 static bool opt_preserve= true;
157 static bool opt_only_print;
158 static bool opt_burnin;
159 static bool opt_ignore_sql_errors= false;
160 static bool opt_silent,
161  auto_generate_sql_autoincrement,
162  auto_generate_sql_guid_primary,
163  auto_generate_sql;
164 std::string opt_auto_generate_sql_type;
165 
166 static int32_t verbose= 0;
167 static uint32_t delimiter_length;
168 static uint32_t commit_rate;
169 static uint32_t detach_rate;
170 static uint32_t opt_timer_length;
171 static uint32_t opt_delayed_start;
172 string num_blob_cols_opt,
173  num_char_cols_opt,
174  num_int_cols_opt;
175 string opt_label;
176 static uint32_t opt_set_random_seed;
177 
178 string auto_generate_selected_columns_opt;
179 
180 /* Yes, we do set defaults here */
181 static uint32_t num_int_cols= 1;
182 static uint32_t num_char_cols= 1;
183 static uint32_t num_blob_cols= 0;
184 static uint32_t num_blob_cols_size;
185 static uint32_t num_blob_cols_size_min;
186 static uint32_t num_int_cols_index= 0;
187 static uint32_t num_char_cols_index= 0;
188 static uint32_t iterations;
189 static uint64_t actual_queries= 0;
190 static uint64_t auto_actual_queries;
191 static uint64_t auto_generate_sql_unique_write_number;
192 static uint64_t auto_generate_sql_unique_query_number;
193 static uint32_t auto_generate_sql_secondary_indexes;
194 static uint64_t num_of_query;
195 static uint64_t auto_generate_sql_number;
196 string concurrency_str;
197 string create_string;
198 std::vector <uint32_t> concurrency;
199 
200 std::string opt_csv_str;
201 int csv_file;
202 
203 static int process_options(void);
204 static uint32_t opt_drizzle_port= 0;
205 
206 static OptionString *engine_options= NULL;
207 static OptionString *query_options= NULL;
208 static Statement *pre_statements= NULL;
209 static Statement *post_statements= NULL;
210 static Statement *create_statements= NULL;
211 
212 static std::vector <Statement *> query_statements;
213 static uint32_t query_statements_count;
214 
215 
216 /* Prototypes */
217 void print_conclusions(Conclusions &con);
218 void print_conclusions_csv(Conclusions &con);
219 void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr);
220 uint32_t parse_comma(const char *string, std::vector <uint32_t> &range);
221 uint32_t parse_delimiter(const char *script, Statement **stmt, char delm);
222 uint32_t parse_option(const char *origin, OptionString **stmt, char delm);
223 static void drop_schema(drizzle_con_st &con, const char *db);
224 uint32_t get_random_string(char *buf, size_t size);
225 static Statement *build_table_string(void);
226 static Statement *build_insert_string(void);
227 static Statement *build_update_string(void);
228 static Statement * build_select_string(bool key);
229 static int generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt);
230 static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr);
231 static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit);
232 void statement_cleanup(Statement *stmt);
233 void option_cleanup(OptionString *stmt);
234 void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr);
235 static void run_statements(drizzle_con_st &con, Statement *stmt);
236 drizzle_con_st *slap_connect(bool connect_to_schema);
237 void slap_close(drizzle_con_st *con);
238 static int run_query(drizzle_con_st &con, drizzle_result_st *result, const char *query, int len);
239 void standard_deviation(Conclusions &con, Stats *sptr);
240 
241 static const char ALPHANUMERICS[]=
242 "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
243 
244 #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
245 
246 
247 static long int timedif(struct timeval a, struct timeval b)
248 {
249  int us, s;
250 
251  us = a.tv_usec - b.tv_usec;
252  us /= 1000;
253  s = a.tv_sec - b.tv_sec;
254  s *= 1000;
255  return s + us;
256 }
257 
258 static void combine_queries(vector<string> queries)
259 {
260  user_supplied_query.erase();
261  for (vector<string>::iterator it= queries.begin();
262  it != queries.end();
263  ++it)
264  {
265  user_supplied_query.append(*it);
266  user_supplied_query.append(delimiter);
267  }
268 }
269 
270 
271 static void run_task(ThreadContext *ctx)
272 {
273  uint64_t counter= 0, queries;
274  uint64_t detach_counter;
275  uint32_t commit_counter;
276  drizzle_result_st result;
277  drizzle_row_t row;
278  Statement *ptr;
279 
280  master_wakeup.wait();
281 
282  drizzle_con_st *con= slap_connect(true);
283 
284  if (verbose >= 3)
285  {
286  printf("connected!\n");
287  }
288  queries= 0;
289 
290  commit_counter= 0;
291  if (commit_rate)
292  {
293  run_query(*con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
294  }
295 
296 limit_not_met:
297  for (ptr= ctx->getStmt(), detach_counter= 0;
298  ptr && ptr->getLength();
299  ptr= ptr->getNext(), detach_counter++)
300  {
301  if (not opt_only_print && detach_rate && !(detach_counter % detach_rate))
302  {
303  slap_close(con);
304  con= slap_connect(true);
305  }
306 
307  /*
308  We have to execute differently based on query type. This should become a function.
309  */
310  bool is_failed_update= false;
311  if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) ||
312  (ptr->getType() == SELECT_TYPE_REQUIRES_PREFIX))
313  {
314  uint32_t key_val;
315  char buffer[HUGE_STRING_LENGTH];
316 
317  /*
318  This should only happen if some sort of new engine was
319  implemented that didn't properly handle UPDATEs.
320 
321  Just in case someone runs this under an experimental engine we don't
322  want a crash so the if() is placed here.
323  */
324  assert(primary_keys.size());
325  if (primary_keys.size())
326  {
327  key_val= (uint32_t)(random() % primary_keys.size());
328  const char *key= primary_keys[key_val].c_str();
329 
330  assert(key);
331 
332  int length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", (int)ptr->getLength(), ptr->getString(), key);
333 
334  if (run_query(*con, &result, buffer, length))
335  {
336  if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
337  {
338  // Expand to check to see if Innodb, if so we should restart the
339  // transaction.
340 
341  is_failed_update= true;
342  failed_update_for_transaction.fetch_and_increment();
343  }
344  else
345  {
346  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
347  SLAP_NAME, (uint32_t)length, buffer, drizzle_con_error(con));
348  abort();
349  }
350  }
351  }
352  }
353  else
354  {
355  if (run_query(*con, &result, ptr->getString(), ptr->getLength()))
356  {
357  if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
358  {
359  // Expand to check to see if Innodb, if so we should restart the
360  // transaction.
361 
362  is_failed_update= true;
363  failed_update_for_transaction.fetch_and_increment();
364  }
365  else
366  {
367  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
368  SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(con));
369  abort();
370  }
371  }
372  }
373 
374  if (not opt_only_print and not is_failed_update)
375  {
376  while ((row = drizzle_row_next(&result)))
377  counter++;
378  drizzle_result_free(&result);
379  }
380  queries++;
381 
382  if (commit_rate && (++commit_counter == commit_rate) and not is_failed_update)
383  {
384  commit_counter= 0;
385  run_query(*con, NULL, "COMMIT", strlen("COMMIT"));
386  }
387 
388  /* If the timer is set, and the alarm is not active then end */
389  if (opt_timer_length && timer_alarm == false)
390  goto end;
391 
392  /* If limit has been reached, and we are not in a timer_alarm just end */
393  if (ctx->getLimit() && queries == ctx->getLimit() && timer_alarm == false)
394  goto end;
395  }
396 
397  if (opt_timer_length && timer_alarm == true)
398  goto limit_not_met;
399 
400  if (ctx->getLimit() && queries < ctx->getLimit())
401  goto limit_not_met;
402 
403 
404 end:
405  if (commit_rate)
406  {
407  run_query(*con, NULL, "COMMIT", strlen("COMMIT"));
408  }
409 
410  slap_close(con);
411  con= NULL;
412 
413  delete ctx;
414 }
415 
434 int main(int argc, char **argv)
435 {
436  std::string stpassword;
437 
438  try
439  {
440  po::options_description commandline_options("Options used only in command line");
441  commandline_options.add_options()
442  ("help,?","Display this help and exit")
443  ("info","Gives information and exit")
444  ("burnin",po::value<bool>(&opt_burnin)->default_value(false)->zero_tokens(),
445  "Run full test case in infinite loop")
446  ("ignore-sql-errors", po::value<bool>(&opt_ignore_sql_errors)->default_value(false)->zero_tokens(),
447  "Ignore SQL errors in query run")
448  ("create-schema",po::value<string>(&create_schema_string)->default_value("drizzleslap"),
449  "Schema to run tests in")
450  ("create",po::value<string>(&create_string)->default_value(""),
451  "File or string to use to create tables")
452  ("detach",po::value<uint32_t>(&detach_rate)->default_value(0),
453  "Detach (close and re open) connections after X number of requests")
454  ("iterations,i",po::value<uint32_t>(&iterations)->default_value(1),
455  "Number of times to run the tests")
456  ("label",po::value<string>(&opt_label)->default_value(""),
457  "Label to use for print and csv")
458  ("number-blob-cols",po::value<string>(&num_blob_cols_opt)->default_value(""),
459  "Number of BLOB columns to create table with if specifying --auto-generate-sql. Example --number-blob-cols=3:1024/2048 would give you 3 blobs with a random size between 1024 and 2048. ")
460  ("number-char-cols,x",po::value<string>(&num_char_cols_opt)->default_value(""),
461  "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.")
462  ("number-int-cols,y",po::value<string>(&num_int_cols_opt)->default_value(""),
463  "Number of INT columns to create in table if specifying --auto-generate-sql.")
464  ("number-of-queries",
465  po::value<uint64_t>(&num_of_query)->default_value(0),
466  "Limit each client to this number of queries(this is not exact)")
467  ("only-print",po::value<bool>(&opt_only_print)->default_value(false)->zero_tokens(),
468  "This causes drizzleslap to not connect to the database instead print out what it would have done instead")
469  ("post-query", po::value<string>(&user_supplied_post_statements)->default_value(""),
470  "Query to run or file containing query to execute after tests have completed.")
471  ("post-system",po::value<string>(&post_system)->default_value(""),
472  "system() string to execute after tests have completed")
473  ("pre-query",
474  po::value<string>(&user_supplied_pre_statements)->default_value(""),
475  "Query to run or file containing query to execute before running tests.")
476  ("pre-system",po::value<string>(&pre_system)->default_value(""),
477  "system() string to execute before running tests.")
478  ("query,q",po::value<vector<string> >(&user_supplied_queries)->composing()->notifier(&combine_queries),
479  "Query to run or file containing query")
480  ("verbose,v", po::value<string>(&opt_verbose)->default_value("v"), "Increase verbosity level by one.")
481  ("version,V","Output version information and exit")
482  ;
483 
484  po::options_description slap_options("Options specific to drizzleslap");
485  slap_options.add_options()
486  ("auto-generate-sql-select-columns",
487  po::value<string>(&auto_generate_selected_columns_opt)->default_value(""),
488  "Provide a string to use for the select fields used in auto tests")
489  ("auto-generate-sql,a",po::value<bool>(&auto_generate_sql)->default_value(false)->zero_tokens(),
490  "Generate SQL where not supplied by file or command line")
491  ("auto-generate-sql-add-autoincrement",
492  po::value<bool>(&auto_generate_sql_autoincrement)->default_value(false)->zero_tokens(),
493  "Add an AUTO_INCREMENT column to auto-generated tables")
494  ("auto-generate-sql-execute-number",
495  po::value<uint64_t>(&auto_actual_queries)->default_value(0),
496  "See this number and generate a set of queries to run")
497  ("auto-generate-sql-guid-primary",
498  po::value<bool>(&auto_generate_sql_guid_primary)->default_value(false)->zero_tokens(),
499  "Add GUID based primary keys to auto-generated tables")
500  ("auto-generate-sql-load-type",
501  po::value<string>(&opt_auto_generate_sql_type)->default_value("mixed"),
502  "Specify test load type: mixed, update, write, key or read; default is mixed")
503  ("auto-generate-sql-secondary-indexes",
504  po::value<uint32_t>(&auto_generate_sql_secondary_indexes)->default_value(0),
505  "Number of secondary indexes to add to auto-generated tables")
506  ("auto-generated-sql-unique-query-number",
507  po::value<uint64_t>(&auto_generate_sql_unique_query_number)->default_value(10),
508  "Number of unique queries to generate for automatic tests")
509  ("auto-generate-sql-unique-write-number",
510  po::value<uint64_t>(&auto_generate_sql_unique_write_number)->default_value(10),
511  "Number of unique queries to generate for auto-generate-sql-write-number")
512  ("auto-generate-sql-write-number",
513  po::value<uint64_t>(&auto_generate_sql_number)->default_value(100),
514  "Number of row inserts to perform for each thread (default is 100).")
515  ("commit",po::value<uint32_t>(&commit_rate)->default_value(0),
516  "Commit records every X number of statements")
517  ("concurrency,c",po::value<string>(&concurrency_str)->default_value(""),
518  "Number of clients to simulate for query to run")
519  ("csv",po::value<std::string>(&opt_csv_str)->default_value(""),
520  "Generate CSV output to named file or to stdout if no file is name.")
521  ("delayed-start",po::value<uint32_t>(&opt_delayed_start)->default_value(0),
522  "Delay the startup of threads by a random number of microsends (the maximum of the delay")
523  ("delimiter,F",po::value<string>(&delimiter)->default_value("\n"),
524  "Delimiter to use in SQL statements supplied in file or command line")
525  ("engine,e",po::value<string>(&default_engine)->default_value(""),
526  "Storage engine to use for creating the table")
527  ("set-random-seed",
528  po::value<uint32_t>(&opt_set_random_seed)->default_value(0),
529  "Seed for random number generator (srandom(3)) ")
530  ("silent,s",po::value<bool>(&opt_silent)->default_value(false)->zero_tokens(),
531  "Run program in silent mode - no output. ")
532  ("timer-length",po::value<uint32_t>(&opt_timer_length)->default_value(0),
533  "Require drizzleslap to run each specific test a certain amount of time in seconds")
534  ;
535 
536  po::options_description client_options("Options specific to the client");
537  client_options.add_options()
538  ("host,h",po::value<string>(&host)->default_value("localhost"),"Connect to the host")
539  ("password,P",po::value<std::string >(&stpassword),
540  "Password to use when connecting to server. If password is not given it's asked from the tty")
541  ("port,p",po::value<uint32_t>(), "Port number to use for connection")
542  ("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
543  "The protocol of connection (mysql or drizzle).")
544  ("user,u",po::value<string>(&user)->default_value(""),
545  "User for login if not current user")
546  ;
547 
548  po::options_description long_options("Allowed Options");
549  long_options.add(commandline_options).add(slap_options).add(client_options);
550 
551  std::string system_config_dir_slap(SYSCONFDIR);
552  system_config_dir_slap.append("/drizzle/drizzleslap.cnf");
553 
554  std::string system_config_dir_client(SYSCONFDIR);
555  system_config_dir_client.append("/drizzle/client.cnf");
556 
557  std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
558 
559  if (user_config_dir.compare(0, 2, "~/") == 0)
560  {
561  char *homedir;
562  homedir= getenv("HOME");
563  if (homedir != NULL)
564  user_config_dir.replace(0, 1, homedir);
565  }
566 
567  uint64_t temp_drizzle_port= 0;
568  boost::scoped_ptr<drizzle_con_st> con_ap(new drizzle_con_st);
569  OptionString *eptr;
570 
571  // Disable allow_guessing
572  int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
573 
574  po::variables_map vm;
575  po::store(po::command_line_parser(argc, argv).options(long_options).
576  style(style).extra_parser(parse_password_arg).run(), vm);
577 
578  std::string user_config_dir_slap(user_config_dir);
579  user_config_dir_slap.append("/drizzle/drizzleslap.cnf");
580 
581  std::string user_config_dir_client(user_config_dir);
582  user_config_dir_client.append("/drizzle/client.cnf");
583 
584  ifstream user_slap_ifs(user_config_dir_slap.c_str());
585  po::store(parse_config_file(user_slap_ifs, slap_options), vm);
586 
587  ifstream user_client_ifs(user_config_dir_client.c_str());
588  po::store(parse_config_file(user_client_ifs, client_options), vm);
589 
590  ifstream system_slap_ifs(system_config_dir_slap.c_str());
591  store(parse_config_file(system_slap_ifs, slap_options), vm);
592 
593  ifstream system_client_ifs(system_config_dir_client.c_str());
594  store(parse_config_file(system_client_ifs, client_options), vm);
595 
596  po::notify(vm);
597 
598  if (process_options())
599  abort();
600 
601  if ( vm.count("help") || vm.count("info"))
602  {
603  printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
604  drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
605  puts("Copyright (C) 2008 Sun Microsystems");
606  puts("This software comes with ABSOLUTELY NO WARRANTY. "
607  "This is free software,\n"
608  "and you are welcome to modify and redistribute it under the GPL "
609  "license\n");
610  puts("Run a query multiple times against the server\n");
611  cout << long_options << endl;
612  abort();
613  }
614 
615  if (vm.count("protocol"))
616  {
617  boost::to_lower(opt_protocol);
618  if (not opt_protocol.compare("mysql"))
619  use_drizzle_protocol=false;
620  else if (not opt_protocol.compare("drizzle"))
621  use_drizzle_protocol=true;
622  else
623  {
624  cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
625  abort();
626  }
627  }
628  if (vm.count("port"))
629  {
630  temp_drizzle_port= vm["port"].as<uint32_t>();
631 
632  if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
633  {
634  fprintf(stderr, _("Value supplied for port is not valid.\n"));
635  abort();
636  }
637  else
638  {
639  opt_drizzle_port= (uint32_t) temp_drizzle_port;
640  }
641  }
642 
643  if ( vm.count("password") )
644  {
645  if (not opt_password.empty())
646  opt_password.erase();
647  if (stpassword == PASSWORD_SENTINEL)
648  {
649  opt_password= "";
650  }
651  else
652  {
653  opt_password= stpassword;
654  tty_password= false;
655  }
656  }
657  else
658  {
659  tty_password= true;
660  }
661 
662 
663 
664  if ( vm.count("version") )
665  {
666  printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
667  drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
668  abort();
669  }
670 
671  /* Seed the random number generator if we will be using it. */
672  if (auto_generate_sql)
673  {
674  if (opt_set_random_seed == 0)
675  opt_set_random_seed= (uint32_t)time(NULL);
676  srandom(opt_set_random_seed);
677  }
678 
679  /* globals? Yes, so we only have to run strlen once */
680  delimiter_length= delimiter.length();
681 
682  drizzle_con_st *con= slap_connect(false);
683 
684  /* Main iterations loop */
685 burnin:
686  eptr= engine_options;
687  do
688  {
689  /* For the final stage we run whatever queries we were asked to run */
690  uint32_t *current;
691 
692  if (verbose >= 2)
693  printf("Starting Concurrency Test\n");
694 
695  if (concurrency.size())
696  {
697  for (current= &concurrency[0]; current && *current; current++)
698  concurrency_loop(*con, *current, eptr);
699  }
700  else
701  {
702  uint32_t infinite= 1;
703  do {
704  concurrency_loop(*con, infinite, eptr);
705  }
706  while (infinite++);
707  }
708 
709  if (not opt_preserve)
710  drop_schema(*con, create_schema_string.c_str());
711 
712  } while (eptr ? (eptr= eptr->getNext()) : 0);
713 
714  if (opt_burnin)
715  {
716  goto burnin;
717  }
718 
719  slap_close(con);
720 
721  /* now free all the strings we created */
722  if (not opt_password.empty())
723  opt_password.erase();
724 
725  concurrency.clear();
726 
727  statement_cleanup(create_statements);
728  for (uint32_t x= 0; x < query_statements_count; x++)
729  statement_cleanup(query_statements[x]);
730  query_statements.clear();
731  statement_cleanup(pre_statements);
732  statement_cleanup(post_statements);
733  option_cleanup(engine_options);
734  option_cleanup(query_options);
735 
736 #ifdef HAVE_SMEM
737  free(shared_memory_base_name);
738 #endif
739 
740  }
741 
742  catch(std::exception &err)
743  {
744  cerr<<"Error:"<<err.what()<<endl;
745  }
746 
747  if (csv_file != fileno(stdout))
748  close(csv_file);
749 
750  return 0;
751 }
752 
753 void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
754 {
755  Stats *head_sptr;
756  Stats *sptr;
757  Conclusions conclusion;
758  uint64_t client_limit;
759 
760  head_sptr= new Stats[iterations];
761  if (head_sptr == NULL)
762  {
763  fprintf(stderr,"Error allocating memory in concurrency_loop\n");
764  abort();
765  }
766 
767  if (auto_actual_queries)
768  client_limit= auto_actual_queries;
769  else if (num_of_query)
770  client_limit= num_of_query / current;
771  else
772  client_limit= actual_queries;
773 
774  uint32_t x;
775  for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
776  {
777  /*
778  We might not want to load any data, such as when we are calling
779  a stored_procedure that doesn't use data, or we know we already have
780  data in the table.
781  */
782  if (opt_preserve == false)
783  drop_schema(con, create_schema_string.c_str());
784 
785  /* First we create */
786  if (create_statements)
787  create_schema(con, create_schema_string.c_str(), create_statements, eptr, sptr);
788 
789  /*
790  If we generated GUID we need to build a list of them from creation that
791  we can later use.
792  */
793  if (verbose >= 2)
794  printf("Generating primary key list\n");
795  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
796  generate_primary_key_list(con, eptr);
797 
798  if (not pre_system.empty())
799  {
800  int ret= system(pre_system.c_str());
801  assert(ret != -1);
802  }
803 
804  /*
805  Pre statements are always run after all other logic so they can
806  correct/adjust any item that they want.
807  */
808  if (pre_statements)
809  run_statements(con, pre_statements);
810 
811  run_scheduler(sptr, &query_statements[0], current, client_limit);
812 
813  if (post_statements)
814  run_statements(con, post_statements);
815 
816  if (not post_system.empty())
817  {
818  int ret= system(post_system.c_str());
819  assert(ret !=-1);
820  }
821 
822  /* We are finished with this run */
823  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
824  primary_keys.clear();
825  }
826 
827  if (verbose >= 2)
828  printf("Generating stats\n");
829 
830  generate_stats(&conclusion, eptr, head_sptr);
831 
832  if (not opt_silent)
833  print_conclusions(conclusion);
834  if (not opt_csv_str.empty())
835  print_conclusions_csv(conclusion);
836 
837  delete[] head_sptr;
838 }
839 
840 
841 uint32_t get_random_string(char *buf, size_t size)
842 {
843  char *buf_ptr= buf;
844 
845  for (size_t x= size; x > 0; x--)
846  *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
847  return(buf_ptr - buf);
848 }
849 
850 
851 /*
852  build_table_string
853 
854  This function builds a create table query if the user opts to not supply
855  a file or string containing a create table statement
856 */
857 static Statement *
858 build_table_string(void)
859 {
860  char buf[HUGE_STRING_LENGTH];
861  uint32_t col_count;
862  Statement *ptr;
863  string table_string;
864 
865  table_string.reserve(HUGE_STRING_LENGTH);
866 
867  table_string= "CREATE TABLE `t1` (";
868 
869  if (auto_generate_sql_autoincrement)
870  {
871  table_string.append("id serial");
872 
873  if (num_int_cols || num_char_cols)
874  table_string.append(",");
875  }
876 
877  if (auto_generate_sql_guid_primary)
878  {
879  table_string.append("id varchar(128) primary key");
880 
881  if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
882  table_string.append(",");
883  }
884 
885  if (auto_generate_sql_secondary_indexes)
886  {
887  for (uint32_t count= 0; count < auto_generate_sql_secondary_indexes; count++)
888  {
889  if (count) /* Except for the first pass we add a comma */
890  table_string.append(",");
891 
892  if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
893  > HUGE_STRING_LENGTH)
894  {
895  fprintf(stderr, "Memory Allocation error in create table\n");
896  abort();
897  }
898  table_string.append(buf);
899  }
900 
901  if (num_int_cols || num_char_cols)
902  table_string.append(",");
903  }
904 
905  if (num_int_cols)
906  for (col_count= 1; col_count <= num_int_cols; col_count++)
907  {
908  if (num_int_cols_index)
909  {
910  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT, INDEX(intcol%d)",
911  col_count, col_count) > HUGE_STRING_LENGTH)
912  {
913  fprintf(stderr, "Memory Allocation error in create table\n");
914  abort();
915  }
916  }
917  else
918  {
919  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT ", col_count)
920  > HUGE_STRING_LENGTH)
921  {
922  fprintf(stderr, "Memory Allocation error in create table\n");
923  abort();
924  }
925  }
926  table_string.append(buf);
927 
928  if (col_count < num_int_cols || num_char_cols > 0)
929  table_string.append(",");
930  }
931 
932  if (num_char_cols)
933  for (col_count= 1; col_count <= num_char_cols; col_count++)
934  {
935  if (num_char_cols_index)
936  {
937  if (snprintf(buf, HUGE_STRING_LENGTH,
938  "charcol%d VARCHAR(128), INDEX(charcol%d) ",
939  col_count, col_count) > HUGE_STRING_LENGTH)
940  {
941  fprintf(stderr, "Memory Allocation error in creating table\n");
942  abort();
943  }
944  }
945  else
946  {
947  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
948  col_count) > HUGE_STRING_LENGTH)
949  {
950  fprintf(stderr, "Memory Allocation error in creating table\n");
951  abort();
952  }
953  }
954  table_string.append(buf);
955 
956  if (col_count < num_char_cols || num_blob_cols > 0)
957  table_string.append(",");
958  }
959 
960  if (num_blob_cols)
961  for (col_count= 1; col_count <= num_blob_cols; col_count++)
962  {
963  if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob",
964  col_count) > HUGE_STRING_LENGTH)
965  {
966  fprintf(stderr, "Memory Allocation error in creating table\n");
967  abort();
968  }
969  table_string.append(buf);
970 
971  if (col_count < num_blob_cols)
972  table_string.append(",");
973  }
974 
975  table_string.append(")");
976  ptr= new Statement;
977  ptr->setString(table_string.length());
978  if (ptr->getString()==NULL)
979  {
980  fprintf(stderr, "Memory Allocation error in creating table\n");
981  abort();
982  }
983  ptr->setType(CREATE_TABLE_TYPE);
984  strcpy(ptr->getString(), table_string.c_str());
985  return(ptr);
986 }
987 
988 /*
989  build_update_string()
990 
991  This function builds insert statements when the user opts to not supply
992  an insert file or string containing insert data
993 */
994 static Statement *
995 build_update_string(void)
996 {
997  char buf[HUGE_STRING_LENGTH];
998  uint32_t col_count;
999  Statement *ptr;
1000  string update_string;
1001 
1002  update_string.reserve(HUGE_STRING_LENGTH);
1003 
1004  update_string= "UPDATE t1 SET ";
1005 
1006  if (num_int_cols)
1007  for (col_count= 1; col_count <= num_int_cols; col_count++)
1008  {
1009  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
1010  random()) > HUGE_STRING_LENGTH)
1011  {
1012  fprintf(stderr, "Memory Allocation error in creating update\n");
1013  abort();
1014  }
1015  update_string.append(buf);
1016 
1017  if (col_count < num_int_cols || num_char_cols > 0)
1018  update_string.append(",", 1);
1019  }
1020 
1021  if (num_char_cols)
1022  for (col_count= 1; col_count <= num_char_cols; col_count++)
1023  {
1024  char rand_buffer[RAND_STRING_SIZE];
1025  int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
1026 
1027  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
1028  buf_len, rand_buffer)
1029  > HUGE_STRING_LENGTH)
1030  {
1031  fprintf(stderr, "Memory Allocation error in creating update\n");
1032  abort();
1033  }
1034  update_string.append(buf);
1035 
1036  if (col_count < num_char_cols)
1037  update_string.append(",", 1);
1038  }
1039 
1040  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1041  update_string.append(" WHERE id = ");
1042 
1043 
1044  ptr= new Statement;
1045 
1046  ptr->setString(update_string.length());
1047  if (ptr->getString() == NULL)
1048  {
1049  fprintf(stderr, "Memory Allocation error in creating update\n");
1050  abort();
1051  }
1052  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1053  ptr->setType(UPDATE_TYPE_REQUIRES_PREFIX);
1054  else
1055  ptr->setType(UPDATE_TYPE);
1056  strncpy(ptr->getString(), update_string.c_str(), ptr->getLength());
1057  return(ptr);
1058 }
1059 
1060 
1061 /*
1062  build_insert_string()
1063 
1064  This function builds insert statements when the user opts to not supply
1065  an insert file or string containing insert data
1066 */
1067 static Statement *
1068 build_insert_string(void)
1069 {
1070  char buf[HUGE_STRING_LENGTH];
1071  uint32_t col_count;
1072  Statement *ptr;
1073  string insert_string;
1074 
1075  insert_string.reserve(HUGE_STRING_LENGTH);
1076 
1077  insert_string= "INSERT INTO t1 VALUES (";
1078 
1079  if (auto_generate_sql_autoincrement)
1080  {
1081  insert_string.append("NULL");
1082 
1083  if (num_int_cols || num_char_cols)
1084  insert_string.append(",");
1085  }
1086 
1087  if (auto_generate_sql_guid_primary)
1088  {
1089  insert_string.append("uuid()");
1090 
1091  if (num_int_cols || num_char_cols)
1092  insert_string.append(",");
1093  }
1094 
1095  if (auto_generate_sql_secondary_indexes)
1096  {
1097  uint32_t count;
1098 
1099  for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1100  {
1101  if (count) /* Except for the first pass we add a comma */
1102  insert_string.append(",");
1103 
1104  insert_string.append("uuid()");
1105  }
1106 
1107  if (num_int_cols || num_char_cols)
1108  insert_string.append(",");
1109  }
1110 
1111  if (num_int_cols)
1112  for (col_count= 1; col_count <= num_int_cols; col_count++)
1113  {
1114  if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1115  {
1116  fprintf(stderr, "Memory Allocation error in creating insert\n");
1117  abort();
1118  }
1119  insert_string.append(buf);
1120 
1121  if (col_count < num_int_cols || num_char_cols > 0)
1122  insert_string.append(",");
1123  }
1124 
1125  if (num_char_cols)
1126  for (col_count= 1; col_count <= num_char_cols; col_count++)
1127  {
1128  int buf_len= get_random_string(buf, RAND_STRING_SIZE);
1129  insert_string.append("'", 1);
1130  insert_string.append(buf, buf_len);
1131  insert_string.append("'", 1);
1132 
1133  if (col_count < num_char_cols || num_blob_cols > 0)
1134  insert_string.append(",", 1);
1135  }
1136 
1137  if (num_blob_cols)
1138  {
1139  vector <char> blob_ptr;
1140 
1141  blob_ptr.resize(num_blob_cols_size);
1142 
1143  for (col_count= 1; col_count <= num_blob_cols; col_count++)
1144  {
1145  uint32_t buf_len;
1146  uint32_t size;
1147  uint32_t difference= num_blob_cols_size - num_blob_cols_size_min;
1148 
1149  size= difference ? (num_blob_cols_size_min + (random() % difference)) :
1150  num_blob_cols_size;
1151 
1152  buf_len= get_random_string(&blob_ptr[0], size);
1153 
1154  insert_string.append("'", 1);
1155  insert_string.append(&blob_ptr[0], buf_len);
1156  insert_string.append("'", 1);
1157 
1158  if (col_count < num_blob_cols)
1159  insert_string.append(",", 1);
1160  }
1161  }
1162 
1163  insert_string.append(")", 1);
1164 
1165  ptr= new Statement;
1166  ptr->setString(insert_string.length());
1167  if (ptr->getString()==NULL)
1168  {
1169  fprintf(stderr, "Memory Allocation error in creating select\n");
1170  abort();
1171  }
1172  ptr->setType(INSERT_TYPE);
1173  strcpy(ptr->getString(), insert_string.c_str());
1174  return(ptr);
1175 }
1176 
1177 
1178 /*
1179  build_select_string()
1180 
1181  This function builds a query if the user opts to not supply a query
1182  statement or file containing a query statement
1183 */
1184 static Statement *
1185 build_select_string(bool key)
1186 {
1187  char buf[HUGE_STRING_LENGTH];
1188  uint32_t col_count;
1189  Statement *ptr;
1190  string query_string;
1191 
1192  query_string.reserve(HUGE_STRING_LENGTH);
1193 
1194  query_string.append("SELECT ", 7);
1195  if (not auto_generate_selected_columns_opt.empty())
1196  {
1197  query_string.append(auto_generate_selected_columns_opt.c_str());
1198  }
1199  else
1200  {
1201  for (col_count= 1; col_count <= num_int_cols; col_count++)
1202  {
1203  if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1204  > HUGE_STRING_LENGTH)
1205  {
1206  fprintf(stderr, "Memory Allocation error in creating select\n");
1207  abort();
1208  }
1209  query_string.append(buf);
1210 
1211  if (col_count < num_int_cols || num_char_cols > 0)
1212  query_string.append(",", 1);
1213 
1214  }
1215  for (col_count= 1; col_count <= num_char_cols; col_count++)
1216  {
1217  if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1218  > HUGE_STRING_LENGTH)
1219  {
1220  fprintf(stderr, "Memory Allocation error in creating select\n");
1221  abort();
1222  }
1223  query_string.append(buf);
1224 
1225  if (col_count < num_char_cols || num_blob_cols > 0)
1226  query_string.append(",", 1);
1227 
1228  }
1229  for (col_count= 1; col_count <= num_blob_cols; col_count++)
1230  {
1231  if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
1232  > HUGE_STRING_LENGTH)
1233  {
1234  fprintf(stderr, "Memory Allocation error in creating select\n");
1235  abort();
1236  }
1237  query_string.append(buf);
1238 
1239  if (col_count < num_blob_cols)
1240  query_string.append(",", 1);
1241  }
1242  }
1243  query_string.append(" FROM t1");
1244 
1245  if ((key) &&
1246  (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1247  query_string.append(" WHERE id = ");
1248 
1249  ptr= new Statement;
1250  ptr->setString(query_string.length());
1251  if (ptr->getString() == NULL)
1252  {
1253  fprintf(stderr, "Memory Allocation error in creating select\n");
1254  abort();
1255  }
1256  if ((key) &&
1257  (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1258  ptr->setType(SELECT_TYPE_REQUIRES_PREFIX);
1259  else
1260  ptr->setType(SELECT_TYPE);
1261  strcpy(ptr->getString(), query_string.c_str());
1262  return(ptr);
1263 }
1264 
1265 static int
1266 process_options(void)
1267 {
1268  struct stat sbuf;
1269  ssize_t bytes_read= 0;
1270 
1271  if (user.empty())
1272  user= "root";
1273 
1274  verbose= opt_verbose.length();
1275 
1276  /* If something is created we clean it up, otherwise we leave schemas alone */
1277  if ( (not create_string.empty()) || auto_generate_sql)
1278  opt_preserve= false;
1279 
1280  if (auto_generate_sql && (not create_string.empty() || !user_supplied_query.empty()))
1281  {
1282  fprintf(stderr,
1283  "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1284  SLAP_NAME);
1285  abort();
1286  }
1287 
1288  if (auto_generate_sql && auto_generate_sql_guid_primary &&
1289  auto_generate_sql_autoincrement)
1290  {
1291  fprintf(stderr,
1292  "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1293  SLAP_NAME);
1294  abort();
1295  }
1296 
1297  if (auto_generate_sql && num_of_query && auto_actual_queries)
1298  {
1299  fprintf(stderr,
1300  "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1301  SLAP_NAME);
1302  abort();
1303  }
1304 
1305  parse_comma(not concurrency_str.empty() ? concurrency_str.c_str() : "1", concurrency);
1306 
1307  if (not opt_csv_str.empty())
1308  {
1309  opt_silent= true;
1310 
1311  if (opt_csv_str[0] == '-')
1312  {
1313  csv_file= fileno(stdout);
1314  }
1315  else
1316  {
1317  if ((csv_file= open(opt_csv_str.c_str(), O_CREAT|O_WRONLY|O_APPEND,
1318  S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
1319  {
1320  fprintf(stderr,"%s: Could not open csv file: %sn\n",
1321  SLAP_NAME, opt_csv_str.c_str());
1322  abort();
1323  }
1324  }
1325  }
1326 
1327  if (opt_only_print)
1328  opt_silent= true;
1329 
1330  if (not num_int_cols_opt.empty())
1331  {
1332  OptionString *str;
1333  parse_option(num_int_cols_opt.c_str(), &str, ',');
1334  num_int_cols= atoi(str->getString());
1335  if (str->getOption())
1336  num_int_cols_index= atoi(str->getOption());
1337  option_cleanup(str);
1338  }
1339 
1340  if (not num_char_cols_opt.empty())
1341  {
1342  OptionString *str;
1343  parse_option(num_char_cols_opt.c_str(), &str, ',');
1344  num_char_cols= atoi(str->getString());
1345  if (str->getOption())
1346  num_char_cols_index= atoi(str->getOption());
1347  else
1348  num_char_cols_index= 0;
1349  option_cleanup(str);
1350  }
1351 
1352  uint32_t sql_type_count= 0;
1353  if (not num_blob_cols_opt.empty())
1354  {
1355  OptionString *str;
1356  parse_option(num_blob_cols_opt.c_str(), &str, ',');
1357  num_blob_cols= atoi(str->getString());
1358  if (str->getOption())
1359  {
1360  char *sep_ptr;
1361 
1362  if ((sep_ptr= strchr(str->getOption(), '/')))
1363  {
1364  num_blob_cols_size_min= atoi(str->getOption());
1365  num_blob_cols_size= atoi(sep_ptr+1);
1366  }
1367  else
1368  {
1369  num_blob_cols_size_min= num_blob_cols_size= atoi(str->getOption());
1370  }
1371  }
1372  else
1373  {
1374  num_blob_cols_size= DEFAULT_BLOB_SIZE;
1375  num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
1376  }
1377  option_cleanup(str);
1378  }
1379 
1380 
1381  if (auto_generate_sql)
1382  {
1383  uint64_t x= 0;
1384  Statement *ptr_statement;
1385 
1386  if (verbose >= 2)
1387  printf("Building Create Statements for Auto\n");
1388 
1389  create_statements= build_table_string();
1390  /*
1391  Pre-populate table
1392  */
1393  for (ptr_statement= create_statements, x= 0;
1394  x < auto_generate_sql_unique_write_number;
1395  x++, ptr_statement= ptr_statement->getNext())
1396  {
1397  ptr_statement->setNext(build_insert_string());
1398  }
1399 
1400  if (verbose >= 2)
1401  printf("Building Query Statements for Auto\n");
1402 
1403  if (opt_auto_generate_sql_type.empty())
1404  opt_auto_generate_sql_type= "mixed";
1405 
1406  query_statements_count=
1407  parse_option(opt_auto_generate_sql_type.c_str(), &query_options, ',');
1408 
1409  query_statements.resize(query_statements_count);
1410 
1411  OptionString* sql_type= query_options;
1412  do
1413  {
1414  if (sql_type->getString()[0] == 'r')
1415  {
1416  if (verbose >= 2)
1417  printf("Generating SELECT Statements for Auto\n");
1418 
1419  query_statements[sql_type_count]= build_select_string(false);
1420  for (ptr_statement= query_statements[sql_type_count], x= 0;
1421  x < auto_generate_sql_unique_query_number;
1422  x++, ptr_statement= ptr_statement->getNext())
1423  {
1424  ptr_statement->setNext(build_select_string(false));
1425  }
1426  }
1427  else if (sql_type->getString()[0] == 'k')
1428  {
1429  if (verbose >= 2)
1430  printf("Generating SELECT for keys Statements for Auto\n");
1431 
1432  if ( auto_generate_sql_autoincrement == false &&
1433  auto_generate_sql_guid_primary == false)
1434  {
1435  fprintf(stderr,
1436  "%s: Can't perform key test without a primary key!\n",
1437  SLAP_NAME);
1438  abort();
1439  }
1440 
1441  query_statements[sql_type_count]= build_select_string(true);
1442  for (ptr_statement= query_statements[sql_type_count], x= 0;
1443  x < auto_generate_sql_unique_query_number;
1444  x++, ptr_statement= ptr_statement->getNext())
1445  {
1446  ptr_statement->setNext(build_select_string(true));
1447  }
1448  }
1449  else if (sql_type->getString()[0] == 'w')
1450  {
1451  /*
1452  We generate a number of strings in case the engine is
1453  Archive (since strings which were identical one after another
1454  would be too easily optimized).
1455  */
1456  if (verbose >= 2)
1457  printf("Generating INSERT Statements for Auto\n");
1458  query_statements[sql_type_count]= build_insert_string();
1459  for (ptr_statement= query_statements[sql_type_count], x= 0;
1460  x < auto_generate_sql_unique_query_number;
1461  x++, ptr_statement= ptr_statement->getNext())
1462  {
1463  ptr_statement->setNext(build_insert_string());
1464  }
1465  }
1466  else if (sql_type->getString()[0] == 'u')
1467  {
1468  if ( auto_generate_sql_autoincrement == false &&
1469  auto_generate_sql_guid_primary == false)
1470  {
1471  fprintf(stderr,
1472  "%s: Can't perform update test without a primary key!\n",
1473  SLAP_NAME);
1474  abort();
1475  }
1476 
1477  query_statements[sql_type_count]= build_update_string();
1478  for (ptr_statement= query_statements[sql_type_count], x= 0;
1479  x < auto_generate_sql_unique_query_number;
1480  x++, ptr_statement= ptr_statement->getNext())
1481  {
1482  ptr_statement->setNext(build_update_string());
1483  }
1484  }
1485  else /* Mixed mode is default */
1486  {
1487  int coin= 0;
1488 
1489  query_statements[sql_type_count]= build_insert_string();
1490  /*
1491  This logic should be extended to do a more mixed load,
1492  at the moment it results in "every other".
1493  */
1494  for (ptr_statement= query_statements[sql_type_count], x= 0;
1495  x < auto_generate_sql_unique_query_number;
1496  x++, ptr_statement= ptr_statement->getNext())
1497  {
1498  if (coin)
1499  {
1500  ptr_statement->setNext(build_insert_string());
1501  coin= 0;
1502  }
1503  else
1504  {
1505  ptr_statement->setNext(build_select_string(true));
1506  coin= 1;
1507  }
1508  }
1509  }
1510  sql_type_count++;
1511  } while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1512  }
1513  else
1514  {
1515  if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1516  {
1517  int data_file;
1518  std::vector<char> tmp_string;
1519  if (not S_ISREG(sbuf.st_mode))
1520  {
1521  fprintf(stderr,"%s: Create file was not a regular file\n",
1522  SLAP_NAME);
1523  abort();
1524  }
1525  if ((data_file= open(create_string.c_str(), O_RDWR)) == -1)
1526  {
1527  fprintf(stderr,"%s: Could not open create file\n", SLAP_NAME);
1528  abort();
1529  }
1530  if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1531  {
1532  fprintf(stderr, "Request for more memory than architecture supports\n");
1533  abort();
1534  }
1535  tmp_string.resize(sbuf.st_size + 1);
1536  bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1537  (size_t)sbuf.st_size);
1538  close(data_file);
1539  if (bytes_read != sbuf.st_size)
1540  {
1541  fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1542  }
1543  parse_delimiter(&tmp_string[0], &create_statements, delimiter[0]);
1544  }
1545  else if (not create_string.empty())
1546  {
1547  parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1548  }
1549 
1550  /* Set this up till we fully support options on user generated queries */
1551  if (not user_supplied_query.empty())
1552  {
1553  query_statements_count=
1554  parse_option("default", &query_options, ',');
1555 
1556  query_statements.resize(query_statements_count);
1557  }
1558 
1559  if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1560  {
1561  int data_file;
1562  std::vector<char> tmp_string;
1563 
1564  if (not S_ISREG(sbuf.st_mode))
1565  {
1566  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1567  SLAP_NAME);
1568  abort();
1569  }
1570  if ((data_file= open(user_supplied_query.c_str(), O_RDWR)) == -1)
1571  {
1572  fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1573  abort();
1574  }
1575  if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1576  {
1577  fprintf(stderr, "Request for more memory than architecture supports\n");
1578  abort();
1579  }
1580  tmp_string.resize((size_t)(sbuf.st_size + 1));
1581  bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1582  (size_t)sbuf.st_size);
1583  close(data_file);
1584  if (bytes_read != sbuf.st_size)
1585  {
1586  fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1587  }
1588  if (not user_supplied_query.empty())
1589  actual_queries= parse_delimiter(&tmp_string[0], &query_statements[0],
1590  delimiter[0]);
1591  }
1592  else if (not user_supplied_query.empty())
1593  {
1594  actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1595  delimiter[0]);
1596  }
1597  }
1598 
1599  if (not user_supplied_pre_statements.empty()
1600  && !stat(user_supplied_pre_statements.c_str(), &sbuf))
1601  {
1602  int data_file;
1603  std::vector<char> tmp_string;
1604 
1605  if (not S_ISREG(sbuf.st_mode))
1606  {
1607  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1608  SLAP_NAME);
1609  abort();
1610  }
1611  if ((data_file= open(user_supplied_pre_statements.c_str(), O_RDWR)) == -1)
1612  {
1613  fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1614  abort();
1615  }
1616  if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1617  {
1618  fprintf(stderr, "Request for more memory than architecture supports\n");
1619  abort();
1620  }
1621  tmp_string.resize((size_t)(sbuf.st_size + 1));
1622  bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1623  (size_t)sbuf.st_size);
1624  close(data_file);
1625  if (bytes_read != sbuf.st_size)
1626  {
1627  fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1628  }
1629  if (not user_supplied_pre_statements.empty())
1630  (void)parse_delimiter(&tmp_string[0], &pre_statements,
1631  delimiter[0]);
1632  }
1633  else if (not user_supplied_pre_statements.empty())
1634  {
1635  (void)parse_delimiter(user_supplied_pre_statements.c_str(),
1636  &pre_statements,
1637  delimiter[0]);
1638  }
1639 
1640  if (not user_supplied_post_statements.empty()
1641  && !stat(user_supplied_post_statements.c_str(), &sbuf))
1642  {
1643  int data_file;
1644  std::vector<char> tmp_string;
1645 
1646  if (not S_ISREG(sbuf.st_mode))
1647  {
1648  fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1649  SLAP_NAME);
1650  abort();
1651  }
1652  if ((data_file= open(user_supplied_post_statements.c_str(), O_RDWR)) == -1)
1653  {
1654  fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1655  abort();
1656  }
1657 
1658  if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1659  {
1660  fprintf(stderr, "Request for more memory than architecture supports\n");
1661  abort();
1662  }
1663  tmp_string.resize((size_t)(sbuf.st_size + 1));
1664 
1665  bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1666  (size_t)(sbuf.st_size));
1667  close(data_file);
1668  if (bytes_read != sbuf.st_size)
1669  {
1670  fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1671  }
1672  if (not user_supplied_post_statements.empty())
1673  (void)parse_delimiter(&tmp_string[0], &post_statements,
1674  delimiter[0]);
1675  }
1676  else if (not user_supplied_post_statements.empty())
1677  {
1678  (void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1679  delimiter[0]);
1680  }
1681 
1682  if (verbose >= 2)
1683  printf("Parsing engines to use.\n");
1684 
1685  if (not default_engine.empty())
1686  parse_option(default_engine.c_str(), &engine_options, ',');
1687 
1688  if (tty_password)
1689  opt_password= client_get_tty_password(NULL);
1690  return(0);
1691 }
1692 
1693 
1694 static int run_query(drizzle_con_st &con, drizzle_result_st *result,
1695  const char *query, int len)
1696 {
1697  drizzle_return_t ret;
1698  drizzle_result_st result_buffer;
1699 
1700  if (opt_only_print)
1701  {
1702  printf("/* CON: %" PRIu64 " */ %.*s;\n",
1703  (uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1704  len, query);
1705  return 0;
1706  }
1707 
1708  if (verbose >= 3)
1709  printf("%.*s;\n", len, query);
1710 
1711  if (result == NULL)
1712  result= &result_buffer;
1713 
1714  result= drizzle_query(&con, result, query, len, &ret);
1715 
1716  if (ret == DRIZZLE_RETURN_OK)
1717  ret= drizzle_result_buffer(result);
1718 
1719  if (result == &result_buffer)
1720  drizzle_result_free(result);
1721 
1722  return ret;
1723 }
1724 
1725 
1726 static int
1727 generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt)
1728 {
1729  drizzle_result_st result;
1730  drizzle_row_t row;
1731  uint64_t counter;
1732 
1733 
1734  /*
1735  Blackhole is a special case, this allows us to test the upper end
1736  of the server during load runs.
1737  */
1738  if (opt_only_print || (engine_stmt &&
1739  strstr(engine_stmt->getString(), "blackhole")))
1740  {
1741  /* Yes, we strdup a const string to simplify the interface */
1742  primary_keys.push_back("796c4422-1d94-102a-9d6d-00e0812d");
1743  }
1744  else
1745  {
1746  if (run_query(con, &result, "SELECT id from t1", strlen("SELECT id from t1")))
1747  {
1748  fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", SLAP_NAME,
1749  drizzle_con_error(&con));
1750  abort();
1751  }
1752 
1753  uint64_t num_rows_ret= drizzle_result_row_count(&result);
1754  if (num_rows_ret > SIZE_MAX)
1755  {
1756  fprintf(stderr, "More primary keys than than architecture supports\n");
1757  abort();
1758  }
1759  size_t primary_keys_number_of;
1760  primary_keys_number_of= (size_t)num_rows_ret;
1761 
1762  /* So why check this? Blackhole :) */
1763  if (primary_keys_number_of)
1764  {
1765  /*
1766  We create the structure and loop and create the items.
1767  */
1768  row= drizzle_row_next(&result);
1769  for (counter= 0; counter < primary_keys_number_of;
1770  counter++, row= drizzle_row_next(&result))
1771  {
1772  primary_keys.push_back(row[0]);
1773  }
1774  }
1775 
1776  drizzle_result_free(&result);
1777  }
1778 
1779  return(0);
1780 }
1781 
1782 static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr)
1783 {
1784  char query[HUGE_STRING_LENGTH];
1785  Statement *ptr;
1786  Statement *after_create;
1787  int len;
1788  struct timeval start_time, end_time;
1789 
1790 
1791  gettimeofday(&start_time, NULL);
1792 
1793  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1794 
1795  if (verbose >= 2)
1796  printf("Loading Pre-data\n");
1797 
1798  if (run_query(con, NULL, query, len))
1799  {
1800  fprintf(stderr,"%s: Cannot create schema %s : %s\n", SLAP_NAME, db,
1801  drizzle_con_error(&con));
1802  abort();
1803  }
1804  else
1805  {
1806  sptr->setCreateCount(sptr->getCreateCount()+1);
1807  }
1808 
1809  if (opt_only_print)
1810  {
1811  printf("/* CON: %" PRIu64 " */ use %s;\n",
1812  (uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1813  db);
1814  }
1815  else
1816  {
1817  drizzle_result_st result;
1818  drizzle_return_t ret;
1819 
1820  if (verbose >= 3)
1821  printf("%s;\n", query);
1822 
1823  if (drizzle_select_db(&con, &result, db, &ret) == NULL ||
1824  ret != DRIZZLE_RETURN_OK)
1825  {
1826  fprintf(stderr,"%s: Cannot select schema '%s': %s\n",SLAP_NAME, db,
1827  ret == DRIZZLE_RETURN_ERROR_CODE ?
1828  drizzle_result_error(&result) : drizzle_con_error(&con));
1829  abort();
1830  }
1831  drizzle_result_free(&result);
1832  sptr->setCreateCount(sptr->getCreateCount()+1);
1833  }
1834 
1835  if (engine_stmt)
1836  {
1837  len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1838  engine_stmt->getString());
1839  if (run_query(con, NULL, query, len))
1840  {
1841  fprintf(stderr,"%s: Cannot set default engine: %s\n", SLAP_NAME,
1842  drizzle_con_error(&con));
1843  abort();
1844  }
1845  sptr->setCreateCount(sptr->getCreateCount()+1);
1846  }
1847 
1848  uint64_t count= 0;
1849  after_create= stmt;
1850 
1851 limit_not_met:
1852  for (ptr= after_create; ptr && ptr->getLength(); ptr= ptr->getNext(), count++)
1853  {
1854  if (auto_generate_sql && ( auto_generate_sql_number == count))
1855  break;
1856 
1857  if (engine_stmt && engine_stmt->getOption() && ptr->getType() == CREATE_TABLE_TYPE)
1858  {
1859  char buffer[HUGE_STRING_LENGTH];
1860 
1861  snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->getString(),
1862  engine_stmt->getOption());
1863  if (run_query(con, NULL, buffer, strlen(buffer)))
1864  {
1865  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1866  SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1867  if (not opt_ignore_sql_errors)
1868  abort();
1869  }
1870  sptr->setCreateCount(sptr->getCreateCount()+1);
1871  }
1872  else
1873  {
1874  if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1875  {
1876  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1877  SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1878  if (not opt_ignore_sql_errors)
1879  abort();
1880  }
1881  sptr->setCreateCount(sptr->getCreateCount()+1);
1882  }
1883  }
1884 
1885  if (auto_generate_sql && (auto_generate_sql_number > count ))
1886  {
1887  /* Special case for auto create, we don't want to create tables twice */
1888  after_create= stmt->getNext();
1889  goto limit_not_met;
1890  }
1891 
1892  gettimeofday(&end_time, NULL);
1893 
1894  sptr->setCreateTiming(timedif(end_time, start_time));
1895 }
1896 
1897 static void drop_schema(drizzle_con_st &con, const char *db)
1898 {
1899  char query[HUGE_STRING_LENGTH];
1900  int len;
1901 
1902  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1903 
1904  if (run_query(con, NULL, query, len))
1905  {
1906  fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1907  SLAP_NAME, db, drizzle_con_error(&con));
1908  abort();
1909  }
1910 }
1911 
1912 static void run_statements(drizzle_con_st &con, Statement *stmt)
1913 {
1914  for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
1915  {
1916  if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1917  {
1918  fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1919  SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1920  abort();
1921  }
1922  }
1923 }
1924 
1925 
1926 static void timer_thread()
1927 {
1928  /*
1929  We lock around the initial call in case were we in a loop. This
1930  also keeps the value properly syncronized across call threads.
1931  */
1932  master_wakeup.wait();
1933 
1934  {
1935  boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1936 
1937  boost::xtime xt;
1938  xtime_get(&xt, boost::TIME_UTC_);
1939  xt.sec += opt_timer_length;
1940 
1941  (void)timer_alarm_threshold.timed_wait(scopedLock, xt);
1942  }
1943 
1944  {
1945  boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1946  timer_alarm= false;
1947  }
1948 }
1949 
1950 typedef boost::shared_ptr<boost::thread> Thread;
1951 typedef std::vector <Thread> Threads;
1952 static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit)
1953 {
1954  uint32_t real_concurrency;
1955  struct timeval start_time, end_time;
1956 
1957  Threads threads;
1958 
1959  {
1960  OptionString *sql_type;
1961 
1962  master_wakeup.reset();
1963 
1964  real_concurrency= 0;
1965 
1966  uint32_t y;
1967  for (y= 0, sql_type= query_options;
1968  y < query_statements_count;
1969  y++, sql_type= sql_type->getNext())
1970  {
1971  uint32_t options_loop= 1;
1972 
1973  if (sql_type->getOption())
1974  {
1975  options_loop= strtol(sql_type->getOption(),
1976  (char **)NULL, 10);
1977  options_loop= options_loop ? options_loop : 1;
1978  }
1979 
1980  while (options_loop--)
1981  {
1982  for (uint32_t x= 0; x < concur; x++)
1983  {
1984  ThreadContext *con;
1985  con= new ThreadContext;
1986  if (con == NULL)
1987  {
1988  fprintf(stderr, "Memory Allocation error in scheduler\n");
1989  abort();
1990  }
1991  con->setStmt(stmts[y]);
1992  con->setLimit(limit);
1993 
1994  real_concurrency++;
1995 
1996  /* now you create the thread */
1997  Thread thread;
1998  thread= Thread(new boost::thread(boost::bind(&run_task, con)));
1999  threads.push_back(thread);
2000 
2001  }
2002  }
2003  }
2004 
2005  /*
2006  The timer_thread belongs to all threads so it too obeys the wakeup
2007  call that run tasks obey.
2008  */
2009  if (opt_timer_length)
2010  {
2011  {
2012  boost::mutex::scoped_lock alarmLock(timer_alarm_mutex);
2013  timer_alarm= true;
2014  }
2015 
2016  Thread thread;
2017  thread= Thread(new boost::thread(&timer_thread));
2018  threads.push_back(thread);
2019  }
2020  }
2021 
2022  master_wakeup.start();
2023 
2024  gettimeofday(&start_time, NULL);
2025 
2026  /*
2027  We loop until we know that all children have cleaned up.
2028  */
2029  for (Threads::iterator iter= threads.begin(); iter != threads.end(); iter++)
2030  {
2031  (*iter)->join();
2032  }
2033 
2034  gettimeofday(&end_time, NULL);
2035 
2036  sptr->setTiming(timedif(end_time, start_time));
2037  sptr->setUsers(concur);
2038  sptr->setRealUsers(real_concurrency);
2039  sptr->setRows(limit);
2040 }
2041 
2042 /*
2043  Parse records from comma seperated string. : is a reserved character and is used for options
2044  on variables.
2045 */
2046 uint32_t parse_option(const char *origin, OptionString **stmt, char delm)
2047 {
2048  char *string;
2049  char *begin_ptr;
2050  char *end_ptr;
2051  uint32_t length= strlen(origin);
2052  uint32_t count= 0; /* We know that there is always one */
2053 
2054  end_ptr= (char *)origin + length;
2055 
2056  OptionString *tmp;
2057  *stmt= tmp= new OptionString;
2058 
2059  for (begin_ptr= (char *)origin;
2060  begin_ptr != end_ptr;
2061  tmp= tmp->getNext())
2062  {
2063  char buffer[HUGE_STRING_LENGTH];
2064  char *buffer_ptr;
2065 
2066  memset(buffer, 0, HUGE_STRING_LENGTH);
2067 
2068  string= strchr(begin_ptr, delm);
2069 
2070  if (string)
2071  {
2072  memcpy(buffer, begin_ptr, string - begin_ptr);
2073  begin_ptr= string+1;
2074  }
2075  else
2076  {
2077  size_t begin_len= strlen(begin_ptr);
2078  memcpy(buffer, begin_ptr, begin_len);
2079  begin_ptr= end_ptr;
2080  }
2081 
2082  if ((buffer_ptr= strchr(buffer, ':')))
2083  {
2084  /* Set a null so that we can get strlen() correct later on */
2085  buffer_ptr[0]= 0;
2086  buffer_ptr++;
2087 
2088  /* Move past the : and the first string */
2089  tmp->setOption(buffer_ptr);
2090  }
2091 
2092  tmp->setString(strdup(buffer));
2093  if (tmp->getString() == NULL)
2094  {
2095  fprintf(stderr,"Error allocating memory while parsing options\n");
2096  abort();
2097  }
2098 
2099  if (isspace(*begin_ptr))
2100  begin_ptr++;
2101 
2102  count++;
2103 
2104  if (begin_ptr != end_ptr)
2105  {
2106  tmp->setNext( new OptionString);
2107  }
2108 
2109  }
2110 
2111  return count;
2112 }
2113 
2114 
2115 /*
2116  Raw parsing interface. If you want the slap specific parser look at
2117  parse_option.
2118 */
2119 uint32_t parse_delimiter(const char *script, Statement **stmt, char delm)
2120 {
2121  char *retstr;
2122  char *ptr= (char *)script;
2123  Statement **sptr= stmt;
2124  Statement *tmp;
2125  uint32_t length= strlen(script);
2126  uint32_t count= 0; /* We know that there is always one */
2127 
2128  for (tmp= *sptr= new Statement;
2129  (retstr= strchr(ptr, delm));
2130  tmp->setNext(new Statement),
2131  tmp= tmp->getNext())
2132  {
2133  if (tmp == NULL)
2134  {
2135  fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2136  abort();
2137  }
2138 
2139  count++;
2140  tmp->setString((size_t)(retstr - ptr));
2141 
2142  if (tmp->getString() == NULL)
2143  {
2144  fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2145  abort();
2146  }
2147 
2148  memcpy(tmp->getString(), ptr, tmp->getLength());
2149  ptr+= retstr - ptr + 1;
2150  if (isspace(*ptr))
2151  ptr++;
2152  }
2153 
2154  if (ptr != script+length)
2155  {
2156  tmp->setString((size_t)((script + length) - ptr));
2157  if (tmp->getString() == NULL)
2158  {
2159  fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2160  abort();
2161  }
2162  memcpy(tmp->getString(), ptr, tmp->getLength());
2163  count++;
2164  }
2165 
2166  return count;
2167 }
2168 
2169 
2170 /*
2171  Parse comma is different from parse_delimeter in that it parses
2172  number ranges from a comma seperated string.
2173  In restrospect, this is a lousy name from this function.
2174 */
2175 uint32_t parse_comma(const char *string, std::vector <uint32_t> &range)
2176 {
2177  uint32_t count= 1; /* We know that there is always one */
2178  char *retstr;
2179  char *ptr= (char *)string;
2180  uint32_t *nptr;
2181 
2182  for (;*ptr; ptr++)
2183  if (*ptr == ',') count++;
2184 
2185  /* One extra spot for the NULL */
2186  range.resize(count +1);
2187  nptr= &range[0];
2188 
2189  ptr= (char *)string;
2190  uint32_t x= 0;
2191  while ((retstr= strchr(ptr,',')))
2192  {
2193  nptr[x++]= atoi(ptr);
2194  ptr+= retstr - ptr + 1;
2195  }
2196  nptr[x++]= atoi(ptr);
2197 
2198  return count;
2199 }
2200 
2201 void print_conclusions(Conclusions &con)
2202 {
2203  printf("Benchmark\n");
2204  if (con.getEngine())
2205  printf("\tRunning for engine %s\n", con.getEngine());
2206 
2207  if (not opt_label.empty() || !opt_auto_generate_sql_type.empty())
2208  {
2209  const char *ptr= opt_auto_generate_sql_type.c_str() ? opt_auto_generate_sql_type.c_str() : "query";
2210  printf("\tLoad: %s\n", !opt_label.empty() ? opt_label.c_str() : ptr);
2211  }
2212  printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
2213  con.getCreateAvgTiming() / 1000, con.getCreateAvgTiming() % 1000);
2214  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2215  con.getAvgTiming() / 1000, con.getAvgTiming() % 1000);
2216  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2217  con.getMinTiming() / 1000, con.getMinTiming() % 1000);
2218  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2219  con.getMaxTiming() / 1000, con.getMaxTiming() % 1000);
2220  printf("\tTotal time for tests: %ld.%03ld seconds\n",
2221  con.getSumOfTime() / 1000, con.getSumOfTime() % 1000);
2222  printf("\tStandard Deviation: %ld.%03ld\n", con.getStdDev() / 1000, con.getStdDev() % 1000);
2223  printf("\tNumber of queries in create queries: %"PRIu64"\n", con.getCreateCount());
2224  printf("\tNumber of clients running queries: %u/%u\n",
2225  con.getUsers(), con.getRealUsers());
2226  printf("\tNumber of times test was run: %u\n", iterations);
2227  printf("\tAverage number of queries per client: %"PRIu64"\n", con.getAvgRows());
2228 
2229  uint64_t temp_val= failed_update_for_transaction;
2230  if (temp_val)
2231  printf("\tFailed number of updates %"PRIu64"\n", temp_val);
2232 
2233  printf("\n");
2234 }
2235 
2236 void print_conclusions_csv(Conclusions &con)
2237 {
2238  char buffer[HUGE_STRING_LENGTH];
2239  char label_buffer[HUGE_STRING_LENGTH];
2240  size_t string_len;
2241  const char *temp_label= opt_label.c_str();
2242 
2243  memset(label_buffer, 0, sizeof(label_buffer));
2244 
2245  if (not opt_label.empty())
2246  {
2247  string_len= opt_label.length();
2248 
2249  for (uint32_t x= 0; x < string_len; x++)
2250  {
2251  if (temp_label[x] == ',')
2252  label_buffer[x]= '-';
2253  else
2254  label_buffer[x]= temp_label[x] ;
2255  }
2256  }
2257  else if (not opt_auto_generate_sql_type.empty())
2258  {
2259  string_len= opt_auto_generate_sql_type.length();
2260 
2261  for (uint32_t x= 0; x < string_len; x++)
2262  {
2263  if (opt_auto_generate_sql_type[x] == ',')
2264  label_buffer[x]= '-';
2265  else
2266  label_buffer[x]= opt_auto_generate_sql_type[x] ;
2267  }
2268  }
2269  else
2270  {
2271  snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2272  }
2273 
2274  snprintf(buffer, HUGE_STRING_LENGTH,
2275  "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
2276  "%u,%u,%u,%"PRIu64"\n",
2277  con.getEngine() ? con.getEngine() : "", /* Storage engine we ran against */
2278  label_buffer, /* Load type */
2279  con.getAvgTiming() / 1000, con.getAvgTiming() % 1000, /* Time to load */
2280  con.getMinTiming() / 1000, con.getMinTiming() % 1000, /* Min time */
2281  con.getMaxTiming() / 1000, con.getMaxTiming() % 1000, /* Max time */
2282  con.getSumOfTime() / 1000, con.getSumOfTime() % 1000, /* Total time */
2283  con.getStdDev() / 1000, con.getStdDev() % 1000, /* Standard Deviation */
2284  iterations, /* Iterations */
2285  con.getUsers(), /* Children used max_timing */
2286  con.getRealUsers(), /* Children used max_timing */
2287  con.getAvgRows() /* Queries run */
2288  );
2289  size_t buff_len= strlen(buffer);
2290  ssize_t write_ret= write(csv_file, (unsigned char*) buffer, buff_len);
2291  if (write_ret != (ssize_t)buff_len)
2292  {
2293  fprintf(stderr, _("Unable to fully write %"PRIu64" bytes. "
2294  "Could only write %"PRId64"."), (uint64_t)write_ret,
2295  (int64_t)buff_len);
2296  exit(-1);
2297  }
2298 }
2299 
2300 void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2301 {
2302  Stats *ptr;
2303  uint32_t x;
2304 
2305  con->setMinTiming(sptr->getTiming());
2306  con->setMaxTiming(sptr->getTiming());
2307  con->setMinRows(sptr->getRows());
2308  con->setMaxRows(sptr->getRows());
2309 
2310  /* At the moment we assume uniform */
2311  con->setUsers(sptr->getUsers());
2312  con->setRealUsers(sptr->getRealUsers());
2313  con->setAvgRows(sptr->getRows());
2314 
2315  /* With no next, we know it is the last element that was malloced */
2316  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2317  {
2318  con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2319 
2320  if (ptr->getTiming() > con->getMaxTiming())
2321  con->setMaxTiming(ptr->getTiming());
2322  if (ptr->getTiming() < con->getMinTiming())
2323  con->setMinTiming(ptr->getTiming());
2324  }
2325  con->setSumOfTime(con->getAvgTiming());
2326  con->setAvgTiming(con->getAvgTiming()/iterations);
2327 
2328  if (eng && eng->getString())
2329  con->setEngine(eng->getString());
2330  else
2331  con->setEngine(NULL);
2332 
2333  standard_deviation(*con, sptr);
2334 
2335  /* Now we do the create time operations */
2336  con->setCreateMinTiming(sptr->getCreateTiming());
2337  con->setCreateMaxTiming(sptr->getCreateTiming());
2338 
2339  /* At the moment we assume uniform */
2340  con->setCreateCount(sptr->getCreateCount());
2341 
2342  /* With no next, we know it is the last element that was malloced */
2343  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2344  {
2345  con->setCreateAvgTiming(ptr->getCreateTiming()+con->getCreateAvgTiming());
2346 
2347  if (ptr->getCreateTiming() > con->getCreateMaxTiming())
2348  con->setCreateMaxTiming(ptr->getCreateTiming());
2349  if (ptr->getCreateTiming() < con->getCreateMinTiming())
2350  con->setCreateMinTiming(ptr->getCreateTiming());
2351  }
2352  con->setCreateAvgTiming(con->getCreateAvgTiming()/iterations);
2353 }
2354 
2355 void
2356 option_cleanup(OptionString *stmt)
2357 {
2358  OptionString *ptr, *nptr;
2359  if (not stmt)
2360  return;
2361 
2362  for (ptr= stmt; ptr; ptr= nptr)
2363  {
2364  nptr= ptr->getNext();
2365  delete ptr;
2366  }
2367 }
2368 
2369 void statement_cleanup(Statement *stmt)
2370 {
2371  Statement *ptr, *nptr;
2372  if (not stmt)
2373  return;
2374 
2375  for (ptr= stmt; ptr; ptr= nptr)
2376  {
2377  nptr= ptr->getNext();
2378  delete ptr;
2379  }
2380 }
2381 
2382 void slap_close(drizzle_con_st *con)
2383 {
2384  drizzle_free(drizzle_con_drizzle(con));
2385 }
2386 
2387 drizzle_con_st* slap_connect(bool connect_to_schema)
2388 {
2389  /* Connect to server */
2390  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
2391  int connect_error= 1;
2392  drizzle_return_t ret;
2393  drizzle_st *drizzle;
2394 
2395  if (opt_delayed_start)
2396  usleep(random()%opt_delayed_start);
2397 
2398  drizzle_con_st* con;
2399  if ((drizzle= drizzle_create()) == NULL or
2400  (con= drizzle_con_add_tcp(drizzle,
2401  host.c_str(), opt_drizzle_port,
2402  user.c_str(), opt_password.c_str(),
2403  connect_to_schema ? create_schema_string.c_str() : NULL,
2404  use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL)) == NULL)
2405  {
2406  fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2407  abort();
2408  }
2409 
2410  drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2411 
2412  if (opt_only_print)
2413  {
2414  return con;
2415  }
2416 
2417  for (uint32_t x= 0; x < 10; x++)
2418  {
2419  if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
2420  {
2421  /* Connect suceeded */
2422  connect_error= 0;
2423  break;
2424  }
2425  usleep(connection_retry_sleep);
2426  }
2427  if (connect_error)
2428  {
2429  fprintf(stderr,"%s: Error when connecting to server: %d %s\n", SLAP_NAME,
2430  ret, drizzle_con_error(con));
2431  abort();
2432  }
2433 
2434  return con;
2435 }
2436 
2437 void standard_deviation(Conclusions &con, Stats *sptr)
2438 {
2439  long int sum_of_squares;
2440  double the_catch;
2441  Stats *ptr;
2442 
2443  if (iterations == 1 || iterations == 0)
2444  {
2445  con.setStdDev(0);
2446  return;
2447  }
2448 
2449  uint32_t x;
2450  for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2451  {
2452  long int deviation;
2453 
2454  deviation= ptr->getTiming() - con.getAvgTiming();
2455  sum_of_squares+= deviation*deviation;
2456  }
2457 
2458  the_catch= sqrt((double)(sum_of_squares/(iterations -1)));
2459  con.setStdDev((long int)the_catch);
2460 }