1
/* Copyright (C) 2005 MySQL AB, 2009 Sun Microsystems, Inc.
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
16
original idea: Brian Aker via playing with ab for too many years
17
coded by: Patrick Galbraith
24
A simple program designed to work as if multiple clients querying the database,
25
then reporting the timing of each stage.
27
MySQL slap runs three stages:
28
1) Create schema,table, and optionally any SP or data you want to beign
29
the test with. (single client)
30
2) Load test (many clients)
31
3) Cleanup (disconnection, drop table if specified, single client)
35
Supply your own create and query SQL statements, with 50 clients
36
querying (200 selects for each):
38
mysqlslap --delimiter=";" \
39
--create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
40
--query="SELECT * FROM A" --concurrency=50 --iterations=200
42
Let the program build the query SQL statement with a table of two int
43
columns, three varchar columns, five clients querying (20 times each),
44
don't create the table or insert the data (using the previous test's
47
mysqlslap --concurrency=5 --iterations=20 \
48
--number-int-cols=2 --number-char-cols=3 \
51
Tell the program to load the create, insert and query SQL statements from
52
the specified files, where the create.sql file has multiple table creation
53
statements delimited by ';' and multiple insert statements delimited by ';'.
54
The --query file will have multiple queries delimited by ';', run all the
55
load statements, and then run all the queries in the query file
56
with five clients (five times each):
58
mysqlslap --concurrency=5 \
59
--iterations=5 --query=query.sql --create=create.sql \
63
Add language for better tests
64
String length for files and those put on the command line are not
65
setup to handle binary data.
67
Break up tests and run them on multiple hosts at once.
68
Allow output to be fed into a database directly.
72
#define SLAP_VERSION "1.0"
74
#define HUGE_STRING_LENGTH 8196
75
#define RAND_STRING_SIZE 126
81
#define UPDATE_TYPE_REQUIRES_PREFIX 3
82
#define CREATE_TABLE_TYPE 4
83
#define SELECT_TYPE_REQUIRES_PREFIX 5
84
#define DELETE_TYPE_REQUIRES_PREFIX 6
86
#include "client_priv.h"
87
#include <mysqld_error.h>
91
#include <sslopt-vars.h>
92
#include <sys/types.h>
101
#define snprintf _snprintf
105
static char *shared_memory_base_name=0;
108
/* Global Thread counter */
110
pthread_mutex_t counter_mutex;
111
pthread_cond_t count_threshhold;
113
pthread_mutex_t sleeper_mutex;
114
pthread_cond_t sleep_threshhold;
116
static char **defaults_argv;
119
unsigned long long primary_keys_number_of;
121
static char *host= NULL, *opt_password= NULL, *user= NULL,
122
*user_supplied_query= NULL,
123
*user_supplied_pre_statements= NULL,
124
*user_supplied_post_statements= NULL,
125
*default_engine= NULL,
128
*opt_mysql_unix_port= NULL;
130
const char *delimiter= "\n";
132
const char *create_schema_string= "mysqlslap";
134
static my_bool opt_preserve= TRUE;
135
static my_bool debug_info_flag= 0, debug_check_flag= 0;
136
static my_bool opt_only_print= FALSE;
137
static my_bool opt_compress= FALSE, tty_password= FALSE,
139
auto_generate_sql_autoincrement= FALSE,
140
auto_generate_sql_guid_primary= FALSE,
141
auto_generate_sql= FALSE;
142
const char *auto_generate_sql_type= "mixed";
144
static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
145
CLIENT_MULTI_STATEMENTS;
147
static int verbose, delimiter_length;
148
static uint commit_rate;
149
static uint detach_rate;
150
const char *num_int_cols_opt;
151
const char *num_char_cols_opt;
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;
172
const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
173
const char *opt_csv_str;
176
static uint opt_protocol= 0;
178
static int get_options(int *argc,char ***argv);
179
static uint opt_mysql_port= 0;
181
static const char *load_default_groups[]= { "mysqlslap","client",0 };
183
typedef struct statement statement;
190
size_t option_length;
194
typedef struct option_string option_string;
196
struct option_string {
200
size_t option_length;
204
typedef struct stats stats;
209
unsigned long long rows;
212
typedef struct thread_context thread_context;
214
struct thread_context {
219
typedef struct conclusions conclusions;
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;
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;
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
uint 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,
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, int len);
266
static const char ALPHANUMERICS[]=
267
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
269
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
272
static long int timedif(struct timeval a, struct timeval b)
276
us = a.tv_usec - b.tv_usec;
278
s = a.tv_sec - b.tv_sec;
284
static int gettimeofday(struct timeval *tp, void *tzp)
287
ticks= GetTickCount();
288
tp->tv_usec= ticks*1000;
289
tp->tv_sec= ticks/1000;
295
int main(int argc, char **argv)
302
load_defaults("my",load_default_groups,&argc,&argv);
304
if (get_options(&argc,&argv))
306
free_defaults(defaults_argv);
311
/* Seed the random number generator if we will be using it. */
312
if (auto_generate_sql)
313
srandom((uint)time(NULL));
315
/* globals? Yes, so we only have to run strlen once */
316
delimiter_length= strlen(delimiter);
320
fprintf(stderr,"%s: Too many arguments\n",my_progname);
321
free_defaults(defaults_argv);
327
mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS);
330
mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca,
331
opt_ssl_capath, opt_ssl_cipher);
334
mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
336
if (shared_memory_base_name)
337
mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name);
339
mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset);
343
if (!(mysql_real_connect(&mysql, host, user, opt_password,
344
NULL, opt_mysql_port,
345
opt_mysql_unix_port, connect_flags)))
347
fprintf(stderr,"%s: Error when connecting to server: %s\n",
348
my_progname,mysql_error(&mysql));
349
free_defaults(defaults_argv);
355
VOID(pthread_mutex_init(&counter_mutex, NULL));
356
VOID(pthread_cond_init(&count_threshhold, NULL));
357
VOID(pthread_mutex_init(&sleeper_mutex, NULL));
358
VOID(pthread_cond_init(&sleep_threshhold, NULL));
360
/* Main iterations loop */
361
eptr= engine_options;
364
/* For the final stage we run whatever queries we were asked to run */
368
printf("Starting Concurrency Test\n");
372
for (current= concurrency; current && *current; current++)
373
concurrency_loop(&mysql, *current, eptr);
379
concurrency_loop(&mysql, infinite, eptr);
385
drop_schema(&mysql, create_schema_string);
387
} while (eptr ? (eptr= eptr->next) : 0);
389
VOID(pthread_mutex_destroy(&counter_mutex));
390
VOID(pthread_cond_destroy(&count_threshhold));
391
VOID(pthread_mutex_destroy(&sleeper_mutex));
392
VOID(pthread_cond_destroy(&sleep_threshhold));
395
mysql_close(&mysql); /* Close & free connection */
397
/* now free all the strings we created */
399
my_free(opt_password, MYF(0));
401
my_free(concurrency, MYF(0));
403
statement_cleanup(create_statements);
404
statement_cleanup(query_statements);
405
statement_cleanup(pre_statements);
406
statement_cleanup(post_statements);
407
option_cleanup(engine_options);
410
if (shared_memory_base_name)
411
my_free(shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR));
413
free_defaults(defaults_argv);
419
void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
424
conclusions conclusion;
425
unsigned long long client_limit;
428
head_sptr= (stats *)my_malloc(sizeof(stats) * iterations,
429
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
431
bzero(&conclusion, sizeof(conclusions));
433
if (auto_actual_queries)
434
client_limit= auto_actual_queries;
435
else if (num_of_query)
436
client_limit= num_of_query / current;
438
client_limit= actual_queries;
440
for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
443
We might not want to load any data, such as when we are calling
444
a stored_procedure that doesn't use data, or we know we already have
448
drop_schema(mysql, create_schema_string);
450
/* First we create */
451
if (create_statements)
452
create_schema(mysql, create_schema_string, create_statements, eptr);
455
If we generated GUID we need to build a list of them from creation that
459
printf("Generating primary key list\n");
460
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
461
generate_primary_key_list(mysql, eptr);
464
run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
467
if ((sysret= system(pre_system)) != 0)
468
fprintf(stderr, "Warning: Execution of pre_system option returned %d.\n",
472
Pre statements are always run after all other logic so they can
473
correct/adjust any item that they want.
476
run_statements(mysql, pre_statements);
478
run_scheduler(sptr, query_statements, current, client_limit);
481
run_statements(mysql, post_statements);
484
if ((sysret= system(post_system)) != 0)
485
fprintf(stderr, "Warning: Execution of post_system option returned %d.\n",
488
/* We are finished with this run */
489
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
490
drop_primary_key_list();
494
printf("Generating stats\n");
496
generate_stats(&conclusion, eptr, head_sptr);
499
print_conclusions(&conclusion);
501
print_conclusions_csv(&conclusion);
503
my_free(head_sptr, MYF(0));
508
static struct my_option my_long_options[] =
510
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
512
{"auto-generate-sql", 'a',
513
"Generate SQL where not supplied by file or command line.",
514
(uchar**) &auto_generate_sql, (uchar**) &auto_generate_sql,
515
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
516
{"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
517
"Add an AUTO_INCREMENT column to auto-generated tables.",
518
(uchar**) &auto_generate_sql_autoincrement,
519
(uchar**) &auto_generate_sql_autoincrement,
520
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
521
{"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
522
"Set this number to generate a set number of queries to run.",
523
(uchar**) &auto_actual_queries, (uchar**) &auto_actual_queries,
524
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
525
{"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
526
"Add GUID based primary keys to auto-generated tables.",
527
(uchar**) &auto_generate_sql_guid_primary,
528
(uchar**) &auto_generate_sql_guid_primary,
529
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
530
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
531
"Specify test load type: mixed, update, write, key, or read; default is mixed.",
532
(uchar**) &auto_generate_sql_type, (uchar**) &auto_generate_sql_type,
533
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
534
{"auto-generate-sql-secondary-indexes",
535
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
536
"Number of secondary indexes to add to auto-generated tables.",
537
(uchar**) &auto_generate_sql_secondary_indexes,
538
(uchar**) &auto_generate_sql_secondary_indexes, 0,
539
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
540
{"auto-generate-sql-unique-query-number",
541
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
542
"Number of unique queries to generate for automatic tests.",
543
(uchar**) &auto_generate_sql_unique_query_number,
544
(uchar**) &auto_generate_sql_unique_query_number,
545
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
546
{"auto-generate-sql-unique-write-number",
547
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
548
"Number of unique queries to generate for auto-generate-sql-write-number.",
549
(uchar**) &auto_generate_sql_unique_write_number,
550
(uchar**) &auto_generate_sql_unique_write_number,
551
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
552
{"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
553
"Number of row inserts to perform for each thread (default is 100).",
554
(uchar**) &auto_generate_sql_number, (uchar**) &auto_generate_sql_number,
555
0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
556
{"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
557
(uchar**) &commit_rate, (uchar**) &commit_rate, 0, GET_UINT, REQUIRED_ARG,
559
{"compress", 'C', "Use compression in server/client protocol.",
560
(uchar**) &opt_compress, (uchar**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
562
{"concurrency", 'c', "Number of clients to simulate for query to run.",
563
(uchar**) &concurrency_str, (uchar**) &concurrency_str, 0, GET_STR,
564
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
565
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
566
(uchar**) &create_string, (uchar**) &create_string, 0, GET_STR, REQUIRED_ARG,
568
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
569
(uchar**) &create_schema_string, (uchar**) &create_schema_string, 0, GET_STR,
570
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
571
{"csv", OPT_SLAP_CSV,
572
"Generate CSV output to named file or to stdout if no file is named.",
573
NULL, NULL, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
575
{"debug", '#', "This is a non-debug version. Catch this and exit.",
576
0, 0, 0, GET_DISABLED, OPT_ARG, 0, 0, 0, 0, 0, 0},
578
{"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.",
579
(uchar**) &default_dbug_option, (uchar**) &default_dbug_option, 0, GET_STR,
580
OPT_ARG, 0, 0, 0, 0, 0, 0},
582
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
583
(uchar**) &debug_check_flag, (uchar**) &debug_check_flag, 0,
584
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
585
{"debug-info", 'T', "Print some debug info at exit.", (uchar**) &debug_info_flag,
586
(uchar**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
588
"Delimiter to use in SQL statements supplied in file or command line.",
589
(uchar**) &delimiter, (uchar**) &delimiter, 0, GET_STR, REQUIRED_ARG,
591
{"detach", OPT_SLAP_DETACH,
592
"Detach (close and reopen) connections after X number of requests.",
593
(uchar**) &detach_rate, (uchar**) &detach_rate, 0, GET_UINT, REQUIRED_ARG,
595
{"engine", 'e', "Storage engine to use for creating the table.",
596
(uchar**) &default_engine, (uchar**) &default_engine, 0,
597
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
598
{"host", 'h', "Connect to host.", (uchar**) &host, (uchar**) &host, 0, GET_STR,
599
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
600
{"iterations", 'i', "Number of times to run the tests.", (uchar**) &iterations,
601
(uchar**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
602
{"number-char-cols", 'x',
603
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
604
(uchar**) &num_char_cols_opt, (uchar**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
606
{"number-int-cols", 'y',
607
"Number of INT columns to create in table if specifying --auto-generate-sql.",
608
(uchar**) &num_int_cols_opt, (uchar**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
610
{"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
611
"Limit each client to this number of queries (this is not exact).",
612
(uchar**) &num_of_query, (uchar**) &num_of_query, 0,
613
GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
614
{"only-print", OPT_MYSQL_ONLY_PRINT,
615
"Do not connect to the databases, but instead print out what would have "
617
(uchar**) &opt_only_print, (uchar**) &opt_only_print, 0, GET_BOOL, NO_ARG,
620
"Password to use when connecting to server. If password is not given it's "
621
"asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
623
{"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG,
624
NO_ARG, 0, 0, 0, 0, 0, 0},
626
{"port", 'P', "Port number to use for connection.", (uchar**) &opt_mysql_port,
627
(uchar**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
629
{"post-query", OPT_SLAP_POST_QUERY,
630
"Query to run or file containing query to execute after tests have completed.",
631
(uchar**) &user_supplied_post_statements,
632
(uchar**) &user_supplied_post_statements,
633
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
634
{"post-system", OPT_SLAP_POST_SYSTEM,
635
"system() string to execute after tests have completed.",
636
(uchar**) &post_system,
637
(uchar**) &post_system,
638
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
639
{"pre-query", OPT_SLAP_PRE_QUERY,
640
"Query to run or file containing query to execute before running tests.",
641
(uchar**) &user_supplied_pre_statements,
642
(uchar**) &user_supplied_pre_statements,
643
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
644
{"pre-system", OPT_SLAP_PRE_SYSTEM,
645
"system() string to execute before running tests.",
646
(uchar**) &pre_system,
647
(uchar**) &pre_system,
648
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
649
{"protocol", OPT_MYSQL_PROTOCOL,
650
"The protocol to use for connection (tcp, socket, pipe, memory).",
651
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
652
{"query", 'q', "Query to run or file containing query to run.",
653
(uchar**) &user_supplied_query, (uchar**) &user_supplied_query,
654
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
656
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
657
"Base name of shared memory.", (uchar**) &shared_memory_base_name,
658
(uchar**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
661
{"silent", 's', "Run program in silent mode - no output.",
662
(uchar**) &opt_silent, (uchar**) &opt_silent, 0, GET_BOOL, NO_ARG,
664
{"socket", 'S', "The socket file to use for connection.",
665
(uchar**) &opt_mysql_unix_port, (uchar**) &opt_mysql_unix_port, 0, GET_STR,
666
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
667
#include <sslopt-longopts.h>
668
#ifndef DONT_ALLOW_USER_CHANGE
669
{"user", 'u', "User for login if not current user.", (uchar**) &user,
670
(uchar**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
673
"More verbose output; you can use this multiple times to get even more "
674
"verbose output.", (uchar**) &verbose, (uchar**) &verbose, 0,
675
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
676
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
677
NO_ARG, 0, 0, 0, 0, 0, 0},
678
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
682
#include <help_start.h>
684
static void print_version(void)
686
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
687
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
691
static void usage(void)
694
puts("Copyright (C) 2005 MySQL AB");
695
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\nand you are welcome to modify and redistribute it under the GPL license.\n");
696
puts("Run a query multiple times against the server.\n");
697
printf("Usage: %s [OPTIONS]\n",my_progname);
698
print_defaults("my",load_default_groups);
699
my_print_help(my_long_options);
702
#include <help_end.h>
705
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
708
DBUG_ENTER("get_one_option");
712
setscreenmode(SCR_AUTOCLOSE_ON_EXIT);
719
if (argument == disabled_my_option)
720
argument= (char*) ""; /* Don't require password */
723
char *start= argument;
724
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
725
opt_password= my_strdup(argument,MYF(MY_FAE));
726
while (*argument) *argument++= 'x'; /* Destroy argument */
728
start[1]= 0; /* Cut length of argument */
736
opt_protocol= MYSQL_PROTOCOL_PIPE;
739
case OPT_MYSQL_PROTOCOL:
740
opt_protocol= find_type_or_exit(argument, &sql_protocol_typelib,
744
DBUG_PUSH(argument ? argument : default_dbug_option);
749
argument= (char *)"-"; /* use stdout */
750
opt_csv_str= argument;
752
#include <sslopt-case.h>
767
get_random_string(char *buf)
771
DBUG_ENTER("get_random_string");
772
for (x= RAND_STRING_SIZE; x > 0; x--)
773
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
774
DBUG_RETURN(buf_ptr - buf);
781
This function builds a create table query if the user opts to not supply
782
a file or string containing a create table statement
785
build_table_string(void)
787
char buf[HUGE_STRING_LENGTH];
788
unsigned int col_count;
790
DYNAMIC_STRING table_string;
791
DBUG_ENTER("build_table_string");
793
DBUG_PRINT("info", ("num int cols %u num char cols %u",
794
num_int_cols, num_char_cols));
796
init_dynamic_string(&table_string, "", 1024, 1024);
798
dynstr_append(&table_string, "CREATE TABLE `t1` (");
800
if (auto_generate_sql_autoincrement)
802
dynstr_append(&table_string, "id serial");
804
if (num_int_cols || num_char_cols)
805
dynstr_append(&table_string, ",");
808
if (auto_generate_sql_guid_primary)
810
dynstr_append(&table_string, "id varchar(32) primary key");
812
if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
813
dynstr_append(&table_string, ",");
816
if (auto_generate_sql_secondary_indexes)
820
for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
822
if (count) /* Except for the first pass we add a comma */
823
dynstr_append(&table_string, ",");
825
if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
826
> HUGE_STRING_LENGTH)
828
fprintf(stderr, "Memory Allocation error in create table\n");
831
dynstr_append(&table_string, buf);
834
if (num_int_cols || num_char_cols)
835
dynstr_append(&table_string, ",");
839
for (col_count= 1; col_count <= num_int_cols; col_count++)
841
if (num_int_cols_index)
843
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32), INDEX(intcol%d)",
844
col_count, col_count) > HUGE_STRING_LENGTH)
846
fprintf(stderr, "Memory Allocation error in create table\n");
852
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT(32) ", col_count)
853
> HUGE_STRING_LENGTH)
855
fprintf(stderr, "Memory Allocation error in create table\n");
859
dynstr_append(&table_string, buf);
861
if (col_count < num_int_cols || num_char_cols > 0)
862
dynstr_append(&table_string, ",");
866
for (col_count= 1; col_count <= num_char_cols; col_count++)
868
if (num_char_cols_index)
870
if (snprintf(buf, HUGE_STRING_LENGTH,
871
"charcol%d VARCHAR(128), INDEX(charcol%d) ",
872
col_count, col_count) > HUGE_STRING_LENGTH)
874
fprintf(stderr, "Memory Allocation error in creating table\n");
880
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
881
col_count) > HUGE_STRING_LENGTH)
883
fprintf(stderr, "Memory Allocation error in creating table\n");
887
dynstr_append(&table_string, buf);
889
if (col_count < num_char_cols)
890
dynstr_append(&table_string, ",");
893
dynstr_append(&table_string, ")");
894
ptr= (statement *)my_malloc(sizeof(statement),
895
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
896
ptr->string = (char *)my_malloc(table_string.length+1,
897
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
898
ptr->length= table_string.length+1;
899
ptr->type= CREATE_TABLE_TYPE;
900
strmov(ptr->string, table_string.str);
901
dynstr_free(&table_string);
906
build_update_string()
908
This function builds insert statements when the user opts to not supply
909
an insert file or string containing insert data
912
build_update_string(void)
914
char buf[HUGE_STRING_LENGTH];
915
unsigned int col_count;
917
DYNAMIC_STRING update_string;
918
DBUG_ENTER("build_update_string");
920
init_dynamic_string(&update_string, "", 1024, 1024);
922
dynstr_append(&update_string, "UPDATE t1 SET ");
925
for (col_count= 1; col_count <= num_int_cols; col_count++)
927
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
928
random()) > HUGE_STRING_LENGTH)
930
fprintf(stderr, "Memory Allocation error in creating update\n");
933
dynstr_append(&update_string, buf);
935
if (col_count < num_int_cols || num_char_cols > 0)
936
dynstr_append_mem(&update_string, ",", 1);
940
for (col_count= 1; col_count <= num_char_cols; col_count++)
942
char rand_buffer[RAND_STRING_SIZE];
943
int buf_len= get_random_string(rand_buffer);
945
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
946
buf_len, rand_buffer)
947
> HUGE_STRING_LENGTH)
949
fprintf(stderr, "Memory Allocation error in creating update\n");
952
dynstr_append(&update_string, buf);
954
if (col_count < num_char_cols)
955
dynstr_append_mem(&update_string, ",", 1);
958
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
959
dynstr_append(&update_string, " WHERE id = ");
962
ptr= (statement *)my_malloc(sizeof(statement),
963
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
965
ptr->string= (char *)my_malloc(update_string.length + 1,
966
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
967
ptr->length= update_string.length+1;
968
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
969
ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
971
ptr->type= UPDATE_TYPE;
972
strmov(ptr->string, update_string.str);
973
dynstr_free(&update_string);
979
build_insert_string()
981
This function builds insert statements when the user opts to not supply
982
an insert file or string containing insert data
985
build_insert_string(void)
987
char buf[HUGE_STRING_LENGTH];
988
unsigned int col_count;
990
DYNAMIC_STRING insert_string;
991
DBUG_ENTER("build_insert_string");
993
init_dynamic_string(&insert_string, "", 1024, 1024);
995
dynstr_append(&insert_string, "INSERT INTO t1 VALUES (");
997
if (auto_generate_sql_autoincrement)
999
dynstr_append(&insert_string, "NULL");
1001
if (num_int_cols || num_char_cols)
1002
dynstr_append(&insert_string, ",");
1005
if (auto_generate_sql_guid_primary)
1007
dynstr_append(&insert_string, "uuid()");
1009
if (num_int_cols || num_char_cols)
1010
dynstr_append(&insert_string, ",");
1013
if (auto_generate_sql_secondary_indexes)
1017
for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1019
if (count) /* Except for the first pass we add a comma */
1020
dynstr_append(&insert_string, ",");
1022
dynstr_append(&insert_string, "uuid()");
1025
if (num_int_cols || num_char_cols)
1026
dynstr_append(&insert_string, ",");
1030
for (col_count= 1; col_count <= num_int_cols; col_count++)
1032
if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1034
fprintf(stderr, "Memory Allocation error in creating insert\n");
1037
dynstr_append(&insert_string, buf);
1039
if (col_count < num_int_cols || num_char_cols > 0)
1040
dynstr_append_mem(&insert_string, ",", 1);
1044
for (col_count= 1; col_count <= num_char_cols; col_count++)
1046
int buf_len= get_random_string(buf);
1047
dynstr_append_mem(&insert_string, "'", 1);
1048
dynstr_append_mem(&insert_string, buf, buf_len);
1049
dynstr_append_mem(&insert_string, "'", 1);
1051
if (col_count < num_char_cols)
1052
dynstr_append_mem(&insert_string, ",", 1);
1055
dynstr_append_mem(&insert_string, ")", 1);
1057
ptr= (statement *)my_malloc(sizeof(statement),
1058
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1059
ptr->string= (char *)my_malloc(insert_string.length + 1,
1060
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1061
ptr->length= insert_string.length+1;
1062
ptr->type= INSERT_TYPE;
1063
strmov(ptr->string, insert_string.str);
1064
dynstr_free(&insert_string);
1070
build_select_string()
1072
This function builds a query if the user opts to not supply a query
1073
statement or file containing a query statement
1076
build_select_string(my_bool key)
1078
char buf[HUGE_STRING_LENGTH];
1079
unsigned int col_count;
1081
static DYNAMIC_STRING query_string;
1082
DBUG_ENTER("build_select_string");
1084
init_dynamic_string(&query_string, "", 1024, 1024);
1086
dynstr_append_mem(&query_string, "SELECT ", 7);
1087
for (col_count= 1; col_count <= num_int_cols; col_count++)
1089
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1090
> HUGE_STRING_LENGTH)
1092
fprintf(stderr, "Memory Allocation error in creating select\n");
1095
dynstr_append(&query_string, buf);
1097
if (col_count < num_int_cols || num_char_cols > 0)
1098
dynstr_append_mem(&query_string, ",", 1);
1101
for (col_count= 1; col_count <= num_char_cols; col_count++)
1103
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1104
> HUGE_STRING_LENGTH)
1106
fprintf(stderr, "Memory Allocation error in creating select\n");
1109
dynstr_append(&query_string, buf);
1111
if (col_count < num_char_cols)
1112
dynstr_append_mem(&query_string, ",", 1);
1115
dynstr_append(&query_string, " FROM t1");
1118
(auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1119
dynstr_append(&query_string, " WHERE id = ");
1121
ptr= (statement *)my_malloc(sizeof(statement),
1122
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1123
ptr->string= (char *)my_malloc(query_string.length + 1,
1124
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1125
ptr->length= query_string.length+1;
1127
(auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1128
ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
1130
ptr->type= SELECT_TYPE;
1131
strmov(ptr->string, query_string.str);
1132
dynstr_free(&query_string);
1137
get_options(int *argc,char ***argv)
1141
MY_STAT sbuf; /* Stat information for the data file */
1143
DBUG_ENTER("get_options");
1144
if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
1146
if (debug_info_flag)
1147
my_end_arg= MY_CHECK_ERROR | MY_GIVE_INFO;
1148
if (debug_check_flag)
1149
my_end_arg= MY_CHECK_ERROR;
1152
user= (char *)"root";
1154
/* If something is created we clean it up, otherwise we leave schemas alone */
1155
if (create_string || auto_generate_sql)
1156
opt_preserve= FALSE;
1158
if (auto_generate_sql && (create_string || user_supplied_query))
1161
"%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1166
if (auto_generate_sql && auto_generate_sql_guid_primary &&
1167
auto_generate_sql_autoincrement)
1170
"%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1176
We are testing to make sure that if someone specified a key search
1177
that we actually added a key!
1179
if (auto_generate_sql && auto_generate_sql_type[0] == 'k')
1180
if ( auto_generate_sql_autoincrement == FALSE &&
1181
auto_generate_sql_guid_primary == FALSE)
1184
"%s: Can't perform key test without a primary key!\n",
1191
if (auto_generate_sql && num_of_query && auto_actual_queries)
1194
"%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1199
parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
1205
if (opt_csv_str[0] == '-')
1207
csv_file= fileno(stdout);
1211
if ((csv_file= my_open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, MYF(0)))
1214
fprintf(stderr,"%s: Could not open csv file: %sn\n",
1215
my_progname, opt_csv_str);
1224
if (num_int_cols_opt)
1227
parse_option(num_int_cols_opt, &str, ',');
1228
num_int_cols= atoi(str->string);
1230
num_int_cols_index= atoi(str->option);
1231
option_cleanup(str);
1234
if (num_char_cols_opt)
1237
parse_option(num_char_cols_opt, &str, ',');
1238
num_char_cols= atoi(str->string);
1240
num_char_cols_index= atoi(str->option);
1242
num_char_cols_index= 0;
1243
option_cleanup(str);
1247
if (auto_generate_sql)
1249
unsigned long long x= 0;
1250
statement *ptr_statement;
1253
printf("Building Create Statements for Auto\n");
1255
create_statements= build_table_string();
1259
for (ptr_statement= create_statements, x= 0;
1260
x < auto_generate_sql_unique_write_number;
1261
x++, ptr_statement= ptr_statement->next)
1263
ptr_statement->next= build_insert_string();
1267
printf("Building Query Statements for Auto\n");
1269
if (auto_generate_sql_type[0] == 'r')
1272
printf("Generating SELECT Statements for Auto\n");
1274
query_statements= build_select_string(FALSE);
1275
for (ptr_statement= query_statements, x= 0;
1276
x < auto_generate_sql_unique_query_number;
1277
x++, ptr_statement= ptr_statement->next)
1279
ptr_statement->next= build_select_string(FALSE);
1282
else if (auto_generate_sql_type[0] == 'k')
1285
printf("Generating SELECT for keys Statements for Auto\n");
1287
query_statements= build_select_string(TRUE);
1288
for (ptr_statement= query_statements, x= 0;
1289
x < auto_generate_sql_unique_query_number;
1290
x++, ptr_statement= ptr_statement->next)
1292
ptr_statement->next= build_select_string(TRUE);
1295
else if (auto_generate_sql_type[0] == 'w')
1298
We generate a number of strings in case the engine is
1299
Archive (since strings which were identical one after another
1300
would be too easily optimized).
1303
printf("Generating INSERT Statements for Auto\n");
1304
query_statements= build_insert_string();
1305
for (ptr_statement= query_statements, x= 0;
1306
x < auto_generate_sql_unique_query_number;
1307
x++, ptr_statement= ptr_statement->next)
1309
ptr_statement->next= build_insert_string();
1312
else if (auto_generate_sql_type[0] == 'u')
1314
query_statements= build_update_string();
1315
for (ptr_statement= query_statements, x= 0;
1316
x < auto_generate_sql_unique_query_number;
1317
x++, ptr_statement= ptr_statement->next)
1319
ptr_statement->next= build_update_string();
1322
else /* Mixed mode is default */
1326
query_statements= build_insert_string();
1328
This logic should be extended to do a more mixed load,
1329
at the moment it results in "every other".
1331
for (ptr_statement= query_statements, x= 0;
1332
x < auto_generate_sql_unique_query_number;
1333
x++, ptr_statement= ptr_statement->next)
1337
ptr_statement->next= build_insert_string();
1342
ptr_statement->next= build_select_string(TRUE);
1350
if (create_string && my_stat(create_string, &sbuf, MYF(0)))
1353
if (!MY_S_ISREG(sbuf.st_mode))
1355
fprintf(stderr,"%s: Create file was not a regular file\n",
1359
if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1361
fprintf(stderr,"%s: Could not open create file\n", my_progname);
1364
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1365
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1366
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1367
tmp_string[sbuf.st_size]= '\0';
1368
my_close(data_file,MYF(0));
1369
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1370
my_free(tmp_string, MYF(0));
1372
else if (create_string)
1374
parse_delimiter(create_string, &create_statements, delimiter[0]);
1377
if (user_supplied_query && my_stat(user_supplied_query, &sbuf, MYF(0)))
1380
if (!MY_S_ISREG(sbuf.st_mode))
1382
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1386
if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1388
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1391
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1392
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1393
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1394
tmp_string[sbuf.st_size]= '\0';
1395
my_close(data_file,MYF(0));
1396
if (user_supplied_query)
1397
actual_queries= parse_delimiter(tmp_string, &query_statements,
1399
my_free(tmp_string, MYF(0));
1401
else if (user_supplied_query)
1403
actual_queries= parse_delimiter(user_supplied_query, &query_statements,
1408
if (user_supplied_pre_statements && my_stat(user_supplied_pre_statements, &sbuf, MYF(0)))
1411
if (!MY_S_ISREG(sbuf.st_mode))
1413
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1417
if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1419
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1422
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1423
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1424
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1425
tmp_string[sbuf.st_size]= '\0';
1426
my_close(data_file,MYF(0));
1427
if (user_supplied_pre_statements)
1428
(void)parse_delimiter(tmp_string, &pre_statements,
1430
my_free(tmp_string, MYF(0));
1432
else if (user_supplied_pre_statements)
1434
(void)parse_delimiter(user_supplied_pre_statements,
1439
if (user_supplied_post_statements && my_stat(user_supplied_post_statements, &sbuf, MYF(0)))
1442
if (!MY_S_ISREG(sbuf.st_mode))
1444
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1448
if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1450
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1453
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1454
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1455
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1456
tmp_string[sbuf.st_size]= '\0';
1457
my_close(data_file,MYF(0));
1458
if (user_supplied_post_statements)
1459
(void)parse_delimiter(tmp_string, &post_statements,
1461
my_free(tmp_string, MYF(0));
1463
else if (user_supplied_post_statements)
1465
(void)parse_delimiter(user_supplied_post_statements, &post_statements,
1470
printf("Parsing engines to use.\n");
1473
parse_option(default_engine, &engine_options, ',');
1476
opt_password= get_tty_password(NullS);
1481
static int run_query(MYSQL *mysql, const char *query, int len)
1485
printf("%.*s;\n", len, query);
1490
printf("%.*s;\n", len, query);
1491
return mysql_real_query(mysql, query, len);
1496
generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1500
unsigned long long counter;
1501
DBUG_ENTER("generate_primary_key_list");
1504
Blackhole is a special case, this allows us to test the upper end
1505
of the server during load runs.
1507
if (opt_only_print || (engine_stmt &&
1508
strstr(engine_stmt->string, "blackhole")))
1510
primary_keys_number_of= 1;
1511
primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1512
primary_keys_number_of),
1513
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1514
/* Yes, we strdup a const string to simplify the interface */
1515
primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0));
1519
if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1521
fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1522
mysql_error(mysql));
1526
result= mysql_store_result(mysql);
1527
primary_keys_number_of= mysql_num_rows(result);
1529
/* So why check this? Blackhole :) */
1530
if (primary_keys_number_of)
1533
We create the structure and loop and create the items.
1535
primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1536
primary_keys_number_of),
1537
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1538
row= mysql_fetch_row(result);
1539
for (counter= 0; counter < primary_keys_number_of;
1540
counter++, row= mysql_fetch_row(result))
1541
primary_keys[counter]= my_strdup(row[0], MYF(0));
1544
mysql_free_result(result);
1551
drop_primary_key_list(void)
1553
unsigned long long counter;
1555
if (primary_keys_number_of)
1557
for (counter= 0; counter < primary_keys_number_of; counter++)
1558
my_free(primary_keys[counter], MYF(0));
1560
my_free(primary_keys, MYF(0));
1567
create_schema(MYSQL *mysql, const char *db, statement *stmt,
1568
option_string *engine_stmt)
1570
char query[HUGE_STRING_LENGTH];
1572
statement *after_create;
1575
DBUG_ENTER("create_schema");
1577
len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1580
printf("Loading Pre-data\n");
1582
if (run_query(mysql, query, len))
1584
fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1585
mysql_error(mysql));
1591
printf("use %s;\n", db);
1596
printf("%s;\n", query);
1598
if (mysql_select_db(mysql, db))
1600
fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1601
mysql_error(mysql));
1608
len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1609
engine_stmt->string);
1610
if (run_query(mysql, query, len))
1612
fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
1613
mysql_error(mysql));
1622
for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1624
if (auto_generate_sql && ( auto_generate_sql_number == count))
1627
if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1629
char buffer[HUGE_STRING_LENGTH];
1631
snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
1632
engine_stmt->option);
1633
if (run_query(mysql, buffer, strlen(buffer)))
1635
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1636
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1642
if (run_query(mysql, ptr->string, ptr->length))
1644
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1645
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1651
if (auto_generate_sql && (auto_generate_sql_number > count ))
1653
/* Special case for auto create, we don't want to create tables twice */
1654
after_create= stmt->next;
1662
drop_schema(MYSQL *mysql, const char *db)
1664
char query[HUGE_STRING_LENGTH];
1666
DBUG_ENTER("drop_schema");
1667
len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1669
if (run_query(mysql, query, len))
1671
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1672
my_progname, db, mysql_error(mysql));
1682
run_statements(MYSQL *mysql, statement *stmt)
1686
DBUG_ENTER("run_statements");
1688
for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1690
if (run_query(mysql, ptr->string, ptr->length))
1692
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1693
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1696
if (mysql_field_count(mysql))
1698
result= mysql_store_result(mysql);
1699
mysql_free_result(result);
1707
run_scheduler(stats *sptr, statement *stmts, uint concur, ulonglong limit)
1710
struct timeval start_time, end_time;
1712
pthread_t mainthread; /* Thread descriptor */
1713
pthread_attr_t attr; /* Thread attributes */
1714
DBUG_ENTER("run_scheduler");
1719
pthread_attr_init(&attr);
1720
pthread_attr_setdetachstate(&attr,
1721
PTHREAD_CREATE_DETACHED);
1723
pthread_mutex_lock(&counter_mutex);
1726
pthread_mutex_lock(&sleeper_mutex);
1728
pthread_mutex_unlock(&sleeper_mutex);
1729
for (x= 0; x < concur; x++)
1731
/* now you create the thread */
1732
if (pthread_create(&mainthread, &attr, run_task,
1735
fprintf(stderr,"%s: Could not create thread\n",
1741
pthread_mutex_unlock(&counter_mutex);
1742
pthread_attr_destroy(&attr);
1744
pthread_mutex_lock(&sleeper_mutex);
1746
pthread_mutex_unlock(&sleeper_mutex);
1747
pthread_cond_broadcast(&sleep_threshhold);
1749
gettimeofday(&start_time, NULL);
1752
We loop until we know that all children have cleaned up.
1754
pthread_mutex_lock(&counter_mutex);
1755
while (thread_counter)
1757
struct timespec abstime;
1759
set_timespec(abstime, 3);
1760
pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1762
pthread_mutex_unlock(&counter_mutex);
1764
gettimeofday(&end_time, NULL);
1767
sptr->timing= timedif(end_time, start_time);
1768
sptr->users= concur;
1775
pthread_handler_t run_task(void *p)
1777
ulonglong counter= 0, queries;
1778
ulonglong detach_counter;
1779
unsigned int commit_counter;
1784
thread_context *con= (thread_context *)p;
1786
DBUG_ENTER("run_task");
1787
DBUG_PRINT("info", ("task script \"%s\"", con->stmt ? con->stmt->string : ""));
1789
pthread_mutex_lock(&sleeper_mutex);
1790
while (master_wakeup)
1792
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
1794
pthread_mutex_unlock(&sleeper_mutex);
1796
if (!(mysql= mysql_init(NULL)))
1798
fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1799
my_progname, mysql_error(mysql));
1803
if (mysql_thread_init())
1805
fprintf(stderr,"%s: mysql_thread_init() failed ERROR : %s\n",
1806
my_progname, mysql_error(mysql));
1810
DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user));
1812
if (!opt_only_print)
1814
if (slap_connect(mysql))
1818
DBUG_PRINT("info", ("connected."));
1820
printf("connected!\n");
1825
run_query(mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
1828
for (ptr= con->stmt, detach_counter= 0;
1830
ptr= ptr->next, detach_counter++)
1832
if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
1836
if (!(mysql= mysql_init(NULL)))
1838
fprintf(stderr,"%s: mysql_init() failed ERROR : %s\n",
1839
my_progname, mysql_error(mysql));
1843
if (slap_connect(mysql))
1848
We have to execute differently based on query type. This should become a function.
1850
if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
1851
(ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
1854
unsigned int key_val;
1856
char buffer[HUGE_STRING_LENGTH];
1859
This should only happen if some sort of new engine was
1860
implemented that didn't properly handle UPDATEs.
1862
Just in case someone runs this under an experimental engine we don't
1863
want a crash so the if() is placed here.
1865
DBUG_ASSERT(primary_keys_number_of);
1866
if (primary_keys_number_of)
1868
key_val= (unsigned int)(random() % primary_keys_number_of);
1869
key= primary_keys[key_val];
1873
length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
1874
(int)ptr->length, ptr->string, key);
1876
if (run_query(mysql, buffer, length))
1878
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1879
my_progname, (uint)length, buffer, mysql_error(mysql));
1886
if (run_query(mysql, ptr->string, ptr->length))
1888
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1889
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1896
if (mysql_field_count(mysql))
1898
result= mysql_store_result(mysql);
1899
while ((row = mysql_fetch_row(result)))
1901
mysql_free_result(result);
1903
} while(mysql_next_result(mysql) == 0);
1906
if (commit_rate && (++commit_counter == commit_rate))
1909
run_query(mysql, "COMMIT", strlen("COMMIT"));
1912
if (con->limit && queries == con->limit)
1916
if (con->limit && queries < con->limit)
1921
run_query(mysql, "COMMIT", strlen("COMMIT"));
1923
if (!opt_only_print)
1928
pthread_mutex_lock(&counter_mutex);
1930
pthread_cond_signal(&count_threshhold);
1931
pthread_mutex_unlock(&counter_mutex);
1937
parse_option(const char *origin, option_string **stmt, char delm)
1940
char *ptr= (char *)origin;
1941
option_string **sptr= stmt;
1943
size_t length= strlen(origin);
1944
uint count= 0; /* We know that there is always one */
1946
for (tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
1947
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1948
(retstr= strchr(ptr, delm));
1949
tmp->next= (option_string *)my_malloc(sizeof(option_string),
1950
MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
1953
char buffer[HUGE_STRING_LENGTH];
1957
strncpy(buffer, ptr, (size_t)(retstr - ptr));
1958
if ((buffer_ptr= strchr(buffer, ':')))
1962
tmp->length= (size_t)(buffer_ptr - buffer);
1963
tmp->string= my_strndup(ptr, (uint)tmp->length, MYF(MY_FAE));
1965
option_ptr= ptr + 1 + tmp->length;
1967
/* Move past the : and the first string */
1968
tmp->option_length= (size_t)(retstr - option_ptr);
1969
tmp->option= my_strndup(option_ptr, (uint)tmp->option_length,
1974
tmp->string= my_strndup(ptr, (size_t)(retstr - ptr), MYF(MY_FAE));
1975
tmp->length= (size_t)(retstr - ptr);
1978
ptr+= retstr - ptr + 1;
1984
if (ptr != origin+length)
1988
if ((origin_ptr= strchr(ptr, ':')))
1992
tmp->length= (size_t)(origin_ptr - ptr);
1993
tmp->string= my_strndup(origin, tmp->length, MYF(MY_FAE));
1995
option_ptr= (char *)ptr + 1 + tmp->length;
1997
/* Move past the : and the first string */
1998
tmp->option_length= (size_t)((ptr + length) - option_ptr);
1999
tmp->option= my_strndup(option_ptr, tmp->option_length,
2004
tmp->length= (size_t)((ptr + length) - ptr);
2005
tmp->string= my_strndup(ptr, tmp->length, MYF(MY_FAE));
2016
parse_delimiter(const char *script, statement **stmt, char delm)
2019
char *ptr= (char *)script;
2020
statement **sptr= stmt;
2022
uint length= strlen(script);
2023
uint count= 0; /* We know that there is always one */
2025
for (tmp= *sptr= (statement *)my_malloc(sizeof(statement),
2026
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2027
(retstr= strchr(ptr, delm));
2028
tmp->next= (statement *)my_malloc(sizeof(statement),
2029
MYF(MY_ZEROFILL|MY_FAE|MY_WME)),
2033
tmp->string= my_strndup(ptr, (uint)(retstr - ptr), MYF(MY_FAE));
2034
tmp->length= (size_t)(retstr - ptr);
2035
ptr+= retstr - ptr + 1;
2040
if (ptr != script+length)
2042
tmp->string= my_strndup(ptr, (uint)((script + length) - ptr),
2044
tmp->length= (size_t)((script + length) - ptr);
2053
parse_comma(const char *string, uint **range)
2055
uint count= 1,x; /* We know that there is always one */
2057
char *ptr= (char *)string;
2061
if (*ptr == ',') count++;
2063
/* One extra spot for the NULL */
2064
nptr= *range= (uint *)my_malloc(sizeof(uint) * (count + 1),
2065
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2067
ptr= (char *)string;
2069
while ((retstr= strchr(ptr,',')))
2071
nptr[x++]= atoi(ptr);
2072
ptr+= retstr - ptr + 1;
2074
nptr[x++]= atoi(ptr);
2080
print_conclusions(conclusions *con)
2082
printf("Benchmark\n");
2084
printf("\tRunning for engine %s\n", con->engine);
2085
printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2086
con->avg_timing / 1000, con->avg_timing % 1000);
2087
printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2088
con->min_timing / 1000, con->min_timing % 1000);
2089
printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2090
con->max_timing / 1000, con->max_timing % 1000);
2091
printf("\tNumber of clients running queries: %d\n", con->users);
2092
printf("\tAverage number of queries per client: %llu\n", con->avg_rows);
2097
print_conclusions_csv(conclusions *con)
2099
char buffer[HUGE_STRING_LENGTH];
2100
const char *ptr= auto_generate_sql_type ? auto_generate_sql_type : "query";
2101
snprintf(buffer, HUGE_STRING_LENGTH,
2102
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%d,%llu\n",
2103
con->engine ? con->engine : "", /* Storage engine we ran against */
2104
ptr, /* Load type */
2105
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2106
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2107
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2108
con->users, /* Children used */
2109
con->avg_rows /* Queries run */
2111
my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2115
generate_stats(conclusions *con, option_string *eng, stats *sptr)
2120
con->min_timing= sptr->timing;
2121
con->max_timing= sptr->timing;
2122
con->min_rows= sptr->rows;
2123
con->max_rows= sptr->rows;
2125
/* At the moment we assume uniform */
2126
con->users= sptr->users;
2127
con->avg_rows= sptr->rows;
2129
/* With no next, we know it is the last element that was malloced */
2130
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2132
con->avg_timing+= ptr->timing;
2134
if (ptr->timing > con->max_timing)
2135
con->max_timing= ptr->timing;
2136
if (ptr->timing < con->min_timing)
2137
con->min_timing= ptr->timing;
2139
con->avg_timing= con->avg_timing/iterations;
2141
if (eng && eng->string)
2142
con->engine= eng->string;
2148
option_cleanup(option_string *stmt)
2150
option_string *ptr, *nptr;
2154
for (ptr= stmt; ptr; ptr= nptr)
2158
my_free(ptr->string, MYF(0));
2160
my_free(ptr->option, MYF(0));
2161
my_free(ptr, MYF(0));
2166
statement_cleanup(statement *stmt)
2168
statement *ptr, *nptr;
2172
for (ptr= stmt; ptr; ptr= nptr)
2176
my_free(ptr->string, MYF(0));
2177
my_free(ptr, MYF(0));
2183
slap_connect(MYSQL *mysql)
2185
/* Connect to server */
2186
static ulong connection_retry_sleep= 100000; /* Microseconds */
2187
int x, connect_error= 1;
2188
for (x= 0; x < 10; x++)
2190
if (mysql_real_connect(mysql, host, user, opt_password,
2191
create_schema_string,
2193
opt_mysql_unix_port,
2196
/* Connect suceeded */
2200
my_sleep(connection_retry_sleep);
2204
fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2205
my_progname, mysql_errno(mysql), mysql_error(mysql));