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
26
A simple program designed to work as if multiple clients querying the database,
27
then reporting the timing of each stage.
29
Drizzle slap runs three stages:
30
1) Create schema,table, and optionally any SP or data you want to beign
31
the test with. (single client)
32
2) Load test (many clients)
33
3) Cleanup (disconnection, drop table if specified, single client)
37
Supply your own create and query SQL statements, with 50 clients
38
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
44
Let the program build the query SQL statement with a table of two int
45
columns, three varchar columns, five clients querying (20 times each),
46
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 \
53
Tell the program to load the create, insert and query SQL statements from
54
the specified files, where the create.sql file has multiple table creation
55
statements delimited by ';' and multiple insert statements delimited by ';'.
56
The --query file will have multiple queries delimited by ';', run all the
57
load statements, and then run all the queries in the query file
58
with five clients (five times each):
60
drizzleslap --concurrency=5 \
61
--iterations=5 --query=query.sql --create=create.sql \
65
Add language for better tests
66
String length for files and those put on the command line are not
67
setup to handle binary data.
69
Break up tests and run them on multiple hosts at once.
70
Allow output to be fed into a database directly.
75
#include "client/client_priv.h"
77
#include "client/option_string.h"
78
#include "client/stats.h"
79
#include "client/thread_context.h"
80
#include "client/conclusions.h"
81
#include "client/wakeup.h"
85
#include <sys/types.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/algorithm/string.hpp>
104
#include <boost/thread.hpp>
105
#include <boost/thread/mutex.hpp>
106
#include <boost/thread/condition_variable.hpp>
107
#include <boost/program_options.hpp>
108
#include <boost/scoped_ptr.hpp>
109
#include <drizzled/atomics.h>
111
#define SLAP_NAME "drizzleslap"
112
#define SLAP_VERSION "1.5"
114
#define HUGE_STRING_LENGTH 8196
115
#define RAND_STRING_SIZE 126
116
#define DEFAULT_BLOB_SIZE 1024
119
using namespace drizzled;
120
namespace po= boost::program_options;
123
static char *shared_memory_base_name=0;
126
client::Wakeup master_wakeup;
128
/* Global Thread timer */
129
static bool timer_alarm= false;
130
boost::mutex timer_alarm_mutex;
131
boost::condition_variable_any timer_alarm_threshold;
133
std::vector < std::string > primary_keys;
135
drizzled::atomic<size_t> connection_count;
136
drizzled::atomic<uint64_t> failed_update_for_transaction;
142
user_supplied_pre_statements,
143
user_supplied_post_statements,
148
static vector<string> user_supplied_queries;
149
static string opt_verbose;
150
std::string opt_protocol;
153
string create_schema_string;
155
static bool use_drizzle_protocol= false;
156
static bool opt_preserve= true;
157
static bool opt_only_print;
158
static bool opt_burnin;
159
static bool opt_ignore_sql_errors= false;
160
static bool opt_silent,
161
auto_generate_sql_autoincrement,
162
auto_generate_sql_guid_primary,
164
std::string opt_auto_generate_sql_type;
166
static int32_t verbose= 0;
167
static uint32_t delimiter_length;
168
static uint32_t commit_rate;
169
static uint32_t detach_rate;
170
static uint32_t opt_timer_length;
171
static uint32_t opt_delayed_start;
172
string num_blob_cols_opt,
176
static uint32_t opt_set_random_seed;
178
string auto_generate_selected_columns_opt;
180
/* Yes, we do set defaults here */
181
static uint32_t num_int_cols= 1;
182
static uint32_t num_char_cols= 1;
183
static uint32_t num_blob_cols= 0;
184
static uint32_t num_blob_cols_size;
185
static uint32_t num_blob_cols_size_min;
186
static uint32_t num_int_cols_index= 0;
187
static uint32_t num_char_cols_index= 0;
188
static uint32_t iterations;
189
static uint64_t actual_queries= 0;
190
static uint64_t auto_actual_queries;
191
static uint64_t auto_generate_sql_unique_write_number;
192
static uint64_t auto_generate_sql_unique_query_number;
193
static uint32_t auto_generate_sql_secondary_indexes;
194
static uint64_t num_of_query;
195
static uint64_t auto_generate_sql_number;
196
string concurrency_str;
197
string create_string;
198
std::vector <uint32_t> concurrency;
200
std::string opt_csv_str;
203
static int process_options(void);
204
static uint32_t opt_drizzle_port= 0;
206
static OptionString *engine_options= NULL;
207
static OptionString *query_options= NULL;
208
static Statement *pre_statements= NULL;
209
static Statement *post_statements= NULL;
210
static Statement *create_statements= NULL;
212
static std::vector <Statement *> query_statements;
213
static uint32_t query_statements_count;
217
void print_conclusions(Conclusions &con);
218
void print_conclusions_csv(Conclusions &con);
219
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr);
220
uint32_t parse_comma(const char *string, std::vector <uint32_t> &range);
221
uint32_t parse_delimiter(const char *script, Statement **stmt, char delm);
222
uint32_t parse_option(const char *origin, OptionString **stmt, char delm);
223
static void drop_schema(drizzle_con_st &con, const char *db);
224
uint32_t get_random_string(char *buf, size_t size);
225
static Statement *build_table_string(void);
226
static Statement *build_insert_string(void);
227
static Statement *build_update_string(void);
228
static Statement * build_select_string(bool key);
229
static int generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt);
230
static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr);
231
static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit);
232
void statement_cleanup(Statement *stmt);
233
void option_cleanup(OptionString *stmt);
234
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr);
235
static void run_statements(drizzle_con_st &con, Statement *stmt);
236
drizzle_con_st *slap_connect(bool connect_to_schema);
237
void slap_close(drizzle_con_st *con);
238
static int run_query(drizzle_con_st &con, drizzle_result_st *result, const char *query, int len);
239
void standard_deviation(Conclusions &con, Stats *sptr);
241
static const char ALPHANUMERICS[]=
242
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
244
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
247
static long int timedif(struct timeval a, struct timeval b)
251
us = a.tv_usec - b.tv_usec;
253
s = a.tv_sec - b.tv_sec;
258
static void combine_queries(vector<string> queries)
260
user_supplied_query.erase();
261
for (vector<string>::iterator it= queries.begin();
265
user_supplied_query.append(*it);
266
user_supplied_query.append(delimiter);
271
static void run_task(ThreadContext *ctx)
273
uint64_t counter= 0, queries;
274
uint64_t detach_counter;
275
uint32_t commit_counter;
276
drizzle_result_st result;
280
master_wakeup.wait();
282
drizzle_con_st *con= slap_connect(true);
286
printf("connected!\n");
293
run_query(*con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
297
for (ptr= ctx->getStmt(), detach_counter= 0;
298
ptr && ptr->getLength();
299
ptr= ptr->getNext(), detach_counter++)
301
if (not opt_only_print && detach_rate && !(detach_counter % detach_rate))
304
con= slap_connect(true);
308
We have to execute differently based on query type. This should become a function.
310
bool is_failed_update= false;
311
if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) ||
312
(ptr->getType() == SELECT_TYPE_REQUIRES_PREFIX))
315
char buffer[HUGE_STRING_LENGTH];
318
This should only happen if some sort of new engine was
319
implemented that didn't properly handle UPDATEs.
321
Just in case someone runs this under an experimental engine we don't
322
want a crash so the if() is placed here.
324
assert(primary_keys.size());
325
if (primary_keys.size())
327
key_val= (uint32_t)(random() % primary_keys.size());
328
const char *key= primary_keys[key_val].c_str();
332
int length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", (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())
407
run_query(*con, NULL, "COMMIT", strlen("COMMIT"));
417
* commandline_options is the set of all options that can only be called via the command line.
419
* client_options is the set of all options that can be defined via both command line and via
420
* the configuration file client.cnf
422
* slap_options is the set of all drizzleslap specific options which behave in a manner
423
* similar to that of client_options. It's configuration file is drizzleslap.cnf
425
* long_options is the union of commandline_options, slap_options and client_options.
427
* There are two configuration files per set of options, one which is defined by the user
428
* which is found at either $XDG_CONFIG_HOME/drizzle or ~/.config/drizzle directory and the other which
429
* is the system configuration file which is found in the SYSCONFDIR/drizzle directory.
431
* The system configuration file is over ridden by the user's configuration file which
432
* in turn is over ridden by the command line.
434
int main(int argc, char **argv)
436
char *password= NULL;
439
po::options_description commandline_options("Options used only in command line");
440
commandline_options.add_options()
441
("help,?","Display this help and exit")
442
("info","Gives information and exit")
443
("burnin",po::value<bool>(&opt_burnin)->default_value(false)->zero_tokens(),
444
"Run full test case in infinite loop")
445
("ignore-sql-errors", po::value<bool>(&opt_ignore_sql_errors)->default_value(false)->zero_tokens(),
446
"Ignore SQL errors in query run")
447
("create-schema",po::value<string>(&create_schema_string)->default_value("drizzleslap"),
448
"Schema to run tests in")
449
("create",po::value<string>(&create_string)->default_value(""),
450
"File or string to use to create tables")
451
("detach",po::value<uint32_t>(&detach_rate)->default_value(0),
452
"Detach (close and re open) connections after X number of requests")
453
("iterations,i",po::value<uint32_t>(&iterations)->default_value(1),
454
"Number of times to run the tests")
455
("label",po::value<string>(&opt_label)->default_value(""),
456
"Label to use for print and csv")
457
("number-blob-cols",po::value<string>(&num_blob_cols_opt)->default_value(""),
458
"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. ")
459
("number-char-cols,x",po::value<string>(&num_char_cols_opt)->default_value(""),
460
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.")
461
("number-int-cols,y",po::value<string>(&num_int_cols_opt)->default_value(""),
462
"Number of INT columns to create in table if specifying --auto-generate-sql.")
463
("number-of-queries",
464
po::value<uint64_t>(&num_of_query)->default_value(0),
465
"Limit each client to this number of queries(this is not exact)")
466
("only-print",po::value<bool>(&opt_only_print)->default_value(false)->zero_tokens(),
467
"This causes drizzleslap to not connect to the database instead print out what it would have done instead")
468
("post-query", po::value<string>(&user_supplied_post_statements)->default_value(""),
469
"Query to run or file containing query to execute after tests have completed.")
470
("post-system",po::value<string>(&post_system)->default_value(""),
471
"system() string to execute after tests have completed")
473
po::value<string>(&user_supplied_pre_statements)->default_value(""),
474
"Query to run or file containing query to execute before running tests.")
475
("pre-system",po::value<string>(&pre_system)->default_value(""),
476
"system() string to execute before running tests.")
477
("query,q",po::value<vector<string> >(&user_supplied_queries)->composing()->notifier(&combine_queries),
478
"Query to run or file containing query")
479
("verbose,v", po::value<string>(&opt_verbose)->default_value("v"), "Increase verbosity level by one.")
480
("version,V","Output version information and exit")
483
po::options_description slap_options("Options specific to drizzleslap");
484
slap_options.add_options()
485
("auto-generate-sql-select-columns",
486
po::value<string>(&auto_generate_selected_columns_opt)->default_value(""),
487
"Provide a string to use for the select fields used in auto tests")
488
("auto-generate-sql,a",po::value<bool>(&auto_generate_sql)->default_value(false)->zero_tokens(),
489
"Generate SQL where not supplied by file or command line")
490
("auto-generate-sql-add-autoincrement",
491
po::value<bool>(&auto_generate_sql_autoincrement)->default_value(false)->zero_tokens(),
492
"Add an AUTO_INCREMENT column to auto-generated tables")
493
("auto-generate-sql-execute-number",
494
po::value<uint64_t>(&auto_actual_queries)->default_value(0),
495
"See this number and generate a set of queries to run")
496
("auto-generate-sql-guid-primary",
497
po::value<bool>(&auto_generate_sql_guid_primary)->default_value(false)->zero_tokens(),
498
"Add GUID based primary keys to auto-generated tables")
499
("auto-generate-sql-load-type",
500
po::value<string>(&opt_auto_generate_sql_type)->default_value("mixed"),
501
"Specify test load type: mixed, update, write, key or read; default is mixed")
502
("auto-generate-sql-secondary-indexes",
503
po::value<uint32_t>(&auto_generate_sql_secondary_indexes)->default_value(0),
504
"Number of secondary indexes to add to auto-generated tables")
505
("auto-generated-sql-unique-query-number",
506
po::value<uint64_t>(&auto_generate_sql_unique_query_number)->default_value(10),
507
"Number of unique queries to generate for automatic tests")
508
("auto-generate-sql-unique-write-number",
509
po::value<uint64_t>(&auto_generate_sql_unique_write_number)->default_value(10),
510
"Number of unique queries to generate for auto-generate-sql-write-number")
511
("auto-generate-sql-write-number",
512
po::value<uint64_t>(&auto_generate_sql_number)->default_value(100),
513
"Number of row inserts to perform for each thread (default is 100).")
514
("commit",po::value<uint32_t>(&commit_rate)->default_value(0),
515
"Commit records every X number of statements")
516
("concurrency,c",po::value<string>(&concurrency_str)->default_value(""),
517
"Number of clients to simulate for query to run")
518
("csv",po::value<std::string>(&opt_csv_str)->default_value(""),
519
"Generate CSV output to named file or to stdout if no file is name.")
520
("delayed-start",po::value<uint32_t>(&opt_delayed_start)->default_value(0),
521
"Delay the startup of threads by a random number of microsends (the maximum of the delay")
522
("delimiter,F",po::value<string>(&delimiter)->default_value("\n"),
523
"Delimiter to use in SQL statements supplied in file or command line")
524
("engine,e",po::value<string>(&default_engine)->default_value(""),
525
"Storage engine to use for creating the table")
527
po::value<uint32_t>(&opt_set_random_seed)->default_value(0),
528
"Seed for random number generator (srandom(3)) ")
529
("silent,s",po::value<bool>(&opt_silent)->default_value(false)->zero_tokens(),
530
"Run program in silent mode - no output. ")
531
("timer-length",po::value<uint32_t>(&opt_timer_length)->default_value(0),
532
"Require drizzleslap to run each specific test a certain amount of time in seconds")
535
po::options_description client_options("Options specific to the client");
536
client_options.add_options()
537
("host,h",po::value<string>(&host)->default_value("localhost"),"Connect to the host")
538
("password,P",po::value<char *>(&password),
539
"Password to use when connecting to server. If password is not given it's asked from the tty")
540
("port,p",po::value<uint32_t>(), "Port number to use for connection")
541
("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
542
"The protocol of connection (mysql or drizzle).")
543
("user,u",po::value<string>(&user)->default_value(""),
544
"User for login if not current user")
547
po::options_description long_options("Allowed Options");
548
long_options.add(commandline_options).add(slap_options).add(client_options);
550
std::string system_config_dir_slap(SYSCONFDIR);
551
system_config_dir_slap.append("/drizzle/drizzleslap.cnf");
553
std::string system_config_dir_client(SYSCONFDIR);
554
system_config_dir_client.append("/drizzle/client.cnf");
556
std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
558
if (user_config_dir.compare(0, 2, "~/") == 0)
561
homedir= getenv("HOME");
563
user_config_dir.replace(0, 1, homedir);
566
uint64_t temp_drizzle_port= 0;
567
boost::scoped_ptr<drizzle_con_st> con_ap(new drizzle_con_st);
570
// Disable allow_guessing
571
int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
573
po::variables_map vm;
574
po::store(po::command_line_parser(argc, argv).options(long_options).
575
style(style).extra_parser(parse_password_arg).run(), vm);
577
std::string user_config_dir_slap(user_config_dir);
578
user_config_dir_slap.append("/drizzle/drizzleslap.cnf");
580
std::string user_config_dir_client(user_config_dir);
581
user_config_dir_client.append("/drizzle/client.cnf");
583
ifstream user_slap_ifs(user_config_dir_slap.c_str());
584
po::store(parse_config_file(user_slap_ifs, slap_options), vm);
586
ifstream user_client_ifs(user_config_dir_client.c_str());
587
po::store(parse_config_file(user_client_ifs, client_options), vm);
589
ifstream system_slap_ifs(system_config_dir_slap.c_str());
590
store(parse_config_file(system_slap_ifs, slap_options), vm);
592
ifstream system_client_ifs(system_config_dir_client.c_str());
593
store(parse_config_file(system_client_ifs, client_options), vm);
597
if (process_options())
600
if ( vm.count("help") || vm.count("info"))
602
printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
603
drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
604
puts("Copyright (C) 2008 Sun Microsystems");
605
puts("This software comes with ABSOLUTELY NO WARRANTY. "
606
"This is free software,\n"
607
"and you are welcome to modify and redistribute it under the GPL "
609
puts("Run a query multiple times against the server\n");
610
cout << long_options << endl;
614
if (vm.count("protocol"))
616
boost::to_lower(opt_protocol);
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
drizzle_con_st *con= slap_connect(false);
683
/* 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);
720
/* now free all the strings we created */
721
if (not opt_password.empty())
722
opt_password.erase();
726
statement_cleanup(create_statements);
727
for (uint32_t x= 0; x < query_statements_count; x++)
728
statement_cleanup(query_statements[x]);
729
query_statements.clear();
730
statement_cleanup(pre_statements);
731
statement_cleanup(post_statements);
732
option_cleanup(engine_options);
733
option_cleanup(query_options);
736
free(shared_memory_base_name);
741
catch(std::exception &err)
743
cerr<<"Error:"<<err.what()<<endl;
746
if (csv_file != fileno(stdout))
752
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
756
Conclusions conclusion;
757
uint64_t client_limit;
759
head_sptr= new Stats[iterations];
760
if (head_sptr == NULL)
762
fprintf(stderr,"Error allocating memory in concurrency_loop\n");
766
if (auto_actual_queries)
767
client_limit= auto_actual_queries;
768
else if (num_of_query)
769
client_limit= num_of_query / current;
771
client_limit= actual_queries;
774
for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
777
We might not want to load any data, such as when we are calling
778
a stored_procedure that doesn't use data, or we know we already have
781
if (opt_preserve == false)
782
drop_schema(con, create_schema_string.c_str());
784
/* First we create */
785
if (create_statements)
786
create_schema(con, create_schema_string.c_str(), create_statements, eptr, sptr);
789
If we generated GUID we need to build a list of them from creation that
793
printf("Generating primary key list\n");
794
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
795
generate_primary_key_list(con, eptr);
797
if (not pre_system.empty())
799
int ret= system(pre_system.c_str());
804
Pre statements are always run after all other logic so they can
805
correct/adjust any item that they want.
808
run_statements(con, pre_statements);
810
run_scheduler(sptr, &query_statements[0], current, client_limit);
813
run_statements(con, post_statements);
815
if (not post_system.empty())
817
int ret= system(post_system.c_str());
821
/* We are finished with this run */
822
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
823
primary_keys.clear();
827
printf("Generating stats\n");
829
generate_stats(&conclusion, eptr, head_sptr);
832
print_conclusions(conclusion);
833
if (not opt_csv_str.empty())
834
print_conclusions_csv(conclusion);
840
uint32_t get_random_string(char *buf, size_t size)
844
for (size_t x= size; x > 0; x--)
845
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
846
return(buf_ptr - buf);
853
This function builds a create table query if the user opts to not supply
854
a file or string containing a create table statement
857
build_table_string(void)
859
char buf[HUGE_STRING_LENGTH];
864
table_string.reserve(HUGE_STRING_LENGTH);
866
table_string= "CREATE TABLE `t1` (";
868
if (auto_generate_sql_autoincrement)
870
table_string.append("id serial");
872
if (num_int_cols || num_char_cols)
873
table_string.append(",");
876
if (auto_generate_sql_guid_primary)
878
table_string.append("id varchar(128) primary key");
880
if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
881
table_string.append(",");
884
if (auto_generate_sql_secondary_indexes)
886
for (uint32_t count= 0; count < auto_generate_sql_secondary_indexes; count++)
888
if (count) /* Except for the first pass we add a comma */
889
table_string.append(",");
891
if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
892
> HUGE_STRING_LENGTH)
894
fprintf(stderr, "Memory Allocation error in create table\n");
897
table_string.append(buf);
900
if (num_int_cols || num_char_cols)
901
table_string.append(",");
905
for (col_count= 1; col_count <= num_int_cols; col_count++)
907
if (num_int_cols_index)
909
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT, INDEX(intcol%d)",
910
col_count, col_count) > HUGE_STRING_LENGTH)
912
fprintf(stderr, "Memory Allocation error in create table\n");
918
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT ", col_count)
919
> HUGE_STRING_LENGTH)
921
fprintf(stderr, "Memory Allocation error in create table\n");
925
table_string.append(buf);
927
if (col_count < num_int_cols || num_char_cols > 0)
928
table_string.append(",");
932
for (col_count= 1; col_count <= num_char_cols; col_count++)
934
if (num_char_cols_index)
936
if (snprintf(buf, HUGE_STRING_LENGTH,
937
"charcol%d VARCHAR(128), INDEX(charcol%d) ",
938
col_count, col_count) > HUGE_STRING_LENGTH)
940
fprintf(stderr, "Memory Allocation error in creating table\n");
946
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
947
col_count) > HUGE_STRING_LENGTH)
949
fprintf(stderr, "Memory Allocation error in creating table\n");
953
table_string.append(buf);
955
if (col_count < num_char_cols || num_blob_cols > 0)
956
table_string.append(",");
960
for (col_count= 1; col_count <= num_blob_cols; col_count++)
962
if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob",
963
col_count) > HUGE_STRING_LENGTH)
965
fprintf(stderr, "Memory Allocation error in creating table\n");
968
table_string.append(buf);
970
if (col_count < num_blob_cols)
971
table_string.append(",");
974
table_string.append(")");
976
ptr->setString(table_string.length());
977
if (ptr->getString()==NULL)
979
fprintf(stderr, "Memory Allocation error in creating table\n");
982
ptr->setType(CREATE_TABLE_TYPE);
983
strcpy(ptr->getString(), table_string.c_str());
988
build_update_string()
990
This function builds insert statements when the user opts to not supply
991
an insert file or string containing insert data
994
build_update_string(void)
996
char buf[HUGE_STRING_LENGTH];
999
string update_string;
1001
update_string.reserve(HUGE_STRING_LENGTH);
1003
update_string= "UPDATE t1 SET ";
1006
for (col_count= 1; col_count <= num_int_cols; col_count++)
1008
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
1009
random()) > HUGE_STRING_LENGTH)
1011
fprintf(stderr, "Memory Allocation error in creating update\n");
1014
update_string.append(buf);
1016
if (col_count < num_int_cols || num_char_cols > 0)
1017
update_string.append(",", 1);
1021
for (col_count= 1; col_count <= num_char_cols; col_count++)
1023
char rand_buffer[RAND_STRING_SIZE];
1024
int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
1026
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
1027
buf_len, rand_buffer)
1028
> HUGE_STRING_LENGTH)
1030
fprintf(stderr, "Memory Allocation error in creating update\n");
1033
update_string.append(buf);
1035
if (col_count < num_char_cols)
1036
update_string.append(",", 1);
1039
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1040
update_string.append(" WHERE id = ");
1045
ptr->setString(update_string.length());
1046
if (ptr->getString() == NULL)
1048
fprintf(stderr, "Memory Allocation error in creating update\n");
1051
if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1052
ptr->setType(UPDATE_TYPE_REQUIRES_PREFIX);
1054
ptr->setType(UPDATE_TYPE);
1055
strncpy(ptr->getString(), update_string.c_str(), ptr->getLength());
1061
build_insert_string()
1063
This function builds insert statements when the user opts to not supply
1064
an insert file or string containing insert data
1067
build_insert_string(void)
1069
char buf[HUGE_STRING_LENGTH];
1072
string insert_string;
1074
insert_string.reserve(HUGE_STRING_LENGTH);
1076
insert_string= "INSERT INTO t1 VALUES (";
1078
if (auto_generate_sql_autoincrement)
1080
insert_string.append("NULL");
1082
if (num_int_cols || num_char_cols)
1083
insert_string.append(",");
1086
if (auto_generate_sql_guid_primary)
1088
insert_string.append("uuid()");
1090
if (num_int_cols || num_char_cols)
1091
insert_string.append(",");
1094
if (auto_generate_sql_secondary_indexes)
1098
for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1100
if (count) /* Except for the first pass we add a comma */
1101
insert_string.append(",");
1103
insert_string.append("uuid()");
1106
if (num_int_cols || num_char_cols)
1107
insert_string.append(",");
1111
for (col_count= 1; col_count <= num_int_cols; col_count++)
1113
if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1115
fprintf(stderr, "Memory Allocation error in creating insert\n");
1118
insert_string.append(buf);
1120
if (col_count < num_int_cols || num_char_cols > 0)
1121
insert_string.append(",");
1125
for (col_count= 1; col_count <= num_char_cols; col_count++)
1127
int buf_len= get_random_string(buf, RAND_STRING_SIZE);
1128
insert_string.append("'", 1);
1129
insert_string.append(buf, buf_len);
1130
insert_string.append("'", 1);
1132
if (col_count < num_char_cols || num_blob_cols > 0)
1133
insert_string.append(",", 1);
1138
vector <char> blob_ptr;
1140
blob_ptr.resize(num_blob_cols_size);
1142
for (col_count= 1; col_count <= num_blob_cols; col_count++)
1146
uint32_t difference= num_blob_cols_size - num_blob_cols_size_min;
1148
size= difference ? (num_blob_cols_size_min + (random() % difference)) :
1151
buf_len= get_random_string(&blob_ptr[0], size);
1153
insert_string.append("'", 1);
1154
insert_string.append(&blob_ptr[0], buf_len);
1155
insert_string.append("'", 1);
1157
if (col_count < num_blob_cols)
1158
insert_string.append(",", 1);
1162
insert_string.append(")", 1);
1165
ptr->setString(insert_string.length());
1166
if (ptr->getString()==NULL)
1168
fprintf(stderr, "Memory Allocation error in creating select\n");
1171
ptr->setType(INSERT_TYPE);
1172
strcpy(ptr->getString(), insert_string.c_str());
1178
build_select_string()
1180
This function builds a query if the user opts to not supply a query
1181
statement or file containing a query statement
1184
build_select_string(bool key)
1186
char buf[HUGE_STRING_LENGTH];
1189
string query_string;
1191
query_string.reserve(HUGE_STRING_LENGTH);
1193
query_string.append("SELECT ", 7);
1194
if (not auto_generate_selected_columns_opt.empty())
1196
query_string.append(auto_generate_selected_columns_opt.c_str());
1200
for (col_count= 1; col_count <= num_int_cols; col_count++)
1202
if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1203
> HUGE_STRING_LENGTH)
1205
fprintf(stderr, "Memory Allocation error in creating select\n");
1208
query_string.append(buf);
1210
if (col_count < num_int_cols || num_char_cols > 0)
1211
query_string.append(",", 1);
1214
for (col_count= 1; col_count <= num_char_cols; col_count++)
1216
if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1217
> HUGE_STRING_LENGTH)
1219
fprintf(stderr, "Memory Allocation error in creating select\n");
1222
query_string.append(buf);
1224
if (col_count < num_char_cols || num_blob_cols > 0)
1225
query_string.append(",", 1);
1228
for (col_count= 1; col_count <= num_blob_cols; col_count++)
1230
if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
1231
> HUGE_STRING_LENGTH)
1233
fprintf(stderr, "Memory Allocation error in creating select\n");
1236
query_string.append(buf);
1238
if (col_count < num_blob_cols)
1239
query_string.append(",", 1);
1242
query_string.append(" FROM t1");
1245
(auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1246
query_string.append(" WHERE id = ");
1249
ptr->setString(query_string.length());
1250
if (ptr->getString() == NULL)
1252
fprintf(stderr, "Memory Allocation error in creating select\n");
1256
(auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1257
ptr->setType(SELECT_TYPE_REQUIRES_PREFIX);
1259
ptr->setType(SELECT_TYPE);
1260
strcpy(ptr->getString(), query_string.c_str());
1265
process_options(void)
1268
ssize_t bytes_read= 0;
1273
verbose= opt_verbose.length();
1275
/* If something is created we clean it up, otherwise we leave schemas alone */
1276
if ( (not create_string.empty()) || auto_generate_sql)
1277
opt_preserve= false;
1279
if (auto_generate_sql && (not create_string.empty() || !user_supplied_query.empty()))
1282
"%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1287
if (auto_generate_sql && auto_generate_sql_guid_primary &&
1288
auto_generate_sql_autoincrement)
1291
"%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1296
if (auto_generate_sql && num_of_query && auto_actual_queries)
1299
"%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1304
parse_comma(not concurrency_str.empty() ? concurrency_str.c_str() : "1", concurrency);
1306
if (not opt_csv_str.empty())
1310
if (opt_csv_str[0] == '-')
1312
csv_file= fileno(stdout);
1316
if ((csv_file= open(opt_csv_str.c_str(), O_CREAT|O_WRONLY|O_APPEND,
1317
S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
1319
fprintf(stderr,"%s: Could not open csv file: %sn\n",
1320
SLAP_NAME, opt_csv_str.c_str());
1329
if (not num_int_cols_opt.empty())
1332
parse_option(num_int_cols_opt.c_str(), &str, ',');
1333
num_int_cols= atoi(str->getString());
1334
if (str->getOption())
1335
num_int_cols_index= atoi(str->getOption());
1336
option_cleanup(str);
1339
if (not num_char_cols_opt.empty())
1342
parse_option(num_char_cols_opt.c_str(), &str, ',');
1343
num_char_cols= atoi(str->getString());
1344
if (str->getOption())
1345
num_char_cols_index= atoi(str->getOption());
1347
num_char_cols_index= 0;
1348
option_cleanup(str);
1351
uint32_t sql_type_count= 0;
1352
if (not num_blob_cols_opt.empty())
1355
parse_option(num_blob_cols_opt.c_str(), &str, ',');
1356
num_blob_cols= atoi(str->getString());
1357
if (str->getOption())
1361
if ((sep_ptr= strchr(str->getOption(), '/')))
1363
num_blob_cols_size_min= atoi(str->getOption());
1364
num_blob_cols_size= atoi(sep_ptr+1);
1368
num_blob_cols_size_min= num_blob_cols_size= atoi(str->getOption());
1373
num_blob_cols_size= DEFAULT_BLOB_SIZE;
1374
num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
1376
option_cleanup(str);
1380
if (auto_generate_sql)
1383
Statement *ptr_statement;
1386
printf("Building Create Statements for Auto\n");
1388
create_statements= build_table_string();
1392
for (ptr_statement= create_statements, x= 0;
1393
x < auto_generate_sql_unique_write_number;
1394
x++, ptr_statement= ptr_statement->getNext())
1396
ptr_statement->setNext(build_insert_string());
1400
printf("Building Query Statements for Auto\n");
1402
if (opt_auto_generate_sql_type.empty())
1403
opt_auto_generate_sql_type= "mixed";
1405
query_statements_count=
1406
parse_option(opt_auto_generate_sql_type.c_str(), &query_options, ',');
1408
query_statements.resize(query_statements_count);
1410
OptionString* sql_type= query_options;
1413
if (sql_type->getString()[0] == 'r')
1416
printf("Generating SELECT Statements for Auto\n");
1418
query_statements[sql_type_count]= build_select_string(false);
1419
for (ptr_statement= query_statements[sql_type_count], x= 0;
1420
x < auto_generate_sql_unique_query_number;
1421
x++, ptr_statement= ptr_statement->getNext())
1423
ptr_statement->setNext(build_select_string(false));
1426
else if (sql_type->getString()[0] == 'k')
1429
printf("Generating SELECT for keys Statements for Auto\n");
1431
if ( auto_generate_sql_autoincrement == false &&
1432
auto_generate_sql_guid_primary == false)
1435
"%s: Can't perform key test without a primary key!\n",
1440
query_statements[sql_type_count]= build_select_string(true);
1441
for (ptr_statement= query_statements[sql_type_count], x= 0;
1442
x < auto_generate_sql_unique_query_number;
1443
x++, ptr_statement= ptr_statement->getNext())
1445
ptr_statement->setNext(build_select_string(true));
1448
else if (sql_type->getString()[0] == 'w')
1451
We generate a number of strings in case the engine is
1452
Archive (since strings which were identical one after another
1453
would be too easily optimized).
1456
printf("Generating INSERT Statements for Auto\n");
1457
query_statements[sql_type_count]= build_insert_string();
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->getNext())
1462
ptr_statement->setNext(build_insert_string());
1465
else if (sql_type->getString()[0] == 'u')
1467
if ( auto_generate_sql_autoincrement == false &&
1468
auto_generate_sql_guid_primary == false)
1471
"%s: Can't perform update test without a primary key!\n",
1476
query_statements[sql_type_count]= build_update_string();
1477
for (ptr_statement= query_statements[sql_type_count], x= 0;
1478
x < auto_generate_sql_unique_query_number;
1479
x++, ptr_statement= ptr_statement->getNext())
1481
ptr_statement->setNext(build_update_string());
1484
else /* Mixed mode is default */
1488
query_statements[sql_type_count]= build_insert_string();
1490
This logic should be extended to do a more mixed load,
1491
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())
1499
ptr_statement->setNext(build_insert_string());
1504
ptr_statement->setNext(build_select_string(true));
1510
} while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1514
if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1517
std::vector<char> tmp_string;
1518
if (not S_ISREG(sbuf.st_mode))
1520
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]);
1544
else if (not create_string.empty())
1546
parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1549
/* Set this up till we fully support options on user generated queries */
1550
if (not user_supplied_query.empty())
1552
query_statements_count=
1553
parse_option("default", &query_options, ',');
1555
query_statements.resize(query_statements_count);
1558
if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1561
std::vector<char> tmp_string;
1563
if (not S_ISREG(sbuf.st_mode))
1565
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],
1591
else if (not user_supplied_query.empty())
1593
actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1598
if (not user_supplied_pre_statements.empty()
1599
&& !stat(user_supplied_pre_statements.c_str(), &sbuf))
1602
std::vector<char> tmp_string;
1604
if (not S_ISREG(sbuf.st_mode))
1606
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,
1632
else if (not user_supplied_pre_statements.empty())
1634
(void)parse_delimiter(user_supplied_pre_statements.c_str(),
1639
if (not user_supplied_post_statements.empty()
1640
&& !stat(user_supplied_post_statements.c_str(), &sbuf))
1643
std::vector<char> tmp_string;
1645
if (not S_ISREG(sbuf.st_mode))
1647
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,
1675
else if (not user_supplied_post_statements.empty())
1677
(void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1682
printf("Parsing engines to use.\n");
1684
if (not default_engine.empty())
1685
parse_option(default_engine.c_str(), &engine_options, ',');
1688
opt_password= client_get_tty_password(NULL);
1693
static int run_query(drizzle_con_st &con, drizzle_result_st *result,
1694
const char *query, int len)
1696
drizzle_return_t ret;
1697
drizzle_result_st result_buffer;
1701
printf("/* CON: %" PRIu64 " */ %.*s;\n",
1702
(uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1708
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);
1726
generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt)
1728
drizzle_result_st result;
1734
Blackhole is a special case, this allows us to test the upper end
1735
of the server during load runs.
1737
if (opt_only_print || (engine_stmt &&
1738
strstr(engine_stmt->getString(), "blackhole")))
1740
/* Yes, we strdup a const string to simplify the interface */
1741
primary_keys.push_back("796c4422-1d94-102a-9d6d-00e0812d");
1745
if (run_query(con, &result, "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));
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;
1761
/* So why check this? Blackhole :) */
1762
if (primary_keys_number_of)
1765
We create the structure and loop and create the items.
1767
row= drizzle_row_next(&result);
1768
for (counter= 0; counter < primary_keys_number_of;
1769
counter++, row= drizzle_row_next(&result))
1771
primary_keys.push_back(row[0]);
1775
drizzle_result_free(&result);
1781
static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr)
1783
char query[HUGE_STRING_LENGTH];
1785
Statement *after_create;
1787
struct timeval start_time, end_time;
1790
gettimeofday(&start_time, NULL);
1792
len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1795
printf("Loading Pre-data\n");
1797
if (run_query(con, NULL, query, len))
1799
fprintf(stderr,"%s: Cannot create schema %s : %s\n", SLAP_NAME, db,
1800
drizzle_con_error(&con));
1805
sptr->setCreateCount(sptr->getCreateCount()+1);
1810
printf("/* CON: %" PRIu64 " */ use %s;\n",
1811
(uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1816
drizzle_result_st result;
1817
drizzle_return_t ret;
1820
printf("%s;\n", query);
1822
if (drizzle_select_db(&con, &result, db, &ret) == NULL ||
1823
ret != DRIZZLE_RETURN_OK)
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));
1830
drizzle_result_free(&result);
1831
sptr->setCreateCount(sptr->getCreateCount()+1);
1836
len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1837
engine_stmt->getString());
1838
if (run_query(con, NULL, query, len))
1840
fprintf(stderr,"%s: Cannot set default engine: %s\n", SLAP_NAME,
1841
drizzle_con_error(&con));
1844
sptr->setCreateCount(sptr->getCreateCount()+1);
1851
for (ptr= after_create; ptr && ptr->getLength(); ptr= ptr->getNext(), count++)
1853
if (auto_generate_sql && ( auto_generate_sql_number == count))
1856
if (engine_stmt && engine_stmt->getOption() && ptr->getType() == CREATE_TABLE_TYPE)
1858
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)))
1864
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)
1869
sptr->setCreateCount(sptr->getCreateCount()+1);
1873
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1875
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)
1880
sptr->setCreateCount(sptr->getCreateCount()+1);
1884
if (auto_generate_sql && (auto_generate_sql_number > count ))
1886
/* Special case for auto create, we don't want to create tables twice */
1887
after_create= stmt->getNext();
1891
gettimeofday(&end_time, NULL);
1893
sptr->setCreateTiming(timedif(end_time, start_time));
1896
static void drop_schema(drizzle_con_st &con, const char *db)
1898
char query[HUGE_STRING_LENGTH];
1901
len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1903
if (run_query(con, NULL, query, len))
1905
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1906
SLAP_NAME, db, drizzle_con_error(&con));
1911
static void run_statements(drizzle_con_st &con, Statement *stmt)
1913
for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
1915
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1917
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()
1928
We lock around the initial call in case were we in a loop. This
1929
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);
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)
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);
2042
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)
2050
uint32_t length= strlen(origin);
2051
uint32_t count= 0; /* We know that there is always one */
2053
end_ptr= (char *)origin + length;
2056
*stmt= tmp= new OptionString;
2058
for (begin_ptr= (char *)origin;
2059
begin_ptr != end_ptr;
2060
tmp= tmp->getNext())
2062
char buffer[HUGE_STRING_LENGTH];
2065
memset(buffer, 0, HUGE_STRING_LENGTH);
2067
string= strchr(begin_ptr, delm);
2071
memcpy(buffer, begin_ptr, string - begin_ptr);
2072
begin_ptr= string+1;
2076
size_t begin_len= strlen(begin_ptr);
2077
memcpy(buffer, begin_ptr, begin_len);
2081
if ((buffer_ptr= strchr(buffer, ':')))
2083
/* Set a null so that we can get strlen() correct later on */
2087
/* Move past the : and the first string */
2088
tmp->setOption(buffer_ptr);
2091
tmp->setString(strdup(buffer));
2092
if (tmp->getString() == NULL)
2094
fprintf(stderr,"Error allocating memory while parsing options\n");
2098
if (isspace(*begin_ptr))
2103
if (begin_ptr != end_ptr)
2105
tmp->setNext( new OptionString);
2115
Raw parsing interface. If you want the slap specific parser look at
2118
uint32_t parse_delimiter(const char *script, Statement **stmt, char delm)
2121
char *ptr= (char *)script;
2122
Statement **sptr= stmt;
2124
uint32_t length= strlen(script);
2125
uint32_t count= 0; /* We know that there is always one */
2127
for (tmp= *sptr= new Statement;
2128
(retstr= strchr(ptr, delm));
2129
tmp->setNext(new Statement),
2130
tmp= tmp->getNext())
2134
fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2139
tmp->setString((size_t)(retstr - ptr));
2141
if (tmp->getString() == NULL)
2143
fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2147
memcpy(tmp->getString(), ptr, tmp->getLength());
2148
ptr+= retstr - ptr + 1;
2153
if (ptr != script+length)
2155
tmp->setString((size_t)((script + length) - ptr));
2156
if (tmp->getString() == NULL)
2158
fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2161
memcpy(tmp->getString(), ptr, tmp->getLength());
2170
Parse comma is different from parse_delimeter in that it parses
2171
number ranges from a comma seperated string.
2172
In restrospect, this is a lousy name from this function.
2174
uint32_t parse_comma(const char *string, std::vector <uint32_t> &range)
2176
uint32_t count= 1; /* We know that there is always one */
2178
char *ptr= (char *)string;
2182
if (*ptr == ',') count++;
2184
/* One extra spot for the NULL */
2185
range.resize(count +1);
2188
ptr= (char *)string;
2190
while ((retstr= strchr(ptr,',')))
2192
nptr[x++]= atoi(ptr);
2193
ptr+= retstr - ptr + 1;
2195
nptr[x++]= atoi(ptr);
2200
void print_conclusions(Conclusions &con)
2202
printf("Benchmark\n");
2203
if (con.getEngine())
2204
printf("\tRunning for engine %s\n", con.getEngine());
2206
if (not opt_label.empty() || !opt_auto_generate_sql_type.empty())
2208
const char *ptr= opt_auto_generate_sql_type.c_str() ? opt_auto_generate_sql_type.c_str() : "query";
2209
printf("\tLoad: %s\n", !opt_label.empty() ? opt_label.c_str() : ptr);
2211
printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
2212
con.getCreateAvgTiming() / 1000, con.getCreateAvgTiming() % 1000);
2213
printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2214
con.getAvgTiming() / 1000, con.getAvgTiming() % 1000);
2215
printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2216
con.getMinTiming() / 1000, con.getMinTiming() % 1000);
2217
printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2218
con.getMaxTiming() / 1000, con.getMaxTiming() % 1000);
2219
printf("\tTotal time for tests: %ld.%03ld seconds\n",
2220
con.getSumOfTime() / 1000, con.getSumOfTime() % 1000);
2221
printf("\tStandard Deviation: %ld.%03ld\n", con.getStdDev() / 1000, con.getStdDev() % 1000);
2222
printf("\tNumber of queries in create queries: %"PRIu64"\n", con.getCreateCount());
2223
printf("\tNumber of clients running queries: %u/%u\n",
2224
con.getUsers(), con.getRealUsers());
2225
printf("\tNumber of times test was run: %u\n", iterations);
2226
printf("\tAverage number of queries per client: %"PRIu64"\n", con.getAvgRows());
2228
uint64_t temp_val= failed_update_for_transaction;
2230
printf("\tFailed number of updates %"PRIu64"\n", temp_val);
2235
void print_conclusions_csv(Conclusions &con)
2237
char buffer[HUGE_STRING_LENGTH];
2238
char label_buffer[HUGE_STRING_LENGTH];
2240
const char *temp_label= opt_label.c_str();
2242
memset(label_buffer, 0, sizeof(label_buffer));
2244
if (not opt_label.empty())
2246
string_len= opt_label.length();
2248
for (uint32_t x= 0; x < string_len; x++)
2250
if (temp_label[x] == ',')
2251
label_buffer[x]= '-';
2253
label_buffer[x]= temp_label[x] ;
2256
else if (not opt_auto_generate_sql_type.empty())
2258
string_len= opt_auto_generate_sql_type.length();
2260
for (uint32_t x= 0; x < string_len; x++)
2262
if (opt_auto_generate_sql_type[x] == ',')
2263
label_buffer[x]= '-';
2265
label_buffer[x]= opt_auto_generate_sql_type[x] ;
2270
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 */
2277
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 */
2283
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,
2299
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2304
con->setMinTiming(sptr->getTiming());
2305
con->setMaxTiming(sptr->getTiming());
2306
con->setMinRows(sptr->getRows());
2307
con->setMaxRows(sptr->getRows());
2309
/* At the moment we assume uniform */
2310
con->setUsers(sptr->getUsers());
2311
con->setRealUsers(sptr->getRealUsers());
2312
con->setAvgRows(sptr->getRows());
2314
/* With no next, we know it is the last element that was malloced */
2315
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2317
con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2319
if (ptr->getTiming() > con->getMaxTiming())
2320
con->setMaxTiming(ptr->getTiming());
2321
if (ptr->getTiming() < con->getMinTiming())
2322
con->setMinTiming(ptr->getTiming());
2324
con->setSumOfTime(con->getAvgTiming());
2325
con->setAvgTiming(con->getAvgTiming()/iterations);
2327
if (eng && eng->getString())
2328
con->setEngine(eng->getString());
2330
con->setEngine(NULL);
2332
standard_deviation(*con, sptr);
2334
/* Now we do the create time operations */
2335
con->setCreateMinTiming(sptr->getCreateTiming());
2336
con->setCreateMaxTiming(sptr->getCreateTiming());
2338
/* At the moment we assume uniform */
2339
con->setCreateCount(sptr->getCreateCount());
2341
/* With no next, we know it is the last element that was malloced */
2342
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
drizzle_con_st* slap_connect(bool connect_to_schema)
2388
/* 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;
2394
if (opt_delayed_start)
2395
usleep(random()%opt_delayed_start);
2397
drizzle_con_st* con;
2398
if ((drizzle= drizzle_create()) == NULL or
2399
(con= drizzle_con_add_tcp(drizzle,
2400
host.c_str(), opt_drizzle_port,
2401
user.c_str(), opt_password.c_str(),
2402
connect_to_schema ? create_schema_string.c_str() : NULL,
2403
use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL)) == NULL)
2405
fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2409
drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2416
for (uint32_t x= 0; x < 10; x++)
2418
if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
2420
/* Connect suceeded */
2424
usleep(connection_retry_sleep);
2428
fprintf(stderr,"%s: Error when connecting to server: %d %s\n", SLAP_NAME,
2429
ret, drizzle_con_error(con));
2436
void standard_deviation(Conclusions &con, Stats *sptr)
2438
long int sum_of_squares;
2442
if (iterations == 1 || iterations == 0)
2449
for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2453
deviation= ptr->getTiming() - con.getAvgTiming();
2454
sum_of_squares+= deviation*deviation;
2457
the_catch= sqrt((double)(sum_of_squares/(iterations -1)));
2458
con.setStdDev((long int)the_catch);