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