97
#include <drizzled/configmake.h>
96
100
/* Added this for string translation. */
97
101
#include <drizzled/gettext.h>
103
#include <boost/thread.hpp>
104
#include <boost/thread/mutex.hpp>
105
#include <boost/thread/condition_variable.hpp>
106
#include <boost/program_options.hpp>
107
#include <boost/scoped_ptr.hpp>
108
#include <drizzled/atomics.h>
110
#define SLAP_NAME "drizzleslap"
111
#define SLAP_VERSION "1.5"
113
#define HUGE_STRING_LENGTH 8196
114
#define RAND_STRING_SIZE 126
115
#define DEFAULT_BLOB_SIZE 1024
99
117
using namespace std;
100
118
using namespace drizzled;
119
namespace po= boost::program_options;
103
122
static char *shared_memory_base_name=0;
106
/* Global Thread counter */
107
uint32_t thread_counter;
108
pthread_mutex_t counter_mutex;
109
pthread_cond_t count_threshhold;
110
uint32_t master_wakeup;
111
pthread_mutex_t sleeper_mutex;
112
pthread_cond_t sleep_threshhold;
125
client::Wakeup master_wakeup;
114
127
/* Global Thread timer */
115
128
static bool timer_alarm= false;
116
pthread_mutex_t timer_alarm_mutex;
117
pthread_cond_t timer_alarm_threshold;
119
static char **defaults_argv;
122
/* This gets passed to malloc, so lets set it to an arch-dependant size */
123
size_t primary_keys_number_of;
125
static char *host= NULL, *opt_password= NULL, *user= NULL,
126
*user_supplied_query= NULL,
127
*user_supplied_pre_statements= NULL,
128
*user_supplied_post_statements= NULL,
129
*default_engine= NULL,
133
const char *delimiter= "\n";
135
const char *create_schema_string= "drizzleslap";
137
static bool opt_mysql= 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;
138
155
static bool opt_preserve= true;
139
static bool opt_only_print= false;
140
static bool opt_burnin= false;
156
static bool opt_only_print;
157
static bool opt_burnin;
141
158
static bool opt_ignore_sql_errors= false;
142
static bool tty_password= false,
144
auto_generate_sql_autoincrement= false,
145
auto_generate_sql_guid_primary= false,
146
auto_generate_sql= false;
147
const char *opt_auto_generate_sql_type= "mixed";
159
static bool opt_silent,
160
auto_generate_sql_autoincrement,
161
auto_generate_sql_guid_primary,
163
std::string opt_auto_generate_sql_type;
149
static int verbose, delimiter_length;
165
static int32_t verbose= 0;
166
static uint32_t delimiter_length;
150
167
static uint32_t commit_rate;
151
168
static uint32_t detach_rate;
152
169
static uint32_t opt_timer_length;
153
170
static uint32_t opt_delayed_start;
154
const char *num_int_cols_opt;
155
const char *num_char_cols_opt;
156
const char *num_blob_cols_opt;
157
const char *opt_label;
158
static unsigned int opt_set_random_seed;
171
string num_blob_cols_opt,
175
static uint32_t opt_set_random_seed;
160
const char *auto_generate_selected_columns_opt;
177
string auto_generate_selected_columns_opt;
162
179
/* Yes, we do set defaults here */
163
static unsigned int num_int_cols= 1;
164
static unsigned int num_char_cols= 1;
165
static unsigned int num_blob_cols= 0;
166
static unsigned int num_blob_cols_size;
167
static unsigned int num_blob_cols_size_min;
168
static unsigned int num_int_cols_index= 0;
169
static unsigned int num_char_cols_index= 0;
170
static unsigned int iterations;
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;
171
188
static uint64_t actual_queries= 0;
172
189
static uint64_t auto_actual_queries;
173
190
static uint64_t auto_generate_sql_unique_write_number;
174
191
static uint64_t auto_generate_sql_unique_query_number;
175
static unsigned int auto_generate_sql_secondary_indexes;
192
static uint32_t auto_generate_sql_secondary_indexes;
176
193
static uint64_t num_of_query;
177
194
static uint64_t auto_generate_sql_number;
178
const char *concurrency_str= NULL;
179
static char *create_string;
180
uint32_t *concurrency;
195
string concurrency_str;
196
string create_string;
197
std::vector <uint32_t> concurrency;
182
const char *default_dbug_option= "d:t:o,/tmp/drizzleslap.trace";
183
const char *opt_csv_str;
199
std::string opt_csv_str;
186
static int get_options(int *argc,char ***argv);
202
static int process_options(void);
187
203
static uint32_t opt_drizzle_port= 0;
189
static const char *load_default_groups[]= { "drizzleslap","client",0 };
196
UPDATE_TYPE_REQUIRES_PREFIX= 3,
197
CREATE_TABLE_TYPE= 4,
198
SELECT_TYPE_REQUIRES_PREFIX= 5,
199
DELETE_TYPE_REQUIRES_PREFIX= 6
202
typedef struct statement statement;
207
slap_query_type type;
209
size_t option_length;
213
typedef struct option_string option_string;
215
struct option_string {
219
size_t option_length;
223
typedef struct stats stats;
230
long int create_timing;
231
uint64_t create_count;
234
typedef struct thread_context thread_context;
236
struct thread_context {
241
typedef struct conclusions conclusions;
251
long int sum_of_time;
253
/* These are just for create time stats */
254
long int create_avg_timing;
255
long int create_max_timing;
256
long int create_min_timing;
257
uint64_t create_count;
258
/* The following are not used yet */
263
static option_string *engine_options= NULL;
264
static option_string *query_options= NULL;
265
static statement *pre_statements= NULL;
266
static statement *post_statements= NULL;
267
static statement *create_statements= NULL;
269
static statement **query_statements= NULL;
270
static unsigned int query_statements_count;
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;
274
void print_conclusions(conclusions *con);
275
void print_conclusions_csv(conclusions *con);
276
void generate_stats(conclusions *con, option_string *eng, stats *sptr);
277
uint32_t parse_comma(const char *string, uint32_t **range);
278
uint32_t parse_delimiter(const char *script, statement **stmt, char delm);
279
uint32_t parse_option(const char *origin, option_string **stmt, char delm);
280
static int drop_schema(drizzle_con_st *con, const char *db);
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);
281
223
uint32_t get_random_string(char *buf, size_t size);
282
static statement *build_table_string(void);
283
static statement *build_insert_string(void);
284
static statement *build_update_string(void);
285
static statement * build_select_string(bool key);
286
static int generate_primary_key_list(drizzle_con_st *con, option_string *engine_stmt);
287
static int drop_primary_key_list(void);
288
static int create_schema(drizzle_con_st *con, const char *db, statement *stmt,
289
option_string *engine_stmt, stats *sptr);
290
static int run_scheduler(stats *sptr, statement **stmts, uint32_t concur,
292
extern "C" pthread_handler_t run_task(void *p);
293
extern "C" pthread_handler_t timer_thread(void *p);
294
void statement_cleanup(statement *stmt);
295
void option_cleanup(option_string *stmt);
296
void concurrency_loop(drizzle_con_st *con, uint32_t current, option_string *eptr);
297
static int run_statements(drizzle_con_st *con, statement *stmt);
298
void slap_connect(drizzle_con_st *con, bool connect_to_schema);
299
void slap_close(drizzle_con_st *con);
300
static int run_query(drizzle_con_st *con, drizzle_result_st *result, const char *query, int len);
301
void standard_deviation (conclusions *con, stats *sptr);
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);
303
240
static const char ALPHANUMERICS[]=
304
241
"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.
320
431
int main(int argc, char **argv)
330
internal::load_defaults("drizzle",load_default_groups,&argc,&argv);
332
if (get_options(&argc,&argv))
334
internal::free_defaults(defaults_argv);
339
/* Seed the random number generator if we will be using it. */
340
if (auto_generate_sql)
342
if (opt_set_random_seed == 0)
343
opt_set_random_seed= (unsigned int)time(NULL);
344
srandom(opt_set_random_seed);
347
/* globals? Yes, so we only have to run strlen once */
348
delimiter_length= strlen(delimiter);
352
fprintf(stderr,"%s: Too many arguments\n",internal::my_progname);
353
internal::free_defaults(defaults_argv);
358
slap_connect(&con, false);
360
pthread_mutex_init(&counter_mutex, NULL);
361
pthread_cond_init(&count_threshhold, NULL);
362
pthread_mutex_init(&sleeper_mutex, NULL);
363
pthread_cond_init(&sleep_threshhold, NULL);
364
pthread_mutex_init(&timer_alarm_mutex, NULL);
365
pthread_cond_init(&timer_alarm_threshold, NULL);
368
/* Main iterations loop */
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,i","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 */
370
eptr= engine_options;
373
/* For the final stage we run whatever queries we were asked to run */
377
printf("Starting Concurrency Test\n");
381
for (current= concurrency; current && *current; current++)
382
concurrency_loop(&con, *current, eptr);
386
uint32_t infinite= 1;
388
concurrency_loop(&con, infinite, eptr);
394
drop_schema(&con, create_schema_string);
396
} while (eptr ? (eptr= eptr->next) : 0);
401
pthread_mutex_destroy(&counter_mutex);
402
pthread_cond_destroy(&count_threshhold);
403
pthread_mutex_destroy(&sleeper_mutex);
404
pthread_cond_destroy(&sleep_threshhold);
405
pthread_mutex_destroy(&timer_alarm_mutex);
406
pthread_cond_destroy(&timer_alarm_threshold);
410
/* now free all the strings we created */
416
statement_cleanup(create_statements);
417
for (x= 0; x < query_statements_count; x++)
418
statement_cleanup(query_statements[x]);
419
free(query_statements);
420
statement_cleanup(pre_statements);
421
statement_cleanup(post_statements);
422
option_cleanup(engine_options);
423
option_cleanup(query_options);
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);
426
if (shared_memory_base_name)
427
free(shared_memory_base_name);
734
if (shared_memory_base_name)
735
free(shared_memory_base_name);
429
internal::free_defaults(defaults_argv);
740
catch(std::exception &err)
742
cerr<<"Error:"<<err.what()<<endl;
745
if (csv_file != fileno(stdout))
435
void concurrency_loop(drizzle_con_st *con, uint32_t current, option_string *eptr)
751
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
440
conclusions conclusion;
755
Conclusions conclusion;
441
756
uint64_t client_limit;
443
head_sptr= (stats *)malloc(sizeof(stats) * iterations);
758
head_sptr= new Stats[iterations];
444
759
if (head_sptr == NULL)
446
761
fprintf(stderr,"Error allocating memory in concurrency_loop\n");
449
memset(head_sptr, 0, sizeof(stats) * iterations);
451
memset(&conclusion, 0, sizeof(conclusions));
453
765
if (auto_actual_queries)
454
766
client_limit= auto_actual_queries;
519
828
generate_stats(&conclusion, eptr, head_sptr);
522
print_conclusions(&conclusion);
524
print_conclusions_csv(&conclusion);
531
static struct my_option my_long_options[] =
533
{"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
535
{"auto-generate-sql-select-columns", OPT_SLAP_AUTO_GENERATE_SELECT_COLUMNS,
536
"Provide a string to use for the select fields used in auto tests.",
537
(char**) &auto_generate_selected_columns_opt,
538
(char**) &auto_generate_selected_columns_opt,
539
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
540
{"auto-generate-sql", 'a',
541
"Generate SQL where not supplied by file or command line.",
542
(char**) &auto_generate_sql, (char**) &auto_generate_sql,
543
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
544
{"auto-generate-sql-add-autoincrement", OPT_SLAP_AUTO_GENERATE_ADD_AUTO,
545
"Add an AUTO_INCREMENT column to auto-generated tables.",
546
(char**) &auto_generate_sql_autoincrement,
547
(char**) &auto_generate_sql_autoincrement,
548
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
549
{"auto-generate-sql-execute-number", OPT_SLAP_AUTO_GENERATE_EXECUTE_QUERIES,
550
"Set this number to generate a set number of queries to run.",
551
(char**) &auto_actual_queries, (char**) &auto_actual_queries,
552
0, GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
553
{"auto-generate-sql-guid-primary", OPT_SLAP_AUTO_GENERATE_GUID_PRIMARY,
554
"Add GUID based primary keys to auto-generated tables.",
555
(char**) &auto_generate_sql_guid_primary,
556
(char**) &auto_generate_sql_guid_primary,
557
0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
558
{"auto-generate-sql-load-type", OPT_SLAP_AUTO_GENERATE_SQL_LOAD_TYPE,
559
"Specify test load type: mixed, update, write, key, or read; default is mixed.",
560
(char**) &opt_auto_generate_sql_type, (char**) &opt_auto_generate_sql_type,
561
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
562
{"auto-generate-sql-secondary-indexes",
563
OPT_SLAP_AUTO_GENERATE_SECONDARY_INDEXES,
564
"Number of secondary indexes to add to auto-generated tables.",
565
(char**) &auto_generate_sql_secondary_indexes,
566
(char**) &auto_generate_sql_secondary_indexes, 0,
567
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
568
{"auto-generate-sql-unique-query-number",
569
OPT_SLAP_AUTO_GENERATE_UNIQUE_QUERY_NUM,
570
"Number of unique queries to generate for automatic tests.",
571
(char**) &auto_generate_sql_unique_query_number,
572
(char**) &auto_generate_sql_unique_query_number,
573
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
574
{"auto-generate-sql-unique-write-number",
575
OPT_SLAP_AUTO_GENERATE_UNIQUE_WRITE_NUM,
576
"Number of unique queries to generate for auto-generate-sql-write-number.",
577
(char**) &auto_generate_sql_unique_write_number,
578
(char**) &auto_generate_sql_unique_write_number,
579
0, GET_ULL, REQUIRED_ARG, 10, 0, 0, 0, 0, 0},
580
{"auto-generate-sql-write-number", OPT_SLAP_AUTO_GENERATE_WRITE_NUM,
581
"Number of row inserts to perform for each thread (default is 100).",
582
(char**) &auto_generate_sql_number, (char**) &auto_generate_sql_number,
583
0, GET_ULL, REQUIRED_ARG, 100, 0, 0, 0, 0, 0},
584
{"burnin", OPT_SLAP_BURNIN, "Run full test case in infinite loop.",
585
(char**) &opt_burnin, (char**) &opt_burnin, 0, GET_BOOL, NO_ARG, 0, 0, 0,
587
{"ignore-sql-errors", OPT_SLAP_IGNORE_SQL_ERRORS,
588
"Ignore SQL erros in query run.",
589
(char**) &opt_ignore_sql_errors,
590
(char**) &opt_ignore_sql_errors,
591
0, GET_BOOL, NO_ARG, 0, 0, 0,
593
{"commit", OPT_SLAP_COMMIT, "Commit records every X number of statements.",
594
(char**) &commit_rate, (char**) &commit_rate, 0, GET_UINT, REQUIRED_ARG,
596
{"concurrency", 'c', "Number of clients to simulate for query to run.",
597
(char**) &concurrency_str, (char**) &concurrency_str, 0, GET_STR,
598
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
599
{"create", OPT_SLAP_CREATE_STRING, "File or string to use create tables.",
600
(char**) &create_string, (char**) &create_string, 0, GET_STR, REQUIRED_ARG,
602
{"create-schema", OPT_CREATE_SLAP_SCHEMA, "Schema to run tests in.",
603
(char**) &create_schema_string, (char**) &create_schema_string, 0, GET_STR,
604
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
605
{"csv", OPT_SLAP_CSV,
606
"Generate CSV output to named file or to stdout if no file is named.",
607
(char**) &opt_csv_str, (char**) &opt_csv_str, 0, GET_STR,
608
OPT_ARG, 0, 0, 0, 0, 0, 0},
609
{"delayed-start", OPT_SLAP_DELAYED_START,
610
"Delay the startup of threads by a random number of microsends (the maximum of the delay)",
611
(char**) &opt_delayed_start, (char**) &opt_delayed_start, 0, GET_UINT,
612
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
614
"Delimiter to use in SQL statements supplied in file or command line.",
615
(char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
617
{"detach", OPT_SLAP_DETACH,
618
"Detach (close and reopen) connections after X number of requests.",
619
(char**) &detach_rate, (char**) &detach_rate, 0, GET_UINT, REQUIRED_ARG,
621
{"engine", 'e', "Storage engine to use for creating the table.",
622
(char**) &default_engine, (char**) &default_engine, 0,
623
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
624
{"host", 'h', "Connect to host.", (char**) &host, (char**) &host, 0, GET_STR,
625
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
626
{"iterations", 'i', "Number of times to run the tests.", (char**) &iterations,
627
(char**) &iterations, 0, GET_UINT, REQUIRED_ARG, 1, 0, 0, 0, 0, 0},
628
{"label", OPT_SLAP_LABEL, "Label to use for print and csv output.",
629
(char**) &opt_label, (char**) &opt_label, 0,
630
GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
631
{"mysql", 'm', N_("Use MySQL Protocol."),
632
(char**) &opt_mysql, (char**) &opt_mysql, 0, GET_BOOL, NO_ARG, 1, 0, 0,
634
{"number-blob-cols", OPT_SLAP_BLOB_COL,
635
"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. ",
636
(char**) &num_blob_cols_opt, (char**) &num_blob_cols_opt, 0, GET_STR, REQUIRED_ARG,
638
{"number-char-cols", 'x',
639
"Number of VARCHAR columns to create in table if specifying --auto-generate-sql.",
640
(char**) &num_char_cols_opt, (char**) &num_char_cols_opt, 0, GET_STR, REQUIRED_ARG,
642
{"number-int-cols", 'y',
643
"Number of INT columns to create in table if specifying --auto-generate-sql.",
644
(char**) &num_int_cols_opt, (char**) &num_int_cols_opt, 0, GET_STR, REQUIRED_ARG,
646
{"number-of-queries", OPT_DRIZZLE_NUMBER_OF_QUERY,
647
"Limit each client to this number of queries (this is not exact).",
648
(char**) &num_of_query, (char**) &num_of_query, 0,
649
GET_ULL, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
650
{"only-print", OPT_DRIZZLE_ONLY_PRINT,
651
"This causes drizzleslap to not connect to the databases, but instead print "
652
"out what it would have done instead.",
653
(char**) &opt_only_print, (char**) &opt_only_print, 0, GET_BOOL, NO_ARG,
656
"Password to use when connecting to server. If password is not given it's "
657
"asked from the tty.", 0, 0, 0, GET_STR, OPT_ARG, 0, 0, 0, 0, 0, 0},
658
{"port", 'p', "Port number to use for connection.",
659
0, 0, 0, GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
660
{"post-query", OPT_SLAP_POST_QUERY,
661
"Query to run or file containing query to execute after tests have completed.",
662
(char**) &user_supplied_post_statements,
663
(char**) &user_supplied_post_statements,
664
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
665
{"post-system", OPT_SLAP_POST_SYSTEM,
666
"system() string to execute after tests have completed.",
667
(char**) &post_system,
668
(char**) &post_system,
669
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
670
{"pre-query", OPT_SLAP_PRE_QUERY,
671
"Query to run or file containing query to execute before running tests.",
672
(char**) &user_supplied_pre_statements,
673
(char**) &user_supplied_pre_statements,
674
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
675
{"pre-system", OPT_SLAP_PRE_SYSTEM,
676
"system() string to execute before running tests.",
677
(char**) &pre_system,
678
(char**) &pre_system,
679
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
680
{"protocol", OPT_DRIZZLE_PROTOCOL,
681
"The protocol of connection (tcp,socket,pipe,memory).",
682
0, 0, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
683
{"query", 'q', "Query to run or file containing query to run.",
684
(char**) &user_supplied_query, (char**) &user_supplied_query,
685
0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
686
{"set-random-seed", OPT_SLAP_SET_RANDOM_SEED,
687
"Seed for random number generator (srandom(3))",
688
(char**)&opt_set_random_seed,
689
(char**)&opt_set_random_seed,0,
690
GET_UINT, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
691
{"silent", 's', "Run program in silent mode - no output.",
692
(char**) &opt_silent, (char**) &opt_silent, 0, GET_BOOL, NO_ARG,
694
{"timer-length", OPT_SLAP_TIMER_LENGTH,
695
"Require drizzleslap to run each specific test a certain amount of time in seconds.",
696
(char**) &opt_timer_length, (char**) &opt_timer_length, 0, GET_UINT,
697
REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
698
{"user", 'u', "User for login if not current user.", (char**) &user,
699
(char**) &user, 0, GET_STR, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
701
"More verbose output; you can use this multiple times to get even more "
702
"verbose output.", (char**) &verbose, (char**) &verbose, 0,
703
GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},
704
{"version", 'V', "Output version information and exit.", 0, 0, 0, GET_NO_ARG,
705
NO_ARG, 0, 0, 0, 0, 0, 0},
706
{0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
710
static void print_version(void)
712
printf("%s Ver %s Distrib %s, for %s-%s (%s)\n",internal::my_progname, SLAP_VERSION,
713
drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
717
static void usage(void)
720
puts("Copyright (C) 2008 Sun Microsystems");
721
puts("This software comes with ABSOLUTELY NO WARRANTY. This is free software,\
722
\nand you are welcome to modify and redistribute it under the GPL \
724
puts("Run a query multiple times against the server\n");
725
printf("Usage: %s [OPTIONS]\n",internal::my_progname);
726
internal::print_defaults("drizzle",load_default_groups);
727
my_print_help(my_long_options);
730
static bool get_one_option(int optid, const struct my_option *, char *argument)
733
uint64_t temp_drizzle_port= 0;
740
temp_drizzle_port= (uint64_t) strtoul(argument, &endchar, 10);
741
/* if there is an alpha character this is not a valid port */
742
if (strlen(endchar) != 0)
744
fprintf(stderr, _("Non-integer value supplied for port. If you are trying to enter a password please use --password instead.\n"));
747
/* If the port number is > 65535 it is not a valid port
748
This also helps with potential data loss casting unsigned long to a
750
if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
752
fprintf(stderr, _("Value supplied for port is not valid.\n"));
757
opt_drizzle_port= (uint32_t) temp_drizzle_port;
763
char *start= argument;
766
opt_password = strdup(argument);
767
if (opt_password == NULL)
769
fprintf(stderr, "Memory allocation error while copying password. "
775
/* Overwriting password with 'x' */
780
/* Cut length of argument */
801
get_random_string(char *buf, size_t size)
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)
803
841
char *buf_ptr= buf;
806
for (x= size; x > 0; x--)
843
for (size_t x= size; x > 0; x--)
807
844
*buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
808
845
return(buf_ptr - buf);
1514
1493
for (ptr_statement= query_statements[sql_type_count], x= 0;
1515
1494
x < auto_generate_sql_unique_query_number;
1516
x++, ptr_statement= ptr_statement->next)
1495
x++, ptr_statement= ptr_statement->getNext())
1520
ptr_statement->next= build_insert_string();
1499
ptr_statement->setNext(build_insert_string());
1525
ptr_statement->next= build_select_string(true);
1504
ptr_statement->setNext(build_select_string(true));
1530
1509
sql_type_count++;
1531
} while (sql_type ? (sql_type= sql_type->next) : 0);
1510
} while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1535
if (create_string && !stat(create_string, &sbuf))
1514
if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1538
if (!S_ISREG(sbuf.st_mode))
1517
std::vector<char> tmp_string;
1518
if (not S_ISREG(sbuf.st_mode))
1540
1520
fprintf(stderr,"%s: Create file was not a regular file\n",
1541
internal::my_progname);
1544
if ((data_file= open(create_string, O_RDWR)) == -1)
1524
if ((data_file= open(create_string.c_str(), O_RDWR)) == -1)
1546
fprintf(stderr,"%s: Could not open create file\n", internal::my_progname);
1526
fprintf(stderr,"%s: Could not open create file\n", SLAP_NAME);
1549
1529
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1551
1531
fprintf(stderr, "Request for more memory than architecture supports\n");
1554
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1555
if (tmp_string == NULL)
1557
fprintf(stderr, "Memory Allocation error in option processing\n");
1560
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1561
bytes_read= read(data_file, (unsigned char*) tmp_string,
1534
tmp_string.resize(sbuf.st_size + 1);
1535
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1562
1536
(size_t)sbuf.st_size);
1563
tmp_string[sbuf.st_size]= '\0';
1564
1537
close(data_file);
1565
1538
if (bytes_read != sbuf.st_size)
1567
1540
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1569
parse_delimiter(tmp_string, &create_statements, delimiter[0]);
1542
parse_delimiter(&tmp_string[0], &create_statements, delimiter[0]);
1572
else if (create_string)
1544
else if (not create_string.empty())
1574
parse_delimiter(create_string, &create_statements, delimiter[0]);
1546
parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1577
1549
/* Set this up till we fully support options on user generated queries */
1578
if (user_supplied_query)
1550
if (not user_supplied_query.empty())
1580
1552
query_statements_count=
1581
1553
parse_option("default", &query_options, ',');
1583
query_statements= (statement **)malloc(sizeof(statement *) * query_statements_count);
1584
if (query_statements == NULL)
1586
fprintf(stderr, "Memory Allocation error in option processing\n");
1589
memset(query_statements, 0, sizeof(statement *) * query_statements_count);
1555
query_statements.resize(query_statements_count);
1592
if (user_supplied_query && !stat(user_supplied_query, &sbuf))
1558
if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1595
if (!S_ISREG(sbuf.st_mode))
1561
std::vector<char> tmp_string;
1563
if (not S_ISREG(sbuf.st_mode))
1597
1565
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1598
internal::my_progname);
1601
if ((data_file= open(user_supplied_query, O_RDWR)) == -1)
1569
if ((data_file= open(user_supplied_query.c_str(), O_RDWR)) == -1)
1603
fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
1571
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1606
1574
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1608
1576
fprintf(stderr, "Request for more memory than architecture supports\n");
1611
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1612
if (tmp_string == NULL)
1614
fprintf(stderr, "Memory Allocation error in option processing\n");
1617
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1618
bytes_read= read(data_file, (unsigned char*) tmp_string,
1579
tmp_string.resize((size_t)(sbuf.st_size + 1));
1580
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1619
1581
(size_t)sbuf.st_size);
1620
tmp_string[sbuf.st_size]= '\0';
1621
1582
close(data_file);
1622
1583
if (bytes_read != sbuf.st_size)
1624
1585
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1626
if (user_supplied_query)
1627
actual_queries= parse_delimiter(tmp_string, &query_statements[0],
1587
if (not user_supplied_query.empty())
1588
actual_queries= parse_delimiter(&tmp_string[0], &query_statements[0],
1631
else if (user_supplied_query)
1591
else if (not user_supplied_query.empty())
1633
actual_queries= parse_delimiter(user_supplied_query, &query_statements[0],
1593
actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1638
if (user_supplied_pre_statements
1639
&& !stat(user_supplied_pre_statements, &sbuf))
1598
if (not user_supplied_pre_statements.empty()
1599
&& !stat(user_supplied_pre_statements.c_str(), &sbuf))
1642
if (!S_ISREG(sbuf.st_mode))
1602
std::vector<char> tmp_string;
1604
if (not S_ISREG(sbuf.st_mode))
1644
1606
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1645
internal::my_progname);
1648
if ((data_file= open(user_supplied_pre_statements, O_RDWR)) == -1)
1610
if ((data_file= open(user_supplied_pre_statements.c_str(), O_RDWR)) == -1)
1650
fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
1612
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1653
1615
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1655
1617
fprintf(stderr, "Request for more memory than architecture supports\n");
1658
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1659
if (tmp_string == NULL)
1661
fprintf(stderr, "Memory Allocation error in option processing\n");
1664
memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
1665
bytes_read= read(data_file, (unsigned char*) tmp_string,
1620
tmp_string.resize((size_t)(sbuf.st_size + 1));
1621
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1666
1622
(size_t)sbuf.st_size);
1667
tmp_string[sbuf.st_size]= '\0';
1668
1623
close(data_file);
1669
1624
if (bytes_read != sbuf.st_size)
1671
1626
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1673
if (user_supplied_pre_statements)
1674
(void)parse_delimiter(tmp_string, &pre_statements,
1628
if (not user_supplied_pre_statements.empty())
1629
(void)parse_delimiter(&tmp_string[0], &pre_statements,
1678
else if (user_supplied_pre_statements)
1632
else if (not user_supplied_pre_statements.empty())
1680
(void)parse_delimiter(user_supplied_pre_statements,
1634
(void)parse_delimiter(user_supplied_pre_statements.c_str(),
1681
1635
&pre_statements,
1685
if (user_supplied_post_statements
1686
&& !stat(user_supplied_post_statements, &sbuf))
1639
if (not user_supplied_post_statements.empty()
1640
&& !stat(user_supplied_post_statements.c_str(), &sbuf))
1689
if (!S_ISREG(sbuf.st_mode))
1643
std::vector<char> tmp_string;
1645
if (not S_ISREG(sbuf.st_mode))
1691
1647
fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1692
internal::my_progname);
1695
if ((data_file= open(user_supplied_post_statements, O_RDWR)) == -1)
1651
if ((data_file= open(user_supplied_post_statements.c_str(), O_RDWR)) == -1)
1697
fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
1653
fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1701
1657
if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1703
1659
fprintf(stderr, "Request for more memory than architecture supports\n");
1706
tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
1707
if (tmp_string == NULL)
1709
fprintf(stderr, "Memory Allocation error in option processing\n");
1712
memset(tmp_string, 0, (size_t)(sbuf.st_size+1));
1662
tmp_string.resize((size_t)(sbuf.st_size + 1));
1714
bytes_read= read(data_file, (unsigned char*) tmp_string,
1664
bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1715
1665
(size_t)(sbuf.st_size));
1716
tmp_string[sbuf.st_size]= '\0';
1717
1666
close(data_file);
1718
1667
if (bytes_read != sbuf.st_size)
1720
1669
fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1722
if (user_supplied_post_statements)
1723
(void)parse_delimiter(tmp_string, &post_statements,
1671
if (not user_supplied_post_statements.empty())
1672
(void)parse_delimiter(&tmp_string[0], &post_statements,
1727
else if (user_supplied_post_statements)
1675
else if (not user_supplied_post_statements.empty())
1729
(void)parse_delimiter(user_supplied_post_statements, &post_statements,
1677
(void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1733
1681
if (verbose >= 2)
1734
1682
printf("Parsing engines to use.\n");
1737
parse_option(default_engine, &engine_options, ',');
1684
if (not default_engine.empty())
1685
parse_option(default_engine.c_str(), &engine_options, ',');
1739
1687
if (tty_password)
1740
1688
opt_password= client_get_tty_password(NULL);
2000
1903
if (run_query(con, NULL, query, len))
2002
1905
fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
2003
internal::my_progname, db, drizzle_con_error(con));
1906
SLAP_NAME, db, drizzle_con_error(&con));
2013
run_statements(drizzle_con_st *con, statement *stmt)
1911
static void run_statements(drizzle_con_st &con, Statement *stmt)
2017
for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
1913
for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
2019
if (run_query(con, NULL, ptr->string, ptr->length))
1915
if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
2021
1917
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2022
internal::my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(con));
2031
run_scheduler(stats *sptr, statement **stmts, uint32_t concur, uint64_t limit)
2035
unsigned int real_concurrency;
2036
struct timeval start_time, end_time;
2037
option_string *sql_type;
2038
thread_context *con;
2039
pthread_t mainthread; /* Thread descriptor */
2040
pthread_attr_t attr; /* Thread attributes */
2043
pthread_attr_init(&attr);
2044
pthread_attr_setdetachstate(&attr,
2045
PTHREAD_CREATE_DETACHED);
2047
pthread_mutex_lock(&counter_mutex);
2050
pthread_mutex_lock(&sleeper_mutex);
2052
pthread_mutex_unlock(&sleeper_mutex);
2054
real_concurrency= 0;
2056
for (y= 0, sql_type= query_options;
2057
y < query_statements_count;
2058
y++, sql_type= sql_type->next)
2060
unsigned int options_loop= 1;
2062
if (sql_type->option)
2064
options_loop= strtol(sql_type->option,
2066
options_loop= options_loop ? options_loop : 1;
2069
while (options_loop--)
2070
for (x= 0; x < concur; x++)
2072
con= (thread_context *)malloc(sizeof(thread_context));
2075
fprintf(stderr, "Memory Allocation error in scheduler\n");
2078
con->stmt= stmts[y];
2082
/* now you create the thread */
2083
if (pthread_create(&mainthread, &attr, run_task,
2086
fprintf(stderr,"%s: Could not create thread\n", internal::my_progname);
2094
The timer_thread belongs to all threads so it too obeys the wakeup
2095
call that run tasks obey.
2097
if (opt_timer_length)
2099
pthread_mutex_lock(&timer_alarm_mutex);
2101
pthread_mutex_unlock(&timer_alarm_mutex);
2103
if (pthread_create(&mainthread, &attr, timer_thread,
2104
(void *)&opt_timer_length) != 0)
2106
fprintf(stderr,"%s: Could not create timer thread\n", internal::my_progname);
2111
pthread_mutex_unlock(&counter_mutex);
2112
pthread_attr_destroy(&attr);
2114
pthread_mutex_lock(&sleeper_mutex);
2116
pthread_mutex_unlock(&sleeper_mutex);
2117
pthread_cond_broadcast(&sleep_threshhold);
2119
gettimeofday(&start_time, NULL);
2122
We loop until we know that all children have cleaned up.
2124
pthread_mutex_lock(&counter_mutex);
2125
while (thread_counter)
2127
struct timespec abstime;
2129
set_timespec(abstime, 3);
2130
pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
2132
pthread_mutex_unlock(&counter_mutex);
2134
gettimeofday(&end_time, NULL);
2137
sptr->timing= timedif(end_time, start_time);
2138
sptr->users= concur;
2139
sptr->real_users= real_concurrency;
2146
pthread_handler_t timer_thread(void *p)
2148
uint32_t *timer_length= (uint32_t *)p;
2149
struct timespec abstime;
1918
SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1925
static void timer_thread()
2153
1928
We lock around the initial call in case were we in a loop. This
2154
1929
also keeps the value properly syncronized across call threads.
2156
pthread_mutex_lock(&sleeper_mutex);
2157
while (master_wakeup)
2159
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2161
pthread_mutex_unlock(&sleeper_mutex);
2163
set_timespec(abstime, *timer_length);
2165
pthread_mutex_lock(&timer_alarm_mutex);
2166
pthread_cond_timedwait(&timer_alarm_threshold, &timer_alarm_mutex, &abstime);
2167
pthread_mutex_unlock(&timer_alarm_mutex);
2169
pthread_mutex_lock(&timer_alarm_mutex);
2171
pthread_mutex_unlock(&timer_alarm_mutex);
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);
2176
pthread_handler_t run_task(void *p)
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
uint64_t counter= 0, queries;
2179
uint64_t detach_counter;
2180
unsigned int commit_counter;
2182
drizzle_result_st result;
2185
thread_context *ctx= (thread_context *)p;
2187
pthread_mutex_lock(&sleeper_mutex);
2188
while (master_wakeup)
2190
pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
2192
pthread_mutex_unlock(&sleeper_mutex);
2194
slap_connect(&con, true);
2197
printf("connected!\n");
2202
run_query(&con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
2205
for (ptr= ctx->stmt, detach_counter= 0;
2207
ptr= ptr->next, detach_counter++)
2209
if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
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())
2212
slap_connect(&con, true);
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);
2216
We have to execute differently based on query type. This should become a function.
2005
The timer_thread belongs to all threads so it too obeys the wakeup
2006
call that run tasks obey.
2218
if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
2219
(ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
2222
unsigned int key_val;
2224
char buffer[HUGE_STRING_LENGTH];
2227
This should only happen if some sort of new engine was
2228
implemented that didn't properly handle UPDATEs.
2230
Just in case someone runs this under an experimental engine we don't
2231
want a crash so the if() is placed here.
2233
assert(primary_keys_number_of);
2234
if (primary_keys_number_of)
2236
key_val= (unsigned int)(random() % primary_keys_number_of);
2237
key= primary_keys[key_val];
2241
length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
2242
(int)ptr->length, ptr->string, key);
2244
if (run_query(&con, &result, buffer, length))
2246
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2247
internal::my_progname, (uint32_t)length, buffer, drizzle_con_error(&con));
2254
if (run_query(&con, &result, ptr->string, ptr->length))
2256
fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
2257
internal::my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(&con));
2262
if (!opt_only_print)
2264
while ((row = drizzle_row_next(&result)))
2266
drizzle_result_free(&result);
2270
if (commit_rate && (++commit_counter == commit_rate))
2273
run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
2276
/* If the timer is set, and the alarm is not active then end */
2277
if (opt_timer_length && timer_alarm == false)
2280
/* If limit has been reached, and we are not in a timer_alarm just end */
2281
if (ctx->limit && queries == ctx->limit && timer_alarm == false)
2285
if (opt_timer_length && timer_alarm == true)
2288
if (ctx->limit && queries < ctx->limit)
2294
run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
2298
pthread_mutex_lock(&counter_mutex);
2300
pthread_cond_signal(&count_threshhold);
2301
pthread_mutex_unlock(&counter_mutex);
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);
2309
2042
Parse records from comma seperated string. : is a reserved character and is used for options
2313
parse_option(const char *origin, option_string **stmt, char delm)
2045
uint32_t parse_option(const char *origin, OptionString **stmt, char delm)
2316
2048
char *begin_ptr;
2318
option_string **sptr= stmt;
2320
2050
uint32_t length= strlen(origin);
2321
2051
uint32_t count= 0; /* We know that there is always one */
2323
2053
end_ptr= (char *)origin + length;
2325
tmp= *sptr= (option_string *)malloc(sizeof(option_string));
2328
fprintf(stderr,"Error allocating memory while parsing options\n");
2331
memset(tmp, 0, sizeof(option_string));
2056
*stmt= tmp= new OptionString;
2333
2058
for (begin_ptr= (char *)origin;
2334
2059
begin_ptr != end_ptr;
2060
tmp= tmp->getNext())
2337
2062
char buffer[HUGE_STRING_LENGTH];
2338
2063
char *buffer_ptr;
2561
2270
snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2563
2273
snprintf(buffer, HUGE_STRING_LENGTH,
2564
2274
"%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
2565
2275
"%u,%u,%u,%"PRIu64"\n",
2566
con->engine ? con->engine : "", /* Storage engine we ran against */
2276
con.getEngine() ? con.getEngine() : "", /* Storage engine we ran against */
2567
2277
label_buffer, /* Load type */
2568
con->avg_timing / 1000, con->avg_timing % 1000, /* Time to load */
2569
con->min_timing / 1000, con->min_timing % 1000, /* Min time */
2570
con->max_timing / 1000, con->max_timing % 1000, /* Max time */
2571
con->sum_of_time / 1000, con->sum_of_time % 1000, /* Total time */
2572
con->std_dev / 1000, con->std_dev % 1000, /* Standard Deviation */
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 */
2573
2283
iterations, /* Iterations */
2574
con->users, /* Children used max_timing */
2575
con->real_users, /* Children used max_timing */
2576
con->avg_rows /* Queries run */
2284
con.getUsers(), /* Children used max_timing */
2285
con.getRealUsers(), /* Children used max_timing */
2286
con.getAvgRows() /* Queries run */
2578
internal::my_write(csv_file, (unsigned char*) buffer, (uint32_t)strlen(buffer), MYF(0));
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,
2582
generate_stats(conclusions *con, option_string *eng, stats *sptr)
2299
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2587
con->min_timing= sptr->timing;
2588
con->max_timing= sptr->timing;
2589
con->min_rows= sptr->rows;
2590
con->max_rows= sptr->rows;
2304
con->setMinTiming(sptr->getTiming());
2305
con->setMaxTiming(sptr->getTiming());
2306
con->setMinRows(sptr->getRows());
2307
con->setMaxRows(sptr->getRows());
2592
2309
/* At the moment we assume uniform */
2593
con->users= sptr->users;
2594
con->real_users= sptr->real_users;
2595
con->avg_rows= sptr->rows;
2310
con->setUsers(sptr->getUsers());
2311
con->setRealUsers(sptr->getRealUsers());
2312
con->setAvgRows(sptr->getRows());
2597
2314
/* With no next, we know it is the last element that was malloced */
2598
2315
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2600
con->avg_timing+= ptr->timing;
2317
con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2602
if (ptr->timing > con->max_timing)
2603
con->max_timing= ptr->timing;
2604
if (ptr->timing < con->min_timing)
2605
con->min_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());
2607
con->sum_of_time= con->avg_timing;
2608
con->avg_timing= con->avg_timing/iterations;
2324
con->setSumOfTime(con->getAvgTiming());
2325
con->setAvgTiming(con->getAvgTiming()/iterations);
2610
if (eng && eng->string)
2611
con->engine= eng->string;
2327
if (eng && eng->getString())
2328
con->setEngine(eng->getString());
2330
con->setEngine(NULL);
2615
standard_deviation(con, sptr);
2332
standard_deviation(*con, sptr);
2617
2334
/* Now we do the create time operations */
2618
con->create_min_timing= sptr->create_timing;
2619
con->create_max_timing= sptr->create_timing;
2335
con->setCreateMinTiming(sptr->getCreateTiming());
2336
con->setCreateMaxTiming(sptr->getCreateTiming());
2621
2338
/* At the moment we assume uniform */
2622
con->create_count= sptr->create_count;
2339
con->setCreateCount(sptr->getCreateCount());
2624
2341
/* With no next, we know it is the last element that was malloced */
2625
2342
for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2627
con->create_avg_timing+= ptr->create_timing;
2629
if (ptr->create_timing > con->create_max_timing)
2630
con->create_max_timing= ptr->create_timing;
2631
if (ptr->create_timing < con->create_min_timing)
2632
con->create_min_timing= ptr->create_timing;
2634
con->create_avg_timing= con->create_avg_timing/iterations;
2638
option_cleanup(option_string *stmt)
2640
option_string *ptr, *nptr;
2644
for (ptr= stmt; ptr; ptr= nptr)
2656
statement_cleanup(statement *stmt)
2658
statement *ptr, *nptr;
2662
for (ptr= stmt; ptr; ptr= nptr)
2672
slap_close(drizzle_con_st *con)
2677
drizzle_free(drizzle_con_drizzle(con));
2681
slap_connect(drizzle_con_st *con, bool connect_to_schema)
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)
2683
2388
/* Connect to server */
2684
2389
static uint32_t connection_retry_sleep= 100000; /* Microseconds */
2685
int x, connect_error= 1;
2390
int connect_error= 1;
2686
2391
drizzle_return_t ret;
2687
2392
drizzle_st *drizzle;
2692
2394
if (opt_delayed_start)
2693
2395
usleep(random()%opt_delayed_start);
2695
2397
if ((drizzle= drizzle_create(NULL)) == NULL ||
2696
drizzle_con_add_tcp(drizzle, con, host, opt_drizzle_port, user,
2698
connect_to_schema ? create_schema_string : NULL,
2699
opt_mysql ? DRIZZLE_CON_MYSQL : DRIZZLE_CON_NONE) == 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)
2701
fprintf(stderr,"%s: Error creating drizzle object\n", internal::my_progname);
2404
fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2705
for (x= 0; x < 10; x++)
2408
drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2413
for (uint32_t x= 0; x < 10; x++)
2707
if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
2415
if ((ret= drizzle_con_connect(&con)) == DRIZZLE_RETURN_OK)
2709
2417
/* Connect suceeded */
2710
2418
connect_error= 0;