1 /*
2 Copyright (c) 2005, 2015, Oracle and/or its affiliates.
3 Copyright (c) 2010, 2017, MariaDB
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; version 2 of the License.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
13
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1335 USA
17 */
18
19 /*
20 MySQL Slap
21
22 A simple program designed to work as if multiple clients querying the database,
23 then reporting the timing of each stage.
24
25 MySQL slap runs three stages:
26 1) Create schema,table, and optionally any SP or data you want to beign
27 the test with. (single client)
28 2) Load test (many clients)
29 3) Cleanup (disconnection, drop table if specified, single client)
30
31 Examples:
32
33 Supply your own create and query SQL statements, with 50 clients
34 querying (200 selects for each):
35
36 mysqlslap --delimiter=";" \
37 --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
38 --query="SELECT * FROM A" --concurrency=50 --iterations=200
39
40 Let the program build the query SQL statement with a table of two int
41 columns, three varchar columns, five clients querying (20 times each),
42 don't create the table or insert the data (using the previous test's
43 schema and data):
44
45 mysqlslap --concurrency=5 --iterations=20 \
46 --number-int-cols=2 --number-char-cols=3 \
47 --auto-generate-sql
48
49 Tell the program to load the create, insert and query SQL statements from
50 the specified files, where the create.sql file has multiple table creation
51 statements delimited by ';' and multiple insert statements delimited by ';'.
52 The --query file will have multiple queries delimited by ';', run all the
53 load statements, and then run all the queries in the query file
54 with five clients (five times each):
55
56 mysqlslap --concurrency=5 \
57 --iterations=5 --query=query.sql --create=create.sql \
58 --delimiter=";"
59
60 TODO:
61 Add language for better tests
62 String length for files and those put on the command line are not
63 setup to handle binary data.
64 More stats
65 Break up tests and run them on multiple hosts at once.
66 Allow output to be fed into a database directly.
67
68 */
69
70 #define SLAP_VERSION "1.0"
71
72 #define HUGE_STRING_LENGTH 8196
73 #define RAND_STRING_SIZE 126
74
75 /* Types */
76 #define SELECT_TYPE 0
77 #define UPDATE_TYPE 1
78 #define INSERT_TYPE 2
79 #define UPDATE_TYPE_REQUIRES_PREFIX 3
80 #define CREATE_TABLE_TYPE 4
81 #define SELECT_TYPE_REQUIRES_PREFIX 5
82 #define DELETE_TYPE_REQUIRES_PREFIX 6
83
84 #include "client_priv.h"
85 #include <mysqld_error.h>
86 #include <my_dir.h>
87 #include <signal.h>
88 #include <sslopt-vars.h>
89 #ifndef __WIN__
90 #include <sys/wait.h>
91 #endif
92 #include <ctype.h>
93 #include <welcome_copyright_notice.h> /* ORACLE_WELCOME_COPYRIGHT_NOTICE */
94
95 #ifdef __WIN__
96 #define srandom srand
97 #define random rand
98 #define snprintf _snprintf
99 #endif
100
101 #ifdef HAVE_SMEM
102 static char *shared_memory_base_name=0;
103 #endif
104
105 /* Global Thread counter */
106 uint thread_counter;
107 pthread_mutex_t counter_mutex;
108 pthread_cond_t count_threshhold;
109 uint master_wakeup;
110 pthread_mutex_t sleeper_mutex;
111 pthread_cond_t sleep_threshhold;
112
113 static char **defaults_argv;
114
115 char **primary_keys;
116 unsigned long long primary_keys_number_of;
117
118 static char *host= NULL, *opt_password= NULL, *user= NULL,
119 *user_supplied_query= NULL,
120 *user_supplied_pre_statements= NULL,
121 *user_supplied_post_statements= NULL,
122 *default_engine= NULL,
123 *pre_system= NULL,
124 *post_system= NULL,
125 *opt_mysql_unix_port= NULL,
126 *opt_init_command= NULL;
127 static char *opt_plugin_dir= 0, *opt_default_auth= 0;
128
129 const char *delimiter= "\n";
130
131 const char *create_schema_string= "mysqlslap";
132
133 static my_bool opt_preserve= TRUE, opt_no_drop= FALSE;
134 static my_bool debug_info_flag= 0, debug_check_flag= 0;
135 static my_bool opt_only_print= FALSE;
136 static my_bool opt_compress= FALSE, tty_password= FALSE,
137 opt_silent= FALSE,
138 auto_generate_sql_autoincrement= FALSE,
139 auto_generate_sql_guid_primary= FALSE,
140 auto_generate_sql= FALSE;
141 const char *auto_generate_sql_type= "mixed";
142
143 static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
144 CLIENT_MULTI_STATEMENTS |
145 CLIENT_REMEMBER_OPTIONS;
146
147 static int verbose;
148 static uint commit_rate;
149 static uint detach_rate;
150 const char *num_int_cols_opt;
151 const char *num_char_cols_opt;
152
153 /* Yes, we do set defaults here */
154 static unsigned int num_int_cols= 1;
155 static unsigned int num_char_cols= 1;
156 static unsigned int num_int_cols_index= 0;
157 static unsigned int num_char_cols_index= 0;
158 static unsigned int iterations;
159 static uint my_end_arg= 0;
160 static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME;
161 static ulonglong actual_queries= 0;
162 static ulonglong auto_actual_queries;
163 static ulonglong auto_generate_sql_unique_write_number;
164 static ulonglong auto_generate_sql_unique_query_number;
165 static unsigned int auto_generate_sql_secondary_indexes;
166 static ulonglong num_of_query;
167 static ulonglong auto_generate_sql_number;
168 const char *concurrency_str= NULL;
169 static char *create_string;
170 uint *concurrency;
171 static char mysql_charsets_dir[FN_REFLEN+1];
172
173 const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
174 const char *opt_csv_str;
175 File csv_file;
176
177 static uint opt_protocol= 0;
178
179 static int get_options(int *argc,char ***argv);
180 static uint opt_mysql_port= 0;
181
182 static const char *load_default_groups[]=
183 { "mysqlslap", "client", "client-server", "client-mariadb", 0 };
184
185 typedef struct statement statement;
186
187 struct statement {
188 char *string;
189 size_t length;
190 unsigned char type;
191 char *option;
192 size_t option_length;
193 statement *next;
194 };
195
196 typedef struct option_string option_string;
197
198 struct option_string {
199 char *string;
200 size_t length;
201 char *option;
202 size_t option_length;
203 option_string *next;
204 };
205
206 typedef struct stats stats;
207
208 struct stats {
209 long int timing;
210 uint users;
211 unsigned long long rows;
212 };
213
214 typedef struct thread_context thread_context;
215
216 struct thread_context {
217 statement *stmt;
218 ulonglong limit;
219 };
220
221 typedef struct conclusions conclusions;
222
223 struct conclusions {
224 char *engine;
225 long int avg_timing;
226 long int max_timing;
227 long int min_timing;
228 uint users;
229 unsigned long long avg_rows;
230 /* The following are not used yet */
231 unsigned long long max_rows;
232 unsigned long long min_rows;
233 };
234
235 static option_string *engine_options= NULL;
236 static statement *pre_statements= NULL;
237 static statement *post_statements= NULL;
238 static statement *create_statements= NULL,
239 *query_statements= NULL;
240
241 /* Prototypes */
242 void print_conclusions(conclusions *con);
243 void print_conclusions_csv(conclusions *con);
244 void generate_stats(conclusions *con, option_string *eng, stats *sptr);
245 uint parse_comma(const char *string, uint **range);
246 uint parse_delimiter(const char *script, statement **stmt, char delm);
247 int parse_option(const char *origin, option_string **stmt, char delm);
248 static int drop_schema(MYSQL *mysql, const char *db);
249 uint get_random_string(char *buf);
250 static statement *build_table_string(void);
251 static statement *build_insert_string(void);
252 static statement *build_update_string(void);
253 static statement * build_select_string(my_bool key);
254 static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt);
255 static int drop_primary_key_list(void);
256 static int create_schema(MYSQL *mysql, const char *db, statement *stmt,
257 option_string *engine_stmt);
258 static int run_scheduler(stats *sptr, statement *stmts, uint concur,
259 ulonglong limit);
260 pthread_handler_t run_task(void *p);
261 void statement_cleanup(statement *stmt);
262 void option_cleanup(option_string *stmt);
263 void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr);
264 static int run_statements(MYSQL *mysql, statement *stmt);
265 int slap_connect(MYSQL *mysql);
266 static int run_query(MYSQL *mysql, const char *query, size_t len);
267
268 static const char ALPHANUMERICS[]=
269 "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
270
271 #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
272
273
timedif(struct timeval a,struct timeval b)274 static long int timedif(struct timeval a, struct timeval b)
275 {
276 register int us, s;
277
278 us = a.tv_usec - b.tv_usec;
279 us /= 1000;
280 s = a.tv_sec - b.tv_sec;
281 s *= 1000;
282 return s + us;
283 }
284
285 #ifdef __WIN__
gettimeofday(struct timeval * tp,void * tzp)286 static int gettimeofday(struct timeval *tp, void *tzp)
287 {
288 unsigned int ticks;
289 ticks= GetTickCount();
290 tp->tv_usec= ticks*1000;
291 tp->tv_sec= ticks/1000;
292
293 return 0;
294 }
295 #endif
296
set_mysql_connect_options(MYSQL * mysql)297 void set_mysql_connect_options(MYSQL *mysql)
298 {
299 if (opt_compress)
300 mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
301 #ifdef HAVE_OPENSSL
302 if (opt_use_ssl)
303 {
304 mysql_ssl_set(mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
305 opt_ssl_capath, opt_ssl_cipher);
306 mysql_options(mysql, MYSQL_OPT_SSL_CRL, opt_ssl_crl);
307 mysql_options(mysql, MYSQL_OPT_SSL_CRLPATH, opt_ssl_crlpath);
308 }
309 #endif
310 if (opt_protocol)
311 mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
312 #ifdef HAVE_SMEM
313 if (shared_memory_base_name)
314 mysql_options(mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
315 #endif
316 mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
317 }
318
319
main(int argc,char ** argv)320 int main(int argc, char **argv)
321 {
322 MYSQL mysql;
323 option_string *eptr;
324
325 MY_INIT(argv[0]);
326 sf_leaking_memory=1; /* don't report memory leaks on early exits */
327
328 load_defaults_or_exit("my", load_default_groups, &argc, &argv);
329 defaults_argv=argv;
330 if (get_options(&argc,&argv))
331 {
332 free_defaults(defaults_argv);
333 my_end(0);
334 exit(1);
335 }
336 sf_leaking_memory=0; /* from now on we cleanup properly */
337
338 /* Seed the random number generator if we will be using it. */
339 if (auto_generate_sql)
340 srandom((uint)time(NULL));
341
342 if (argc > 2)
343 {
344 fprintf(stderr,"%s: Too many arguments\n",my_progname);
345 free_defaults(defaults_argv);
346 my_end(0);
347 exit(1);
348 }
349 mysql_init(&mysql);
350 set_mysql_connect_options(&mysql);
351
352 if (opt_plugin_dir && *opt_plugin_dir)
353 mysql_options(&mysql, MYSQL_PLUGIN_DIR, opt_plugin_dir);
354
355 if (opt_default_auth && *opt_default_auth)
356 mysql_options(&mysql, MYSQL_DEFAULT_AUTH, opt_default_auth);
357
358 mysql_options(&mysql, MYSQL_OPT_CONNECT_ATTR_RESET, 0);
359 mysql_options4(&mysql, MYSQL_OPT_CONNECT_ATTR_ADD,
360 "program_name", "mysqlslap");
361 if (!opt_only_print)
362 {
363 if (!(mysql_real_connect(&mysql, host, user, opt_password,
364 NULL, opt_mysql_port,
365 opt_mysql_unix_port, connect_flags)))
366 {
367 fprintf(stderr,"%s: Error when connecting to server: %s\n",
368 my_progname,mysql_error(&mysql));
369 mysql_close(&mysql);
370 free_defaults(defaults_argv);
371 my_end(0);
372 exit(1);
373 }
374 }
375
376 pthread_mutex_init(&counter_mutex, NULL);
377 pthread_cond_init(&count_threshhold, NULL);
378 pthread_mutex_init(&sleeper_mutex, NULL);
379 pthread_cond_init(&sleep_threshhold, NULL);
380
381 /* Main iterations loop */
382 eptr= engine_options;
383 do
384 {
385 /* For the final stage we run whatever queries we were asked to run */
386 uint *current;
387
388 if (verbose >= 2)
389 printf("Starting Concurrency Test\n");
390
391 if (*concurrency)
392 {
393 for (current= concurrency; current && *current; current++)
394 concurrency_loop(&mysql, *current, eptr);
395 }
396 else
397 {
398 uint infinite= 1;
399 do {
400 concurrency_loop(&mysql, infinite, eptr);
401 }
402 while (infinite++);
403 }
404
405 if (!opt_preserve)
406 drop_schema(&mysql, create_schema_string);
407
408 } while (eptr ? (eptr= eptr->next) : 0);
409
410 pthread_mutex_destroy(&counter_mutex);
411 pthread_cond_destroy(&count_threshhold);
412 pthread_mutex_destroy(&sleeper_mutex);
413 pthread_cond_destroy(&sleep_threshhold);
414
415 mysql_close(&mysql); /* Close & free connection */
416
417 /* now free all the strings we created */
418 my_free(opt_password);
419 my_free(concurrency);
420
421 statement_cleanup(create_statements);
422 statement_cleanup(query_statements);
423 statement_cleanup(pre_statements);
424 statement_cleanup(post_statements);
425 option_cleanup(engine_options);
426
427 #ifdef HAVE_SMEM
428 my_free(shared_memory_base_name);
429 #endif
430 free_defaults(defaults_argv);
431 mysql_library_end();
432 my_end(my_end_arg);
433
434 return 0;
435 }
436
concurrency_loop(MYSQL * mysql,uint current,option_string * eptr)437 void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
438 {
439 unsigned int x;
440 stats *head_sptr;
441 stats *sptr;
442 conclusions conclusion;
443 unsigned long long client_limit;
444 int sysret;
445
446 head_sptr= (stats *)my_malloc(sizeof(stats) * iterations,
447 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
448
449 bzero(&conclusion, sizeof(conclusions));
450
451 if (auto_actual_queries)
452 client_limit= auto_actual_queries;
453 else if (num_of_query)
454 client_limit= num_of_query / current;
455 else
456 client_limit= actual_queries;
457
458 for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
459 {
460 /*
461 We might not want to load any data, such as when we are calling
462 a stored_procedure that doesn't use data, or we know we already have
463 data in the table.
464 */
465 if (!opt_preserve)
466 drop_schema(mysql, create_schema_string);
467
468 /* First we create */
469 if (create_statements)
470 {
471 /*
472 If we have an --engine option, then we indicate
473 create_schema() to add the engine type to the DDL.
474 */
475 if (eptr)
476 create_statements->type= CREATE_TABLE_TYPE;
477
478 create_schema(mysql, create_schema_string, create_statements, eptr);
479 }
480
481 /*
482 If we generated GUID we need to build a list of them from creation that
483 we can later use.
484 */
485 if (verbose >= 2)
486 printf("Generating primary key list\n");
487 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
488 generate_primary_key_list(mysql, eptr);
489
490 if (commit_rate)
491 run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
492
493 if (pre_system && (sysret= system(pre_system)) != 0)
494 fprintf(stderr,
495 "Warning: Execution of pre_system option returned %d.\n",
496 sysret);
497
498 /*
499 Pre statements are always run after all other logic so they can
500 correct/adjust any item that they want.
501 */
502 if (pre_statements)
503 run_statements(mysql, pre_statements);
504
505 run_scheduler(sptr, query_statements, current, client_limit);
506
507 if (post_statements)
508 run_statements(mysql, post_statements);
509
510 if (post_system && (sysret= system(post_system)) != 0)
511 fprintf(stderr,
512 "Warning: Execution of post_system option returned %d.\n",
513 sysret);
514 /* We are finished with this run */
515 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
516 drop_primary_key_list();
517 }
518
519 if (verbose >= 2)
520 printf("Generating stats\n");
521
522 generate_stats(&conclusion, eptr, head_sptr);
523
524 if (!opt_silent)
525 print_conclusions(&conclusion);
526 if (opt_csv_str)
527 print_conclusions_csv(&conclusion);
528
529 my_free(head_sptr);
530
531 }
532
533
534 static struct my_option my_long_options[] =
535 {
536 {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
537 0, 0, 0, 0, 0, 0},
538 {"auto-generate-sql", 'a',
539 "Generate SQL where not supplied by file or command line.",
540 &auto_generate_sql, &auto_generate_sql,
541 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
542 {"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
543 "Add an AUTO_INCREMENT column to auto-generated tables.",
544 &auto_generate_sql_autoincrement,
545 &auto_generate_sql_autoincrement,
546 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
547 {"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
548 "Set this number to generate a set number of queries to run.",
549 &auto_actual_queries, &auto_actual_queries,
550 0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
551 {"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
552 "Add GUID based primary keys to auto-generated tables.",
553 &auto_generate_sql_guid_primary,
554 &auto_generate_sql_guid_primary,
555 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
556 {"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
557 "Specify test load type: mixed, update, write, key, or read; default is mixed.",
558 (char**) &auto_generate_sql_type, (char**) &auto_generate_sql_type,
559 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
560 {"auto-generate-sql-secondary-indexes",
561 OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
562 "Number of secondary indexes to add to auto-generated tables.",
563 &auto_generate_sql_secondary_indexes,
564 &auto_generate_sql_secondary_indexes, 0,
565 GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
566 {"auto-generate-sql-unique-query-number",
567 OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
568 "Number of unique queries to generate for automatic tests.",
569 &auto_generate_sql_unique_query_number,
570 &auto_generate_sql_unique_query_number,
571 0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
572 {"auto-generate-sql-unique-write-number",
573 OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
574 "Number of unique queries to generate for auto-generate-sql-write-number.",
575 &auto_generate_sql_unique_write_number,
576 &auto_generate_sql_unique_write_number,
577 0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
578 {"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
579 "Number of row inserts to perform for each thread (default is 100).",
580 &auto_generate_sql_number, &auto_generate_sql_number,
581 0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
582 {"character-sets-dir", OPT_CHARSETS_DIR,
583 "Directory for character set files.", (char **)&charsets_dir,
584 (char **)&charsets_dir, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
585 {"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
586 &commit_rate, &commit_rate, 0, GET_UINT, REQUIRED_ARG,
587 0, 0, 0, 0, 0, 0},
588 {"compress", 'C', "Use compression in server/client protocol.",
589 &opt_compress, &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
590 0, 0, 0},
591 {"concurrency", 'c', "Number of clients to simulate for query to run.",
592 (char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
593 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
594 {"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
595 &create_string, &create_string, 0, GET_STR, REQUIRED_ARG,
596 0, 0, 0, 0, 0, 0},
597 {"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
598 (char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR,
599 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
600 {"csv", OPT_SLAP_CSV,
601 "Generate CSV output to named file or to stdout if no file is named.",
602 NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
603 #ifdef DBUG_OFF
604 {"debug", '#', "This is a non-debug version. Catch this and exit.",
605 0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
606 #else
607 {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
608 (char**) &default_dbug_option, (char**) &default_dbug_option, 0, GET_STR,
609 OPT_ARG, 0, 0, 0, 0, 0, 0},
610 #endif
611 {"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
612 &debug_check_flag, &debug_check_flag, 0,
613 GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
614 {"debug-info", 'T', "Print some debug info at exit.", &debug_info_flag,
615 &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
616 {"default_auth", OPT_DEFAULT_AUTH,
617 "Default authentication client-side plugin to use.",
618 &opt_default_auth, &opt_default_auth, 0,
619 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
620 {"delimiter", 'F',
621 "Delimiter to use in SQL statements supplied in file or command line.",
622 (char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
623 0, 0, 0, 0, 0, 0},
624 {"detach", OPT_SLAP_DETACH,
625 "Detach (close and reopen) connections after X number of requests.",
626 &detach_rate, &detach_rate, 0, GET_UINT, REQUIRED_ARG,
627 0, 0, 0, 0, 0, 0},
628 {"engine", 'e',
629 "Comma separated list of storage engines to use for creating the table."
630 " The test is run for each engine. You can also specify an option for an "
631 "engine after a `:', like memory:max_row=2300",
632 &default_engine, &default_engine, 0,
633 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
634 {"host", 'h', "Connect to host.", &host, &host, 0, GET_STR,
635 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
636 {"init-command", OPT_INIT_COMMAND,
637 "SQL Command to execute when connecting to MySQL server. Will "
638 "automatically be re-executed when reconnecting.",
639 &opt_init_command, &opt_init_command, 0,
640 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
641 {"iterations", 'i', "Number of times to run the tests.", &iterations,
642 &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
643 {"no-drop", OPT_SLAP_NO_DROP, "Do not drop the schema after the test.",
644 &opt_no_drop, &opt_no_drop, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
645 {"number-char-cols", 'x',
646 "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
647 (char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
648 0, 0, 0, 0, 0, 0},
649 {"number-int-cols", 'y',
650 "Number of INT columns to create in table if specifying --auto-generate-sql.",
651 (char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
652 0, 0, 0, 0, 0, 0},
653 {"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
654 "Limit each client to this number of queries (this is not exact).",
655 &num_of_query, &num_of_query, 0,
656 GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
657 {"only-print", OPT_MYSQL_ONLY_PRINT,
658 "Do not connect to the databases, but instead print out what would have "
659 "been done.",
660 &opt_only_print, &opt_only_print, 0, GET_BOOL, NO_ARG,
661 0, 0, 0, 0, 0, 0},
662 {"password", 'p',
663 "Password to use when connecting to server. If password is not given it's "
664 "asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
665 #ifdef __WIN__
666 {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
667 NO_ARG, 0, 0, 0, 0, 0, 0},
668 #endif
669 {"plugin_dir", OPT_PLUGIN_DIR, "Directory for client-side plugins.",
670 &opt_plugin_dir, &opt_plugin_dir, 0,
671 GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
672 {"port", 'P', "Port number to use for connection.", &opt_mysql_port,
673 &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
674 0},
675 {"post-query", OPT_SLAP_POST_QUERY,
676 "Query to run or file containing query to execute after tests have completed.",
677 &user_supplied_post_statements, &user_supplied_post_statements,
678 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
679 {"post-system", OPT_SLAP_POST_SYSTEM,
680 "system() string to execute after tests have completed.",
681 &post_system, &post_system,
682 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
683 {"pre-query", OPT_SLAP_PRE_QUERY,
684 "Query to run or file containing query to execute before running tests.",
685 &user_supplied_pre_statements, &user_supplied_pre_statements,
686 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
687 {"pre-system", OPT_SLAP_PRE_SYSTEM,
688 "system() string to execute before running tests.",
689 &pre_system, &pre_system,
690 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
691 {"protocol", OPT_MYSQL_PROTOCOL,
692 "The protocol to use for connection (tcp, socket, pipe, memory).",
693 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
694 {"query", 'q', "Query to run or file containing query to run.",
695 &user_supplied_query, &user_supplied_query,
696 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
697 #ifdef HAVE_SMEM
698 {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
699 "Base name of shared memory.", &shared_memory_base_name,
700 &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
701 0, 0, 0, 0, 0, 0},
702 #endif
703 {"silent", 's', "Run program in silent mode - no output.",
704 &opt_silent, &opt_silent, 0, GET_BOOL, NO_ARG,
705 0, 0, 0, 0, 0, 0},
706 {"socket", 'S', "The socket file to use for connection.",
707 &opt_mysql_unix_port, &opt_mysql_unix_port, 0, GET_STR,
708 REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
709 #include <sslopt-longopts.h>
710 #ifndef DONT_ALLOW_USER_CHANGE
711 {"user", 'u', "User for login if not current user.", &user,
712 &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
713 #endif
714 {"verbose", 'v',
715 "More verbose output; you can use this multiple times to get even more "
716 "verbose output.", &verbose, &verbose, 0, GET_NO_ARG, NO_ARG,
717 0, 0, 0, 0, 0, 0},
718 {"version", 'V', "Output version information and exit.", 0, 0, 0,
719 GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
720 {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
721 };
722
723
print_version(void)724 static void print_version(void)
725 {
726 printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
727 MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
728 }
729
730
usage(void)731 static void usage(void)
732 {
733 print_version();
734 puts(ORACLE_WELCOME_COPYRIGHT_NOTICE("2005"));
735 puts("Run a query multiple times against the server.\n");
736 printf("Usage: %s [OPTIONS]\n",my_progname);
737 print_defaults("my",load_default_groups);
738 puts("");
739 my_print_help(my_long_options);
740 my_print_variables(my_long_options);
741 }
742
743
744 static my_bool
get_one_option(int optid,const struct my_option * opt,char * argument)745 get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
746 char *argument)
747 {
748 DBUG_ENTER("get_one_option");
749 switch(optid) {
750 case 'v':
751 verbose++;
752 break;
753 case 'p':
754 if (argument == disabled_my_option)
755 argument= (char*) ""; /* Don't require password */
756 if (argument)
757 {
758 char *start= argument;
759 my_free(opt_password);
760 opt_password= my_strdup(argument,MYF(MY_FAE));
761 while (*argument) *argument++= 'x'; /* Destroy argument */
762 if (*start)
763 start[1]= 0; /* Cut length of argument */
764 tty_password= 0;
765 }
766 else
767 tty_password= 1;
768 break;
769 case 'W':
770 #ifdef __WIN__
771 opt_protocol= MYSQL_PROTOCOL_PIPE;
772 #endif
773 break;
774 case OPT_MYSQL_PROTOCOL:
775 if ((opt_protocol= find_type_with_warning(argument, &sql_protocol_typelib,
776 opt->name)) <= 0)
777 {
778 sf_leaking_memory= 1; /* no memory leak reports here */
779 exit(1);
780 }
781 break;
782 case '#':
783 DBUG_PUSH(argument ? argument : default_dbug_option);
784 debug_check_flag= 1;
785 break;
786 case OPT_CHARSETS_DIR:
787 strmake_buf(mysql_charsets_dir, argument);
788 charsets_dir = mysql_charsets_dir;
789 break;
790 case OPT_SLAP_CSV:
791 if (!argument)
792 argument= (char *)"-"; /* use stdout */
793 opt_csv_str= argument;
794 break;
795 #include <sslopt-case.h>
796 case 'V':
797 print_version();
798 exit(0);
799 break;
800 case '?':
801 case 'I': /* Info */
802 usage();
803 exit(0);
804 }
805 DBUG_RETURN(0);
806 }
807
808
809 uint
get_random_string(char * buf)810 get_random_string(char *buf)
811 {
812 char *buf_ptr= buf;
813 int x;
814 DBUG_ENTER("get_random_string");
815 for (x= RAND_STRING_SIZE; x > 0; x--)
816 *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
817 DBUG_RETURN((uint)(buf_ptr - buf));
818 }
819
820
821 /*
822 build_table_string
823
824 This function builds a create table query if the user opts to not supply
825 a file or string containing a create table statement
826 */
827 static statement *
build_table_string(void)828 build_table_string(void)
829 {
830 char buf[HUGE_STRING_LENGTH];
831 unsigned int col_count;
832 statement *ptr;
833 DYNAMIC_STRING table_string;
834 DBUG_ENTER("build_table_string");
835
836 DBUG_PRINT("info", ("num int cols %u num char cols %u",
837 num_int_cols, num_char_cols));
838
839 init_dynamic_string(&table_string, "", 1024, 1024);
840
841 dynstr_append(&table_string, "CREATE TABLE `t1` (");
842
843 if (auto_generate_sql_autoincrement)
844 {
845 dynstr_append(&table_string, "id serial");
846
847 if (num_int_cols || num_char_cols)
848 dynstr_append(&table_string, ",");
849 }
850
851 if (auto_generate_sql_guid_primary)
852 {
853 dynstr_append(&table_string, "id varchar(36) primary key");
854
855 if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
856 dynstr_append(&table_string, ",");
857 }
858
859 if (auto_generate_sql_secondary_indexes)
860 {
861 unsigned int count;
862
863 for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
864 {
865 if (count) /* Except for the first pass we add a comma */
866 dynstr_append(&table_string, ",");
867
868 if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(36) unique key", count)
869 > HUGE_STRING_LENGTH)
870 {
871 fprintf(stderr, "Memory Allocation error in create table\n");
872 exit(1);
873 }
874 dynstr_append(&table_string, buf);
875 }
876
877 if (num_int_cols || num_char_cols)
878 dynstr_append(&table_string, ",");
879 }
880
881 if (num_int_cols)
882 for (col_count= 1; col_count <= num_int_cols; col_count++)
883 {
884 if (num_int_cols_index)
885 {
886 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)",
887 col_count, col_count) > HUGE_STRING_LENGTH)
888 {
889 fprintf(stderr, "Memory Allocation error in create table\n");
890 exit(1);
891 }
892 }
893 else
894 {
895 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count)
896 > HUGE_STRING_LENGTH)
897 {
898 fprintf(stderr, "Memory Allocation error in create table\n");
899 exit(1);
900 }
901 }
902 dynstr_append(&table_string, buf);
903
904 if (col_count < num_int_cols || num_char_cols > 0)
905 dynstr_append(&table_string, ",");
906 }
907
908 if (num_char_cols)
909 for (col_count= 1; col_count <= num_char_cols; col_count++)
910 {
911 if (num_char_cols_index)
912 {
913 if (snprintf(buf, HUGE_STRING_LENGTH,
914 "charcol%d VARCHAR(128), INDEX(charcol%d) ",
915 col_count, col_count) > HUGE_STRING_LENGTH)
916 {
917 fprintf(stderr, "Memory Allocation error in creating table\n");
918 exit(1);
919 }
920 }
921 else
922 {
923 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
924 col_count) > HUGE_STRING_LENGTH)
925 {
926 fprintf(stderr, "Memory Allocation error in creating table\n");
927 exit(1);
928 }
929 }
930 dynstr_append(&table_string, buf);
931
932 if (col_count < num_char_cols)
933 dynstr_append(&table_string, ",");
934 }
935
936 dynstr_append(&table_string, ")");
937 ptr= (statement *)my_malloc(sizeof(statement),
938 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
939 ptr->string = (char *)my_malloc(table_string.length+1,
940 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
941 ptr->length= table_string.length+1;
942 ptr->type= CREATE_TABLE_TYPE;
943 strmov(ptr->string, table_string.str);
944 dynstr_free(&table_string);
945 DBUG_RETURN(ptr);
946 }
947
948 /*
949 build_update_string()
950
951 This function builds insert statements when the user opts to not supply
952 an insert file or string containing insert data
953 */
954 static statement *
build_update_string(void)955 build_update_string(void)
956 {
957 char buf[HUGE_STRING_LENGTH];
958 unsigned int col_count;
959 statement *ptr;
960 DYNAMIC_STRING update_string;
961 DBUG_ENTER("build_update_string");
962
963 init_dynamic_string(&update_string, "", 1024, 1024);
964
965 dynstr_append(&update_string, "UPDATE t1 SET ");
966
967 if (num_int_cols)
968 for (col_count= 1; col_count <= num_int_cols; col_count++)
969 {
970 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
971 random()) > HUGE_STRING_LENGTH)
972 {
973 fprintf(stderr, "Memory Allocation error in creating update\n");
974 exit(1);
975 }
976 dynstr_append(&update_string, buf);
977
978 if (col_count < num_int_cols || num_char_cols > 0)
979 dynstr_append_mem(&update_string, ",", 1);
980 }
981
982 if (num_char_cols)
983 for (col_count= 1; col_count <= num_char_cols; col_count++)
984 {
985 char rand_buffer[RAND_STRING_SIZE];
986 int buf_len= get_random_string(rand_buffer);
987
988 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
989 buf_len, rand_buffer)
990 > HUGE_STRING_LENGTH)
991 {
992 fprintf(stderr, "Memory Allocation error in creating update\n");
993 exit(1);
994 }
995 dynstr_append(&update_string, buf);
996
997 if (col_count < num_char_cols)
998 dynstr_append_mem(&update_string, ",", 1);
999 }
1000
1001 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1002 dynstr_append(&update_string, " WHERE id = ");
1003
1004
1005 ptr= (statement *)my_malloc(sizeof(statement),
1006 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1007
1008 ptr->string= (char *)my_malloc(update_string.length + 1,
1009 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1010 ptr->length= update_string.length+1;
1011 if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1012 ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
1013 else
1014 ptr->type= UPDATE_TYPE;
1015
1016 strmov(ptr->string, update_string.str);
1017 dynstr_free(&update_string);
1018 DBUG_RETURN(ptr);
1019 }
1020
1021
1022 /*
1023 build_insert_string()
1024
1025 This function builds insert statements when the user opts to not supply
1026 an insert file or string containing insert data
1027 */
1028 static statement *
build_insert_string(void)1029 build_insert_string(void)
1030 {
1031 char buf[HUGE_STRING_LENGTH];
1032 unsigned int col_count;
1033 statement *ptr;
1034 DYNAMIC_STRING insert_string;
1035 DBUG_ENTER("build_insert_string");
1036
1037 init_dynamic_string(&insert_string, "", 1024, 1024);
1038
1039 dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
1040
1041 if (auto_generate_sql_autoincrement)
1042 {
1043 dynstr_append(&insert_string, "NULL");
1044
1045 if (num_int_cols || num_char_cols)
1046 dynstr_append(&insert_string, ",");
1047 }
1048
1049 if (auto_generate_sql_guid_primary)
1050 {
1051 dynstr_append(&insert_string, "uuid()");
1052
1053 if (num_int_cols || num_char_cols)
1054 dynstr_append(&insert_string, ",");
1055 }
1056
1057 if (auto_generate_sql_secondary_indexes)
1058 {
1059 unsigned int count;
1060
1061 for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1062 {
1063 if (count) /* Except for the first pass we add a comma */
1064 dynstr_append(&insert_string, ",");
1065
1066 dynstr_append(&insert_string, "uuid()");
1067 }
1068
1069 if (num_int_cols || num_char_cols)
1070 dynstr_append(&insert_string, ",");
1071 }
1072
1073 if (num_int_cols)
1074 for (col_count= 1; col_count <= num_int_cols; col_count++)
1075 {
1076 if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1077 {
1078 fprintf(stderr, "Memory Allocation error in creating insert\n");
1079 exit(1);
1080 }
1081 dynstr_append(&insert_string, buf);
1082
1083 if (col_count < num_int_cols || num_char_cols > 0)
1084 dynstr_append_mem(&insert_string, ",", 1);
1085 }
1086
1087 if (num_char_cols)
1088 for (col_count= 1; col_count <= num_char_cols; col_count++)
1089 {
1090 int buf_len= get_random_string(buf);
1091 dynstr_append_mem(&insert_string, "'", 1);
1092 dynstr_append_mem(&insert_string, buf, buf_len);
1093 dynstr_append_mem(&insert_string, "'", 1);
1094
1095 if (col_count < num_char_cols)
1096 dynstr_append_mem(&insert_string, ",", 1);
1097 }
1098
1099 dynstr_append_mem(&insert_string, ")", 1);
1100
1101 ptr= (statement *)my_malloc(sizeof(statement),
1102 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1103 ptr->string= (char *)my_malloc(insert_string.length + 1,
1104 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1105 ptr->length= insert_string.length+1;
1106 ptr->type= INSERT_TYPE;
1107 strmov(ptr->string, insert_string.str);
1108 dynstr_free(&insert_string);
1109 DBUG_RETURN(ptr);
1110 }
1111
1112
1113 /*
1114 build_select_string()
1115
1116 This function builds a query if the user opts to not supply a query
1117 statement or file containing a query statement
1118 */
1119 static statement *
build_select_string(my_bool key)1120 build_select_string(my_bool key)
1121 {
1122 char buf[HUGE_STRING_LENGTH];
1123 unsigned int col_count;
1124 statement *ptr;
1125 static DYNAMIC_STRING query_string;
1126 DBUG_ENTER("build_select_string");
1127
1128 init_dynamic_string(&query_string, "", 1024, 1024);
1129
1130 dynstr_append_mem(&query_string, "SELECT ", 7);
1131 for (col_count= 1; col_count <= num_int_cols; col_count++)
1132 {
1133 if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1134 > HUGE_STRING_LENGTH)
1135 {
1136 fprintf(stderr, "Memory Allocation error in creating select\n");
1137 exit(1);
1138 }
1139 dynstr_append(&query_string, buf);
1140
1141 if (col_count < num_int_cols || num_char_cols > 0)
1142 dynstr_append_mem(&query_string, ",", 1);
1143
1144 }
1145 for (col_count= 1; col_count <= num_char_cols; col_count++)
1146 {
1147 if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1148 > HUGE_STRING_LENGTH)
1149 {
1150 fprintf(stderr, "Memory Allocation error in creating select\n");
1151 exit(1);
1152 }
1153 dynstr_append(&query_string, buf);
1154
1155 if (col_count < num_char_cols)
1156 dynstr_append_mem(&query_string, ",", 1);
1157
1158 }
1159 dynstr_append(&query_string, " FROM t1");
1160
1161 if ((key) &&
1162 (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1163 dynstr_append(&query_string, " WHERE id = ");
1164
1165 ptr= (statement *)my_malloc(sizeof(statement),
1166 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1167 ptr->string= (char *)my_malloc(query_string.length + 1,
1168 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1169 ptr->length= query_string.length+1;
1170 if ((key) &&
1171 (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1172 ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1173 else
1174 ptr->type= SELECT_TYPE;
1175
1176 strmov(ptr->string, query_string.str);
1177 dynstr_free(&query_string);
1178 DBUG_RETURN(ptr);
1179 }
1180
1181 static int
get_options(int * argc,char *** argv)1182 get_options(int *argc,char ***argv)
1183 {
1184 int ho_error;
1185 char *tmp_string;
1186 MY_STAT sbuf; /* Stat information for the data file */
1187
1188 DBUG_ENTER("get_options");
1189 if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1190 exit(ho_error);
1191 if (debug_info_flag)
1192 my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1193 if (debug_check_flag)
1194 my_end_arg= MY_CHECK_ERROR;
1195
1196 /*
1197 If something is created and --no-drop is not specified, we drop the
1198 schema.
1199 */
1200 if (!opt_no_drop && (create_string || auto_generate_sql))
1201 opt_preserve= FALSE;
1202
1203 if (auto_generate_sql && (create_string || user_supplied_query))
1204 {
1205 fprintf(stderr,
1206 "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1207 my_progname);
1208 exit(1);
1209 }
1210
1211 if (auto_generate_sql && auto_generate_sql_guid_primary &&
1212 auto_generate_sql_autoincrement)
1213 {
1214 fprintf(stderr,
1215 "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1216 my_progname);
1217 exit(1);
1218 }
1219
1220 /*
1221 We are testing to make sure that if someone specified a key search
1222 that we actually added a key!
1223 */
1224 if (auto_generate_sql && auto_generate_sql_type[0] == 'k')
1225 if ( auto_generate_sql_autoincrement == FALSE &&
1226 auto_generate_sql_guid_primary == FALSE)
1227 {
1228 fprintf(stderr,
1229 "%s: Can't perform key test without a primary key!\n",
1230 my_progname);
1231 exit(1);
1232 }
1233
1234 if (auto_generate_sql && num_of_query && auto_actual_queries)
1235 {
1236 fprintf(stderr,
1237 "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1238 my_progname);
1239 exit(1);
1240 }
1241
1242 parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1243
1244 if (opt_csv_str)
1245 {
1246 opt_silent= TRUE;
1247
1248 if (opt_csv_str[0] == '-')
1249 {
1250 csv_file= my_fileno(stdout);
1251 }
1252 else
1253 {
1254 if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1255 == -1)
1256 {
1257 fprintf(stderr,"%s: Could not open csv file: %sn\n",
1258 my_progname, opt_csv_str);
1259 exit(1);
1260 }
1261 }
1262 }
1263
1264 if (opt_only_print)
1265 opt_silent= TRUE;
1266
1267 if (num_int_cols_opt)
1268 {
1269 option_string *str;
1270 if(parse_option(num_int_cols_opt, &str, ',') == -1)
1271 {
1272 fprintf(stderr, "Invalid value specified for the option "
1273 "'number-int-cols'\n");
1274 option_cleanup(str);
1275 return 1;
1276 }
1277 num_int_cols= atoi(str->string);
1278 if (str->option)
1279 num_int_cols_index= atoi(str->option);
1280
1281 option_cleanup(str);
1282 }
1283
1284 if (num_char_cols_opt)
1285 {
1286 option_string *str;
1287 if(parse_option(num_char_cols_opt, &str, ',') == -1)
1288 {
1289 fprintf(stderr, "Invalid value specified for the option "
1290 "'number-char-cols'\n");
1291 option_cleanup(str);
1292 return 1;
1293 }
1294 num_char_cols= atoi(str->string);
1295 if (str->option)
1296 num_char_cols_index= atoi(str->option);
1297 else
1298 num_char_cols_index= 0;
1299
1300 option_cleanup(str);
1301 }
1302
1303
1304 if (auto_generate_sql)
1305 {
1306 unsigned long long x= 0;
1307 statement *ptr_statement;
1308
1309 if (verbose >= 2)
1310 printf("Building Create Statements for Auto\n");
1311
1312 create_statements= build_table_string();
1313 /*
1314 Pre-populate table
1315 */
1316 for (ptr_statement= create_statements, x= 0;
1317 x < auto_generate_sql_unique_write_number;
1318 x++, ptr_statement= ptr_statement->next)
1319 {
1320 ptr_statement->next= build_insert_string();
1321 }
1322
1323 if (verbose >= 2)
1324 printf("Building Query Statements for Auto\n");
1325
1326 if (auto_generate_sql_type[0] == 'r')
1327 {
1328 if (verbose >= 2)
1329 printf("Generating SELECT Statements for Auto\n");
1330
1331 query_statements= build_select_string(FALSE);
1332 for (ptr_statement= query_statements, x= 0;
1333 x < auto_generate_sql_unique_query_number;
1334 x++, ptr_statement= ptr_statement->next)
1335 {
1336 ptr_statement->next= build_select_string(FALSE);
1337 }
1338 }
1339 else if (auto_generate_sql_type[0] == 'k')
1340 {
1341 if (verbose >= 2)
1342 printf("Generating SELECT for keys Statements for Auto\n");
1343
1344 query_statements= build_select_string(TRUE);
1345 for (ptr_statement= query_statements, x= 0;
1346 x < auto_generate_sql_unique_query_number;
1347 x++, ptr_statement= ptr_statement->next)
1348 {
1349 ptr_statement->next= build_select_string(TRUE);
1350 }
1351 }
1352 else if (auto_generate_sql_type[0] == 'w')
1353 {
1354 /*
1355 We generate a number of strings in case the engine is
1356 Archive (since strings which were identical one after another
1357 would be too easily optimized).
1358 */
1359 if (verbose >= 2)
1360 printf("Generating INSERT Statements for Auto\n");
1361 query_statements= build_insert_string();
1362 for (ptr_statement= query_statements, x= 0;
1363 x < auto_generate_sql_unique_query_number;
1364 x++, ptr_statement= ptr_statement->next)
1365 {
1366 ptr_statement->next= build_insert_string();
1367 }
1368 }
1369 else if (auto_generate_sql_type[0] == 'u')
1370 {
1371 query_statements= build_update_string();
1372 for (ptr_statement= query_statements, x= 0;
1373 x < auto_generate_sql_unique_query_number;
1374 x++, ptr_statement= ptr_statement->next)
1375 {
1376 ptr_statement->next= build_update_string();
1377 }
1378 }
1379 else /* Mixed mode is default */
1380 {
1381 int coin= 0;
1382
1383 query_statements= build_insert_string();
1384 /*
1385 This logic should be extended to do a more mixed load,
1386 at the moment it results in "every other".
1387 */
1388 for (ptr_statement= query_statements, x= 0;
1389 x < auto_generate_sql_unique_query_number;
1390 x++, ptr_statement= ptr_statement->next)
1391 {
1392 if (coin)
1393 {
1394 ptr_statement->next= build_insert_string();
1395 coin= 0;
1396 }
1397 else
1398 {
1399 ptr_statement->next= build_select_string(TRUE);
1400 coin= 1;
1401 }
1402 }
1403 }
1404 }
1405 else
1406 {
1407 if (create_string && my_stat(create_string, &sbuf, MYF(0)))
1408 {
1409 File data_file;
1410 if (!MY_S_ISREG(sbuf.st_mode))
1411 {
1412 fprintf(stderr,"%s: Create file was not a regular file\n",
1413 my_progname);
1414 exit(1);
1415 }
1416 if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1417 {
1418 fprintf(stderr,"%s: Could not open create file\n", my_progname);
1419 exit(1);
1420 }
1421 tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
1422 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1423 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1424 tmp_string[sbuf.st_size]= '\0';
1425 my_close(data_file,MYF(0));
1426 parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1427 my_free(tmp_string);
1428 }
1429 else if (create_string)
1430 {
1431 parse_delimiter(create_string, &create_statements, delimiter[0]);
1432 }
1433
1434 if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0)))
1435 {
1436 File data_file;
1437 if (!MY_S_ISREG(sbuf.st_mode))
1438 {
1439 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1440 my_progname);
1441 exit(1);
1442 }
1443 if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1444 {
1445 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1446 exit(1);
1447 }
1448 tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
1449 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1450 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1451 tmp_string[sbuf.st_size]= '\0';
1452 my_close(data_file,MYF(0));
1453 if (user_supplied_query)
1454 actual_queries= parse_delimiter(tmp_string, &query_statements,
1455 delimiter[0]);
1456 my_free(tmp_string);
1457 }
1458 else if (user_supplied_query)
1459 {
1460 actual_queries= parse_delimiter(user_supplied_query, &query_statements,
1461 delimiter[0]);
1462 }
1463 }
1464
1465 if (user_supplied_pre_statements && my_stat(user_supplied_pre_statements, &sbuf, MYF(0)))
1466 {
1467 File data_file;
1468 if (!MY_S_ISREG(sbuf.st_mode))
1469 {
1470 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1471 my_progname);
1472 exit(1);
1473 }
1474 if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1475 {
1476 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1477 exit(1);
1478 }
1479 tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
1480 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1481 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1482 tmp_string[sbuf.st_size]= '\0';
1483 my_close(data_file,MYF(0));
1484 if (user_supplied_pre_statements)
1485 (void)parse_delimiter(tmp_string, &pre_statements,
1486 delimiter[0]);
1487 my_free(tmp_string);
1488 }
1489 else if (user_supplied_pre_statements)
1490 {
1491 (void)parse_delimiter(user_supplied_pre_statements,
1492 &pre_statements,
1493 delimiter[0]);
1494 }
1495
1496 if (user_supplied_post_statements && my_stat(user_supplied_post_statements, &sbuf, MYF(0)))
1497 {
1498 File data_file;
1499 if (!MY_S_ISREG(sbuf.st_mode))
1500 {
1501 fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1502 my_progname);
1503 exit(1);
1504 }
1505 if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1506 {
1507 fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1508 exit(1);
1509 }
1510 tmp_string= (char *)my_malloc((size_t)sbuf.st_size + 1,
1511 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1512 my_read(data_file, (uchar*) tmp_string, (size_t)sbuf.st_size, MYF(0));
1513 tmp_string[sbuf.st_size]= '\0';
1514 my_close(data_file,MYF(0));
1515 if (user_supplied_post_statements)
1516 (void)parse_delimiter(tmp_string, &post_statements,
1517 delimiter[0]);
1518 my_free(tmp_string);
1519 }
1520 else if (user_supplied_post_statements)
1521 {
1522 (void)parse_delimiter(user_supplied_post_statements, &post_statements,
1523 delimiter[0]);
1524 }
1525
1526 if (verbose >= 2)
1527 printf("Parsing engines to use.\n");
1528
1529 if (default_engine)
1530 {
1531 if(parse_option(default_engine, &engine_options, ',') == -1)
1532 {
1533 fprintf(stderr, "Invalid value specified for the option 'engine'\n");
1534 return 1;
1535 }
1536 }
1537
1538 if (tty_password)
1539 opt_password= get_tty_password(NullS);
1540
1541 DBUG_RETURN(0);
1542 }
1543
1544
run_query(MYSQL * mysql,const char * query,size_t len)1545 static int run_query(MYSQL *mysql, const char *query, size_t len)
1546 {
1547 if (opt_only_print)
1548 {
1549 printf("%.*s;\n", (int)len, query);
1550 return 0;
1551 }
1552
1553 if (verbose >= 3)
1554 printf("%.*s;\n", (int)len, query);
1555
1556 return mysql_real_query(mysql, query, (ulong)len);
1557 }
1558
1559
1560 static int
generate_primary_key_list(MYSQL * mysql,option_string * engine_stmt)1561 generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1562 {
1563 MYSQL_RES *result;
1564 MYSQL_ROW row;
1565 unsigned long long counter;
1566 DBUG_ENTER("generate_primary_key_list");
1567
1568 /*
1569 Blackhole is a special case, this allows us to test the upper end
1570 of the server during load runs.
1571 */
1572 if (opt_only_print || (engine_stmt &&
1573 strstr(engine_stmt->string, "blackhole")))
1574 {
1575 primary_keys_number_of= 1;
1576 primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1577 primary_keys_number_of),
1578 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1579 /* Yes, we strdup a const string to simplify the interface */
1580 primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0));
1581 }
1582 else
1583 {
1584 if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1585 {
1586 fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1587 mysql_error(mysql));
1588 exit(1);
1589 }
1590
1591 if (!(result= mysql_store_result(mysql)))
1592 {
1593 fprintf(stderr, "%s: Error when storing result: %d %s\n",
1594 my_progname, mysql_errno(mysql), mysql_error(mysql));
1595 exit(1);
1596 }
1597 primary_keys_number_of= mysql_num_rows(result);
1598
1599 /* So why check this? Blackhole :) */
1600 if (primary_keys_number_of)
1601 {
1602 /*
1603 We create the structure and loop and create the items.
1604 */
1605 primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1606 primary_keys_number_of),
1607 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1608 row= mysql_fetch_row(result);
1609 for (counter= 0; counter < primary_keys_number_of;
1610 counter++, row= mysql_fetch_row(result))
1611 primary_keys[counter]= my_strdup(row[0], MYF(0));
1612 }
1613
1614 mysql_free_result(result);
1615 }
1616
1617 DBUG_RETURN(0);
1618 }
1619
1620 static int
drop_primary_key_list(void)1621 drop_primary_key_list(void)
1622 {
1623 unsigned long long counter;
1624
1625 if (primary_keys_number_of)
1626 {
1627 for (counter= 0; counter < primary_keys_number_of; counter++)
1628 my_free(primary_keys[counter]);
1629
1630 my_free(primary_keys);
1631 }
1632
1633 return 0;
1634 }
1635
1636 static int
create_schema(MYSQL * mysql,const char * db,statement * stmt,option_string * engine_stmt)1637 create_schema(MYSQL *mysql, const char *db, statement *stmt,
1638 option_string *engine_stmt)
1639 {
1640 char query[HUGE_STRING_LENGTH];
1641 statement *ptr;
1642 statement *after_create;
1643 int len;
1644 ulonglong count;
1645 DBUG_ENTER("create_schema");
1646
1647 len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1648
1649 if (verbose >= 2)
1650 printf("Loading Pre-data\n");
1651
1652 if (run_query(mysql, query, len))
1653 {
1654 fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1655 mysql_error(mysql));
1656 exit(1);
1657 }
1658
1659 if (opt_only_print)
1660 {
1661 printf("use %s;\n", db);
1662 }
1663 else
1664 {
1665 if (verbose >= 3)
1666 printf("%s;\n", query);
1667
1668 if (mysql_select_db(mysql, db))
1669 {
1670 fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1671 mysql_error(mysql));
1672 exit(1);
1673 }
1674 }
1675
1676 count= 0;
1677 after_create= stmt;
1678
1679 limit_not_met:
1680 for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1681 {
1682 if (auto_generate_sql && ( auto_generate_sql_number == count))
1683 break;
1684
1685 if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1686 {
1687 char buffer[HUGE_STRING_LENGTH];
1688
1689 snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s %s",
1690 ptr->string, engine_stmt->string, engine_stmt->option);
1691 if (run_query(mysql, buffer, strlen(buffer)))
1692 {
1693 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1694 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1695 exit(1);
1696 }
1697 }
1698 else if (engine_stmt && engine_stmt->string && ptr->type == CREATE_TABLE_TYPE)
1699 {
1700 char buffer[HUGE_STRING_LENGTH];
1701
1702 snprintf(buffer, HUGE_STRING_LENGTH, "%s Engine = %s",
1703 ptr->string, engine_stmt->string);
1704 if (run_query(mysql, buffer, strlen(buffer)))
1705 {
1706 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1707 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1708 exit(1);
1709 }
1710 }
1711 else
1712 {
1713 if (run_query(mysql, ptr->string, ptr->length))
1714 {
1715 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1716 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1717 exit(1);
1718 }
1719 }
1720 }
1721
1722 if (auto_generate_sql && (auto_generate_sql_number > count ))
1723 {
1724 /* Special case for auto create, we don't want to create tables twice */
1725 after_create= stmt->next;
1726 goto limit_not_met;
1727 }
1728
1729 DBUG_RETURN(0);
1730 }
1731
1732 static int
drop_schema(MYSQL * mysql,const char * db)1733 drop_schema(MYSQL *mysql, const char *db)
1734 {
1735 char query[HUGE_STRING_LENGTH];
1736 int len;
1737
1738 DBUG_ENTER("drop_schema");
1739 len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1740
1741 if (run_query(mysql, query, len))
1742 {
1743 fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1744 my_progname, db, mysql_error(mysql));
1745 exit(1);
1746 }
1747
1748
1749
1750 DBUG_RETURN(0);
1751 }
1752
1753 static int
run_statements(MYSQL * mysql,statement * stmt)1754 run_statements(MYSQL *mysql, statement *stmt)
1755 {
1756 statement *ptr;
1757 MYSQL_RES *result;
1758 DBUG_ENTER("run_statements");
1759
1760 for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1761 {
1762 if (run_query(mysql, ptr->string, ptr->length))
1763 {
1764 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1765 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1766 exit(1);
1767 }
1768 if (mysql_field_count(mysql))
1769 {
1770 result= mysql_store_result(mysql);
1771 mysql_free_result(result);
1772 }
1773 }
1774
1775 DBUG_RETURN(0);
1776 }
1777
1778 static int
run_scheduler(stats * sptr,statement * stmts,uint concur,ulonglong limit)1779 run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit)
1780 {
1781 uint x;
1782 struct timeval start_time, end_time;
1783 thread_context con;
1784 pthread_t mainthread; /* Thread descriptor */
1785 pthread_attr_t attr; /* Thread attributes */
1786 DBUG_ENTER("run_scheduler");
1787
1788 con.stmt= stmts;
1789 con.limit= limit;
1790
1791 pthread_attr_init(&attr);
1792 pthread_attr_setdetachstate(&attr,
1793 PTHREAD_CREATE_DETACHED);
1794
1795 pthread_mutex_lock(&counter_mutex);
1796 thread_counter= 0;
1797
1798 pthread_mutex_lock(&sleeper_mutex);
1799 master_wakeup= 1;
1800 pthread_mutex_unlock(&sleeper_mutex);
1801 for (x= 0; x < concur; x++)
1802 {
1803 /* now you create the thread */
1804 if (pthread_create(&mainthread, &attr, run_task,
1805 (void *)&con) != 0)
1806 {
1807 fprintf(stderr,"%s: Could not create thread\n",
1808 my_progname);
1809 exit(0);
1810 }
1811 thread_counter++;
1812 }
1813 pthread_mutex_unlock(&counter_mutex);
1814 pthread_attr_destroy(&attr);
1815
1816 pthread_mutex_lock(&sleeper_mutex);
1817 master_wakeup= 0;
1818 pthread_cond_broadcast(&sleep_threshhold);
1819 pthread_mutex_unlock(&sleeper_mutex);
1820
1821 gettimeofday(&start_time, NULL);
1822
1823 /*
1824 We loop until we know that all children have cleaned up.
1825 */
1826 pthread_mutex_lock(&counter_mutex);
1827 while (thread_counter)
1828 {
1829 struct timespec abstime;
1830
1831 set_timespec(abstime, 3);
1832 pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1833 }
1834 pthread_mutex_unlock(&counter_mutex);
1835
1836 gettimeofday(&end_time, NULL);
1837
1838
1839 sptr->timing= timedif(end_time, start_time);
1840 sptr->users= concur;
1841 sptr->rows= limit;
1842
1843 DBUG_RETURN(0);
1844 }
1845
1846
run_task(void * p)1847 pthread_handler_t run_task(void *p)
1848 {
1849 ulonglong counter= 0, queries;
1850 ulonglong detach_counter;
1851 unsigned int commit_counter;
1852 MYSQL *mysql;
1853 MYSQL_RES *result;
1854 MYSQL_ROW row;
1855 statement *ptr;
1856 thread_context *con= (thread_context *)p;
1857
1858 DBUG_ENTER("run_task");
1859 DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : ""));
1860
1861 pthread_mutex_lock(&sleeper_mutex);
1862 while (master_wakeup)
1863 {
1864 pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
1865 }
1866 pthread_mutex_unlock(&sleeper_mutex);
1867
1868 if (mysql_thread_init())
1869 {
1870 fprintf(stderr,"%s: mysql_thread_init() failed\n", my_progname);
1871 exit(0);
1872 }
1873
1874 if (!(mysql= mysql_init(NULL)))
1875 {
1876 fprintf(stderr,"%s: mysql_init() failed\n", my_progname);
1877 mysql_thread_end();
1878 exit(0);
1879 }
1880
1881 set_mysql_connect_options(mysql);
1882
1883 DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user));
1884
1885 if (!opt_only_print)
1886 {
1887 if (slap_connect(mysql))
1888 goto end;
1889 }
1890
1891 DBUG_PRINT("info", ("connected."));
1892 if (verbose >= 3)
1893 printf("connected!\n");
1894 queries= 0;
1895
1896 commit_counter= 0;
1897 if (commit_rate)
1898 run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
1899
1900 limit_not_met:
1901 for (ptr= con->stmt, detach_counter= 0;
1902 ptr && ptr->length;
1903 ptr= ptr->next, detach_counter++)
1904 {
1905 if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
1906 {
1907 mysql_close(mysql);
1908
1909 if (!(mysql= mysql_init(NULL)))
1910 {
1911 fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1912 my_progname, mysql_error(mysql));
1913 exit(0);
1914 }
1915 if (slap_connect(mysql))
1916 goto end;
1917 }
1918
1919 /*
1920 We have to execute differently based on query type. This should become a function.
1921 */
1922 if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
1923 (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
1924 {
1925 int length;
1926 unsigned int key_val;
1927 char *key;
1928 char buffer[HUGE_STRING_LENGTH];
1929
1930 /*
1931 This should only happen if some sort of new engine was
1932 implemented that didn't properly handle UPDATEs.
1933
1934 Just in case someone runs this under an experimental engine we don't
1935 want a crash so the if() is placed here.
1936 */
1937 DBUG_ASSERT(primary_keys_number_of);
1938 if (primary_keys_number_of)
1939 {
1940 key_val= (unsigned int)(random() % primary_keys_number_of);
1941 key= primary_keys[key_val];
1942
1943 DBUG_ASSERT(key);
1944
1945 length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
1946 (int)ptr->length, ptr->string, key);
1947
1948 if (run_query(mysql, buffer, length))
1949 {
1950 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1951 my_progname, (uint)length, buffer, mysql_error(mysql));
1952 exit(0);
1953 }
1954 }
1955 }
1956 else
1957 {
1958 if (run_query(mysql, ptr->string, ptr->length))
1959 {
1960 fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1961 my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1962 exit(0);
1963 }
1964 }
1965
1966 do
1967 {
1968 if (mysql_field_count(mysql))
1969 {
1970 if (!(result= mysql_store_result(mysql)))
1971 fprintf(stderr, "%s: Error when storing result: %d %s\n",
1972 my_progname, mysql_errno(mysql), mysql_error(mysql));
1973 else
1974 {
1975 while ((row= mysql_fetch_row(result)))
1976 counter++;
1977 mysql_free_result(result);
1978 }
1979 }
1980 } while(mysql_next_result(mysql) == 0);
1981 queries++;
1982
1983 if (commit_rate && (++commit_counter == commit_rate))
1984 {
1985 commit_counter= 0;
1986 run_query(mysql, "COMMIT", strlen("COMMIT"));
1987 }
1988
1989 if (con->limit && queries == con->limit)
1990 goto end;
1991 }
1992
1993 if (con->limit && queries < con->limit)
1994 goto limit_not_met;
1995
1996 end:
1997 if (commit_rate)
1998 run_query(mysql, "COMMIT", strlen("COMMIT"));
1999
2000 mysql_close(mysql);
2001
2002 mysql_thread_end();
2003
2004 pthread_mutex_lock(&counter_mutex);
2005 thread_counter--;
2006 pthread_cond_signal(&count_threshhold);
2007 pthread_mutex_unlock(&counter_mutex);
2008
2009 DBUG_RETURN(0);
2010 }
2011
2012 int
parse_option(const char * origin,option_string ** stmt,char delm)2013 parse_option(const char *origin, option_string **stmt, char delm)
2014 {
2015 char *retstr;
2016 char *ptr= (char *)origin;
2017 option_string **sptr= stmt;
2018 option_string *tmp;
2019 size_t length= strlen(origin);
2020 uint count= 0; /* We know that there is always one */
2021
2022 for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
2023 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2024 (retstr= strchr(ptr, delm));
2025 tmp->next= (option_string *)my_malloc(sizeof(option_string),
2026 MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2027 tmp= tmp->next)
2028 {
2029 /*
2030 Initialize buffer, because otherwise an
2031 --engine=<storage_engine>:<option>,<eng1>,<eng2>
2032 will crash.
2033 */
2034 char buffer[HUGE_STRING_LENGTH]= "";
2035 char *buffer_ptr;
2036
2037 /*
2038 Return an error if the length of the any of the comma seprated value
2039 exceeds HUGE_STRING_LENGTH.
2040 */
2041 if ((size_t)(retstr - ptr) > HUGE_STRING_LENGTH)
2042 return -1;
2043
2044 count++;
2045 strncpy(buffer, ptr, (size_t)(retstr - ptr));
2046 /*
2047 Handle --engine=memory:max_row=200 cases, or more general speaking
2048 --engine=<storage_engine>:<options>, which will be translated to
2049 Engine = storage_engine option.
2050 */
2051 if ((buffer_ptr= strchr(buffer, ':')))
2052 {
2053 char *option_ptr;
2054
2055 tmp->length= (size_t)(buffer_ptr - buffer);
2056 tmp->string= my_strndup(ptr, (uint)tmp->length, MYF(MY_FAE));
2057
2058 option_ptr= ptr + 1 + tmp->length;
2059
2060 /* Move past the : and the first string */
2061 tmp->option_length= (size_t)(retstr - option_ptr);
2062 tmp->option= my_strndup(option_ptr, (uint)tmp->option_length,
2063 MYF(MY_FAE));
2064 }
2065 else
2066 {
2067 tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
2068 tmp->length= (size_t)(retstr - ptr);
2069 }
2070
2071 /* Skip delimiter delm */
2072 ptr+= retstr - ptr + 1;
2073 if (isspace(*ptr))
2074 ptr++;
2075
2076 count++;
2077 }
2078
2079 if (ptr != origin + length)
2080 {
2081 char *origin_ptr;
2082
2083 /*
2084 Return an error if the length of the any of the comma seprated value
2085 exceeds HUGE_STRING_LENGTH.
2086 */
2087 if (strlen(ptr) > HUGE_STRING_LENGTH)
2088 return -1;
2089
2090 if ((origin_ptr= strchr(ptr, ':')))
2091 {
2092 char *option_ptr;
2093
2094 tmp->length= (size_t)(origin_ptr - ptr);
2095 tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
2096
2097 option_ptr= (char *)ptr + 1 + tmp->length;
2098
2099 /* Move past the : and the first string */
2100 tmp->option_length= strlen(option_ptr);
2101 tmp->option= my_strndup(option_ptr, tmp->option_length,
2102 MYF(MY_FAE));
2103 }
2104 else
2105 {
2106 tmp->length= strlen(ptr);
2107 tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
2108 }
2109
2110 count++;
2111 }
2112
2113 return count;
2114 }
2115
2116
2117 uint
parse_delimiter(const char * script,statement ** stmt,char delm)2118 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 size_t length= strlen(script);
2125 uint count= 0; /* We know that there is always one */
2126
2127 for (tmp= *sptr= (statement *)my_malloc(sizeof(statement),
2128 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2129 (retstr= strchr(ptr, delm));
2130 tmp->next= (statement *)my_malloc(sizeof(statement),
2131 MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2132 tmp= tmp->next)
2133 {
2134 count++;
2135 tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE));
2136 tmp->length= (size_t)(retstr - ptr);
2137 ptr+= retstr - ptr + 1;
2138 if (isspace(*ptr))
2139 ptr++;
2140 }
2141
2142 if (ptr != script+length)
2143 {
2144 tmp->string= my_strndup(ptr, (uint)((script + length) - ptr),
2145 MYF(MY_FAE));
2146 tmp->length= (size_t)((script + length) - ptr);
2147 count++;
2148 }
2149
2150 return count;
2151 }
2152
2153
2154 uint
parse_comma(const char * string,uint ** range)2155 parse_comma(const char *string, uint **range)
2156 {
2157 uint count= 1,x; /* We know that there is always one */
2158 char *retstr;
2159 char *ptr= (char *)string;
2160 uint *nptr;
2161
2162 for (;*ptr; ptr++)
2163 if (*ptr == ',') count++;
2164
2165 /* One extra spot for the NULL */
2166 nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1),
2167 MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2168
2169 ptr= (char *)string;
2170 x= 0;
2171 while ((retstr= strchr(ptr,',')))
2172 {
2173 nptr[x++]= atoi(ptr);
2174 ptr+= retstr - ptr + 1;
2175 }
2176 nptr[x++]= atoi(ptr);
2177
2178 return count;
2179 }
2180
2181 void
print_conclusions(conclusions * con)2182 print_conclusions(conclusions *con)
2183 {
2184 printf("Benchmark\n");
2185 if (con->engine)
2186 printf("\tRunning for engine %s\n", con->engine);
2187 printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2188 con->avg_timing / 1000, con->avg_timing % 1000);
2189 printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2190 con->min_timing / 1000, con->min_timing % 1000);
2191 printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2192 con->max_timing / 1000, con->max_timing % 1000);
2193 printf("\tNumber of clients running queries: %d\n", con->users);
2194 printf("\tAverage number of queries per client: %llu\n", con->avg_rows);
2195 printf("\n");
2196 }
2197
2198 void
print_conclusions_csv(conclusions * con)2199 print_conclusions_csv(conclusions *con)
2200 {
2201 char buffer[HUGE_STRING_LENGTH];
2202 const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query";
2203
2204 snprintf(buffer, HUGE_STRING_LENGTH,
2205 "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
2206 con->engine ? con->engine : "", /* Storage engine we ran against */
2207 ptr, /* Load type */
2208 con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2209 con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2210 con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2211 con->users, /* Children used */
2212 con->avg_rows /* Queries run */
2213 );
2214 my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2215 }
2216
2217 void
generate_stats(conclusions * con,option_string * eng,stats * sptr)2218 generate_stats(conclusions *con, option_string *eng, stats *sptr)
2219 {
2220 stats *ptr;
2221 unsigned int x;
2222
2223 con->min_timing= sptr->timing;
2224 con->max_timing= sptr->timing;
2225 con->min_rows= sptr->rows;
2226 con->max_rows= sptr->rows;
2227
2228 /* At the moment we assume uniform */
2229 con->users= sptr->users;
2230 con->avg_rows= sptr->rows;
2231
2232 /* With no next, we know it is the last element that was malloced */
2233 for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2234 {
2235 con->avg_timing+= ptr->timing;
2236
2237 if (ptr->timing > con->max_timing)
2238 con->max_timing= ptr->timing;
2239 if (ptr->timing < con->min_timing)
2240 con->min_timing= ptr->timing;
2241 }
2242 con->avg_timing= con->avg_timing/iterations;
2243
2244 if (eng && eng->string)
2245 con->engine= eng->string;
2246 else
2247 con->engine= NULL;
2248 }
2249
2250 void
option_cleanup(option_string * stmt)2251 option_cleanup(option_string *stmt)
2252 {
2253 option_string *ptr, *nptr;
2254 if (!stmt)
2255 return;
2256
2257 for (ptr= stmt; ptr; ptr= nptr)
2258 {
2259 nptr= ptr->next;
2260 my_free(ptr->string);
2261 my_free(ptr->option);
2262 my_free(ptr);
2263 }
2264 }
2265
2266 void
statement_cleanup(statement * stmt)2267 statement_cleanup(statement *stmt)
2268 {
2269 statement *ptr, *nptr;
2270 if (!stmt)
2271 return;
2272
2273 for (ptr= stmt; ptr; ptr= nptr)
2274 {
2275 nptr= ptr->next;
2276 my_free(ptr->string);
2277 my_free(ptr);
2278 }
2279 }
2280
2281
2282 int
slap_connect(MYSQL * mysql)2283 slap_connect(MYSQL *mysql)
2284 {
2285 /* Connect to server */
2286 static ulong connection_retry_sleep= 100000; /* Microseconds */
2287 int x, connect_error= 1;
2288 for (x= 0; x < 10; x++)
2289 {
2290 set_mysql_connect_options(mysql);
2291 if (opt_init_command)
2292 mysql_options(mysql, MYSQL_INIT_COMMAND, opt_init_command);
2293 if (mysql_real_connect(mysql, host, user, opt_password,
2294 create_schema_string,
2295 opt_mysql_port,
2296 opt_mysql_unix_port,
2297 connect_flags))
2298 {
2299 /* Connect succeeded */
2300 connect_error= 0;
2301 break;
2302 }
2303 my_sleep(connection_retry_sleep);
2304 }
2305 if (connect_error)
2306 {
2307 fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2308 my_progname, mysql_errno(mysql), mysql_error(mysql));
2309 return 1;
2310 }
2311
2312 return 0;
2313 }
2314