1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
2
* vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
4
* Copyright (C) 2010 Vijay Samuel
5
* Copyright (C) 2008 MySQL
7
* This program is free software; you can redistribute it and/or modify
8
* it under the terms of the GNU General Public License as published by
9
* the Free Software Foundation; either version 2 of the License, or
10
* (at your option) any later version.
12
* This program is distributed in the hope that it will be useful,
13
* but WITHOUT ANY WARRANTY; without even the implied warranty of
14
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
* GNU General Public License for more details.
17
* You should have received a copy of the GNU General Public License
18
* along with this program; if not, write to the Free Software
19
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
1
/* Copyright (C) 2005 MySQL AB
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
26
24
A simple program designed to work as if multiple clients querying the database,
27
25
then reporting the timing of each stage.
29
Drizzle slap runs three stages:
27
MySQL slap runs three stages:
30
28
1) Create schema,table, and optionally any SP or data you want to beign
31
the test with. (single client)
29
the test with. (single client)
32
30
2) Load test (many clients)
33
31
3) Cleanup (disconnection, drop table if specified, single client)
37
Supply your own create and query SQL statements, with 50 clients
35
Supply your own create and query SQL statements, with 50 clients
38
36
querying (200 selects for each):
40
drizzleslap --delimiter=";" \
41
--create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
42
--query="SELECT * FROM A" --concurrency=50 --iterations=200
38
mysqlslap --delimiter=";" \
39
--create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
40
--query="SELECT * FROM A" --concurrency=50 --iterations=200
44
42
Let the program build the query SQL statement with a table of two int
45
43
columns, three varchar columns, five clients querying (20 times each),
46
44
don't create the table or insert the data (using the previous test's
49
drizzleslap --concurrency=5 --iterations=20 \
50
--number-int-cols=2 --number-char-cols=3 \
47
mysqlslap --concurrency=5 --iterations=20 \
48
--number-int-cols=2 --number-char-cols=3 \
53
51
Tell the program to load the create, insert and query SQL statements from
54
52
the specified files, where the create.sql file has multiple table creation
55
53
statements delimited by ';' and multiple insert statements delimited by ';'.
56
The --query file will have multiple queries delimited by ';', run all the
54
The --query file will have multiple queries delimited by ';', run all the
57
55
load statements, and then run all the queries in the query file
58
56
with five clients (five times each):
60
drizzleslap --concurrency=5 \
61
--iterations=5 --query=query.sql --create=create.sql \
58
mysqlslap --concurrency=5 \
59
--iterations=5 --query=query.sql --create=create.sql \
65
63
Add language for better tests
66
64
String length for files and those put on the command line are not
67
setup to handle binary data.
65
setup to handle binary data.
69
67
Break up tests and run them on multiple hosts at once.
70
68
Allow output to be fed into a database directly.
72
#define SLAP_VERSION "1.5"
74
#define HUGE_STRING_LENGTH 8196
75
#define RAND_STRING_SIZE 126
76
#define DEFAULT_BLOB_SIZE 1024
75
78
#include "client_priv.h"
77
#include "option_string.h"
79
#include "thread_context.h"
80
#include "conclusions.h"
79
#include <mysqld_error.h>
83
81
#include <signal.h>
84
82
#include <stdarg.h>
85
83
#include <sys/types.h>
86
84
#include <sys/wait.h>
87
#ifdef HAVE_SYS_STAT_H
88
# include <sys/stat.h>
97
#include <drizzled/configmake.h>
100
/* Added this for string translation. */
101
#include <drizzled/gettext.h>
103
#include <boost/thread.hpp>
104
#include <boost/thread/mutex.hpp>
105
#include <boost/thread/condition_variable.hpp>
106
#include <boost/program_options.hpp>
107
#include <boost/scoped_ptr.hpp>
108
#include <drizzled/atomics.h>
110
#define SLAP_NAME "drizzleslap"
111
#define SLAP_VERSION "1.5"
113
#define HUGE_STRING_LENGTH 8196
114
#define RAND_STRING_SIZE 126
115
#define DEFAULT_BLOB_SIZE 1024
118
using namespace drizzled;
119
namespace po= boost::program_options;
122
88
static char *shared_memory_base_name=0;
125
client::Wakeup master_wakeup;
91
/* Global Thread counter */
93
pthread_mutex_t counter_mutex;
94
pthread_cond_t count_threshhold;
96
pthread_mutex_t sleeper_mutex;
97
pthread_cond_t sleep_threshhold;
127
99
/* Global Thread timer */
128
100
static bool timer_alarm= false;
129
boost::mutex timer_alarm_mutex;
130
boost::condition_variable_any timer_alarm_threshold;
132
std::vector < std::string > primary_keys;
134
drizzled::atomic<size_t> connection_count;
135
drizzled::atomic<uint64_t> failed_update_for_transaction;
141
user_supplied_pre_statements,
142
user_supplied_post_statements,
147
static vector<string> user_supplied_queries;
148
static string opt_verbose;
149
std::string opt_protocol;
152
string create_schema_string;
154
static bool use_drizzle_protocol= false;
101
pthread_mutex_t timer_alarm_mutex;
102
pthread_cond_t timer_alarm_threshold;
104
static char **defaults_argv;
107
unsigned long long primary_keys_number_of;
109
static char *host= NULL, *opt_password= NULL, *user= NULL,
110
*user_supplied_query= NULL,
111
*user_supplied_pre_statements= NULL,
112
*user_supplied_post_statements= NULL,
113
*default_engine= NULL,
116
*opt_mysql_unix_port= NULL;
118
const char *delimiter= "\n";
120
const char *create_schema_string= "mysqlslap";
155
122
static bool opt_preserve= true;
156
static bool opt_only_print;
157
static bool opt_burnin;
123
static bool debug_info_flag= 0, debug_check_flag= 0;
124
static bool opt_only_print= false;
125
static bool opt_burnin= false;
158
126
static bool opt_ignore_sql_errors= false;
159
static bool opt_silent,
160
auto_generate_sql_autoincrement,
161
auto_generate_sql_guid_primary,
163
std::string opt_auto_generate_sql_type;
165
static int32_t verbose= 0;
166
static uint32_t delimiter_length;
167
static uint32_t commit_rate;
168
static uint32_t detach_rate;
169
static uint32_t opt_timer_length;
170
static uint32_t opt_delayed_start;
171
string num_blob_cols_opt,
175
static uint32_t opt_set_random_seed;
177
string auto_generate_selected_columns_opt;
127
static bool opt_compress= false, tty_password= false,
129
auto_generate_sql_autoincrement= false,
130
auto_generate_sql_guid_primary= false,
131
auto_generate_sql= false;
132
const char *opt_auto_generate_sql_type= "mixed";
134
static unsigned long connect_flags= CLIENT_MULTI_RESULTS |
135
CLIENT_MULTI_STATEMENTS;
137
static int verbose, delimiter_length;
138
static uint commit_rate;
139
static uint detach_rate;
140
static uint opt_timer_length;
141
static uint opt_delayed_start;
142
const char *num_int_cols_opt;
143
const char *num_char_cols_opt;
144
const char *num_blob_cols_opt;
145
const char *opt_label;
146
static unsigned int opt_set_random_seed;
148
const char *auto_generate_selected_columns_opt;
179
150
/* Yes, we do set defaults here */
180
static uint32_t num_int_cols= 1;
181
static uint32_t num_char_cols= 1;
182
static uint32_t num_blob_cols= 0;
183
static uint32_t num_blob_cols_size;
184
static uint32_t num_blob_cols_size_min;
185
static uint32_t num_int_cols_index= 0;
186
static uint32_t num_char_cols_index= 0;
187
static uint32_t iterations;
151
static unsigned int num_int_cols= 1;
152
static unsigned int num_char_cols= 1;
153
static unsigned int num_blob_cols= 0;
154
static unsigned int num_blob_cols_size;
155
static unsigned int num_blob_cols_size_min;
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;
188
161
static uint64_t actual_queries= 0;
189
162
static uint64_t auto_actual_queries;
190
163
static uint64_t auto_generate_sql_unique_write_number;
191
164
static uint64_t auto_generate_sql_unique_query_number;
192
static uint32_t auto_generate_sql_secondary_indexes;
165
static unsigned int auto_generate_sql_secondary_indexes;
193
166
static uint64_t num_of_query;
194
167
static uint64_t auto_generate_sql_number;
195
string concurrency_str;
196
string create_string;
197
std::vector <uint32_t> concurrency;
199
std::string opt_csv_str;
202
static int process_options(void);
203
static uint32_t opt_drizzle_port= 0;
205
static OptionString *engine_options= NULL;
206
static OptionString *query_options= NULL;
207
static Statement *pre_statements= NULL;
208
static Statement *post_statements= NULL;
209
static Statement *create_statements= NULL;
211
static std::vector <Statement *> query_statements;
212
static uint32_t query_statements_count;
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= MYSQL_PROTOCOL_TCP;
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 };
188
UPDATE_TYPE_REQUIRES_PREFIX= 3,
189
CREATE_TABLE_TYPE= 4,
190
SELECT_TYPE_REQUIRES_PREFIX= 5,
191
DELETE_TYPE_REQUIRES_PREFIX= 6
194
typedef struct statement statement;
199
slap_query_type type;
201
size_t option_length;
205
typedef struct option_string option_string;
207
struct option_string {
211
size_t option_length;
215
typedef struct stats stats;
221
unsigned long long rows;
222
long int create_timing;
223
unsigned long long create_count;
226
typedef struct thread_context thread_context;
228
struct thread_context {
233
typedef struct conclusions conclusions;
242
unsigned long long avg_rows;
243
long int sum_of_time;
245
/* These are just for create time stats */
246
long int create_avg_timing;
247
long int create_max_timing;
248
long int create_min_timing;
249
unsigned long long create_count;
250
/* The following are not used yet */
251
unsigned long long max_rows;
252
unsigned long long min_rows;
255
static option_string *engine_options= NULL;
256
static option_string *query_options= NULL;
257
static statement *pre_statements= NULL;
258
static statement *post_statements= NULL;
259
static statement *create_statements= NULL;
261
static statement **query_statements= NULL;
262
static unsigned int query_statements_count;
216
void print_conclusions(Conclusions &con);
217
void print_conclusions_csv(Conclusions &con);
218
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr);
219
uint32_t parse_comma(const char *string, std::vector <uint32_t> &range);
220
uint32_t parse_delimiter(const char *script, Statement **stmt, char delm);
221
uint32_t parse_option(const char *origin, OptionString **stmt, char delm);
222
static void drop_schema(drizzle_con_st &con, const char *db);
223
uint32_t get_random_string(char *buf, size_t size);
224
static Statement *build_table_string(void);
225
static Statement *build_insert_string(void);
226
static Statement *build_update_string(void);
227
static Statement * build_select_string(bool key);
228
static int generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt);
229
static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr);
230
static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit);
231
void statement_cleanup(Statement *stmt);
232
void option_cleanup(OptionString *stmt);
233
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr);
234
static void run_statements(drizzle_con_st &con, Statement *stmt);
235
void slap_connect(drizzle_con_st &con, bool connect_to_schema);
236
void slap_close(drizzle_con_st &con);
237
static int run_query(drizzle_con_st &con, drizzle_result_st *result, const char *query, int len);
238
void standard_deviation(Conclusions &con, Stats *sptr);
266
void print_conclusions(conclusions *con);
267
void print_conclusions_csv(conclusions *con);
268
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
269
uint parse_comma(const char *string, uint **range);
270
uint parse_delimiter(const char *script, statement **stmt, char delm);
271
uint parse_option(const char *origin, option_string **stmt, char delm);
272
static int drop_schema(MYSQL *mysql, const char *db);
273
uint get_random_string(char *buf, size_t size);
274
static statement *build_table_string(void);
275
static statement *build_insert_string(void);
276
static statement *build_update_string(void);
277
static statement * build_select_string(bool key);
278
static int generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt);
279
static int drop_primary_key_list(void);
280
static int create_schema(MYSQL *mysql, const char *db, statement *stmt,
281
option_string *engine_stmt, stats *sptr);
282
static int run_scheduler(stats *sptr, statement **stmts, uint concur,
284
pthread_handler_t run_task(void *p);
285
pthread_handler_t timer_thread(void *p);
286
void statement_cleanup(statement *stmt);
287
void option_cleanup(option_string *stmt);
288
void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr);
289
static int run_statements(MYSQL *mysql, statement *stmt);
290
void slap_connect(MYSQL *mysql, bool connect_to_schema);
291
void slap_close(MYSQL *mysql);
292
static int run_query(MYSQL *mysql, const char *query, int len);
293
void standard_deviation (conclusions *con, stats *sptr);
240
295
static const char ALPHANUMERICS[]=
241
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
296
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
243
298
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
246
301
static long int timedif(struct timeval a, struct timeval b)
250
us = a.tv_usec - b.tv_usec;
252
s = a.tv_sec - b.tv_sec;
257
static void combine_queries(vector<string> queries)
259
user_supplied_query.erase();
260
for (vector<string>::iterator it= queries.begin();
264
user_supplied_query.append(*it);
265
user_supplied_query.append(delimiter);
270
static void run_task(ThreadContext *ctx)
272
uint64_t counter= 0, queries;
273
uint64_t detach_counter;
274
uint32_t commit_counter;
275
boost::scoped_ptr<drizzle_con_st> con_ap(new drizzle_con_st);
276
drizzle_con_st &con= *con_ap.get();
277
drizzle_result_st result;
281
master_wakeup.wait();
283
slap_connect(con, true);
286
printf("connected!\n");
291
run_query(con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
294
for (ptr= ctx->getStmt(), detach_counter= 0;
295
ptr && ptr->getLength();
296
ptr= ptr->getNext(), detach_counter++)
298
if (not opt_only_print && detach_rate && !(detach_counter % detach_rate))
301
slap_connect(con, true);
305
We have to execute differently based on query type. This should become a function.
307
bool is_failed_update= false;
308
if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) ||
309
(ptr->getType() == SELECT_TYPE_REQUIRES_PREFIX))
313
char buffer[HUGE_STRING_LENGTH];
316
This should only happen if some sort of new engine was
317
implemented that didn't properly handle UPDATEs.
319
Just in case someone runs this under an experimental engine we don't
320
want a crash so the if() is placed here.
322
assert(primary_keys.size());
323
if (primary_keys.size())
325
key_val= (uint32_t)(random() % primary_keys.size());
327
key= primary_keys[key_val].c_str();
331
length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
332
(int)ptr->getLength(), ptr->getString(), key);
334
if (run_query(con, &result, buffer, length))
336
if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
338
// Expand to check to see if Innodb, if so we should restart the
341
is_failed_update= true;
342
failed_update_for_transaction.fetch_and_increment();
346
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
347
SLAP_NAME, (uint32_t)length, buffer, drizzle_con_error(&con));
355
if (run_query(con, &result, ptr->getString(), ptr->getLength()))
357
if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
359
// Expand to check to see if Innodb, if so we should restart the
362
is_failed_update= true;
363
failed_update_for_transaction.fetch_and_increment();
367
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
368
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
374
if (not opt_only_print and not is_failed_update)
376
while ((row = drizzle_row_next(&result)))
378
drizzle_result_free(&result);
382
if (commit_rate && (++commit_counter == commit_rate) and not is_failed_update)
385
run_query(con, NULL, "COMMIT", strlen("COMMIT"));
388
/* If the timer is set, and the alarm is not active then end */
389
if (opt_timer_length && timer_alarm == false)
392
/* If limit has been reached, and we are not in a timer_alarm just end */
393
if (ctx->getLimit() && queries == ctx->getLimit() && timer_alarm == false)
397
if (opt_timer_length && timer_alarm == true)
400
if (ctx->getLimit() && queries < ctx->getLimit())
406
run_query(con, NULL, "COMMIT", strlen("COMMIT"));
414
* commandline_options is the set of all options that can only be called via the command line.
416
* client_options is the set of all options that can be defined via both command line and via
417
* the configuration file client.cnf
419
* slap_options is the set of all drizzleslap specific options which behave in a manner
420
* similar to that of client_options. It's configuration file is drizzleslap.cnf
422
* long_options is the union of commandline_options, slap_options and client_options.
424
* There are two configuration files per set of options, one which is defined by the user
425
* which is found at either $XDG_CONFIG_HOME/drizzle or ~/.config/drizzle directory and the other which
426
* is the system configuration file which is found in the SYSCONFDIR/drizzle directory.
428
* The system configuration file is over ridden by the user's configuration file which
429
* in turn is over ridden by the command line.
305
us = a.tv_usec - b.tv_usec;
307
s = a.tv_sec - b.tv_sec;
431
312
int main(int argc, char **argv)
433
char *password= NULL;
436
po::options_description commandline_options("Options used only in command line");
437
commandline_options.add_options()
438
("help,?","Display this help and exit")
439
("info","Gives information and exit")
440
("burnin",po::value<bool>(&opt_burnin)->default_value(false)->zero_tokens(),
441
"Run full test case in infinite loop")
442
("ignore-sql-errors", po::value<bool>(&opt_ignore_sql_errors)->default_value(false)->zero_tokens(),
443
"Ignore SQL errors in query run")
444
("create-schema",po::value<string>(&create_schema_string)->default_value("drizzleslap"),
445
"Schema to run tests in")
446
("create",po::value<string>(&create_string)->default_value(""),
447
"File or string to use to create tables")
448
("detach",po::value<uint32_t>(&detach_rate)->default_value(0),
449
"Detach (close and re open) connections after X number of requests")
450
("iterations,i",po::value<uint32_t>(&iterations)->default_value(1),
451
"Number of times to run the tests")
452
("label",po::value<string>(&opt_label)->default_value(""),
453
"Label to use for print and csv")
454
("number-blob-cols",po::value<string>(&num_blob_cols_opt)->default_value(""),
455
"Number of BLOB columns to create table with if specifying --auto-generate-sql. Example --number-blob-cols=3:1024/2048 would give you 3 blobs with a random size between 1024 and 2048. ")
456
("number-char-cols,x",po::value<string>(&num_char_cols_opt)->default_value(""),
457
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.")
458
("number-int-cols,y",po::value<string>(&num_int_cols_opt)->default_value(""),
459
"Number of INT columns to create in table if specifying --auto-generate-sql.")
460
("number-of-queries",
461
po::value<uint64_t>(&num_of_query)->default_value(0),
462
"Limit each client to this number of queries(this is not exact)")
463
("only-print",po::value<bool>(&opt_only_print)->default_value(false)->zero_tokens(),
464
"This causes drizzleslap to not connect to the database instead print out what it would have done instead")
465
("post-query", po::value<string>(&user_supplied_post_statements)->default_value(""),
466
"Query to run or file containing query to execute after tests have completed.")
467
("post-system",po::value<string>(&post_system)->default_value(""),
468
"system() string to execute after tests have completed")
470
po::value<string>(&user_supplied_pre_statements)->default_value(""),
471
"Query to run or file containing query to execute before running tests.")
472
("pre-system",po::value<string>(&pre_system)->default_value(""),
473
"system() string to execute before running tests.")
474
("query,q",po::value<vector<string> >(&user_supplied_queries)->composing()->notifier(&combine_queries),
475
"Query to run or file containing query")
476
("verbose,v", po::value<string>(&opt_verbose)->default_value("v"), "Increase verbosity level by one.")
477
("version,V","Output version information and exit")
480
po::options_description slap_options("Options specific to drizzleslap");
481
slap_options.add_options()
482
("auto-generate-sql-select-columns",
483
po::value<string>(&auto_generate_selected_columns_opt)->default_value(""),
484
"Provide a string to use for the select fields used in auto tests")
485
("auto-generate-sql,a",po::value<bool>(&auto_generate_sql)->default_value(false)->zero_tokens(),
486
"Generate SQL where not supplied by file or command line")
487
("auto-generate-sql-add-autoincrement",
488
po::value<bool>(&auto_generate_sql_autoincrement)->default_value(false)->zero_tokens(),
489
"Add an AUTO_INCREMENT column to auto-generated tables")
490
("auto-generate-sql-execute-number",
491
po::value<uint64_t>(&auto_actual_queries)->default_value(0),
492
"See this number and generate a set of queries to run")
493
("auto-generate-sql-guid-primary",
494
po::value<bool>(&auto_generate_sql_guid_primary)->default_value(false)->zero_tokens(),
495
"Add GUID based primary keys to auto-generated tables")
496
("auto-generate-sql-load-type",
497
po::value<string>(&opt_auto_generate_sql_type)->default_value("mixed"),
498
"Specify test load type: mixed, update, write, key or read; default is mixed")
499
("auto-generate-sql-secondary-indexes",
500
po::value<uint32_t>(&auto_generate_sql_secondary_indexes)->default_value(0),
501
"Number of secondary indexes to add to auto-generated tables")
502
("auto-generated-sql-unique-query-number",
503
po::value<uint64_t>(&auto_generate_sql_unique_query_number)->default_value(10),
504
"Number of unique queries to generate for automatic tests")
505
("auto-generate-sql-unique-write-number",
506
po::value<uint64_t>(&auto_generate_sql_unique_write_number)->default_value(10),
507
"Number of unique queries to generate for auto-generate-sql-write-number")
508
("auto-generate-sql-write-number",
509
po::value<uint64_t>(&auto_generate_sql_number)->default_value(100),
510
"Number of row inserts to perform for each thread (default is 100).")
511
("commit",po::value<uint32_t>(&commit_rate)->default_value(0),
512
"Commit records every X number of statements")
513
("concurrency,c",po::value<string>(&concurrency_str)->default_value(""),
514
"Number of clients to simulate for query to run")
515
("csv",po::value<std::string>(&opt_csv_str)->default_value(""),
516
"Generate CSV output to named file or to stdout if no file is name.")
517
("delayed-start",po::value<uint32_t>(&opt_delayed_start)->default_value(0),
518
"Delay the startup of threads by a random number of microsends (the maximum of the delay")
519
("delimiter,F",po::value<string>(&delimiter)->default_value("\n"),
520
"Delimiter to use in SQL statements supplied in file or command line")
521
("engine,e",po::value<string>(&default_engine)->default_value(""),
522
"Storage engine to use for creating the table")
524
po::value<uint32_t>(&opt_set_random_seed)->default_value(0),
525
"Seed for random number generator (srandom(3)) ")
526
("silent,s",po::value<bool>(&opt_silent)->default_value(false)->zero_tokens(),
527
"Run program in silent mode - no output. ")
528
("timer-length",po::value<uint32_t>(&opt_timer_length)->default_value(0),
529
"Require drizzleslap to run each specific test a certain amount of time in seconds")
532
po::options_description client_options("Options specific to the client");
533
client_options.add_options()
534
("host,h",po::value<string>(&host)->default_value("localhost"),"Connect to the host")
535
("password,P",po::value<char *>(&password),
536
"Password to use when connecting to server. If password is not given it's asked from the tty")
537
("port,p",po::value<uint32_t>(), "Port number to use for connection")
538
("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
539
"The protocol of connection (mysql or drizzle).")
540
("user,u",po::value<string>(&user)->default_value(""),
541
"User for login if not current user")
544
po::options_description long_options("Allowed Options");
545
long_options.add(commandline_options).add(slap_options).add(client_options);
547
std::string system_config_dir_slap(SYSCONFDIR);
548
system_config_dir_slap.append("/drizzle/drizzleslap.cnf");
550
std::string system_config_dir_client(SYSCONFDIR);
551
system_config_dir_client.append("/drizzle/client.cnf");
553
std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
555
if (user_config_dir.compare(0, 2, "~/") == 0)
558
homedir= getenv("HOME");
560
user_config_dir.replace(0, 1, homedir);
563
uint64_t temp_drizzle_port= 0;
564
boost::scoped_ptr<drizzle_con_st> con_ap(new drizzle_con_st);
565
drizzle_con_st &con= *con_ap.get();
568
// Disable allow_guessing
569
int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
571
po::variables_map vm;
572
po::store(po::command_line_parser(argc, argv).options(long_options).
573
style(style).extra_parser(parse_password_arg).run(), vm);
575
std::string user_config_dir_slap(user_config_dir);
576
user_config_dir_slap.append("/drizzle/drizzleslap.cnf");
578
std::string user_config_dir_client(user_config_dir);
579
user_config_dir_client.append("/drizzle/client.cnf");
581
ifstream user_slap_ifs(user_config_dir_slap.c_str());
582
po::store(parse_config_file(user_slap_ifs, slap_options), vm);
584
ifstream user_client_ifs(user_config_dir_client.c_str());
585
po::store(parse_config_file(user_client_ifs, client_options), vm);
587
ifstream system_slap_ifs(system_config_dir_slap.c_str());
588
store(parse_config_file(system_slap_ifs, slap_options), vm);
590
ifstream system_client_ifs(system_config_dir_client.c_str());
591
store(parse_config_file(system_client_ifs, client_options), vm);
595
if (process_options())
598
if ( vm.count("help") || vm.count("info"))
600
printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
601
drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
602
puts("Copyright (C) 2008 Sun Microsystems");
603
puts("This software comes with ABSOLUTELY NO WARRANTY. "
604
"This is free software,\n"
605
"and you are welcome to modify and redistribute it under the GPL "
607
puts("Run a query multiple times against the server\n");
608
cout << long_options << endl;
612
if (vm.count("protocol"))
614
std::transform(opt_protocol.begin(), opt_protocol.end(),
615
opt_protocol.begin(), ::tolower);
617
if (not opt_protocol.compare("mysql"))
618
use_drizzle_protocol=false;
619
else if (not opt_protocol.compare("drizzle"))
620
use_drizzle_protocol=true;
623
cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
627
if (vm.count("port"))
629
temp_drizzle_port= vm["port"].as<uint32_t>();
631
if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
633
fprintf(stderr, _("Value supplied for port is not valid.\n"));
638
opt_drizzle_port= (uint32_t) temp_drizzle_port;
642
if ( vm.count("password") )
644
if (not opt_password.empty())
645
opt_password.erase();
646
if (password == PASSWORD_SENTINEL)
652
opt_password= password;
663
if ( vm.count("version") )
665
printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
666
drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
670
/* Seed the random number generator if we will be using it. */
671
if (auto_generate_sql)
673
if (opt_set_random_seed == 0)
674
opt_set_random_seed= (uint32_t)time(NULL);
675
srandom(opt_set_random_seed);
678
/* globals? Yes, so we only have to run strlen once */
679
delimiter_length= delimiter.length();
681
slap_connect(con, false);
683
/* Main iterations loop */
322
if (!(mysql_thread_safe()))
323
fprintf(stderr, "This application was compiled incorrectly. Please recompile with thread support.\n");
325
load_defaults("my",load_default_groups,&argc,&argv);
327
if (get_options(&argc,&argv))
329
free_defaults(defaults_argv);
334
/* Seed the random number generator if we will be using it. */
335
if (auto_generate_sql)
337
if (opt_set_random_seed == 0)
338
opt_set_random_seed= (unsigned int)time(NULL);
339
srandom(opt_set_random_seed);
342
/* globals? Yes, so we only have to run strlen once */
343
delimiter_length= strlen(delimiter);
347
fprintf(stderr,"%s: Too many arguments\n",my_progname);
348
free_defaults(defaults_argv);
353
slap_connect(&mysql, false);
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));
359
VOID(pthread_mutex_init(&timer_alarm_mutex, NULL));
360
VOID(pthread_cond_init(&timer_alarm_threshold, NULL));
363
/* Main iterations loop */
685
eptr= engine_options;
688
/* For the final stage we run whatever queries we were asked to run */
692
printf("Starting Concurrency Test\n");
694
if (concurrency.size())
696
for (current= &concurrency[0]; current && *current; current++)
697
concurrency_loop(con, *current, eptr);
701
uint32_t infinite= 1;
703
concurrency_loop(con, infinite, eptr);
708
if (not opt_preserve)
709
drop_schema(con, create_schema_string.c_str());
711
} while (eptr ? (eptr= eptr->getNext()) : 0);
718
/* now free all the strings we created */
719
if (not opt_password.empty())
720
opt_password.erase();
724
statement_cleanup(create_statements);
725
for (uint32_t x= 0; x < query_statements_count; x++)
726
statement_cleanup(query_statements[x]);
727
query_statements.clear();
728
statement_cleanup(pre_statements);
729
statement_cleanup(post_statements);
730
option_cleanup(engine_options);
731
option_cleanup(query_options);
365
eptr= engine_options;
368
/* For the final stage we run whatever queries we were asked to run */
372
printf("Starting Concurrency Test\n");
376
for (current= concurrency; current && *current; current++)
377
concurrency_loop(&mysql, *current, eptr);
383
concurrency_loop(&mysql, infinite, eptr);
389
drop_schema(&mysql, create_schema_string);
391
} while (eptr ? (eptr= eptr->next) : 0);
396
VOID(pthread_mutex_destroy(&counter_mutex));
397
VOID(pthread_cond_destroy(&count_threshhold));
398
VOID(pthread_mutex_destroy(&sleeper_mutex));
399
VOID(pthread_cond_destroy(&sleep_threshhold));
400
VOID(pthread_mutex_destroy(&timer_alarm_mutex));
401
VOID(pthread_cond_destroy(&timer_alarm_threshold));
405
/* now free all the strings we created */
407
my_free(opt_password, MYF(0));
409
my_free(concurrency, MYF(0));
411
statement_cleanup(create_statements);
412
for (x= 0; x < query_statements_count; x++)
413
statement_cleanup(query_statements[x]);
414
my_free(query_statements, MYF(0));
415
statement_cleanup(pre_statements);
416
statement_cleanup(post_statements);
417
option_cleanup(engine_options);
418
option_cleanup(query_options);
734
if (shared_memory_base_name)
735
free(shared_memory_base_name);
421
if (shared_memory_base_name)
422
my_free(shared_memory_base_name, MYF(MY_ALLOW_ZERO_PTR));
740
catch(std::exception &err)
742
cerr<<"Error:"<<err.what()<<endl;
745
if (csv_file != fileno(stdout))
424
free_defaults(defaults_argv);
751
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
430
void concurrency_loop(MYSQL *mysql, uint current, option_string *eptr)
755
Conclusions conclusion;
756
uint64_t client_limit;
758
head_sptr= new Stats[iterations];
759
if (head_sptr == NULL)
761
fprintf(stderr,"Error allocating memory in concurrency_loop\n");
435
conclusions conclusion;
436
unsigned long long client_limit;
438
head_sptr= (stats *)my_malloc(sizeof(stats) * iterations,
439
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
441
bzero(&conclusion, sizeof(conclusions));
765
443
if (auto_actual_queries)
766
444
client_limit= auto_actual_queries;
828
502
generate_stats(&conclusion, eptr, head_sptr);
831
print_conclusions(conclusion);
832
if (not opt_csv_str.empty())
833
print_conclusions_csv(conclusion);
839
uint32_t get_random_string(char *buf, size_t size)
505
print_conclusions(&conclusion);
507
print_conclusions_csv(&conclusion);
509
my_free(head_sptr, MYF(0));
514
static struct my_option my_long_options[] =
516
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
518
{"auto-generate-sql-select-columns", OPT_SLAP_AUTO_GENERATE_SELECT_COLUMNS,
519
"Provide a string to use for the select fields used in auto tests.",
520
(char**) &auto_generate_selected_columns_opt,
521
(char**) &auto_generate_selected_columns_opt,
522
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
523
{"auto-generate-sql", 'a',
524
"Generate SQL where not supplied by file or command line.",
525
(char**) &auto_generate_sql, (char**) &auto_generate_sql,
526
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
527
{"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
528
"Add an AUTO_INCREMENT column to auto-generated tables.",
529
(char**) &auto_generate_sql_autoincrement,
530
(char**) &auto_generate_sql_autoincrement,
531
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
532
{"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
533
"Set this number to generate a set number of queries to run.",
534
(char**) &auto_actual_queries, (char**) &auto_actual_queries,
535
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
536
{"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
537
"Add GUID based primary keys to auto-generated tables.",
538
(char**) &auto_generate_sql_guid_primary,
539
(char**) &auto_generate_sql_guid_primary,
540
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
541
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
542
"Specify test load type: mixed, update, write, key, or read; default is mixed.",
543
(char**) &opt_auto_generate_sql_type, (char**) &opt_auto_generate_sql_type,
544
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
545
{"auto-generate-sql-secondary-indexes",
546
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
547
"Number of secondary indexes to add to auto-generated tables.",
548
(char**) &auto_generate_sql_secondary_indexes,
549
(char**) &auto_generate_sql_secondary_indexes, 0,
550
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
551
{"auto-generate-sql-unique-query-number",
552
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
553
"Number of unique queries to generate for automatic tests.",
554
(char**) &auto_generate_sql_unique_query_number,
555
(char**) &auto_generate_sql_unique_query_number,
556
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
557
{"auto-generate-sql-unique-write-number",
558
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
559
"Number of unique queries to generate for auto-generate-sql-write-number.",
560
(char**) &auto_generate_sql_unique_write_number,
561
(char**) &auto_generate_sql_unique_write_number,
562
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
563
{"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
564
"Number of row inserts to perform for each thread (default is 100).",
565
(char**) &auto_generate_sql_number, (char**) &auto_generate_sql_number,
566
0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
567
{"burnin", OPT_SLAP_BURNIN, "Run full test case in infinite loop.",
568
(char**) &opt_burnin, (char**) &opt_burnin, 0, GET_BOOL, NO_ARG, 0, 0, 0,
570
{"ignore-sql-errors", OPT_SLAP_IGNORE_SQL_ERRORS,
571
"Ignore SQL erros in query run.",
572
(char**) &opt_ignore_sql_errors,
573
(char**) &opt_ignore_sql_errors,
574
0, GET_BOOL, NO_ARG, 0, 0, 0,
576
{"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
577
(char**) &commit_rate, (char**) &commit_rate, 0, GET_UINT, REQUIRED_ARG,
579
{"compress", 'C', "Use compression in server/client protocol.",
580
(char**) &opt_compress, (char**) &opt_compress, 0, GET_BOOL, NO_ARG, 0, 0, 0,
582
{"concurrency", 'c', "Number of clients to simulate for query to run.",
583
(char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
584
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
585
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
586
(char**) &create_string, (char**) &create_string, 0, GET_STR, REQUIRED_ARG,
588
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
589
(char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR,
590
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
591
{"csv", OPT_SLAP_CSV,
592
"Generate CSV output to named file or to stdout if no file is named.",
593
(char**) &opt_csv_str, (char**) &opt_csv_str, 0, GET_STR,
594
OPT_ARG, 0, 0, 0, 0, 0, 0},
595
{"debug-check", OPT_DEBUG_CHECK, "Check memory and open file usage at exit.",
596
(char**) &debug_check_flag, (char**) &debug_check_flag, 0,
597
GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
598
{"debug-info", 'T', "Print some debug info at exit.", (char**) &debug_info_flag,
599
(char**) &debug_info_flag, 0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
600
{"delayed-start", OPT_SLAP_DELAYED_START,
601
"Delay the startup of threads by a random number of microsends (the maximum of the delay)",
602
(char**) &opt_delayed_start, (char**) &opt_delayed_start, 0, GET_UINT,
603
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
605
"Delimiter to use in SQL statements supplied in file or command line.",
606
(char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
608
{"detach", OPT_SLAP_DETACH,
609
"Detach (close and reopen) connections after X number of requests.",
610
(char**) &detach_rate, (char**) &detach_rate, 0, GET_UINT, REQUIRED_ARG,
612
{"engine", 'e', "Storage engine to use for creating the table.",
613
(char**) &default_engine, (char**) &default_engine, 0,
614
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
615
{"host", 'h', "Connect to host.", (char**) &host, (char**) &host, 0, GET_STR,
616
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
617
{"iterations", 'i', "Number of times to run the tests.", (char**) &iterations,
618
(char**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
619
{"label", OPT_SLAP_LABEL, "Label to use for print and csv output.",
620
(char**) &opt_label, (char**) &opt_label, 0,
621
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
622
{"number-blob-cols", OPT_SLAP_BLOB_COL,
623
"Number of BLOB columns to create table with if specifying --auto-generate-sql. Example --number-blob-cols=3:1024/2048 would give you 3 blobs with a random size between 1024 and 2048. ",
624
(char**) &num_blob_cols_opt, (char**) &num_blob_cols_opt, 0, GET_STR, REQUIRED_ARG,
626
{"number-char-cols", 'x',
627
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
628
(char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
630
{"number-int-cols", 'y',
631
"Number of INT columns to create in table if specifying --auto-generate-sql.",
632
(char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
634
{"number-of-queries", OPT_MYSQL_NUMBER_OF_QUERY,
635
"Limit each client to this number of queries (this is not exact).",
636
(char**) &num_of_query, (char**) &num_of_query, 0,
637
GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
638
{"only-print", OPT_MYSQL_ONLY_PRINT,
639
"This causes mysqlslap to not connect to the databases, but instead print "
640
"out what it would have done instead.",
641
(char**) &opt_only_print, (char**) &opt_only_print, 0, GET_BOOL, NO_ARG,
644
"Password to use when connecting to server. If password is not given it's "
645
"asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
646
{"port", 'P', "Port number to use for connection.", (char**) &opt_mysql_port,
647
(char**) &opt_mysql_port, 0, GET_UINT, REQUIRED_ARG, MYSQL_PORT, 0, 0, 0, 0,
649
{"post-query", OPT_SLAP_POST_QUERY,
650
"Query to run or file containing query to execute after tests have completed.",
651
(char**) &user_supplied_post_statements,
652
(char**) &user_supplied_post_statements,
653
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
654
{"post-system", OPT_SLAP_POST_SYSTEM,
655
"system() string to execute after tests have completed.",
656
(char**) &post_system,
657
(char**) &post_system,
658
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
659
{"pre-query", OPT_SLAP_PRE_QUERY,
660
"Query to run or file containing query to execute before running tests.",
661
(char**) &user_supplied_pre_statements,
662
(char**) &user_supplied_pre_statements,
663
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
664
{"pre-system", OPT_SLAP_PRE_SYSTEM,
665
"system() string to execute before running tests.",
666
(char**) &pre_system,
667
(char**) &pre_system,
668
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
669
{"protocol", OPT_MYSQL_PROTOCOL,
670
"The protocol of connection (tcp,socket,pipe,memory).",
671
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
672
{"query", 'q', "Query to run or file containing query to run.",
673
(char**) &user_supplied_query, (char**) &user_supplied_query,
674
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
675
{"set-random-seed", OPT_SLAP_SET_RANDOM_SEED,
676
"Seed for random number generator (srandom(3))",
677
(char**)&opt_set_random_seed,
678
(char**)&opt_set_random_seed,0,
679
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
681
{"shared-memory-base-name", OPT_SHARED_MEMORY_BASE_NAME,
682
"Base name of shared memory.", (char**) &shared_memory_base_name,
683
(char**) &shared_memory_base_name, 0, GET_STR_ALLOC, REQUIRED_ARG,
686
{"silent", 's', "Run program in silent mode - no output.",
687
(char**) &opt_silent, (char**) &opt_silent, 0, GET_BOOL, NO_ARG,
689
{"socket", 'S', "Socket file to use for connection.",
690
(char**) &opt_mysql_unix_port, (char**) &opt_mysql_unix_port, 0, GET_STR,
691
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
692
{"timer-length", OPT_SLAP_TIMER_LENGTH,
693
"Require mysqlslap to run each specific test a certain amount of time in seconds.",
694
(char**) &opt_timer_length, (char**) &opt_timer_length, 0, GET_UINT,
695
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
696
#ifndef DONT_ALLOW_USER_CHANGE
697
{"user", 'u', "User for login if not current user.", (char**) &user,
698
(char**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
701
"More verbose output; you can use this multiple times to get even more "
702
"verbose output.", (char**) &verbose, (char**) &verbose, 0,
703
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
704
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
705
NO_ARG, 0, 0, 0, 0, 0, 0},
706
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
710
#include <help_start.h>
712
static void print_version(void)
714
printf("%s Ver %s Distrib %s, for %s (%s)\n",my_progname, SLAP_VERSION,
715
MYSQL_SERVER_VERSION,SYSTEM_TYPE,MACHINE_TYPE);
719
static void usage(void)
722
puts("Copyright (C) 2005 MySQL AB");
723
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
724
\nand you are welcome to modify and redistribute it under the GPL \
726
puts("Run a query multiple times against the server\n");
727
printf("Usage: %s [OPTIONS]\n",my_progname);
728
print_defaults("my",load_default_groups);
729
my_print_help(my_long_options);
732
#include <help_end.h>
735
get_one_option(int optid, const struct my_option *opt __attribute__((unused)),
746
char *start= argument;
747
my_free(opt_password, MYF(MY_ALLOW_ZERO_PTR));
748
opt_password= my_strdup(argument,MYF(MY_FAE));
749
while (*argument) *argument++= 'x'; /* Destroy argument */
751
start[1]= 0; /* Cut length of argument */
771
get_random_string(char *buf, size_t size)
841
773
char *buf_ptr= buf;
843
for (size_t x= size; x > 0; x--)
776
for (x= size; x > 0; x--)
844
777
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
845
778
return(buf_ptr - buf);
1488
1453
query_statements[sql_type_count]= build_insert_string();
1490
1455
This logic should be extended to do a more mixed load,
1491
1456
at the moment it results in "every other".
1493
for (ptr_statement= query_statements[sql_type_count], x= 0;
1494
x < auto_generate_sql_unique_query_number;
1495
x++, ptr_statement= ptr_statement->getNext())
1458
for (ptr_statement= query_statements[sql_type_count], x= 0;
1459
x < auto_generate_sql_unique_query_number;
1460
x++, ptr_statement= ptr_statement->next)
1499
ptr_statement->setNext(build_insert_string());
1464
ptr_statement->next= build_insert_string();
1504
ptr_statement->setNext(build_select_string(true));
1469
ptr_statement->next= build_select_string(true);
1509
1474
sql_type_count++;
1510
} while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1475
} while (sql_type ? (sql_type= sql_type->next) : 0);
1514
if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1479
if (create_string && !stat(create_string, &sbuf))
1517
std::vector<char> tmp_string;
1518
if (not S_ISREG(sbuf.st_mode))
1482
if (!MY_S_ISREG(sbuf.st_mode))
1520
1484
fprintf(stderr,"%s: Create file was not a regular file\n",
1524
if ((data_file= open(create_string.c_str(), O_RDWR)) == -1)
1526
fprintf(stderr,"%s: Could not open create file\n", SLAP_NAME);
1529
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1531
fprintf(stderr, "Request for more memory than architecture supports\n");
1534
tmp_string.resize(sbuf.st_size + 1);
1535
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1536
(size_t)sbuf.st_size);
1538
if (bytes_read != sbuf.st_size)
1540
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1542
parse_delimiter(&tmp_string[0], &create_statements, delimiter[0]);
1488
if ((data_file= my_open(create_string, O_RDWR, MYF(0))) == -1)
1490
fprintf(stderr,"%s: Could not open create file\n", my_progname);
1493
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1494
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1495
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1496
tmp_string[sbuf.st_size]= '\0';
1497
my_close(data_file,MYF(0));
1498
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1499
my_free(tmp_string, MYF(0));
1544
else if (not create_string.empty())
1501
else if (create_string)
1546
parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1503
parse_delimiter(create_string, &create_statements, delimiter[0]);
1549
1506
/* Set this up till we fully support options on user generated queries */
1550
if (not user_supplied_query.empty())
1507
if (user_supplied_query)
1552
query_statements_count=
1509
query_statements_count=
1553
1510
parse_option("default", &query_options, ',');
1555
query_statements.resize(query_statements_count);
1512
query_statements= (statement **)my_malloc(sizeof(statement *),
1513
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1558
if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1516
if (user_supplied_query && !stat(user_supplied_query, &sbuf))
1561
std::vector<char> tmp_string;
1563
if (not S_ISREG(sbuf.st_mode))
1519
if (!MY_S_ISREG(sbuf.st_mode))
1565
1521
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1569
if ((data_file= open(user_supplied_query.c_str(), O_RDWR)) == -1)
1571
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1574
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1576
fprintf(stderr, "Request for more memory than architecture supports\n");
1579
tmp_string.resize((size_t)(sbuf.st_size + 1));
1580
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1581
(size_t)sbuf.st_size);
1583
if (bytes_read != sbuf.st_size)
1585
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1587
if (not user_supplied_query.empty())
1588
actual_queries= parse_delimiter(&tmp_string[0], &query_statements[0],
1525
if ((data_file= my_open(user_supplied_query, O_RDWR, MYF(0))) == -1)
1527
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1530
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1531
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1532
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1533
tmp_string[sbuf.st_size]= '\0';
1534
my_close(data_file,MYF(0));
1535
if (user_supplied_query)
1536
actual_queries= parse_delimiter(tmp_string, &query_statements[0],
1591
else if (not user_supplied_query.empty())
1538
my_free(tmp_string, MYF(0));
1540
else if (user_supplied_query)
1593
actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1542
actual_queries= parse_delimiter(user_supplied_query, &query_statements[0],
1598
if (not user_supplied_pre_statements.empty()
1599
&& !stat(user_supplied_pre_statements.c_str(), &sbuf))
1547
if (user_supplied_pre_statements
1548
&& !stat(user_supplied_pre_statements, &sbuf))
1602
std::vector<char> tmp_string;
1604
if (not S_ISREG(sbuf.st_mode))
1551
if (!MY_S_ISREG(sbuf.st_mode))
1606
1553
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1610
if ((data_file= open(user_supplied_pre_statements.c_str(), O_RDWR)) == -1)
1612
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1615
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1617
fprintf(stderr, "Request for more memory than architecture supports\n");
1620
tmp_string.resize((size_t)(sbuf.st_size + 1));
1621
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1622
(size_t)sbuf.st_size);
1624
if (bytes_read != sbuf.st_size)
1626
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1628
if (not user_supplied_pre_statements.empty())
1629
(void)parse_delimiter(&tmp_string[0], &pre_statements,
1557
if ((data_file= my_open(user_supplied_pre_statements, O_RDWR, MYF(0))) == -1)
1559
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1562
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1563
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1564
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1565
tmp_string[sbuf.st_size]= '\0';
1566
my_close(data_file,MYF(0));
1567
if (user_supplied_pre_statements)
1568
(void)parse_delimiter(tmp_string, &pre_statements,
1632
else if (not user_supplied_pre_statements.empty())
1570
my_free(tmp_string, MYF(0));
1572
else if (user_supplied_pre_statements)
1634
(void)parse_delimiter(user_supplied_pre_statements.c_str(),
1574
(void)parse_delimiter(user_supplied_pre_statements,
1635
1575
&pre_statements,
1639
if (not user_supplied_post_statements.empty()
1640
&& !stat(user_supplied_post_statements.c_str(), &sbuf))
1579
if (user_supplied_post_statements
1580
&& !stat(user_supplied_post_statements, &sbuf))
1643
std::vector<char> tmp_string;
1645
if (not S_ISREG(sbuf.st_mode))
1583
if (!MY_S_ISREG(sbuf.st_mode))
1647
1585
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1651
if ((data_file= open(user_supplied_post_statements.c_str(), O_RDWR)) == -1)
1653
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1657
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1659
fprintf(stderr, "Request for more memory than architecture supports\n");
1662
tmp_string.resize((size_t)(sbuf.st_size + 1));
1664
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1665
(size_t)(sbuf.st_size));
1667
if (bytes_read != sbuf.st_size)
1669
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1671
if (not user_supplied_post_statements.empty())
1672
(void)parse_delimiter(&tmp_string[0], &post_statements,
1589
if ((data_file= my_open(user_supplied_post_statements, O_RDWR, MYF(0))) == -1)
1591
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1594
tmp_string= (char *)my_malloc(sbuf.st_size + 1,
1595
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1596
my_read(data_file, (uchar*) tmp_string, sbuf.st_size, MYF(0));
1597
tmp_string[sbuf.st_size]= '\0';
1598
my_close(data_file,MYF(0));
1599
if (user_supplied_post_statements)
1600
(void)parse_delimiter(tmp_string, &post_statements,
1675
else if (not user_supplied_post_statements.empty())
1602
my_free(tmp_string, MYF(0));
1604
else if (user_supplied_post_statements)
1677
(void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1606
(void)parse_delimiter(user_supplied_post_statements, &post_statements,
1681
1610
if (verbose >= 2)
1682
1611
printf("Parsing engines to use.\n");
1684
if (not default_engine.empty())
1685
parse_option(default_engine.c_str(), &engine_options, ',');
1614
parse_option(default_engine, &engine_options, ',');
1687
1616
if (tty_password)
1688
opt_password= client_get_tty_password(NULL);
1617
opt_password= get_tty_password(NullS);
1693
static int run_query(drizzle_con_st &con, drizzle_result_st *result,
1694
const char *query, int len)
1622
static int run_query(MYSQL *mysql, const char *query, int len)
1696
drizzle_return_t ret;
1697
drizzle_result_st result_buffer;
1699
1624
if (opt_only_print)
1701
printf("/* CON: %" PRIu64 " */ %.*s;\n",
1702
(uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1626
printf("%.*s;\n", len, query);
1707
1630
if (verbose >= 3)
1708
1631
printf("%.*s;\n", len, query);
1711
result= &result_buffer;
1713
result= drizzle_query(&con, result, query, len, &ret);
1715
if (ret == DRIZZLE_RETURN_OK)
1716
ret= drizzle_result_buffer(result);
1718
if (result == &result_buffer)
1719
drizzle_result_free(result);
1632
return mysql_real_query(mysql, query, len);
1726
generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt)
1637
generate_primary_key_list(MYSQL *mysql, option_string *engine_stmt)
1728
drizzle_result_st result;
1734
Blackhole is a special case, this allows us to test the upper end
1641
unsigned long long counter;
1645
Blackhole is a special case, this allows us to test the upper end
1735
1646
of the server during load runs.
1737
if (opt_only_print || (engine_stmt &&
1738
strstr(engine_stmt->getString(), "blackhole")))
1648
if (opt_only_print || (engine_stmt &&
1649
strstr(engine_stmt->string, "blackhole")))
1651
primary_keys_number_of= 1;
1652
primary_keys= (char **)my_malloc((uint)(sizeof(char *) *
1653
primary_keys_number_of),
1654
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
1740
1655
/* Yes, we strdup a const string to simplify the interface */
1741
primary_keys.push_back("796c4422-1d94-102a-9d6d-00e0812d");
1656
primary_keys[0]= my_strdup("796c4422-1d94-102a-9d6d-00e0812d", MYF(0));
1745
if (run_query(con, &result, "SELECT id from t1", strlen("SELECT id from t1")))
1660
if (run_query(mysql, "SELECT id from t1", strlen("SELECT id from t1")))
1747
fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", SLAP_NAME,
1748
drizzle_con_error(&con));
1662
fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", my_progname,
1663
mysql_error(mysql));
1752
uint64_t num_rows_ret= drizzle_result_row_count(&result);
1753
if (num_rows_ret > SIZE_MAX)
1755
fprintf(stderr, "More primary keys than than architecture supports\n");
1758
size_t primary_keys_number_of;
1759
primary_keys_number_of= (size_t)num_rows_ret;
1667
result= mysql_store_result(mysql);
1668
primary_keys_number_of= mysql_num_rows(result);
1761
1670
/* So why check this? Blackhole :) */
1762
1671
if (primary_keys_number_of)
1794
1723
if (verbose >= 2)
1795
1724
printf("Loading Pre-data\n");
1797
if (run_query(con, NULL, query, len))
1726
if (run_query(mysql, query, len))
1799
fprintf(stderr,"%s: Cannot create schema %s : %s\n", SLAP_NAME, db,
1800
drizzle_con_error(&con));
1728
fprintf(stderr,"%s: Cannot create schema %s : %s\n", my_progname, db,
1729
mysql_error(mysql));
1805
sptr->setCreateCount(sptr->getCreateCount()+1);
1734
sptr->create_count++;
1808
1737
if (opt_only_print)
1810
printf("/* CON: %" PRIu64 " */ use %s;\n",
1811
(uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1739
printf("use %s;\n", db);
1816
drizzle_result_st result;
1817
drizzle_return_t ret;
1819
1743
if (verbose >= 3)
1820
1744
printf("%s;\n", query);
1822
if (drizzle_select_db(&con, &result, db, &ret) == NULL ||
1823
ret != DRIZZLE_RETURN_OK)
1746
if (mysql_select_db(mysql, db))
1825
fprintf(stderr,"%s: Cannot select schema '%s': %s\n",SLAP_NAME, db,
1826
ret == DRIZZLE_RETURN_ERROR_CODE ?
1827
drizzle_result_error(&result) : drizzle_con_error(&con));
1748
fprintf(stderr,"%s: Cannot select schema '%s': %s\n",my_progname, db,
1749
mysql_error(mysql));
1830
drizzle_result_free(&result);
1831
sptr->setCreateCount(sptr->getCreateCount()+1);
1752
sptr->create_count++;
1834
1755
if (engine_stmt)
1836
1757
len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1837
engine_stmt->getString());
1838
if (run_query(con, NULL, query, len))
1758
engine_stmt->string);
1759
if (run_query(mysql, query, len))
1840
fprintf(stderr,"%s: Cannot set default engine: %s\n", SLAP_NAME,
1841
drizzle_con_error(&con));
1761
fprintf(stderr,"%s: Cannot set default engine: %s\n", my_progname,
1762
mysql_error(mysql));
1844
sptr->setCreateCount(sptr->getCreateCount()+1);
1765
sptr->create_count++;
1848
1769
after_create= stmt;
1851
for (ptr= after_create; ptr && ptr->getLength(); ptr= ptr->getNext(), count++)
1772
for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
1853
1774
if (auto_generate_sql && ( auto_generate_sql_number == count))
1856
if (engine_stmt && engine_stmt->getOption() && ptr->getType() == CREATE_TABLE_TYPE)
1777
if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
1858
1779
char buffer[HUGE_STRING_LENGTH];
1860
snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->getString(),
1861
engine_stmt->getOption());
1862
if (run_query(con, NULL, buffer, strlen(buffer)))
1781
snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
1782
engine_stmt->option);
1783
if (run_query(mysql, buffer, strlen(buffer)))
1864
1785
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1865
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1866
if (not opt_ignore_sql_errors)
1786
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1787
if (!opt_ignore_sql_errors)
1869
sptr->setCreateCount(sptr->getCreateCount()+1);
1790
sptr->create_count++;
1873
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1794
if (run_query(mysql, ptr->string, ptr->length))
1875
1796
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1876
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1877
if (not opt_ignore_sql_errors)
1797
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1798
if (!opt_ignore_sql_errors)
1880
sptr->setCreateCount(sptr->getCreateCount()+1);
1801
sptr->create_count++;
1884
1805
if (auto_generate_sql && (auto_generate_sql_number > count ))
1886
1807
/* Special case for auto create, we don't want to create tables twice */
1887
after_create= stmt->getNext();
1808
after_create= stmt->next;
1888
1809
goto limit_not_met;
1891
1812
gettimeofday(&end_time, NULL);
1893
sptr->setCreateTiming(timedif(end_time, start_time));
1814
sptr->create_timing= timedif(end_time, start_time);
1896
static void drop_schema(drizzle_con_st &con, const char *db)
1820
drop_schema(MYSQL *mysql, const char *db)
1898
1822
char query[HUGE_STRING_LENGTH];
1901
1825
len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1903
if (run_query(con, NULL, query, len))
1827
if (run_query(mysql, query, len))
1905
1829
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1906
SLAP_NAME, db, drizzle_con_error(&con));
1830
my_progname, db, mysql_error(mysql));
1911
static void run_statements(drizzle_con_st &con, Statement *stmt)
1840
run_statements(MYSQL *mysql, statement *stmt)
1913
for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
1846
for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1915
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1848
if (run_query(mysql, ptr->string, ptr->length))
1917
1850
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1918
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1851
my_progname, (uint)ptr->length, ptr->string, mysql_error(mysql));
1854
if (!opt_only_print)
1856
if (mysql_field_count(mysql))
1858
result= mysql_store_result(mysql);
1859
mysql_free_result(result);
1925
static void timer_thread()
1868
run_scheduler(stats *sptr, statement **stmts, uint concur, uint64_t limit)
1872
unsigned int real_concurrency;
1873
struct timeval start_time, end_time;
1874
option_string *sql_type;
1875
thread_context *con;
1876
pthread_t mainthread; /* Thread descriptor */
1877
pthread_attr_t attr; /* Thread attributes */
1880
pthread_attr_init(&attr);
1881
pthread_attr_setdetachstate(&attr,
1882
PTHREAD_CREATE_DETACHED);
1884
pthread_mutex_lock(&counter_mutex);
1887
pthread_mutex_lock(&sleeper_mutex);
1889
pthread_mutex_unlock(&sleeper_mutex);
1891
real_concurrency= 0;
1893
for (y= 0, sql_type= query_options;
1894
y < query_statements_count;
1895
y++, sql_type= sql_type->next)
1897
unsigned int options_loop= 1;
1899
if (sql_type->option)
1901
options_loop= strtol(sql_type->option,
1903
options_loop= options_loop ? options_loop : 1;
1906
while (options_loop--)
1907
for (x= 0; x < concur; x++)
1909
con= (thread_context *)my_malloc(sizeof(thread_context), MYF(0));
1910
con->stmt= stmts[y];
1914
/* now you create the thread */
1915
if (pthread_create(&mainthread, &attr, run_task,
1918
fprintf(stderr,"%s: Could not create thread\n", my_progname);
1926
The timer_thread belongs to all threads so it too obeys the wakeup
1927
call that run tasks obey.
1929
if (opt_timer_length)
1931
pthread_mutex_lock(&timer_alarm_mutex);
1933
pthread_mutex_unlock(&timer_alarm_mutex);
1935
if (pthread_create(&mainthread, &attr, timer_thread,
1936
(void *)&opt_timer_length) != 0)
1938
fprintf(stderr,"%s: Could not create timer thread\n", my_progname);
1943
pthread_mutex_unlock(&counter_mutex);
1944
pthread_attr_destroy(&attr);
1946
pthread_mutex_lock(&sleeper_mutex);
1948
pthread_mutex_unlock(&sleeper_mutex);
1949
pthread_cond_broadcast(&sleep_threshhold);
1951
gettimeofday(&start_time, NULL);
1928
We lock around the initial call in case were we in a loop. This
1954
We loop until we know that all children have cleaned up.
1956
pthread_mutex_lock(&counter_mutex);
1957
while (thread_counter)
1959
struct timespec abstime;
1961
set_timespec(abstime, 3);
1962
pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
1964
pthread_mutex_unlock(&counter_mutex);
1966
gettimeofday(&end_time, NULL);
1969
sptr->timing= timedif(end_time, start_time);
1970
sptr->users= concur;
1971
sptr->real_users= real_concurrency;
1978
pthread_handler_t timer_thread(void *p)
1980
uint *timer_length= (uint *)p;
1981
struct timespec abstime;
1985
if (mysql_thread_init())
1987
fprintf(stderr,"%s: mysql_thread_init() failed.\n",
1993
We lock around the initial call in case were we in a loop. This
1929
1994
also keeps the value properly syncronized across call threads.
1931
master_wakeup.wait();
1934
boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1937
xtime_get(&xt, boost::TIME_UTC);
1938
xt.sec += opt_timer_length;
1940
(void)timer_alarm_threshold.timed_wait(scopedLock, xt);
1944
boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1996
pthread_mutex_lock(&sleeper_mutex);
1997
while (master_wakeup)
1999
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2001
pthread_mutex_unlock(&sleeper_mutex);
2003
set_timespec(abstime, *timer_length);
2005
pthread_mutex_lock(&timer_alarm_mutex);
2006
pthread_cond_timedwait(&timer_alarm_threshold, &timer_alarm_mutex, &abstime);
2007
pthread_mutex_unlock(&timer_alarm_mutex);
2009
pthread_mutex_lock(&timer_alarm_mutex);
2011
pthread_mutex_unlock(&timer_alarm_mutex);
1949
typedef boost::shared_ptr<boost::thread> Thread;
1950
typedef std::vector <Thread> Threads;
1951
static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit)
2017
pthread_handler_t run_task(void *p)
1953
uint32_t real_concurrency;
1954
struct timeval start_time, end_time;
1959
OptionString *sql_type;
1961
master_wakeup.reset();
1963
real_concurrency= 0;
1966
for (y= 0, sql_type= query_options;
1967
y < query_statements_count;
1968
y++, sql_type= sql_type->getNext())
1970
uint32_t options_loop= 1;
1972
if (sql_type->getOption())
1974
options_loop= strtol(sql_type->getOption(),
1976
options_loop= options_loop ? options_loop : 1;
1979
while (options_loop--)
1981
for (uint32_t x= 0; x < concur; x++)
1984
con= new ThreadContext;
1987
fprintf(stderr, "Memory Allocation error in scheduler\n");
1990
con->setStmt(stmts[y]);
1991
con->setLimit(limit);
1995
/* now you create the thread */
1997
thread= Thread(new boost::thread(boost::bind(&run_task, con)));
1998
threads.push_back(thread);
2005
The timer_thread belongs to all threads so it too obeys the wakeup
2006
call that run tasks obey.
2008
if (opt_timer_length)
2011
boost::mutex::scoped_lock alarmLock(timer_alarm_mutex);
2016
thread= Thread(new boost::thread(&timer_thread));
2017
threads.push_back(thread);
2021
master_wakeup.start();
2023
gettimeofday(&start_time, NULL);
2026
We loop until we know that all children have cleaned up.
2028
for (Threads::iterator iter= threads.begin(); iter != threads.end(); iter++)
2033
gettimeofday(&end_time, NULL);
2035
sptr->setTiming(timedif(end_time, start_time));
2036
sptr->setUsers(concur);
2037
sptr->setRealUsers(real_concurrency);
2038
sptr->setRows(limit);
2019
uint64_t counter= 0, queries;
2020
uint64_t detach_counter;
2021
unsigned int commit_counter;
2026
thread_context *con= (thread_context *)p;
2028
if (mysql_thread_init())
2030
fprintf(stderr,"%s: mysql_thread_init() failed.\n",
2035
pthread_mutex_lock(&sleeper_mutex);
2036
while (master_wakeup)
2038
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2040
pthread_mutex_unlock(&sleeper_mutex);
2042
slap_connect(&mysql, true);
2045
printf("connected!\n");
2050
run_query(&mysql, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
2053
for (ptr= con->stmt, detach_counter= 0;
2055
ptr= ptr->next, detach_counter++)
2057
if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
2060
slap_connect(&mysql, true);
2064
We have to execute differently based on query type. This should become a function.
2066
if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
2067
(ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
2070
unsigned int key_val;
2072
char buffer[HUGE_STRING_LENGTH];
2075
This should only happen if some sort of new engine was
2076
implemented that didn't properly handle UPDATEs.
2078
Just in case someone runs this under an experimental engine we don't
2079
want a crash so the if() is placed here.
2081
assert(primary_keys_number_of);
2082
if (primary_keys_number_of)
2084
key_val= (unsigned int)(random() % primary_keys_number_of);
2085
key= primary_keys[key_val];
2089
length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
2090
(int)ptr->length, ptr->string, key);
2092
if (run_query(&mysql, buffer, length))
2094
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2095
my_progname, (uint)length, buffer, mysql_error(&mysql));
2102
if (run_query(&mysql, ptr->string, ptr->length))
2104
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2105
my_progname, (uint)ptr->length, ptr->string, mysql_error(&mysql));
2110
if (!opt_only_print)
2114
if (mysql_field_count(&mysql))
2116
result= mysql_store_result(&mysql);
2117
while ((row = mysql_fetch_row(result)))
2119
mysql_free_result(result);
2121
} while(mysql_next_result(&mysql) == 0);
2125
if (commit_rate && (++commit_counter == commit_rate))
2128
run_query(&mysql, "COMMIT", strlen("COMMIT"));
2131
/* If the timer is set, and the alarm is not active then end */
2132
if (opt_timer_length && timer_alarm == false)
2135
/* If limit has been reached, and we are not in a timer_alarm just end */
2136
if (con->limit && queries == con->limit && timer_alarm == false)
2140
if (opt_timer_length && timer_alarm == true)
2143
if (con->limit && queries < con->limit)
2149
run_query(&mysql, "COMMIT", strlen("COMMIT"));
2153
pthread_mutex_lock(&counter_mutex);
2155
pthread_cond_signal(&count_threshhold);
2156
pthread_mutex_unlock(&counter_mutex);
2158
my_free(con, MYF(0));
2042
2165
Parse records from comma seperated string. : is a reserved character and is used for options
2045
uint32_t parse_option(const char *origin, OptionString **stmt, char delm)
2169
parse_option(const char *origin, option_string **stmt, char delm)
2048
2172
char *begin_ptr;
2050
uint32_t length= strlen(origin);
2051
uint32_t count= 0; /* We know that there is always one */
2174
option_string **sptr= stmt;
2176
uint length= strlen(origin);
2177
uint count= 0; /* We know that there is always one */
2053
2179
end_ptr= (char *)origin + length;
2056
*stmt= tmp= new OptionString;
2181
tmp= *sptr= (option_string *)my_malloc(sizeof(option_string),
2182
MYF(MY_ZEROFILL|MY_FAE|MY_WME));
2058
2184
for (begin_ptr= (char *)origin;
2059
2185
begin_ptr != end_ptr;
2060
tmp= tmp->getNext())
2062
2188
char buffer[HUGE_STRING_LENGTH];
2063
2189
char *buffer_ptr;
2065
memset(buffer, 0, HUGE_STRING_LENGTH);
2191
bzero(buffer, HUGE_STRING_LENGTH);
2067
string= strchr(begin_ptr, delm);
2193
string= strchr(begin_ptr, delm);
2270
2374
snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2273
snprintf(buffer, HUGE_STRING_LENGTH,
2274
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
2275
"%u,%u,%u,%"PRIu64"\n",
2276
con.getEngine() ? con.getEngine() : "", /* Storage engine we ran against */
2376
snprintf(buffer, HUGE_STRING_LENGTH,
2377
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%u,%u,%u,%llu\n",
2378
con->engine ? con->engine : "", /* Storage engine we ran against */
2277
2379
label_buffer, /* Load type */
2278
con.getAvgTiming() / 1000, con.getAvgTiming() % 1000, /* Time to load */
2279
con.getMinTiming() / 1000, con.getMinTiming() % 1000, /* Min time */
2280
con.getMaxTiming() / 1000, con.getMaxTiming() % 1000, /* Max time */
2281
con.getSumOfTime() / 1000, con.getSumOfTime() % 1000, /* Total time */
2282
con.getStdDev() / 1000, con.getStdDev() % 1000, /* Standard Deviation */
2380
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2381
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2382
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2383
con->sum_of_time / 1000, con->sum_of_time % 1000, /* Total time */
2384
con->std_dev / 1000, con->std_dev % 1000, /* Standard Deviation */
2283
2385
iterations, /* Iterations */
2284
con.getUsers(), /* Children used max_timing */
2285
con.getRealUsers(), /* Children used max_timing */
2286
con.getAvgRows() /* Queries run */
2288
size_t buff_len= strlen(buffer);
2289
ssize_t write_ret= write(csv_file, (unsigned char*) buffer, buff_len);
2290
if (write_ret != (ssize_t)buff_len)
2292
fprintf(stderr, _("Unable to fully write %"PRIu64" bytes. "
2293
"Could only write %"PRId64"."), (uint64_t)write_ret,
2386
con->users, /* Children used max_timing */
2387
con->real_users, /* Children used max_timing */
2388
con->avg_rows /* Queries run */
2390
my_write(csv_file, (uchar*) buffer, (uint)strlen(buffer), MYF(0));
2299
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2394
generate_stats(conclusions *con, option_string *eng, stats *sptr)
2304
con->setMinTiming(sptr->getTiming());
2305
con->setMaxTiming(sptr->getTiming());
2306
con->setMinRows(sptr->getRows());
2307
con->setMaxRows(sptr->getRows());
2399
con->min_timing= sptr->timing;
2400
con->max_timing= sptr->timing;
2401
con->min_rows= sptr->rows;
2402
con->max_rows= sptr->rows;
2309
2404
/* At the moment we assume uniform */
2310
con->setUsers(sptr->getUsers());
2311
con->setRealUsers(sptr->getRealUsers());
2312
con->setAvgRows(sptr->getRows());
2405
con->users= sptr->users;
2406
con->real_users= sptr->real_users;
2407
con->avg_rows= sptr->rows;
2314
2409
/* With no next, we know it is the last element that was malloced */
2315
2410
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2317
con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2412
con->avg_timing+= ptr->timing;
2319
if (ptr->getTiming() > con->getMaxTiming())
2320
con->setMaxTiming(ptr->getTiming());
2321
if (ptr->getTiming() < con->getMinTiming())
2322
con->setMinTiming(ptr->getTiming());
2414
if (ptr->timing > con->max_timing)
2415
con->max_timing= ptr->timing;
2416
if (ptr->timing < con->min_timing)
2417
con->min_timing= ptr->timing;
2324
con->setSumOfTime(con->getAvgTiming());
2325
con->setAvgTiming(con->getAvgTiming()/iterations);
2419
con->sum_of_time= con->avg_timing;
2420
con->avg_timing= con->avg_timing/iterations;
2327
if (eng && eng->getString())
2328
con->setEngine(eng->getString());
2422
if (eng && eng->string)
2423
con->engine= eng->string;
2330
con->setEngine(NULL);
2332
standard_deviation(*con, sptr);
2427
standard_deviation(con, sptr);
2334
2429
/* Now we do the create time operations */
2335
con->setCreateMinTiming(sptr->getCreateTiming());
2336
con->setCreateMaxTiming(sptr->getCreateTiming());
2430
con->create_min_timing= sptr->create_timing;
2431
con->create_max_timing= sptr->create_timing;
2338
2433
/* At the moment we assume uniform */
2339
con->setCreateCount(sptr->getCreateCount());
2434
con->create_count= sptr->create_count;
2341
2436
/* With no next, we know it is the last element that was malloced */
2342
2437
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2344
con->setCreateAvgTiming(ptr->getCreateTiming()+con->getCreateAvgTiming());
2346
if (ptr->getCreateTiming() > con->getCreateMaxTiming())
2347
con->setCreateMaxTiming(ptr->getCreateTiming());
2348
if (ptr->getCreateTiming() < con->getCreateMinTiming())
2349
con->setCreateMinTiming(ptr->getCreateTiming());
2351
con->setCreateAvgTiming(con->getCreateAvgTiming()/iterations);
2355
option_cleanup(OptionString *stmt)
2357
OptionString *ptr, *nptr;
2361
for (ptr= stmt; ptr; ptr= nptr)
2363
nptr= ptr->getNext();
2368
void statement_cleanup(Statement *stmt)
2370
Statement *ptr, *nptr;
2374
for (ptr= stmt; ptr; ptr= nptr)
2376
nptr= ptr->getNext();
2381
void slap_close(drizzle_con_st &con)
2383
drizzle_free(drizzle_con_drizzle(&con));
2386
void slap_connect(drizzle_con_st &con, bool connect_to_schema)
2439
con->create_avg_timing+= ptr->create_timing;
2441
if (ptr->create_timing > con->create_max_timing)
2442
con->create_max_timing= ptr->create_timing;
2443
if (ptr->create_timing < con->create_min_timing)
2444
con->create_min_timing= ptr->create_timing;
2446
con->create_avg_timing= con->create_avg_timing/iterations;
2450
option_cleanup(option_string *stmt)
2452
option_string *ptr, *nptr;
2456
for (ptr= stmt; ptr; ptr= nptr)
2460
my_free(ptr->string, MYF(0));
2462
my_free(ptr->option, MYF(0));
2463
my_free(ptr, MYF(0));
2468
statement_cleanup(statement *stmt)
2470
statement *ptr, *nptr;
2474
for (ptr= stmt; ptr; ptr= nptr)
2478
my_free(ptr->string, MYF(0));
2479
my_free(ptr, MYF(0));
2484
slap_close(MYSQL *mysql)
2493
slap_connect(MYSQL *mysql, bool connect_to_schema)
2388
2495
/* Connect to server */
2389
static uint32_t connection_retry_sleep= 100000; /* Microseconds */
2390
int connect_error= 1;
2391
drizzle_return_t ret;
2392
drizzle_st *drizzle;
2496
static ulong connection_retry_sleep= 100000; /* Microseconds */
2497
int x, connect_error= 1;
2394
2502
if (opt_delayed_start)
2395
usleep(random()%opt_delayed_start);
2397
if ((drizzle= drizzle_create(NULL)) == NULL ||
2398
drizzle_con_add_tcp(drizzle, &con, host.c_str(), opt_drizzle_port,
2400
opt_password.c_str(),
2401
connect_to_schema ? create_schema_string.c_str() : NULL,
2402
use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL) == NULL)
2404
fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2408
drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2413
for (uint32_t x= 0; x < 10; x++)
2415
if ((ret= drizzle_con_connect(&con)) == DRIZZLE_RETURN_OK)
2503
my_sleep(random()%opt_delayed_start);
2508
mysql_options(mysql,MYSQL_OPT_COMPRESS,NullS);
2509
/* We always do opt_protocol to TCP/IP */
2510
mysql_options(mysql,MYSQL_OPT_PROTOCOL,(char*)&opt_protocol);
2511
mysql_options(mysql, MYSQL_SET_CHARSET_NAME, default_charset);
2513
for (x= 0; x < 10; x++)
2517
if (mysql_real_connect(mysql, host, user, opt_password,
2518
connect_to_schema ? create_schema_string : NULL,
2520
opt_mysql_unix_port,
2417
2523
/* Connect suceeded */
2418
2524
connect_error= 0;
2421
usleep(connection_retry_sleep);
2527
my_sleep(connection_retry_sleep);
2423
2529
if (connect_error)
2425
fprintf(stderr,"%s: Error when connecting to server: %d %s\n", SLAP_NAME,
2426
ret, drizzle_con_error(&con));
2531
fprintf(stderr,"%s: Error when connecting to server: %d %s\n",
2532
my_progname, mysql_errno(mysql), mysql_error(mysql));
2431
void standard_deviation(Conclusions &con, Stats *sptr)
2540
standard_deviation (conclusions *con, stats *sptr)
2433
2543
long int sum_of_squares;
2437
2547
if (iterations == 1 || iterations == 0)
2444
2553
for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2446
2555
long int deviation;
2448
deviation= ptr->getTiming() - con.getAvgTiming();
2557
deviation= ptr->timing - con->avg_timing;
2449
2558
sum_of_squares+= deviation*deviation;
2452
the_catch= sqrt((double)(sum_of_squares/(iterations -1)));
2453
con.setStdDev((long int)the_catch);
2561
catch= sqrt((double)(sum_of_squares/(iterations -1)));
2562
con->std_dev= (long int)catch;