/* Copyright (C) 2005 MySQL AB This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA coded by: Patrick Galbraith */ /* MySQL Slap A simple program designed to work as if multiple clients querying the database, then reporting the timing of each stage. MySQL slap runs three stages: 1) Create table (single client) 2) Insert data (many clients) 3) Load test (many clients) 4) Cleanup (disconnection, drop table if specified, single client) Examples: Supply your own create, insert and query SQL statements, with eight clients loading data (eight inserts for each) and 50 clients querying (200 selects for each): mysqlslap --create="CREATE TABLE A (a int)" \ --data="INSERT INTO A (23)" --load-concurrency=8 --number-rows=8 \ --query="SELECT * FROM A" --concurrency=50 --iterations=200 \ --load-concurrency=5 Let the program build create, insert and query SQL statements with a table of two int columns, three varchar columns, with five clients loading data (12 inserts each), five clients querying (20 times each), and drop schema before creating: mysqlslap --concurrency=5 --concurrency-load=5 --iterations=20 \ --number-int-cols=2 --number-char-cols=3 --number-rows=12 \ --auto-generate-sql Let the program build the query SQL statement with a table of two int columns, three varchar columns, five clients querying (20 times each), don't create the table or insert the data (using the previous test's schema and data): mysqlslap --concurrency=5 --iterations=20 \ --number-int-cols=2 --number-char-cols=3 \ --number-rows=12 --auto-generate-sql \ --skip-data-load --skip-create-schema Tell the program to load the create, insert and query SQL statements from the specified files, where the create.sql file has multiple table creation statements delimited by ';', multiple insert statements delimited by ';', and multiple queries delimited by ';', run all the load statements with five clients (five times each), and run all the queries in the query file with five clients (five times each): mysqlslap --drop-schema --concurrency=5 --concurrency-load=5 \ --iterations=5 --query=query.sql --create=create.sql \ --data=insert.sql --delimiter=";" --number-rows=5 Same as the last test run, with short options mysqlslap -D -c 5 -l 5 -i 5 -q query.sql \ --create create.sql -d insert.sql -F ";" -n 5 */ #define SHOW_VERSION "0.1" #define HUGE_STRING_LENGTH 8096 #define RAND_STRING_SIZE 126 #include "client_priv.h" #include #include #include #include #include #include #include #include #include #include static int drop_schema(MYSQL *mysql, const char *db); unsigned int get_random_string(char *buf); static int build_table_string(void); static int build_insert_string(void); static int build_query_string(void); static int create_schema(MYSQL *mysql, const char *db,const char *script); static int run_scheduler(const char *script, int(*task)(const char *), unsigned int concur); int run_task(const char *script); int load_data(const char *script); static char **defaults_argv; static char *host= NULL, *opt_password= NULL, *user= NULL, *user_supplied_query= NULL, *user_supplied_data= NULL, *create_string= NULL, *default_engine= NULL, *delimiter= NULL, *opt_mysql_unix_port= NULL; static my_bool opt_compress= FALSE, tty_password= FALSE, opt_drop= FALSE, create_string_alloced= FALSE, insert_string_alloced= FALSE, query_string_alloced= FALSE, generated_insert_flag= FALSE, opt_silent= FALSE, auto_generate_sql= FALSE, opt_skip_create= FALSE, opt_skip_data_load= FALSE, opt_skip_query= FALSE; static int verbose= 0, num_int_cols=0, num_char_cols=0, delimiter_length= 0; static char *default_charset= (char*) MYSQL_DEFAULT_CHARSET_NAME; static unsigned int number_of_rows= 1000, number_of_iterations= 1000, concurrency= 1, concurrency_load= 1, children_spawned= 1; const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace"; static uint opt_protocol= 0; static int get_options(int *argc,char ***argv); static uint opt_mysql_port= 0; static const char *load_default_groups[]= { "mysqlslap","client",0 }; static const char ALPHANUMERICS[]= "0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz"; #define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1) /* Return the time in ms between two timevals */ static double timedif(struct timeval end, struct timeval begin) { double seconds; DBUG_ENTER("timedif"); seconds= (double)(end.tv_usec - begin.tv_usec)/1000000; DBUG_PRINT("info", ("end.tv_usec %d - begin.tv_usec %d = " "%d microseconds ( fseconds %f)", end.tv_usec, begin.tv_usec, (end.tv_usec - begin.tv_usec), seconds)); seconds += (double)(end.tv_sec - begin.tv_sec); DBUG_PRINT("info", ("end.tv_sec %d - begin.tv_sec %d = " "%d seconds (fseconds %f)", end.tv_sec, begin.tv_sec, (end.tv_sec - begin.tv_sec), seconds)); DBUG_PRINT("info", ("returning time %f seconds", seconds)); DBUG_RETURN(seconds); } int main(int argc, char **argv) { MYSQL mysql; int client_flag= 0; double time_difference; struct timeval start_time, load_time, run_time; DBUG_ENTER("main"); MY_INIT(argv[0]); /* Seed the random number generator if we will be using it. */ if (auto_generate_sql) srandom((unsigned int)time(NULL)); load_defaults("my",load_default_groups,&argc,&argv); defaults_argv=argv; if (get_options(&argc,&argv)) { free_defaults(defaults_argv); my_end(0); exit(1); } ; /* globals? Yes, so we only have to run strlen once */ if (delimiter) delimiter_length= strlen(delimiter); if (argc > 2) { fprintf(stderr,"%s: Too many arguments\n",my_progname); free_defaults(defaults_argv); my_end(0); exit(1); } mysql_init(&mysql); if (opt_compress) mysql_options(&mysql,MYSQL_OPT_COMPRESS,NullS); #ifdef HAVE_OPENSSL if (opt_use_ssl) mysql_ssl_set(&mysql, opt_ssl_key, opt_ssl_cert, opt_ssl_ca, opt_ssl_capath, opt_ssl_cipher); #endif if (opt_protocol) mysql_options(&mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol); #ifdef HAVE_SMEM if (shared_memory_base_name) mysql_options(&mysql,MYSQL_SHARED_MEMORY_BASE_NAME,shared_memory_base_name); #endif mysql_options(&mysql, MYSQL_SET_CHARSET_NAME, default_charset); client_flag|= CLIENT_MULTI_RESULTS; if (!(mysql_real_connect(&mysql,host,user,opt_password, argv[0],opt_mysql_port,opt_mysql_unix_port, client_flag))) { fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql)); free_defaults(defaults_argv); my_end(0); exit(1); } /* We might not want to load any data, such as when we are calling a stored_procedure that doesn't use data, or we know we already have data in the table. */ if (opt_drop) drop_schema(&mysql, "mysqlslap"); if (!opt_skip_create) create_schema(&mysql, "mysqlslap", create_string); if (!opt_skip_data_load) { gettimeofday(&start_time, NULL); DBUG_PRINT("info", ("user_supplied_data %s", user_supplied_data)); run_scheduler(user_supplied_data, load_data, concurrency_load); gettimeofday(&load_time, NULL); time_difference= timedif(load_time, start_time); if (!opt_silent) { printf("Seconds to load data: %.5f\n",time_difference); printf("Number of clients loading data: %d\n", children_spawned); printf("Number of inserts per client: %d\n", number_of_rows); } } if (!opt_skip_query) { run_scheduler(user_supplied_query, run_task, concurrency); gettimeofday(&run_time, 0); time_difference= timedif(run_time, load_time); if (!opt_silent) { printf("Seconds to run all queries: %.5f\n", time_difference); printf("Number of clients running queries: %d\n", children_spawned); printf("Number of queries per client: %d\n", number_of_iterations); } } if (opt_drop) drop_schema(&mysql, "mysqlslap"); mysql_close(&mysql); /* Close & free connection */ /* now free all the strings we created */ if (opt_password) my_free(opt_password,MYF(0)); if (create_string_alloced) my_free(create_string,MYF(0)); if (insert_string_alloced) my_free(user_supplied_data,MYF(0)); if (query_string_alloced) my_free(user_supplied_query,MYF(0)); #ifdef HAVE_SMEM if (shared_memory_base_name) my_free(shared_memory_base_name,MYF(MY_ALLOW_ZERO_PTR)); #endif free_defaults(defaults_argv); my_end(0); DBUG_RETURN(0); /* No compiler warnings */ } static struct my_option my_long_options[] = { {"auto-generate-sql", 'a', "Generate SQL where not supplied by file or command line.", (gptr*) &auto_generate_sql, (gptr*) &auto_generate_sql, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"compress", 'C', "Use compression in server/client protocol.", (gptr*) &opt_compress, (gptr*) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"concurrency-load", 'l', "Number of clients to use when loading data.", (gptr*) &concurrency_load, (gptr*) &concurrency_load, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, {"concurrency", 'c', "Number of clients to simulate for query to run.", (gptr*) &concurrency, (gptr*) &concurrency, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0}, {"create", OPT_CREATE_SLAP_SCHEMA, "File or string to use for create.", (gptr*) &create_string, (gptr*) &create_string, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"data", 'd', "File or string with INSERT to use for populating data.", (gptr*) &user_supplied_data, (gptr*) &user_supplied_data, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"debug", '#', "Output debug log. Often this is 'd:t:o,filename'.", (gptr*) &default_dbug_option, (gptr*) &default_dbug_option, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"delimiter", 'F', "Delimiter to use in SQL statements supplied in file or command line.", (gptr*) &delimiter, (gptr*) &delimiter, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"drop-schema", 'D', "Drop schema if it exists prior to running and after running.", (gptr*) &opt_drop, (gptr*) &opt_drop, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"engine", 'e', "Storage engine to use for creating the table.", (gptr*) &default_engine, (gptr*) &default_engine, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"host", 'h', "Connect to host.", (gptr*) &host, (gptr*) &host, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"iterations", 'i', "Number of iterations.", (gptr*) &number_of_iterations, (gptr*) &number_of_iterations, 0, GET_UINT, REQUIRED_ARG, 1000, 0, 0, 0, 0, 0}, {"number-char-cols", 'x', "Number of INT columns to create table with if specifying --sql-generate-sql.", (gptr*) &num_char_cols, (gptr*) &num_char_cols, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"number-int-cols", 'y', "Number of VARCHAR columns to create table with if specifying --sql-generate-sql.", (gptr*) &num_int_cols, (gptr*) &num_int_cols, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"number-rows", 'n', "Number of rows to insert when loading data.", (gptr*) &number_of_rows, (gptr*) &number_of_rows, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"password", 'p', "Password to use when connecting to server. If password is not given it's asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0}, {"port", 'P', "Port number to use for connection.", (gptr*) &opt_mysql_port, (gptr*) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0, 0}, #ifdef __WIN__ {"pipe", 'W', "Use named pipes to connect to server.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, #endif {"protocol", OPT_MYSQL_PROTOCOL, "The protocol of connection (tcp,socket,pipe,memory).", 0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"skip-create-schema", 'A', "Don't create a schema, use existing schema.", (gptr*) &opt_skip_create, (gptr*) &opt_skip_create, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-data-load", 'L', "Don't load any data, use existing data set.", (gptr*) &opt_skip_data_load, (gptr*) &opt_skip_data_load, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"skip-query", 'Q', "Don't run any queries.", (gptr*) &opt_skip_query, (gptr*) &opt_skip_query, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, {"silent", 's', "Run program in silent mode - no output.", (gptr*) &opt_silent, (gptr*) &opt_silent, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0}, #ifdef HAVE_SMEM {"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME, "Base name of shared memory.", (gptr*) &shared_memory_base_name, (gptr*) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"query", 'q', "Query to run or file containing query to run.", (gptr*) &user_supplied_query, (gptr*) &user_supplied_query, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, {"socket", 'S', "Socket file to use for connection.", (gptr*) &opt_mysql_unix_port, (gptr*) &opt_mysql_unix_port, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #include #ifndef DONT_ALLOW_USER_CHANGE {"user", 'u', "User for login if not current user.", (gptr*) &user, (gptr*) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0}, #endif {"verbose", 'v', "More verbose output; You can use this multiple times to get even more verbose output.", (gptr*) &verbose, (gptr*) &verbose, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}, {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0} }; #include static void print_version(void) { printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname,SHOW_VERSION, MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE); } static void usage(void) { print_version(); puts("Copyright (C) 2005 MySQL AB"); 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"); puts("Run a query multiple times against the server\n"); printf("Usage: %s [OPTIONS]\n",my_progname); print_defaults("my",load_default_groups); my_print_help(my_long_options); } #include static my_bool get_one_option(int optid, const struct my_option *opt __attribute__((unused)), char *argument) { DBUG_ENTER("get_one_option"); switch(optid) { #ifdef __NETWARE__ case OPT_AUTO_CLOSE: setscreenmode(SCR_AUTOCLOSE_ON_EXIT); break; #endif case 'v': verbose++; break; case 'p': if (argument) { char *start= argument; my_free(opt_password,MYF(MY_ALLOW_ZERO_PTR)); opt_password= my_strdup(argument,MYF(MY_FAE)); while (*argument) *argument++= 'x'; /* Destroy argument */ if (*start) start[1]= 0; /* Cut length of argument */ tty_password= 0; } else tty_password= 1; break; case 'W': #ifdef __WIN__ opt_protocol= MYSQL_PROTOCOL_PIPE; #endif break; case OPT_MYSQL_PROTOCOL: { if ((opt_protocol= find_type(argument, &sql_protocol_typelib,0)) <= 0) { fprintf(stderr, "Unknown option to protocol: %s\n", argument); exit(1); } break; } case '#': DBUG_PUSH(argument ? argument : default_dbug_option); break; #include case 'V': print_version(); exit(0); break; case '?': case 'I': /* Info */ usage(); exit(0); } DBUG_RETURN(0); } unsigned int get_random_string(char *buf) { char *buf_ptr= buf; int x; DBUG_ENTER("get_random_string"); for (x= RAND_STRING_SIZE; x > 0; x--) *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE]; DBUG_PRINT("info", ("random string: '%*s'", buf_ptr - buf, buf)); DBUG_RETURN(buf_ptr - buf); } /* build_table_string This function builds a create table query if the user opts to not supply a file or string containing a create table statement */ static int build_table_string(void) { char buf[512]; int col_count; DYNAMIC_STRING table_string; DBUG_ENTER("build_table_string"); DBUG_PRINT("info", ("num int cols %d num char cols %d", num_int_cols, num_char_cols)); init_dynamic_string(&table_string, "", 1024, 1024); dynstr_append_mem(&table_string, "CREATE TABLE `t1` (\n", 20); for (col_count= 1; col_count <= num_int_cols; col_count++) { sprintf(buf, "intcol%d INT(32)", col_count); dynstr_append(&table_string, buf); if (col_count < num_int_cols || num_char_cols > 0) dynstr_append_mem(&table_string, ",", 1); dynstr_append_mem(&table_string, "\n", 1); } for (col_count= 1; col_count <= num_char_cols; col_count++) { sprintf(buf, "charcol%d VARCHAR(128)", col_count); dynstr_append(&table_string, buf); if (col_count < num_char_cols) dynstr_append_mem(&table_string, ",", 1); dynstr_append_mem(&table_string, "\n", 1); } dynstr_append_mem(&table_string, ")\n", 2); create_string= (char *)my_malloc(table_string.length+1, MYF(MY_WME)); create_string_alloced= 1; strmov(create_string, table_string.str); DBUG_PRINT("info", ("create_string %s", create_string)); dynstr_free(&table_string); DBUG_RETURN(0); } /* build_insert_string() This function builds insert statements when the user opts to not supply a insert file or string containing insert data */ static int build_insert_string(void) { char buf[RAND_STRING_SIZE]; int col_count; DYNAMIC_STRING insert_string; DBUG_ENTER("build_insert_string"); init_dynamic_string(&insert_string, "", 1024, 1024); dynstr_append_mem(&insert_string, "INSERT INTO t1 VALUES (", 23); for (col_count= 1; col_count <= num_int_cols; col_count++) { sprintf(buf, "%ld", random()); dynstr_append(&insert_string, buf); if (col_count < num_int_cols || num_char_cols > 0) dynstr_append_mem(&insert_string, ",", 1); } for (col_count= 1; col_count <= num_char_cols; col_count++) { int buf_len= get_random_string(buf); dynstr_append_mem(&insert_string, "'", 1); dynstr_append_mem(&insert_string, buf, buf_len); dynstr_append_mem(&insert_string, "'", 1); if (col_count < num_char_cols) dynstr_append_mem(&insert_string, ",", 1); } dynstr_append_mem(&insert_string, ")", 1); /* since this function can be called if the user wants varying insert statement in the for loop where inserts run, free in advance */ if (insert_string_alloced) my_free(user_supplied_data,MYF(0)); user_supplied_data= (char *)my_malloc(insert_string.length+1, MYF(MY_WME)); insert_string_alloced= 1; strmov(user_supplied_data, insert_string.str); DBUG_PRINT("info", ("generated_insert_data %s", user_supplied_data)); dynstr_free(&insert_string); DBUG_RETURN(insert_string.length+1); } /* build_query_string() This function builds a query if the user opts to not supply a query statement or file containing a query statement */ static int build_query_string(void) { char buf[512]; int col_count; static DYNAMIC_STRING query_string; DBUG_ENTER("build_query_string"); init_dynamic_string(&query_string, "", 1024, 1024); dynstr_append_mem(&query_string, "SELECT ", 7); for (col_count= 1; col_count <= num_int_cols; col_count++) { sprintf(buf, "intcol%d", col_count); dynstr_append(&query_string, buf); if (col_count < num_int_cols || num_char_cols > 0) dynstr_append_mem(&query_string, ",", 1); } for (col_count= 1; col_count <= num_char_cols; col_count++) { sprintf(buf, "charcol%d", col_count); dynstr_append(&query_string, buf); if (col_count < num_char_cols) dynstr_append_mem(&query_string, ",", 1); } dynstr_append_mem(&query_string, " FROM t1", 8); user_supplied_query= (char *)my_malloc(query_string.length+1, MYF(MY_WME)); query_string_alloced= 1; strmov(user_supplied_query, query_string.str); DBUG_PRINT("info", ("user_supplied_query %s", user_supplied_query)); dynstr_free(&query_string); DBUG_RETURN(0); } static int get_options(int *argc,char ***argv) { int ho_error; MY_STAT sbuf; /* Stat information for the data file */ DBUG_ENTER("get_options"); if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option))) exit(ho_error); /* Default policy - if they don't supply either char or int cols, and also no data, then default to 1 of each. */ if (num_int_cols == 0 && num_char_cols == 0 && auto_generate_sql && !user_supplied_data) { num_int_cols= 1; num_char_cols= 1; } if (!default_engine) default_engine= (char *)"MYISAM"; if (!user) user= (char *)"root"; if(auto_generate_sql && create_string && user_supplied_data && user_supplied_query) { fprintf(stderr, "%s: Can't use --auto-generate-sql when create, insert, and query strings are specified!\n", my_progname); exit(1); } if (opt_skip_create && opt_drop) { fprintf(stderr,"You cannot specify to drop the schema and skip schema creation!\n"); exit(1); } if (!opt_skip_create) { if (auto_generate_sql && !create_string) build_table_string(); else if (create_string && my_stat(create_string, &sbuf, MYF(0))) { File data_file; if (!MY_S_ISREG(sbuf.st_mode)) { fprintf(stderr,"%s: Create file was not a regular file\n", my_progname); exit(1); } if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1) { fprintf(stderr,"%s: Could not open create file\n", my_progname); exit(1); } create_string= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME)); create_string_alloced= 1; my_read(data_file, create_string, sbuf.st_size, MYF(0)); create_string[sbuf.st_size]= '\0'; my_close(data_file,MYF(0)); } else if (!auto_generate_sql && !create_string) { fprintf(stderr,"%s: Must use --auto-generate-sql or --create option\n", my_progname); exit(1); } } if (opt_skip_data_load) { if (user_supplied_data) fprintf(stderr, "Warning: Specified data to INSERT, but data load is disabled.\n"); } else { if (!user_supplied_data && auto_generate_sql) { int length; generated_insert_flag= 1; length= build_insert_string(); DBUG_PRINT("info", ("user_supplied_data is %s", user_supplied_data)); } else if (my_stat(user_supplied_data, &sbuf, MYF(0))) { File data_file; if (!MY_S_ISREG(sbuf.st_mode)) { fprintf(stderr,"%s: User data supplied file was not a regular file\n", my_progname); exit(1); } if ((data_file= my_open(user_supplied_data, O_RDWR, MYF(0))) == -1) { fprintf(stderr,"%s: Could not open data supplied file\n", my_progname); exit(1); } user_supplied_data= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME)); insert_string_alloced= 1; my_read(data_file, user_supplied_data, sbuf.st_size, MYF(0)); user_supplied_data[sbuf.st_size]= '\0'; my_close(data_file,MYF(0)); } else if (!user_supplied_query && !auto_generate_sql) { fprintf(stderr,"%s: No user supplied data to insert or --auto-generate-sql\ specified!\n", my_progname); exit(1); } } if (!opt_skip_query) { if (!user_supplied_query && auto_generate_sql) { build_query_string(); } else if (my_stat(user_supplied_query, &sbuf, MYF(0))) { File data_file; if (!MY_S_ISREG(sbuf.st_mode)) { fprintf(stderr,"%s: User query supplied file was not a regular file\n", my_progname); exit(1); } if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1) { fprintf(stderr,"%s: Could not open query supplied file\n", my_progname); exit(1); } user_supplied_query= (char *)my_malloc(sbuf.st_size+1, MYF(MY_WME)); query_string_alloced= 1; my_read(data_file, user_supplied_query, sbuf.st_size, MYF(0)); user_supplied_query[sbuf.st_size]= '\0'; my_close(data_file,MYF(0)); } else if (!user_supplied_query && !auto_generate_sql) { fprintf(stderr,"%s: No user supplied query or --auto-generate-sql\ specified!\n", my_progname); exit(1); } } if (tty_password) opt_password= get_tty_password(NullS); DBUG_RETURN(0); } static int create_schema(MYSQL *mysql,const char *db,const char *script) { char query[HUGE_STRING_LENGTH], buffer[HUGE_STRING_LENGTH]; DBUG_ENTER("create_schema"); snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db); DBUG_PRINT("info", ("query %s", query)); mysql_query(mysql, query); snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db); DBUG_PRINT("info", ("query %s", query)); if (mysql_query(mysql, query)) { fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db, mysql_error(mysql)); exit(1); } if (mysql_select_db(mysql,db)) { fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db, mysql_error(mysql)); exit(1); } snprintf(buffer, HUGE_STRING_LENGTH, "set storage_engine=`%s`", default_engine); if (mysql_query(mysql, buffer)) { fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname, mysql_error(mysql)); exit(1); } if (delimiter) { char *retstr; char buf[HUGE_STRING_LENGTH]; while ((retstr= strstr(script, delimiter))) { strncpy(buf, script, retstr - script); buf[retstr - script]= '\0'; script+= retstr - script + delimiter_length; DBUG_PRINT("info", ("running create QUERY %s", (char *)buf)); if (mysql_query(mysql, buf)) { fprintf(stderr,"%s: Cannot run query %s ERROR : %s\n", my_progname, (char *)buf, mysql_error(mysql)); exit(1); } } } /* remainder, if there was a delimeter, or the whole query if not a delimiter. If less than 3, can't be anything useful */ if ((strlen(script)) < 3) DBUG_RETURN(0); if (mysql_query(mysql, script)) { fprintf(stderr,"%s: Cannot create tables: %s\n", my_progname, mysql_error(mysql)); exit(1); } DBUG_RETURN(0); } static int drop_schema(MYSQL *mysql,const char *db) { char query[HUGE_STRING_LENGTH]; DBUG_ENTER("drop_schema"); snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db); if (mysql_query(mysql, query)) { fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n", my_progname, db, mysql_error(mysql)); exit(1); } DBUG_RETURN(0); } static int run_scheduler(const char *script, int(*task)(const char *), unsigned int concur) { uint x; DBUG_ENTER("run_scheduler"); /* reset to 0 */ children_spawned= 0; for (x= 0; x < concur; x++) { int pid; DBUG_PRINT("info", ("x %d concurrency %d", x, concurrency)); pid= fork(); switch(pid) { case 0: /* child */ DBUG_PRINT("info", ("fork returned 0, calling task(\"%s\"), pid %d gid %d", script, pid, getgid())); if (verbose >= 2) fprintf(stderr, "%s: fork returned 0, calling task(\"%s\") pid %d gid %d\n", my_progname, script, pid, getgid()); task(script); exit(0); break; case -1: /* error */ DBUG_PRINT("info", ("fork returned -1, failing pid %d gid %d", pid, getgid())); fprintf(stderr, "%s: Failed on fork: -1, max procs per parent exceeded.\n", my_progname); /*exit(1);*/ goto WAIT; default: /* parent, forked */ DBUG_PRINT("info", ("default, break: pid %d gid %d", pid, getgid())); if (verbose >= 2) fprintf(stderr,"%s: fork returned %d, gid %d\n", my_progname, pid, getgid()); break; } children_spawned++; } WAIT: while (x--) { int status, pid; pid= wait(&status); DBUG_PRINT("info", ("Parent: child %d status %d", pid, status)); } DBUG_RETURN(0); } int run_task(const char *script) { uint counter= 0, x; MYSQL mysql; MYSQL_RES *result; MYSQL_ROW row; DBUG_ENTER("run_task"); DBUG_PRINT("info", ("task script \"%s\"", script)); mysql_init(&mysql); DBUG_PRINT("info", ("trying to connect to host %s as user %s", host, user)); if (!(mysql_real_connect(&mysql, host, user, opt_password, "mysqlslap", opt_mysql_port, opt_mysql_unix_port, 0))) { fprintf(stderr,"%s: %s\n",my_progname,mysql_error(&mysql)); exit(1); } DBUG_PRINT("info", ("connected.")); for (x= 0; x < number_of_iterations; x++) { if (delimiter) { char *retstr; char buf[HUGE_STRING_LENGTH]; while((retstr= strstr(script, delimiter))) { strncpy(buf, script, retstr - script); buf[retstr - script]= '\0'; script+= retstr - script + delimiter_length; DBUG_PRINT("info", ("running QUERY %s", buf)); if (mysql_query(&mysql, buf)) { fprintf(stderr,"%s: Cannot run query %s ERROR : %s\n", my_progname, buf, mysql_error(&mysql)); exit(1); } result= mysql_store_result(&mysql); while ((row = mysql_fetch_row(result))) { counter++; } mysql_free_result(result); result= 0; } } if ((strlen(script)) < 3) goto end; if (mysql_query(&mysql, script)) { fprintf(stderr,"%s: Cannot run query %s ERROR : %s\n", my_progname, script, mysql_error(&mysql)); exit(1); } result= mysql_store_result(&mysql); while ((row = mysql_fetch_row(result))) counter++; mysql_free_result(result); result= 0; } end: mysql_close(&mysql); DBUG_RETURN(0); } int load_data(const char *script) { unsigned int x; MYSQL mysql; DBUG_ENTER("load_data"); DBUG_PRINT("info", ("task load_data, pid %d", getpid())); mysql_init(&mysql); if (!(mysql_real_connect(&mysql, host, user, opt_password, "mysqlslap", opt_mysql_port, opt_mysql_unix_port, 0))) { fprintf(stderr,"%s: Unable to connect to mysqlslap ERROR: %s\n", my_progname, mysql_error(&mysql)); exit(1); } for (x= 0; x < number_of_rows; x++) { if (delimiter) { char *retstr; char buf[HUGE_STRING_LENGTH]; while((retstr= strstr(script, delimiter))) { strncpy(buf, script, retstr - script); buf[retstr - script]= '\0'; script+= retstr - script + delimiter_length; DBUG_PRINT("info", ("running INSERT %s", buf)); if (mysql_query(&mysql, buf)) { fprintf(stderr,"%s: Cannot run query %s ERROR : %s\n", my_progname, buf, mysql_error(&mysql)); exit(1); } } } if ((strlen(script)) < 3) goto end; if (mysql_query(&mysql, script)) { DBUG_PRINT("info", ("iteration %d with INSERT statement %s", script)); fprintf(stderr,"%s: Cannot insert into table using script: %s ERROR: %s\n", my_progname, script, mysql_error(&mysql)); exit(1); } /* this causes variable data on the insert string */ if (auto_generate_sql) { build_insert_string(); strmov((char *)script, (char *)user_supplied_data); } } end: mysql_close(&mysql); DBUG_RETURN(0); }