1
0
mirror of https://github.com/MariaDB/server.git synced 2025-08-01 03:47:19 +03:00

WORKLOG #2983 Post review fixes

This commit is contained in:
patg@krsna.patg.net
2005-12-02 22:07:11 -08:00
parent 094d91fdec
commit 9503c7e514
2 changed files with 108 additions and 199 deletions

View File

@ -19,51 +19,62 @@
/*
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 Schema (single client)
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 5 clients
loading (10 inserts for each), 50 clients querying:
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)" --iterations=200
--query="SELECT * FROM A" --number-rows=10 --concurrency=50 --load-concurrency=5
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, 3 varchar columns, with 5 clients loading data
(12 inserts each), 5 clients querying, drop schema before creating:
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
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, 3 varchar columns, 5 clients querying, don't
create the table or insert the data (using the previous test's schema
and data)
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
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 which the create.sql file has multiple table creation
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 5
clients, 5 times per client, and run all the queries in the query file with
5 clients:
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
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
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"
@ -88,7 +99,6 @@ Same as the last test run, with short options
static int drop_schema(MYSQL *mysql, const char *db);
unsigned int get_random_number(void);
unsigned int get_random_string(char *buf);
static int build_table_string(void);
static int build_insert_string(void);
@ -98,20 +108,21 @@ 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, opt_count= FALSE, tty_password= FALSE,
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=-1, num_char_cols=-1, delimiter_length= 0;
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;
@ -120,30 +131,31 @@ const char *default_dbug_option="d:t:o,/tmp/mysqlslap.trace";
static uint opt_protocol= 0;
static void get_options(int *argc,char ***argv);
static int get_options(int *argc,char ***argv);
static uint opt_mysql_port= 0;
static const char *load_default_groups[]= { "mysqlslap","client",0 };
#if ELEGANT_SOLUTION
static const char ALPHANUMERICS[]=
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
static const ALPHANUMERICS_SIZE= (sizeof(ALPHANUMERICS)-1);
#endif
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
/* returns the time in ms between two timevals */
/* 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)",
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)",
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));
@ -154,64 +166,36 @@ static double timedif(struct timeval end, struct timeval begin)
int main(int argc, char **argv)
{
my_bool first_argument_uses_wildcards= 0;
char *wild;
MYSQL mysql;
int client_flag= 0;
double time_difference;
struct timeval tmp_time, start_time, load_time, run_time;
/* for the string generation later */
struct timeval start_time, load_time, run_time;
DBUG_ENTER("main");
MY_INIT(argv[0]);
/* for any string generation later on */
/* Seed the random number generator if we will be using it. */
if (auto_generate_sql)
srandom((unsigned int) tmp_time.tv_usec);
srandom((unsigned int)time(NULL));
bzero(&load_time, sizeof(struct timeval));
bzero(&run_time, sizeof(struct timeval));
load_defaults("my",load_default_groups,&argc,&argv);
get_options(&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);
wild= 0;
if (argc)
{
char *pos= argv[argc-1], *to;
for (to= pos ; *pos ; pos++, to++)
{
switch (*pos) {
case '*':
*pos= '%';
first_argument_uses_wildcards= 1;
break;
case '?':
*pos= '_';
first_argument_uses_wildcards= 1;
break;
case '%':
case '_':
first_argument_uses_wildcards= 1;
break;
case '\\':
pos++;
default: break;
}
*to= *pos;
}
*to= *pos; /* just to copy a '\0' if '\\' was used */
}
if (first_argument_uses_wildcards)
wild= argv[--argc];
else if (argc == 3) /* We only want one field */
wild= argv[--argc];
if (argc > 2)
{
fprintf(stderr,"%s: Too many arguments\n",my_progname);
free_defaults(defaults_argv);
my_end(0);
exit(1);
}
mysql_init(&mysql);
@ -232,18 +216,19 @@ int main(int argc, char **argv)
client_flag|= CLIENT_MULTI_RESULTS;
if (!(mysql_real_connect(&mysql,host,user,opt_password,
(first_argument_uses_wildcards) ? "" :
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, if for instance we are calling
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
data in the table.
*/
if (opt_drop)
drop_schema(&mysql, "mysqlslap");
@ -297,6 +282,7 @@ int main(int argc, char **argv)
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 */
@ -304,34 +290,37 @@ int main(int argc, char **argv)
static struct my_option my_long_options[] =
{
{"auto-generate-sql", 'a', "Generate SQL where not supplied by file or command line.",
{"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 simulate for data load.",
{"concurrency-load", 'l', "Number of clients to use when loading data.",
(gptr*) &concurrency_load, (gptr*) &concurrency_load, 0,
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 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, 0, 0, 0, 0, 0, 0},
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 table(s).",
"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.",
{"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},
"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},
@ -340,7 +329,8 @@ static struct my_option my_long_options[] =
{"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, 0, 0, 0, 0, 0, 0},
(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},
@ -417,7 +407,7 @@ static void usage(void)
\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] [database [table [column]]]\n",my_progname);
printf("Usage: %s [OPTIONS]\n",my_progname);
print_defaults("my",load_default_groups);
my_print_help(my_long_options);
}
@ -482,81 +472,20 @@ get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
DBUG_RETURN(0);
}
/*
get_random_number()
returns a random number to be used in building an sql statement
*/
unsigned int
get_random_number(void)
{
int num;
char rstate[8];
struct timeval timestruct;
DBUG_ENTER("get_random_number");
gettimeofday(&timestruct, NULL);
initstate(timestruct.tv_usec, rstate, sizeof(rstate));
setstate(rstate);
num= random();
DBUG_RETURN(num);
}
unsigned int
get_random_string(char *buf)
{
char *buf_ptr= buf;
int x, chr= 0;
int x;
DBUG_ENTER("get_random_string");
for (x= RAND_STRING_SIZE; x > 0; x--)
{
/*
why this tmp_num? Because for some reason, x's value gets
munged during call of random()
*/
int tmp_num= x;
chr= random()% tmp_num;
/*
avoiding problematic chars for insert
*/
if (chr >= 48 && chr <= 122 && chr != 96 && chr != 92)
*buf_ptr++= chr;
}
/*
strlen
*/
DBUG_RETURN(buf_ptr- buf);
}
#if ELEGANT_SOLUTION
/*
I would like to use this, but for some reason, subsequent calls to
this function result in buf having non-alpha characters added beyond it's
size, which in turn corrupt the insert string.
*/
unsigned int
get_random_string(char *buf)
{
char *buf_ptr=buf;
int x= RAND_STRING_SIZE;
DBUG_ENTER("get_random_string");
DBUG_PRINT("info", ("RANDOM STRING buf %s length %d", buf, buf_ptr - buf));
while(x--)
{
int tmp_x=x;
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
x= tmp_x;
//fprintf(stderr, "get_random_string %s %lx x %d\n", buf_ptr, buf_ptr,
//tmp_x);
}
DBUG_PRINT("info", ("RANDOM STRING buf %s length %d", buf, buf_ptr - buf));
/* strlen */
DBUG_PRINT("info", ("random string: '%*s'", buf_ptr - buf, buf));
DBUG_RETURN(buf_ptr - buf);
}
#endif
/*
build_table_string
@ -618,16 +547,14 @@ build_insert_string(void)
char buf[RAND_STRING_SIZE];
int col_count;
DYNAMIC_STRING insert_string;
MYSQL mysql;
DBUG_ENTER("build_insert_string");
mysql_init(&mysql);
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, "%d", get_random_number());
sprintf(buf, "%ld", random());
dynstr_append(&insert_string, buf);
if (col_count < num_int_cols || num_char_cols > 0)
@ -635,18 +562,13 @@ build_insert_string(void)
}
for (col_count= 1; col_count <= num_char_cols; col_count++)
{
char *buf_tmp= (char *) my_malloc(RAND_STRING_SIZE, MYF(MY_WME));
int buf_len;
buf_len= get_random_string((char *) &buf);
mysql_real_escape_string(&mysql, buf_tmp, (char *) &buf, buf_len);
int buf_len= get_random_string(buf);
dynstr_append_mem(&insert_string, "'", 1);
dynstr_append_mem(&insert_string, buf_tmp, buf_len);
dynstr_append_mem(&insert_string, buf, buf_len);
dynstr_append_mem(&insert_string, "'", 1);
my_free(buf_tmp, MYF(0));
if (col_count < num_char_cols)
dynstr_append_mem(&insert_string, ",", 1);
}
dynstr_append_mem(&insert_string, ")", 1);
@ -661,7 +583,6 @@ build_insert_string(void)
strmov(user_supplied_data, insert_string.str);
DBUG_PRINT("info", ("generated_insert_data %s", user_supplied_data));
dynstr_free(&insert_string);
mysql_close(&mysql);
DBUG_RETURN(insert_string.length+1);
}
@ -709,7 +630,7 @@ build_query_string(void)
DBUG_RETURN(0);
}
static void
static int
get_options(int *argc,char ***argv)
{
int ho_error;
@ -862,15 +783,7 @@ get_options(int *argc,char ***argv)
if (tty_password)
opt_password= get_tty_password(NullS);
if (opt_count)
{
/*
We need to set verbose to 2 as we need to change the output to include
the number-of-rows column
*/
verbose= 2;
}
DBUG_VOID_RETURN;
DBUG_RETURN(0);
}
@ -916,7 +829,7 @@ create_schema(MYSQL *mysql,const char *db,const char *script)
while ((retstr= strstr(script, delimiter)))
{
strncpy((char*)&buf, script, retstr - script);
strncpy(buf, script, retstr - script);
buf[retstr - script]= '\0';
script+= retstr - script + delimiter_length;
DBUG_PRINT("info", ("running create QUERY %s", (char *)buf));
@ -969,9 +882,7 @@ run_scheduler(const char *script,
uint x;
DBUG_ENTER("run_scheduler");
/*
reset to 0
*/
/* reset to 0 */
children_spawned= 0;
for (x= 0; x < concur; x++)
@ -1055,11 +966,11 @@ run_task(const char *script)
while((retstr= strstr(script, delimiter)))
{
strncpy((char*)&buf, script, retstr - script);
strncpy(buf, script, retstr - script);
buf[retstr - script]= '\0';
script+= retstr - script + delimiter_length;
DBUG_PRINT("info", ("running QUERY %s", (char *)buf));
if (mysql_query(&mysql, (char *)buf))
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));
@ -1076,7 +987,7 @@ run_task(const char *script)
}
}
if ((strlen(script)) < 3)
DBUG_RETURN(0);
goto end;
if (mysql_query(&mysql, script))
{
fprintf(stderr,"%s: Cannot run query %s ERROR : %s\n",
@ -1092,8 +1003,8 @@ run_task(const char *script)
}
end:
mysql_close(&mysql);
DBUG_RETURN(0);
}
@ -1126,11 +1037,11 @@ load_data(const char *script)
while((retstr= strstr(script, delimiter)))
{
strncpy((char*)&buf, script, retstr - script);
strncpy(buf, script, retstr - script);
buf[retstr - script]= '\0';
script+= retstr - script + delimiter_length;
DBUG_PRINT("info", ("running INSERT %s", (char *)buf));
if (mysql_query(&mysql, (char *)buf))
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));
@ -1139,7 +1050,7 @@ load_data(const char *script)
}
}
if ((strlen(script)) < 3)
DBUG_RETURN(0);
goto end;
if (mysql_query(&mysql, script))
{
DBUG_PRINT("info", ("iteration %d with INSERT statement %s", script));
@ -1155,8 +1066,7 @@ load_data(const char *script)
}
}
end:
mysql_close(&mysql);
DBUG_RETURN(0);
}

View File

@ -5,7 +5,7 @@ and you are welcome to modify and redistribute it under the GPL license
Run a query multiple times against the server
Usage: /home/patg/mysql-build/mysql-5.1-slap/client/.libs/lt-mysqlslap [OPTIONS] [database [table [column]]]
Usage: /home/patg/mysql-build/mysql-5.1-slap/client/.libs/lt-mysqlslap [OPTIONS]
Default options are read from the following files in the given order:
/etc/my.cnf ~/.my.cnf
@ -19,17 +19,16 @@ The following options may be given as the first argument:
Generate SQL where not supplied by file or command line.
-C, --compress Use compression in server/client protocol.
-l, --concurrency-load=#
Number of clients to simulate for data load.
Number of clients to use when loading data.
-c, --concurrency=# Number of clients to simulate for query to run.
--create=name File or string to use for create.
-d, --data=name File or string with INSERT to use for populating
table(s).
-d, --data=name File or string with INSERT to use for populating data.
-#, --debug[=name] Output debug log. Often this is 'd:t:o,filename'.
-F, --delimiter=name
Delimiter to use in SQL statements supplied in file or
command line.
-D, --drop-schema Drop schema if it exists prior to running, and after
running
-D, --drop-schema Drop schema if it exists prior to running and after
running.
-e, --engine=name Storage engine to use for creating the table.
-?, --help Display this help and exit.
-h, --host=name Connect to host.