97
#include <drizzled/configmake.h>
100
96
/* Added this for string translation. */
101
97
#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
117
99
using namespace std;
118
using namespace drizzled;
119
namespace po= boost::program_options;
122
102
static char *shared_memory_base_name=0;
125
client::Wakeup master_wakeup;
106
bool get_one_option(int optid, const struct my_option *, char *argument);
108
/* Global Thread counter */
109
uint32_t thread_counter;
110
pthread_mutex_t counter_mutex;
111
pthread_cond_t count_threshhold;
112
uint32_t master_wakeup;
113
pthread_mutex_t sleeper_mutex;
114
pthread_cond_t sleep_threshhold;
127
116
/* Global Thread timer */
128
117
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;
118
pthread_mutex_t timer_alarm_mutex;
119
pthread_cond_t timer_alarm_threshold;
121
static char **defaults_argv;
124
/* This gets passed to malloc, so lets set it to an arch-dependant size */
125
size_t primary_keys_number_of;
127
static char *host= NULL, *opt_password= NULL, *user= NULL,
128
*user_supplied_query= NULL,
129
*user_supplied_pre_statements= NULL,
130
*user_supplied_post_statements= NULL,
131
*default_engine= NULL,
135
const char *delimiter= "\n";
137
const char *create_schema_string= "drizzleslap";
139
static bool opt_mysql= false;
155
140
static bool opt_preserve= true;
156
static bool opt_only_print;
157
static bool opt_burnin;
141
static bool opt_only_print= false;
142
static bool opt_burnin= false;
158
143
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;
144
static bool tty_password= false,
146
auto_generate_sql_autoincrement= false,
147
auto_generate_sql_guid_primary= false,
148
auto_generate_sql= false;
149
const char *opt_auto_generate_sql_type= "mixed";
165
static int32_t verbose= 0;
166
static uint32_t delimiter_length;
151
static int verbose, delimiter_length;
167
152
static uint32_t commit_rate;
168
153
static uint32_t detach_rate;
169
154
static uint32_t opt_timer_length;
170
155
static uint32_t opt_delayed_start;
171
string num_blob_cols_opt,
175
static uint32_t opt_set_random_seed;
156
const char *num_int_cols_opt;
157
const char *num_char_cols_opt;
158
const char *num_blob_cols_opt;
159
const char *opt_label;
160
static unsigned int opt_set_random_seed;
177
string auto_generate_selected_columns_opt;
162
const char *auto_generate_selected_columns_opt;
179
164
/* 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;
165
static unsigned int num_int_cols= 1;
166
static unsigned int num_char_cols= 1;
167
static unsigned int num_blob_cols= 0;
168
static unsigned int num_blob_cols_size;
169
static unsigned int num_blob_cols_size_min;
170
static unsigned int num_int_cols_index= 0;
171
static unsigned int num_char_cols_index= 0;
172
static unsigned int iterations;
188
173
static uint64_t actual_queries= 0;
189
174
static uint64_t auto_actual_queries;
190
175
static uint64_t auto_generate_sql_unique_write_number;
191
176
static uint64_t auto_generate_sql_unique_query_number;
192
static uint32_t auto_generate_sql_secondary_indexes;
177
static unsigned int auto_generate_sql_secondary_indexes;
193
178
static uint64_t num_of_query;
194
179
static uint64_t auto_generate_sql_number;
195
string concurrency_str;
196
string create_string;
197
std::vector <uint32_t> concurrency;
180
const char *concurrency_str= NULL;
181
static char *create_string;
182
uint32_t *concurrency;
199
std::string opt_csv_str;
184
const char *default_dbug_option= "d:t:o,/tmp/drizzleslap.trace";
185
const char *opt_csv_str;
202
static int process_options(void);
188
static int get_options(int *argc,char ***argv);
203
189
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;
191
static const char *load_default_groups[]= { "drizzleslap","client",0 };
198
UPDATE_TYPE_REQUIRES_PREFIX= 3,
199
CREATE_TABLE_TYPE= 4,
200
SELECT_TYPE_REQUIRES_PREFIX= 5,
201
DELETE_TYPE_REQUIRES_PREFIX= 6
204
typedef struct statement statement;
209
slap_query_type type;
211
size_t option_length;
215
typedef struct option_string option_string;
217
struct option_string {
221
size_t option_length;
225
typedef struct stats stats;
232
long int create_timing;
233
uint64_t create_count;
236
typedef struct thread_context thread_context;
238
struct thread_context {
243
typedef struct conclusions conclusions;
253
long int sum_of_time;
255
/* These are just for create time stats */
256
long int create_avg_timing;
257
long int create_max_timing;
258
long int create_min_timing;
259
uint64_t create_count;
260
/* The following are not used yet */
265
static option_string *engine_options= NULL;
266
static option_string *query_options= NULL;
267
static statement *pre_statements= NULL;
268
static statement *post_statements= NULL;
269
static statement *create_statements= NULL;
271
static statement **query_statements= NULL;
272
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);
276
void print_conclusions(conclusions *con);
277
void print_conclusions_csv(conclusions *con);
278
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
279
uint32_t parse_comma(const char *string, uint32_t **range);
280
uint32_t parse_delimiter(const char *script, statement **stmt, char delm);
281
uint32_t parse_option(const char *origin, option_string **stmt, char delm);
282
static int drop_schema(drizzle_con_st *con, const char *db);
223
283
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);
284
static statement *build_table_string(void);
285
static statement *build_insert_string(void);
286
static statement *build_update_string(void);
287
static statement * build_select_string(bool key);
288
static int generate_primary_key_list(drizzle_con_st *con, option_string *engine_stmt);
289
static int drop_primary_key_list(void);
290
static int create_schema(drizzle_con_st *con, const char *db, statement *stmt,
291
option_string *engine_stmt, stats *sptr);
292
static int run_scheduler(stats *sptr, statement **stmts, uint32_t concur,
294
extern "C" pthread_handler_t run_task(void *p);
295
extern "C" pthread_handler_t timer_thread(void *p);
296
void statement_cleanup(statement *stmt);
297
void option_cleanup(option_string *stmt);
298
void concurrency_loop(drizzle_con_st *con, uint32_t current, option_string *eptr);
299
static int run_statements(drizzle_con_st *con, statement *stmt);
300
void slap_connect(drizzle_con_st *con, bool connect_to_schema);
301
void slap_close(drizzle_con_st *con);
302
static int run_query(drizzle_con_st *con, drizzle_result_st *result, const char *query, int len);
303
void standard_deviation (conclusions *con, stats *sptr);
240
305
static const char ALPHANUMERICS[]=
241
306
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
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.
431
322
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 */
332
load_defaults("drizzle",load_default_groups,&argc,&argv);
334
if (get_options(&argc,&argv))
336
free_defaults(defaults_argv);
341
/* Seed the random number generator if we will be using it. */
342
if (auto_generate_sql)
344
if (opt_set_random_seed == 0)
345
opt_set_random_seed= (unsigned int)time(NULL);
346
srandom(opt_set_random_seed);
349
/* globals? Yes, so we only have to run strlen once */
350
delimiter_length= strlen(delimiter);
354
fprintf(stderr,"%s: Too many arguments\n",my_progname);
355
free_defaults(defaults_argv);
360
slap_connect(&con, false);
362
pthread_mutex_init(&counter_mutex, NULL);
363
pthread_cond_init(&count_threshhold, NULL);
364
pthread_mutex_init(&sleeper_mutex, NULL);
365
pthread_cond_init(&sleep_threshhold, NULL);
366
pthread_mutex_init(&timer_alarm_mutex, NULL);
367
pthread_cond_init(&timer_alarm_threshold, NULL);
370
/* 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);
372
eptr= engine_options;
375
/* For the final stage we run whatever queries we were asked to run */
379
printf("Starting Concurrency Test\n");
383
for (current= concurrency; current && *current; current++)
384
concurrency_loop(&con, *current, eptr);
388
uint32_t infinite= 1;
390
concurrency_loop(&con, infinite, eptr);
396
drop_schema(&con, create_schema_string);
398
} while (eptr ? (eptr= eptr->next) : 0);
403
pthread_mutex_destroy(&counter_mutex);
404
pthread_cond_destroy(&count_threshhold);
405
pthread_mutex_destroy(&sleeper_mutex);
406
pthread_cond_destroy(&sleep_threshhold);
407
pthread_mutex_destroy(&timer_alarm_mutex);
408
pthread_cond_destroy(&timer_alarm_threshold);
412
/* now free all the strings we created */
418
statement_cleanup(create_statements);
419
for (x= 0; x < query_statements_count; x++)
420
statement_cleanup(query_statements[x]);
421
free(query_statements);
422
statement_cleanup(pre_statements);
423
statement_cleanup(post_statements);
424
option_cleanup(engine_options);
425
option_cleanup(query_options);
734
if (shared_memory_base_name)
735
free(shared_memory_base_name);
428
if (shared_memory_base_name)
429
free(shared_memory_base_name);
740
catch(std::exception &err)
742
cerr<<"Error:"<<err.what()<<endl;
745
if (csv_file != fileno(stdout))
431
free_defaults(defaults_argv);
751
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
437
void concurrency_loop(drizzle_con_st *con, uint32_t current, option_string *eptr)
755
Conclusions conclusion;
442
conclusions conclusion;
756
443
uint64_t client_limit;
758
head_sptr= new Stats[iterations];
445
head_sptr= (stats *)malloc(sizeof(stats) * iterations);
759
446
if (head_sptr == NULL)
761
448
fprintf(stderr,"Error allocating memory in concurrency_loop\n");
451
memset(head_sptr, 0, sizeof(stats) * iterations);
453
memset(&conclusion, 0, sizeof(conclusions));
765
455
if (auto_actual_queries)
766
456
client_limit= auto_actual_queries;
828
521
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)
524
print_conclusions(&conclusion);
526
print_conclusions_csv(&conclusion);
533
static struct my_option my_long_options[] =
535
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
537
{"auto-generate-sql-select-columns", OPT_SLAP_AUTO_GENERATE_SELECT_COLUMNS,
538
"Provide a string to use for the select fields used in auto tests.",
539
(char**) &auto_generate_selected_columns_opt,
540
(char**) &auto_generate_selected_columns_opt,
541
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
542
{"auto-generate-sql", 'a',
543
"Generate SQL where not supplied by file or command line.",
544
(char**) &auto_generate_sql, (char**) &auto_generate_sql,
545
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
546
{"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
547
"Add an AUTO_INCREMENT column to auto-generated tables.",
548
(char**) &auto_generate_sql_autoincrement,
549
(char**) &auto_generate_sql_autoincrement,
550
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
551
{"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
552
"Set this number to generate a set number of queries to run.",
553
(char**) &auto_actual_queries, (char**) &auto_actual_queries,
554
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
555
{"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
556
"Add GUID based primary keys to auto-generated tables.",
557
(char**) &auto_generate_sql_guid_primary,
558
(char**) &auto_generate_sql_guid_primary,
559
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
560
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
561
"Specify test load type: mixed, update, write, key, or read; default is mixed.",
562
(char**) &opt_auto_generate_sql_type, (char**) &opt_auto_generate_sql_type,
563
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
564
{"auto-generate-sql-secondary-indexes",
565
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
566
"Number of secondary indexes to add to auto-generated tables.",
567
(char**) &auto_generate_sql_secondary_indexes,
568
(char**) &auto_generate_sql_secondary_indexes, 0,
569
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
570
{"auto-generate-sql-unique-query-number",
571
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
572
"Number of unique queries to generate for automatic tests.",
573
(char**) &auto_generate_sql_unique_query_number,
574
(char**) &auto_generate_sql_unique_query_number,
575
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
576
{"auto-generate-sql-unique-write-number",
577
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
578
"Number of unique queries to generate for auto-generate-sql-write-number.",
579
(char**) &auto_generate_sql_unique_write_number,
580
(char**) &auto_generate_sql_unique_write_number,
581
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
582
{"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
583
"Number of row inserts to perform for each thread (default is 100).",
584
(char**) &auto_generate_sql_number, (char**) &auto_generate_sql_number,
585
0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
586
{"burnin", OPT_SLAP_BURNIN, "Run full test case in infinite loop.",
587
(char**) &opt_burnin, (char**) &opt_burnin, 0, GET_BOOL, NO_ARG, 0, 0, 0,
589
{"ignore-sql-errors", OPT_SLAP_IGNORE_SQL_ERRORS,
590
"Ignore SQL erros in query run.",
591
(char**) &opt_ignore_sql_errors,
592
(char**) &opt_ignore_sql_errors,
593
0, GET_BOOL, NO_ARG, 0, 0, 0,
595
{"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
596
(char**) &commit_rate, (char**) &commit_rate, 0, GET_UINT, REQUIRED_ARG,
598
{"concurrency", 'c', "Number of clients to simulate for query to run.",
599
(char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
600
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
601
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
602
(char**) &create_string, (char**) &create_string, 0, GET_STR, REQUIRED_ARG,
604
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
605
(char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR,
606
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
607
{"csv", OPT_SLAP_CSV,
608
"Generate CSV output to named file or to stdout if no file is named.",
609
(char**) &opt_csv_str, (char**) &opt_csv_str, 0, GET_STR,
610
OPT_ARG, 0, 0, 0, 0, 0, 0},
611
{"delayed-start", OPT_SLAP_DELAYED_START,
612
"Delay the startup of threads by a random number of microsends (the maximum of the delay)",
613
(char**) &opt_delayed_start, (char**) &opt_delayed_start, 0, GET_UINT,
614
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
616
"Delimiter to use in SQL statements supplied in file or command line.",
617
(char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
619
{"detach", OPT_SLAP_DETACH,
620
"Detach (close and reopen) connections after X number of requests.",
621
(char**) &detach_rate, (char**) &detach_rate, 0, GET_UINT, REQUIRED_ARG,
623
{"engine", 'e', "Storage engine to use for creating the table.",
624
(char**) &default_engine, (char**) &default_engine, 0,
625
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
626
{"host", 'h', "Connect to host.", (char**) &host, (char**) &host, 0, GET_STR,
627
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
628
{"iterations", 'i', "Number of times to run the tests.", (char**) &iterations,
629
(char**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
630
{"label", OPT_SLAP_LABEL, "Label to use for print and csv output.",
631
(char**) &opt_label, (char**) &opt_label, 0,
632
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
633
{"mysql", 'm', N_("Use MySQL Protocol."),
634
(char**) &opt_mysql, (char**) &opt_mysql, 0, GET_BOOL, NO_ARG, 0, 0, 0,
636
{"number-blob-cols", OPT_SLAP_BLOB_COL,
637
"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. ",
638
(char**) &num_blob_cols_opt, (char**) &num_blob_cols_opt, 0, GET_STR, REQUIRED_ARG,
640
{"number-char-cols", 'x',
641
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
642
(char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
644
{"number-int-cols", 'y',
645
"Number of INT columns to create in table if specifying --auto-generate-sql.",
646
(char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
648
{"number-of-queries", OPT_DRIZZLE_NUMBER_OF_QUERY,
649
"Limit each client to this number of queries (this is not exact).",
650
(char**) &num_of_query, (char**) &num_of_query, 0,
651
GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
652
{"only-print", OPT_DRIZZLE_ONLY_PRINT,
653
"This causes drizzleslap to not connect to the databases, but instead print "
654
"out what it would have done instead.",
655
(char**) &opt_only_print, (char**) &opt_only_print, 0, GET_BOOL, NO_ARG,
658
"Password to use when connecting to server. If password is not given it's "
659
"asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
660
{"port", 'p', "Port number to use for connection.",
661
0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
662
{"post-query", OPT_SLAP_POST_QUERY,
663
"Query to run or file containing query to execute after tests have completed.",
664
(char**) &user_supplied_post_statements,
665
(char**) &user_supplied_post_statements,
666
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
667
{"post-system", OPT_SLAP_POST_SYSTEM,
668
"system() string to execute after tests have completed.",
669
(char**) &post_system,
670
(char**) &post_system,
671
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
672
{"pre-query", OPT_SLAP_PRE_QUERY,
673
"Query to run or file containing query to execute before running tests.",
674
(char**) &user_supplied_pre_statements,
675
(char**) &user_supplied_pre_statements,
676
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
677
{"pre-system", OPT_SLAP_PRE_SYSTEM,
678
"system() string to execute before running tests.",
679
(char**) &pre_system,
680
(char**) &pre_system,
681
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
682
{"protocol", OPT_DRIZZLE_PROTOCOL,
683
"The protocol of connection (tcp,socket,pipe,memory).",
684
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
685
{"query", 'q', "Query to run or file containing query to run.",
686
(char**) &user_supplied_query, (char**) &user_supplied_query,
687
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
688
{"set-random-seed", OPT_SLAP_SET_RANDOM_SEED,
689
"Seed for random number generator (srandom(3))",
690
(char**)&opt_set_random_seed,
691
(char**)&opt_set_random_seed,0,
692
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
693
{"silent", 's', "Run program in silent mode - no output.",
694
(char**) &opt_silent, (char**) &opt_silent, 0, GET_BOOL, NO_ARG,
696
{"timer-length", OPT_SLAP_TIMER_LENGTH,
697
"Require drizzleslap to run each specific test a certain amount of time in seconds.",
698
(char**) &opt_timer_length, (char**) &opt_timer_length, 0, GET_UINT,
699
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
700
{"user", 'u', "User for login if not current user.", (char**) &user,
701
(char**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
703
"More verbose output; you can use this multiple times to get even more "
704
"verbose output.", (char**) &verbose, (char**) &verbose, 0,
705
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
706
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
707
NO_ARG, 0, 0, 0, 0, 0, 0},
708
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
712
static void print_version(void)
714
printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",my_progname, SLAP_VERSION,
715
drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
719
static void usage(void)
722
puts("Copyright (C) 2008 Sun Microsystems");
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("drizzle",load_default_groups);
729
my_print_help(my_long_options);
732
bool get_one_option(int optid, const struct my_option *, char *argument)
735
uint64_t temp_drizzle_port= 0;
742
temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
743
/* if there is an alpha character this is not a valid port */
744
if (strlen(endchar) != 0)
746
fprintf(stderr, _("Non-integer value supplied for port. If you are trying to enter a password please use --password instead.\n"));
749
/* If the port number is > 65535 it is not a valid port
750
This also helps with potential data loss casting unsigned long to a
752
if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
754
fprintf(stderr, _("Value supplied for port is not valid.\n"));
759
opt_drizzle_port= (uint32_t) temp_drizzle_port;
765
char *start= argument;
768
opt_password = strdup(argument);
769
if (opt_password == NULL)
771
fprintf(stderr, "Memory allocation error while copying password. "
777
/* Overwriting password with 'x' */
782
/* Cut length of argument */
803
get_random_string(char *buf, size_t size)
841
805
char *buf_ptr= buf;
843
for (size_t x= size; x > 0; x--)
808
for (x= size; x > 0; x--)
844
809
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
845
810
return(buf_ptr - buf);
1493
1516
for (ptr_statement= query_statements[sql_type_count], x= 0;
1494
1517
x < auto_generate_sql_unique_query_number;
1495
x++, ptr_statement= ptr_statement->getNext())
1518
x++, ptr_statement= ptr_statement->next)
1499
ptr_statement->setNext(build_insert_string());
1522
ptr_statement->next= build_insert_string();
1504
ptr_statement->setNext(build_select_string(true));
1527
ptr_statement->next= build_select_string(true);
1509
1532
sql_type_count++;
1510
} while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1533
} while (sql_type ? (sql_type= sql_type->next) : 0);
1514
if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1537
if (create_string && !stat(create_string, &sbuf))
1517
std::vector<char> tmp_string;
1518
if (not S_ISREG(sbuf.st_mode))
1540
if (!S_ISREG(sbuf.st_mode))
1520
1542
fprintf(stderr,"%s: Create file was not a regular file\n",
1524
if ((data_file= open(create_string.c_str(), O_RDWR)) == -1)
1546
if ((data_file= open(create_string, O_RDWR)) == -1)
1526
fprintf(stderr,"%s: Could not open create file\n", SLAP_NAME);
1548
fprintf(stderr,"%s: Could not open create file\n", my_progname);
1529
1551
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1531
1553
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],
1556
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1557
if (tmp_string == NULL)
1559
fprintf(stderr, "Memory Allocation error in option processing\n");
1562
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1563
bytes_read= read(data_file, (unsigned char*) tmp_string,
1536
1564
(size_t)sbuf.st_size);
1565
tmp_string[sbuf.st_size]= '\0';
1537
1566
close(data_file);
1538
1567
if (bytes_read != sbuf.st_size)
1540
1569
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1542
parse_delimiter(&tmp_string[0], &create_statements, delimiter[0]);
1571
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1544
else if (not create_string.empty())
1574
else if (create_string)
1546
parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1576
parse_delimiter(create_string, &create_statements, delimiter[0]);
1549
1579
/* Set this up till we fully support options on user generated queries */
1550
if (not user_supplied_query.empty())
1580
if (user_supplied_query)
1552
1582
query_statements_count=
1553
1583
parse_option("default", &query_options, ',');
1555
query_statements.resize(query_statements_count);
1585
query_statements= (statement **)malloc(sizeof(statement *) * query_statements_count);
1586
if (query_statements == NULL)
1588
fprintf(stderr, "Memory Allocation error in option processing\n");
1591
memset(query_statements, 0, sizeof(statement *) * query_statements_count);
1558
if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1594
if (user_supplied_query && !stat(user_supplied_query, &sbuf))
1561
std::vector<char> tmp_string;
1563
if (not S_ISREG(sbuf.st_mode))
1597
if (!S_ISREG(sbuf.st_mode))
1565
1599
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)
1603
if ((data_file= open(user_supplied_query, O_RDWR)) == -1)
1571
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1605
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1574
1608
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1576
1610
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],
1613
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1614
if (tmp_string == NULL)
1616
fprintf(stderr, "Memory Allocation error in option processing\n");
1619
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1620
bytes_read= read(data_file, (unsigned char*) tmp_string,
1581
1621
(size_t)sbuf.st_size);
1622
tmp_string[sbuf.st_size]= '\0';
1582
1623
close(data_file);
1583
1624
if (bytes_read != sbuf.st_size)
1585
1626
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],
1628
if (user_supplied_query)
1629
actual_queries= parse_delimiter(tmp_string, &query_statements[0],
1591
else if (not user_supplied_query.empty())
1633
else if (user_supplied_query)
1593
actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1635
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))
1640
if (user_supplied_pre_statements
1641
&& !stat(user_supplied_pre_statements, &sbuf))
1602
std::vector<char> tmp_string;
1604
if (not S_ISREG(sbuf.st_mode))
1644
if (!S_ISREG(sbuf.st_mode))
1606
1646
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)
1650
if ((data_file= open(user_supplied_pre_statements, O_RDWR)) == -1)
1612
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1652
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1615
1655
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1617
1657
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],
1660
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1661
if (tmp_string == NULL)
1663
fprintf(stderr, "Memory Allocation error in option processing\n");
1666
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1667
bytes_read= read(data_file, (unsigned char*) tmp_string,
1622
1668
(size_t)sbuf.st_size);
1669
tmp_string[sbuf.st_size]= '\0';
1623
1670
close(data_file);
1624
1671
if (bytes_read != sbuf.st_size)
1626
1673
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,
1675
if (user_supplied_pre_statements)
1676
(void)parse_delimiter(tmp_string, &pre_statements,
1632
else if (not user_supplied_pre_statements.empty())
1680
else if (user_supplied_pre_statements)
1634
(void)parse_delimiter(user_supplied_pre_statements.c_str(),
1682
(void)parse_delimiter(user_supplied_pre_statements,
1635
1683
&pre_statements,
1639
if (not user_supplied_post_statements.empty()
1640
&& !stat(user_supplied_post_statements.c_str(), &sbuf))
1687
if (user_supplied_post_statements
1688
&& !stat(user_supplied_post_statements, &sbuf))
1643
std::vector<char> tmp_string;
1645
if (not S_ISREG(sbuf.st_mode))
1691
if (!S_ISREG(sbuf.st_mode))
1647
1693
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)
1697
if ((data_file= open(user_supplied_post_statements, O_RDWR)) == -1)
1653
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1699
fprintf(stderr,"%s: Could not open query supplied file\n", my_progname);
1657
1703
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1659
1705
fprintf(stderr, "Request for more memory than architecture supports\n");
1662
tmp_string.resize((size_t)(sbuf.st_size + 1));
1708
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1709
if (tmp_string == NULL)
1711
fprintf(stderr, "Memory Allocation error in option processing\n");
1714
memset(tmp_string, 0, (size_t)(sbuf.st_size+1));
1664
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1716
bytes_read= read(data_file, (unsigned char*) tmp_string,
1665
1717
(size_t)(sbuf.st_size));
1718
tmp_string[sbuf.st_size]= '\0';
1666
1719
close(data_file);
1667
1720
if (bytes_read != sbuf.st_size)
1669
1722
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,
1724
if (user_supplied_post_statements)
1725
(void)parse_delimiter(tmp_string, &post_statements,
1675
else if (not user_supplied_post_statements.empty())
1729
else if (user_supplied_post_statements)
1677
(void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1731
(void)parse_delimiter(user_supplied_post_statements, &post_statements,
1681
1735
if (verbose >= 2)
1682
1736
printf("Parsing engines to use.\n");
1684
if (not default_engine.empty())
1685
parse_option(default_engine.c_str(), &engine_options, ',');
1739
parse_option(default_engine, &engine_options, ',');
1687
1741
if (tty_password)
1688
1742
opt_password= client_get_tty_password(NULL);
1903
2002
if (run_query(con, NULL, query, len))
1905
2004
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1906
SLAP_NAME, db, drizzle_con_error(&con));
2005
my_progname, db, drizzle_con_error(con));
1911
static void run_statements(drizzle_con_st &con, Statement *stmt)
2015
run_statements(drizzle_con_st *con, statement *stmt)
1913
for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
2019
for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1915
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
2021
if (run_query(con, NULL, ptr->string, ptr->length))
1917
2023
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1918
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1925
static void timer_thread()
2024
my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(con));
2033
run_scheduler(stats *sptr, statement **stmts, uint32_t concur, uint64_t limit)
2037
unsigned int real_concurrency;
2038
struct timeval start_time, end_time;
2039
option_string *sql_type;
2040
thread_context *con;
2041
pthread_t mainthread; /* Thread descriptor */
2042
pthread_attr_t attr; /* Thread attributes */
2045
pthread_attr_init(&attr);
2046
pthread_attr_setdetachstate(&attr,
2047
PTHREAD_CREATE_DETACHED);
2049
pthread_mutex_lock(&counter_mutex);
2052
pthread_mutex_lock(&sleeper_mutex);
2054
pthread_mutex_unlock(&sleeper_mutex);
2056
real_concurrency= 0;
2058
for (y= 0, sql_type= query_options;
2059
y < query_statements_count;
2060
y++, sql_type= sql_type->next)
2062
unsigned int options_loop= 1;
2064
if (sql_type->option)
2066
options_loop= strtol(sql_type->option,
2068
options_loop= options_loop ? options_loop : 1;
2071
while (options_loop--)
2072
for (x= 0; x < concur; x++)
2074
con= (thread_context *)malloc(sizeof(thread_context));
2077
fprintf(stderr, "Memory Allocation error in scheduler\n");
2080
con->stmt= stmts[y];
2084
/* now you create the thread */
2085
if (pthread_create(&mainthread, &attr, run_task,
2088
fprintf(stderr,"%s: Could not create thread\n", my_progname);
2096
The timer_thread belongs to all threads so it too obeys the wakeup
2097
call that run tasks obey.
2099
if (opt_timer_length)
2101
pthread_mutex_lock(&timer_alarm_mutex);
2103
pthread_mutex_unlock(&timer_alarm_mutex);
2105
if (pthread_create(&mainthread, &attr, timer_thread,
2106
(void *)&opt_timer_length) != 0)
2108
fprintf(stderr,"%s: Could not create timer thread\n", my_progname);
2113
pthread_mutex_unlock(&counter_mutex);
2114
pthread_attr_destroy(&attr);
2116
pthread_mutex_lock(&sleeper_mutex);
2118
pthread_mutex_unlock(&sleeper_mutex);
2119
pthread_cond_broadcast(&sleep_threshhold);
2121
gettimeofday(&start_time, NULL);
2124
We loop until we know that all children have cleaned up.
2126
pthread_mutex_lock(&counter_mutex);
2127
while (thread_counter)
2129
struct timespec abstime;
2131
set_timespec(abstime, 3);
2132
pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
2134
pthread_mutex_unlock(&counter_mutex);
2136
gettimeofday(&end_time, NULL);
2139
sptr->timing= timedif(end_time, start_time);
2140
sptr->users= concur;
2141
sptr->real_users= real_concurrency;
2148
pthread_handler_t timer_thread(void *p)
2150
uint32_t *timer_length= (uint32_t *)p;
2151
struct timespec abstime;
1928
2155
We lock around the initial call in case were we in a loop. This
1929
2156
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);
2158
pthread_mutex_lock(&sleeper_mutex);
2159
while (master_wakeup)
2161
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2163
pthread_mutex_unlock(&sleeper_mutex);
2165
set_timespec(abstime, *timer_length);
2167
pthread_mutex_lock(&timer_alarm_mutex);
2168
pthread_cond_timedwait(&timer_alarm_threshold, &timer_alarm_mutex, &abstime);
2169
pthread_mutex_unlock(&timer_alarm_mutex);
2171
pthread_mutex_lock(&timer_alarm_mutex);
2173
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)
2178
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++)
2180
uint64_t counter= 0, queries;
2181
uint64_t detach_counter;
2182
unsigned int commit_counter;
2184
drizzle_result_st result;
2187
thread_context *ctx= (thread_context *)p;
2189
pthread_mutex_lock(&sleeper_mutex);
2190
while (master_wakeup)
2192
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2194
pthread_mutex_unlock(&sleeper_mutex);
2196
slap_connect(&con, true);
2199
printf("connected!\n");
2204
run_query(&con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
2207
for (ptr= ctx->stmt, detach_counter= 0;
2209
ptr= ptr->next, detach_counter++)
2211
if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
2214
slap_connect(&con, true);
2218
We have to execute differently based on query type. This should become a function.
2220
if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
2221
(ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
2224
unsigned int key_val;
2226
char buffer[HUGE_STRING_LENGTH];
2229
This should only happen if some sort of new engine was
2230
implemented that didn't properly handle UPDATEs.
2232
Just in case someone runs this under an experimental engine we don't
2233
want a crash so the if() is placed here.
2235
assert(primary_keys_number_of);
2236
if (primary_keys_number_of)
2238
key_val= (unsigned int)(random() % primary_keys_number_of);
2239
key= primary_keys[key_val];
2243
length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
2244
(int)ptr->length, ptr->string, key);
2246
if (run_query(&con, &result, buffer, length))
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);
2248
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2249
my_progname, (uint32_t)length, buffer, drizzle_con_error(&con));
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)
2256
if (run_query(&con, &result, ptr->string, ptr->length))
2011
boost::mutex::scoped_lock alarmLock(timer_alarm_mutex);
2258
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2259
my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(&con));
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);
2264
if (!opt_only_print)
2266
while ((row = drizzle_row_next(&result)))
2268
drizzle_result_free(&result);
2272
if (commit_rate && (++commit_counter == commit_rate))
2275
run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
2278
/* If the timer is set, and the alarm is not active then end */
2279
if (opt_timer_length && timer_alarm == false)
2282
/* If limit has been reached, and we are not in a timer_alarm just end */
2283
if (ctx->limit && queries == ctx->limit && timer_alarm == false)
2287
if (opt_timer_length && timer_alarm == true)
2290
if (ctx->limit && queries < ctx->limit)
2296
run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
2300
pthread_mutex_lock(&counter_mutex);
2302
pthread_cond_signal(&count_threshhold);
2303
pthread_mutex_unlock(&counter_mutex);
2042
2311
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)
2315
parse_option(const char *origin, option_string **stmt, char delm)
2048
2318
char *begin_ptr;
2320
option_string **sptr= stmt;
2050
2322
uint32_t length= strlen(origin);
2051
2323
uint32_t count= 0; /* We know that there is always one */
2053
2325
end_ptr= (char *)origin + length;
2056
*stmt= tmp= new OptionString;
2327
tmp= *sptr= (option_string *)malloc(sizeof(option_string));
2330
fprintf(stderr,"Error allocating memory while parsing options\n");
2333
memset(tmp, 0, sizeof(option_string));
2058
2335
for (begin_ptr= (char *)origin;
2059
2336
begin_ptr != end_ptr;
2060
tmp= tmp->getNext())
2062
2339
char buffer[HUGE_STRING_LENGTH];
2063
2340
char *buffer_ptr;
2270
2563
snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2273
2565
snprintf(buffer, HUGE_STRING_LENGTH,
2274
2566
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
2275
2567
"%u,%u,%u,%"PRIu64"\n",
2276
con.getEngine() ? con.getEngine() : "", /* Storage engine we ran against */
2568
con->engine ? con->engine : "", /* Storage engine we ran against */
2277
2569
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 */
2570
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2571
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2572
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2573
con->sum_of_time / 1000, con->sum_of_time % 1000, /* Total time */
2574
con->std_dev / 1000, con->std_dev % 1000, /* Standard Deviation */
2283
2575
iterations, /* Iterations */
2284
con.getUsers(), /* Children used max_timing */
2285
con.getRealUsers(), /* Children used max_timing */
2286
con.getAvgRows() /* Queries run */
2576
con->users, /* Children used max_timing */
2577
con->real_users, /* Children used max_timing */
2578
con->avg_rows /* 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,
2580
my_write(csv_file, (unsigned char*) buffer, (uint32_t)strlen(buffer), MYF(0));
2299
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2584
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());
2589
con->min_timing= sptr->timing;
2590
con->max_timing= sptr->timing;
2591
con->min_rows= sptr->rows;
2592
con->max_rows= sptr->rows;
2309
2594
/* At the moment we assume uniform */
2310
con->setUsers(sptr->getUsers());
2311
con->setRealUsers(sptr->getRealUsers());
2312
con->setAvgRows(sptr->getRows());
2595
con->users= sptr->users;
2596
con->real_users= sptr->real_users;
2597
con->avg_rows= sptr->rows;
2314
2599
/* With no next, we know it is the last element that was malloced */
2315
2600
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2317
con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2602
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());
2604
if (ptr->timing > con->max_timing)
2605
con->max_timing= ptr->timing;
2606
if (ptr->timing < con->min_timing)
2607
con->min_timing= ptr->timing;
2324
con->setSumOfTime(con->getAvgTiming());
2325
con->setAvgTiming(con->getAvgTiming()/iterations);
2609
con->sum_of_time= con->avg_timing;
2610
con->avg_timing= con->avg_timing/iterations;
2327
if (eng && eng->getString())
2328
con->setEngine(eng->getString());
2612
if (eng && eng->string)
2613
con->engine= eng->string;
2330
con->setEngine(NULL);
2332
standard_deviation(*con, sptr);
2617
standard_deviation(con, sptr);
2334
2619
/* Now we do the create time operations */
2335
con->setCreateMinTiming(sptr->getCreateTiming());
2336
con->setCreateMaxTiming(sptr->getCreateTiming());
2620
con->create_min_timing= sptr->create_timing;
2621
con->create_max_timing= sptr->create_timing;
2338
2623
/* At the moment we assume uniform */
2339
con->setCreateCount(sptr->getCreateCount());
2624
con->create_count= sptr->create_count;
2341
2626
/* With no next, we know it is the last element that was malloced */
2342
2627
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)
2629
con->create_avg_timing+= ptr->create_timing;
2631
if (ptr->create_timing > con->create_max_timing)
2632
con->create_max_timing= ptr->create_timing;
2633
if (ptr->create_timing < con->create_min_timing)
2634
con->create_min_timing= ptr->create_timing;
2636
con->create_avg_timing= con->create_avg_timing/iterations;
2640
option_cleanup(option_string *stmt)
2642
option_string *ptr, *nptr;
2646
for (ptr= stmt; ptr; ptr= nptr)
2658
statement_cleanup(statement *stmt)
2660
statement *ptr, *nptr;
2664
for (ptr= stmt; ptr; ptr= nptr)
2674
slap_close(drizzle_con_st *con)
2679
drizzle_free(drizzle_con_drizzle(con));
2683
slap_connect(drizzle_con_st *con, bool connect_to_schema)
2388
2685
/* Connect to server */
2389
2686
static uint32_t connection_retry_sleep= 100000; /* Microseconds */
2390
int connect_error= 1;
2687
int x, connect_error= 1;
2391
2688
drizzle_return_t ret;
2392
2689
drizzle_st *drizzle;
2394
2694
if (opt_delayed_start)
2395
2695
usleep(random()%opt_delayed_start);
2397
2697
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)
2698
drizzle_con_add_tcp(drizzle, con, host, opt_drizzle_port, user,
2700
connect_to_schema ? create_schema_string : NULL,
2701
opt_mysql ? DRIZZLE_CON_MYSQL : DRIZZLE_CON_NONE) == NULL)
2404
fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2703
fprintf(stderr,"%s: Error creating drizzle object\n", my_progname);
2408
drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2413
for (uint32_t x= 0; x < 10; x++)
2707
for (x= 0; x < 10; x++)
2415
if ((ret= drizzle_con_connect(&con)) == DRIZZLE_RETURN_OK)
2709
if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
2417
2711
/* Connect suceeded */
2418
2712
connect_error= 0;