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