~ubuntu-branches/ubuntu/trusty/drizzle/trusty

« back to all changes in this revision

Viewing changes to client/drizzleslap.cc

  • Committer: Bazaar Package Importer
  • Author(s): Monty Taylor
  • Date: 2010-03-18 12:12:31 UTC
  • Revision ID: james.westby@ubuntu.com-20100318121231-k6g1xe6cshbwa0f8
Tags: upstream-2010.03.1347
ImportĀ upstreamĀ versionĀ 2010.03.1347

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* - mode: c; c-basic-offset: 2; indent-tabs-mode: nil; -*-
 
2
 *  vim:expandtab:shiftwidth=2:tabstop=2:smarttab:
 
3
 *
 
4
 *  Copyright (C) 2008 MySQL
 
5
 *
 
6
 *  This program is free software; you can redistribute it and/or modify
 
7
 *  it under the terms of the GNU General Public License as published by
 
8
 *  the Free Software Foundation; either version 2 of the License, or
 
9
 *  (at your option) any later version.
 
10
 *
 
11
 *  This program is distributed in the hope that it will be useful,
 
12
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *  GNU General Public License for more details.
 
15
 *
 
16
 *  You should have received a copy of the GNU General Public License
 
17
 *  along with this program; if not, write to the Free Software
 
18
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 
19
 */
 
20
 
 
21
 
 
22
/*
 
23
  Drizzle Slap
 
24
 
 
25
  A simple program designed to work as if multiple clients querying the database,
 
26
  then reporting the timing of each stage.
 
27
 
 
28
  Drizzle slap runs three stages:
 
29
  1) Create schema,table, and optionally any SP or data you want to beign
 
30
  the test with. (single client)
 
31
  2) Load test (many clients)
 
32
  3) Cleanup (disconnection, drop table if specified, single client)
 
33
 
 
34
  Examples:
 
35
 
 
36
  Supply your own create and query SQL statements, with 50 clients
 
37
  querying (200 selects for each):
 
38
 
 
39
  drizzleslap --delimiter=";" \
 
40
  --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
 
41
  --query="SELECT * FROM A" --concurrency=50 --iterations=200
 
42
 
 
43
  Let the program build the query SQL statement with a table of two int
 
44
  columns, three varchar columns, five clients querying (20 times each),
 
45
  don't create the table or insert the data (using the previous test's
 
46
  schema and data):
 
47
 
 
48
  drizzleslap --concurrency=5 --iterations=20 \
 
49
  --number-int-cols=2 --number-char-cols=3 \
 
50
  --auto-generate-sql
 
51
 
 
52
  Tell the program to load the create, insert and query SQL statements from
 
53
  the specified files, where the create.sql file has multiple table creation
 
54
  statements delimited by ';' and multiple insert statements delimited by ';'.
 
55
  The --query file will have multiple queries delimited by ';', run all the
 
56
  load statements, and then run all the queries in the query file
 
57
  with five clients (five times each):
 
58
 
 
59
  drizzleslap --concurrency=5 \
 
60
  --iterations=5 --query=query.sql --create=create.sql \
 
61
  --delimiter=";"
 
62
 
 
63
  TODO:
 
64
  Add language for better tests
 
65
  String length for files and those put on the command line are not
 
66
  setup to handle binary data.
 
67
  More stats
 
68
  Break up tests and run them on multiple hosts at once.
 
69
  Allow output to be fed into a database directly.
 
70
 
 
71
*/
 
72
 
 
73
#define SLAP_VERSION "1.5"
 
74
 
 
75
#define HUGE_STRING_LENGTH 8196
 
76
#define RAND_STRING_SIZE 126
 
77
#define DEFAULT_BLOB_SIZE 1024
 
78
 
 
79
#include "client_priv.h"
 
80
#include <signal.h>
 
81
#include <stdarg.h>
 
82
#include <sys/types.h>
 
83
#include <sys/wait.h>
 
84
#ifdef HAVE_SYS_STAT_H
 
85
# include <sys/stat.h>
 
86
#endif
 
87
#include <fcntl.h>
 
88
#include <math.h>
 
89
#include <ctype.h>
 
90
#include <cassert>
 
91
#include <cstdlib>
 
92
#include <string>
 
93
 
 
94
#include <pthread.h>
 
95
 
 
96
/* Added this for string translation. */
 
97
#include <drizzled/gettext.h>
 
98
 
 
99
using namespace std;
 
100
using namespace drizzled;
 
101
 
 
102
#ifdef HAVE_SMEM
 
103
static char *shared_memory_base_name=0;
 
104
#endif
 
105
 
 
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;
 
113
 
 
114
/* Global Thread timer */
 
115
static bool timer_alarm= false;
 
116
pthread_mutex_t timer_alarm_mutex;
 
117
pthread_cond_t timer_alarm_threshold;
 
118
 
 
119
static char **defaults_argv;
 
120
 
 
121
char **primary_keys;
 
122
/* This gets passed to malloc, so lets set it to an arch-dependant size */
 
123
size_t primary_keys_number_of;
 
124
 
 
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,
 
130
  *pre_system= NULL,
 
131
  *post_system= NULL;
 
132
 
 
133
const char *delimiter= "\n";
 
134
 
 
135
const char *create_schema_string= "drizzleslap";
 
136
 
 
137
static bool opt_mysql= false;
 
138
static bool opt_preserve= true;
 
139
static bool opt_only_print= false;
 
140
static bool opt_burnin= false;
 
141
static bool opt_ignore_sql_errors= false;
 
142
static bool tty_password= false,
 
143
  opt_silent= 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";
 
148
 
 
149
static int verbose, delimiter_length;
 
150
static uint32_t commit_rate;
 
151
static uint32_t detach_rate;
 
152
static uint32_t opt_timer_length;
 
153
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;
 
159
 
 
160
const char *auto_generate_selected_columns_opt;
 
161
 
 
162
/* 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;
 
171
static uint64_t actual_queries= 0;
 
172
static uint64_t auto_actual_queries;
 
173
static uint64_t auto_generate_sql_unique_write_number;
 
174
static uint64_t auto_generate_sql_unique_query_number;
 
175
static unsigned int auto_generate_sql_secondary_indexes;
 
176
static uint64_t num_of_query;
 
177
static uint64_t auto_generate_sql_number;
 
178
const char *concurrency_str= NULL;
 
179
static char *create_string;
 
180
uint32_t *concurrency;
 
181
 
 
182
const char *default_dbug_option= "d:t:o,/tmp/drizzleslap.trace";
 
183
const char *opt_csv_str;
 
184
int csv_file;
 
185
 
 
186
static int get_options(int *argc,char ***argv);
 
187
static uint32_t opt_drizzle_port= 0;
 
188
 
 
189
static const char *load_default_groups[]= { "drizzleslap","client",0 };
 
190
 
 
191
/* Types */
 
192
typedef enum {
 
193
  SELECT_TYPE= 0,
 
194
  UPDATE_TYPE= 1,
 
195
  INSERT_TYPE= 2,
 
196
  UPDATE_TYPE_REQUIRES_PREFIX= 3,
 
197
  CREATE_TABLE_TYPE= 4,
 
198
  SELECT_TYPE_REQUIRES_PREFIX= 5,
 
199
  DELETE_TYPE_REQUIRES_PREFIX= 6
 
200
} slap_query_type;
 
201
 
 
202
typedef struct statement statement;
 
203
 
 
204
struct statement {
 
205
  char *string;
 
206
  size_t length;
 
207
  slap_query_type type;
 
208
  char *option;
 
209
  size_t option_length;
 
210
  statement *next;
 
211
};
 
212
 
 
213
typedef struct option_string option_string;
 
214
 
 
215
struct option_string {
 
216
  char *string;
 
217
  size_t length;
 
218
  char *option;
 
219
  size_t option_length;
 
220
  option_string *next;
 
221
};
 
222
 
 
223
typedef struct stats stats;
 
224
 
 
225
struct stats {
 
226
  long int timing;
 
227
  uint32_t users;
 
228
  uint32_t real_users;
 
229
  uint64_t rows;
 
230
  long int create_timing;
 
231
  uint64_t create_count;
 
232
};
 
233
 
 
234
typedef struct thread_context thread_context;
 
235
 
 
236
struct thread_context {
 
237
  statement *stmt;
 
238
  uint64_t limit;
 
239
};
 
240
 
 
241
typedef struct conclusions conclusions;
 
242
 
 
243
struct conclusions {
 
244
  char *engine;
 
245
  long int avg_timing;
 
246
  long int max_timing;
 
247
  long int min_timing;
 
248
  uint32_t users;
 
249
  uint32_t real_users;
 
250
  uint64_t avg_rows;
 
251
  long int sum_of_time;
 
252
  long int std_dev;
 
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 */
 
259
  uint64_t max_rows;
 
260
  uint64_t min_rows;
 
261
};
 
262
 
 
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;
 
268
 
 
269
static statement **query_statements= NULL;
 
270
static unsigned int query_statements_count;
 
271
 
 
272
 
 
273
/* Prototypes */
 
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);
 
281
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,
 
291
                         uint64_t limit);
 
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);
 
302
 
 
303
static const char ALPHANUMERICS[]=
 
304
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
 
305
 
 
306
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
 
307
 
 
308
 
 
309
static long int timedif(struct timeval a, struct timeval b)
 
310
{
 
311
  register int us, s;
 
312
 
 
313
  us = a.tv_usec - b.tv_usec;
 
314
  us /= 1000;
 
315
  s = a.tv_sec - b.tv_sec;
 
316
  s *= 1000;
 
317
  return s + us;
 
318
}
 
319
 
 
320
int main(int argc, char **argv)
 
321
{
 
322
  drizzle_con_st con;
 
323
  option_string *eptr;
 
324
  unsigned int x;
 
325
 
 
326
  internal::my_init();
 
327
 
 
328
  MY_INIT(argv[0]);
 
329
 
 
330
  internal::load_defaults("drizzle",load_default_groups,&argc,&argv);
 
331
  defaults_argv=argv;
 
332
  if (get_options(&argc,&argv))
 
333
  {
 
334
    internal::free_defaults(defaults_argv);
 
335
    internal::my_end();
 
336
    exit(1);
 
337
  }
 
338
 
 
339
  /* Seed the random number generator if we will be using it. */
 
340
  if (auto_generate_sql)
 
341
  {
 
342
    if (opt_set_random_seed == 0)
 
343
      opt_set_random_seed= (unsigned int)time(NULL);
 
344
    srandom(opt_set_random_seed);
 
345
  }
 
346
 
 
347
  /* globals? Yes, so we only have to run strlen once */
 
348
  delimiter_length= strlen(delimiter);
 
349
 
 
350
  if (argc > 2)
 
351
  {
 
352
    fprintf(stderr,"%s: Too many arguments\n",internal::my_progname);
 
353
    internal::free_defaults(defaults_argv);
 
354
    internal::my_end();
 
355
    exit(1);
 
356
  }
 
357
 
 
358
  slap_connect(&con, false);
 
359
 
 
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);
 
366
 
 
367
 
 
368
  /* Main iterations loop */
 
369
burnin:
 
370
  eptr= engine_options;
 
371
  do
 
372
  {
 
373
    /* For the final stage we run whatever queries we were asked to run */
 
374
    uint32_t *current;
 
375
 
 
376
    if (verbose >= 2)
 
377
      printf("Starting Concurrency Test\n");
 
378
 
 
379
    if (*concurrency)
 
380
    {
 
381
      for (current= concurrency; current && *current; current++)
 
382
        concurrency_loop(&con, *current, eptr);
 
383
    }
 
384
    else
 
385
    {
 
386
      uint32_t infinite= 1;
 
387
      do {
 
388
        concurrency_loop(&con, infinite, eptr);
 
389
      }
 
390
      while (infinite++);
 
391
    }
 
392
 
 
393
    if (!opt_preserve)
 
394
      drop_schema(&con, create_schema_string);
 
395
 
 
396
  } while (eptr ? (eptr= eptr->next) : 0);
 
397
 
 
398
  if (opt_burnin)
 
399
    goto burnin;
 
400
 
 
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);
 
407
 
 
408
  slap_close(&con);
 
409
 
 
410
  /* now free all the strings we created */
 
411
  if (opt_password)
 
412
    free(opt_password);
 
413
 
 
414
  free(concurrency);
 
415
 
 
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);
 
424
 
 
425
#ifdef HAVE_SMEM
 
426
  if (shared_memory_base_name)
 
427
    free(shared_memory_base_name);
 
428
#endif
 
429
  internal::free_defaults(defaults_argv);
 
430
  internal::my_end();
 
431
 
 
432
  return 0;
 
433
}
 
434
 
 
435
void concurrency_loop(drizzle_con_st *con, uint32_t current, option_string *eptr)
 
436
{
 
437
  unsigned int x;
 
438
  stats *head_sptr;
 
439
  stats *sptr;
 
440
  conclusions conclusion;
 
441
  uint64_t client_limit;
 
442
 
 
443
  head_sptr= (stats *)malloc(sizeof(stats) * iterations);
 
444
  if (head_sptr == NULL)
 
445
  {
 
446
    fprintf(stderr,"Error allocating memory in concurrency_loop\n");
 
447
    exit(1);
 
448
  }
 
449
  memset(head_sptr, 0, sizeof(stats) * iterations);
 
450
 
 
451
  memset(&conclusion, 0, sizeof(conclusions));
 
452
 
 
453
  if (auto_actual_queries)
 
454
    client_limit= auto_actual_queries;
 
455
  else if (num_of_query)
 
456
    client_limit=  num_of_query / current;
 
457
  else
 
458
    client_limit= actual_queries;
 
459
 
 
460
  for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
 
461
  {
 
462
    /*
 
463
      We might not want to load any data, such as when we are calling
 
464
      a stored_procedure that doesn't use data, or we know we already have
 
465
      data in the table.
 
466
    */
 
467
    if (opt_preserve == false)
 
468
      drop_schema(con, create_schema_string);
 
469
 
 
470
    /* First we create */
 
471
    if (create_statements)
 
472
      create_schema(con, create_schema_string, create_statements, eptr, sptr);
 
473
 
 
474
    /*
 
475
      If we generated GUID we need to build a list of them from creation that
 
476
      we can later use.
 
477
    */
 
478
    if (verbose >= 2)
 
479
      printf("Generating primary key list\n");
 
480
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
 
481
      generate_primary_key_list(con, eptr);
 
482
 
 
483
    if (commit_rate)
 
484
      run_query(con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
 
485
 
 
486
    if (pre_system)
 
487
    {
 
488
      int ret= system(pre_system);
 
489
      assert(ret != -1);
 
490
    }
 
491
       
 
492
 
 
493
    /*
 
494
      Pre statements are always run after all other logic so they can
 
495
      correct/adjust any item that they want.
 
496
    */
 
497
    if (pre_statements)
 
498
      run_statements(con, pre_statements);
 
499
 
 
500
    run_scheduler(sptr, query_statements, current, client_limit);
 
501
 
 
502
    if (post_statements)
 
503
      run_statements(con, post_statements);
 
504
 
 
505
    if (post_system)
 
506
    {
 
507
      int ret=  system(post_system);
 
508
      assert(ret !=-1);
 
509
    }
 
510
 
 
511
    /* We are finished with this run */
 
512
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
 
513
      drop_primary_key_list();
 
514
  }
 
515
 
 
516
  if (verbose >= 2)
 
517
    printf("Generating stats\n");
 
518
 
 
519
  generate_stats(&conclusion, eptr, head_sptr);
 
520
 
 
521
  if (!opt_silent)
 
522
    print_conclusions(&conclusion);
 
523
  if (opt_csv_str)
 
524
    print_conclusions_csv(&conclusion);
 
525
 
 
526
  free(head_sptr);
 
527
 
 
528
}
 
529
 
 
530
 
 
531
static struct my_option my_long_options[] =
 
532
{
 
533
  {"help", '?', "Display this help and exit.", 0, 0, 0, GET_NO_ARG, NO_ARG,
 
534
   0, 0, 0, 0, 0, 0},
 
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,
 
586
   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,
 
592
   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,
 
595
   0, 0, 0, 0, 0, 0},
 
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,
 
601
   0, 0, 0, 0, 0, 0},
 
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},
 
613
  {"delimiter", 'F',
 
614
   "Delimiter to use in SQL statements supplied in file or command line.",
 
615
   (char**) &delimiter, (char**) &delimiter, 0, GET_STR, REQUIRED_ARG,
 
616
   0, 0, 0, 0, 0, 0},
 
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,
 
620
   0, 0, 0, 0, 0, 0},
 
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,
 
633
   0, 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,
 
637
   0, 0, 0, 0, 0, 0},
 
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,
 
641
   0, 0, 0, 0, 0, 0},
 
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,
 
645
   0, 0, 0, 0, 0, 0},
 
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,
 
654
   0, 0, 0, 0, 0, 0},
 
655
  {"password", 'P',
 
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,
 
693
   0, 0, 0, 0, 0, 0},
 
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},
 
700
  {"verbose", 'v',
 
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}
 
707
};
 
708
 
 
709
 
 
710
static void print_version(void)
 
711
{
 
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);
 
714
}
 
715
 
 
716
 
 
717
static void usage(void)
 
718
{
 
719
  print_version();
 
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 \
 
723
       license\n");
 
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);
 
728
}
 
729
 
 
730
static bool get_one_option(int optid, const struct my_option *, char *argument)
 
731
{
 
732
  char *endchar= NULL;
 
733
  uint64_t temp_drizzle_port= 0;
 
734
 
 
735
  switch(optid) {
 
736
  case 'v':
 
737
    verbose++;
 
738
    break;
 
739
  case 'p':
 
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)
 
743
    {
 
744
      fprintf(stderr, _("Non-integer value supplied for port.  If you are trying to enter a password please use --password instead.\n"));
 
745
      exit(1);
 
746
    }
 
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
 
749
       uint32_t. */
 
750
    if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
 
751
    {
 
752
      fprintf(stderr, _("Value supplied for port is not valid.\n"));
 
753
      exit(1);
 
754
    }
 
755
    else
 
756
    {
 
757
      opt_drizzle_port= (uint32_t) temp_drizzle_port;
 
758
    }
 
759
    break;
 
760
  case 'P':
 
761
    if (argument)
 
762
    {
 
763
      char *start= argument;
 
764
      if (opt_password)
 
765
        free(opt_password);
 
766
      opt_password = strdup(argument);
 
767
      if (opt_password == NULL)
 
768
      {
 
769
        fprintf(stderr, "Memory allocation error while copying password. "
 
770
                        "Aborting.\n");
 
771
        exit(ENOMEM);
 
772
      }
 
773
      while (*argument)
 
774
      {
 
775
        /* Overwriting password with 'x' */
 
776
        *argument++= 'x';
 
777
      }
 
778
      if (*start)
 
779
      {
 
780
        /* Cut length of argument */
 
781
        start[1]= 0;
 
782
      }
 
783
      tty_password= 0;
 
784
    }
 
785
    else
 
786
      tty_password= 1;
 
787
    break;
 
788
  case 'V':
 
789
    print_version();
 
790
    exit(0);
 
791
  case '?':
 
792
  case 'I':          /* Info */
 
793
    usage();
 
794
    exit(0);
 
795
  }
 
796
  return(0);
 
797
}
 
798
 
 
799
 
 
800
uint
 
801
get_random_string(char *buf, size_t size)
 
802
{
 
803
  char *buf_ptr= buf;
 
804
  size_t x;
 
805
 
 
806
  for (x= size; x > 0; x--)
 
807
    *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
 
808
  return(buf_ptr - buf);
 
809
}
 
810
 
 
811
 
 
812
/*
 
813
  build_table_string
 
814
 
 
815
  This function builds a create table query if the user opts to not supply
 
816
  a file or string containing a create table statement
 
817
*/
 
818
static statement *
 
819
build_table_string(void)
 
820
{
 
821
  char       buf[HUGE_STRING_LENGTH];
 
822
  unsigned int        col_count;
 
823
  statement *ptr;
 
824
  string table_string;
 
825
 
 
826
  table_string.reserve(HUGE_STRING_LENGTH);
 
827
 
 
828
  table_string= "CREATE TABLE `t1` (";
 
829
 
 
830
  if (auto_generate_sql_autoincrement)
 
831
  {
 
832
    table_string.append("id serial");
 
833
 
 
834
    if (num_int_cols || num_char_cols)
 
835
      table_string.append(",");
 
836
  }
 
837
 
 
838
  if (auto_generate_sql_guid_primary)
 
839
  {
 
840
    table_string.append("id varchar(128) primary key");
 
841
 
 
842
    if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
 
843
      table_string.append(",");
 
844
  }
 
845
 
 
846
  if (auto_generate_sql_secondary_indexes)
 
847
  {
 
848
    unsigned int count;
 
849
 
 
850
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
 
851
    {
 
852
      if (count) /* Except for the first pass we add a comma */
 
853
        table_string.append(",");
 
854
 
 
855
      if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
 
856
          > HUGE_STRING_LENGTH)
 
857
      {
 
858
        fprintf(stderr, "Memory Allocation error in create table\n");
 
859
        exit(1);
 
860
      }
 
861
      table_string.append(buf);
 
862
    }
 
863
 
 
864
    if (num_int_cols || num_char_cols)
 
865
      table_string.append(",");
 
866
  }
 
867
 
 
868
  if (num_int_cols)
 
869
    for (col_count= 1; col_count <= num_int_cols; col_count++)
 
870
    {
 
871
      if (num_int_cols_index)
 
872
      {
 
873
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT, INDEX(intcol%d)",
 
874
                     col_count, col_count) > HUGE_STRING_LENGTH)
 
875
        {
 
876
          fprintf(stderr, "Memory Allocation error in create table\n");
 
877
          exit(1);
 
878
        }
 
879
      }
 
880
      else
 
881
      {
 
882
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT ", col_count)
 
883
            > HUGE_STRING_LENGTH)
 
884
        {
 
885
          fprintf(stderr, "Memory Allocation error in create table\n");
 
886
          exit(1);
 
887
        }
 
888
      }
 
889
      table_string.append(buf);
 
890
 
 
891
      if (col_count < num_int_cols || num_char_cols > 0)
 
892
        table_string.append(",");
 
893
    }
 
894
 
 
895
  if (num_char_cols)
 
896
    for (col_count= 1; col_count <= num_char_cols; col_count++)
 
897
    {
 
898
      if (num_char_cols_index)
 
899
      {
 
900
        if (snprintf(buf, HUGE_STRING_LENGTH,
 
901
                     "charcol%d VARCHAR(128), INDEX(charcol%d) ",
 
902
                     col_count, col_count) > HUGE_STRING_LENGTH)
 
903
        {
 
904
          fprintf(stderr, "Memory Allocation error in creating table\n");
 
905
          exit(1);
 
906
        }
 
907
      }
 
908
      else
 
909
      {
 
910
        if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
 
911
                     col_count) > HUGE_STRING_LENGTH)
 
912
        {
 
913
          fprintf(stderr, "Memory Allocation error in creating table\n");
 
914
          exit(1);
 
915
        }
 
916
      }
 
917
      table_string.append(buf);
 
918
 
 
919
      if (col_count < num_char_cols || num_blob_cols > 0)
 
920
        table_string.append(",");
 
921
    }
 
922
 
 
923
  if (num_blob_cols)
 
924
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
 
925
    {
 
926
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob",
 
927
                   col_count) > HUGE_STRING_LENGTH)
 
928
      {
 
929
        fprintf(stderr, "Memory Allocation error in creating table\n");
 
930
        exit(1);
 
931
      }
 
932
      table_string.append(buf);
 
933
 
 
934
      if (col_count < num_blob_cols)
 
935
        table_string.append(",");
 
936
    }
 
937
 
 
938
  table_string.append(")");
 
939
  ptr= (statement *)malloc(sizeof(statement));
 
940
  if (ptr == NULL)
 
941
  {
 
942
    fprintf(stderr, "Memory Allocation error in creating table\n");
 
943
    exit(1);
 
944
  }
 
945
  memset(ptr, 0, sizeof(statement));
 
946
  ptr->string = (char *)malloc(table_string.length()+1);
 
947
  if (ptr->string == NULL)
 
948
  {
 
949
    fprintf(stderr, "Memory Allocation error in creating table\n");
 
950
    exit(1);
 
951
  }
 
952
  memset(ptr->string, 0, table_string.length()+1);
 
953
  ptr->length= table_string.length()+1;
 
954
  ptr->type= CREATE_TABLE_TYPE;
 
955
  strcpy(ptr->string, table_string.c_str());
 
956
  return(ptr);
 
957
}
 
958
 
 
959
/*
 
960
  build_update_string()
 
961
 
 
962
  This function builds insert statements when the user opts to not supply
 
963
  an insert file or string containing insert data
 
964
*/
 
965
static statement *
 
966
build_update_string(void)
 
967
{
 
968
  char       buf[HUGE_STRING_LENGTH];
 
969
  unsigned int        col_count;
 
970
  statement *ptr;
 
971
  string update_string;
 
972
 
 
973
  update_string.reserve(HUGE_STRING_LENGTH);
 
974
 
 
975
  update_string= "UPDATE t1 SET ";
 
976
 
 
977
  if (num_int_cols)
 
978
    for (col_count= 1; col_count <= num_int_cols; col_count++)
 
979
    {
 
980
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
 
981
                   random()) > HUGE_STRING_LENGTH)
 
982
      {
 
983
        fprintf(stderr, "Memory Allocation error in creating update\n");
 
984
        exit(1);
 
985
      }
 
986
      update_string.append(buf);
 
987
 
 
988
      if (col_count < num_int_cols || num_char_cols > 0)
 
989
        update_string.append(",", 1);
 
990
    }
 
991
 
 
992
  if (num_char_cols)
 
993
    for (col_count= 1; col_count <= num_char_cols; col_count++)
 
994
    {
 
995
      char rand_buffer[RAND_STRING_SIZE];
 
996
      int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
 
997
 
 
998
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
 
999
                   buf_len, rand_buffer)
 
1000
          > HUGE_STRING_LENGTH)
 
1001
      {
 
1002
        fprintf(stderr, "Memory Allocation error in creating update\n");
 
1003
        exit(1);
 
1004
      }
 
1005
      update_string.append(buf);
 
1006
 
 
1007
      if (col_count < num_char_cols)
 
1008
        update_string.append(",", 1);
 
1009
    }
 
1010
 
 
1011
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
 
1012
    update_string.append(" WHERE id = ");
 
1013
 
 
1014
 
 
1015
  ptr= (statement *)malloc(sizeof(statement));
 
1016
  if (ptr == NULL)
 
1017
  {
 
1018
    fprintf(stderr, "Memory Allocation error in creating update\n");
 
1019
    exit(1);
 
1020
  }
 
1021
  memset(ptr, 0, sizeof(statement));
 
1022
 
 
1023
  ptr->length= update_string.length()+1;
 
1024
  ptr->string= (char *)malloc(ptr->length);
 
1025
  if (ptr->string == NULL)
 
1026
  {
 
1027
    fprintf(stderr, "Memory Allocation error in creating update\n");
 
1028
    exit(1);
 
1029
  }
 
1030
  memset(ptr->string, 0, ptr->length);
 
1031
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
 
1032
    ptr->type= UPDATE_TYPE_REQUIRES_PREFIX ;
 
1033
  else
 
1034
    ptr->type= UPDATE_TYPE;
 
1035
  strncpy(ptr->string, update_string.c_str(), ptr->length);
 
1036
  return(ptr);
 
1037
}
 
1038
 
 
1039
 
 
1040
/*
 
1041
  build_insert_string()
 
1042
 
 
1043
  This function builds insert statements when the user opts to not supply
 
1044
  an insert file or string containing insert data
 
1045
*/
 
1046
static statement *
 
1047
build_insert_string(void)
 
1048
{
 
1049
  char       buf[HUGE_STRING_LENGTH];
 
1050
  unsigned int        col_count;
 
1051
  statement *ptr;
 
1052
  string insert_string;
 
1053
 
 
1054
  insert_string.reserve(HUGE_STRING_LENGTH);
 
1055
 
 
1056
  insert_string= "INSERT INTO t1 VALUES (";
 
1057
 
 
1058
  if (auto_generate_sql_autoincrement)
 
1059
  {
 
1060
    insert_string.append("NULL");
 
1061
 
 
1062
    if (num_int_cols || num_char_cols)
 
1063
      insert_string.append(",");
 
1064
  }
 
1065
 
 
1066
  if (auto_generate_sql_guid_primary)
 
1067
  {
 
1068
    insert_string.append("uuid()");
 
1069
 
 
1070
    if (num_int_cols || num_char_cols)
 
1071
      insert_string.append(",");
 
1072
  }
 
1073
 
 
1074
  if (auto_generate_sql_secondary_indexes)
 
1075
  {
 
1076
    unsigned int count;
 
1077
 
 
1078
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
 
1079
    {
 
1080
      if (count) /* Except for the first pass we add a comma */
 
1081
        insert_string.append(",");
 
1082
 
 
1083
      insert_string.append("uuid()");
 
1084
    }
 
1085
 
 
1086
    if (num_int_cols || num_char_cols)
 
1087
      insert_string.append(",");
 
1088
  }
 
1089
 
 
1090
  if (num_int_cols)
 
1091
    for (col_count= 1; col_count <= num_int_cols; col_count++)
 
1092
    {
 
1093
      if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
 
1094
      {
 
1095
        fprintf(stderr, "Memory Allocation error in creating insert\n");
 
1096
        exit(1);
 
1097
      }
 
1098
      insert_string.append(buf);
 
1099
 
 
1100
      if (col_count < num_int_cols || num_char_cols > 0)
 
1101
        insert_string.append(",");
 
1102
    }
 
1103
 
 
1104
  if (num_char_cols)
 
1105
    for (col_count= 1; col_count <= num_char_cols; col_count++)
 
1106
    {
 
1107
      int buf_len= get_random_string(buf, RAND_STRING_SIZE);
 
1108
      insert_string.append("'", 1);
 
1109
      insert_string.append(buf, buf_len);
 
1110
      insert_string.append("'", 1);
 
1111
 
 
1112
      if (col_count < num_char_cols || num_blob_cols > 0)
 
1113
        insert_string.append(",", 1);
 
1114
    }
 
1115
 
 
1116
  if (num_blob_cols)
 
1117
  {
 
1118
    char *blob_ptr;
 
1119
 
 
1120
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
 
1121
    {
 
1122
      blob_ptr= (char *)malloc(sizeof(char)*num_blob_cols_size);
 
1123
      if (!blob_ptr)
 
1124
      {
 
1125
        fprintf(stderr, "Memory Allocation error in creating select\n");
 
1126
        exit(1);
 
1127
      }
 
1128
      memset(blob_ptr, 0, sizeof(char)*num_blob_cols_size);
 
1129
    }
 
1130
    else
 
1131
    {
 
1132
      blob_ptr= buf;
 
1133
    }
 
1134
 
 
1135
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
 
1136
    {
 
1137
      unsigned int buf_len;
 
1138
      unsigned int size;
 
1139
      unsigned int difference= num_blob_cols_size - num_blob_cols_size_min;
 
1140
 
 
1141
      size= difference ? (num_blob_cols_size_min + (random() % difference)) :
 
1142
        num_blob_cols_size;
 
1143
 
 
1144
      buf_len= get_random_string(blob_ptr, size);
 
1145
 
 
1146
      insert_string.append("'", 1);
 
1147
      insert_string.append(blob_ptr, buf_len);
 
1148
      insert_string.append("'", 1);
 
1149
 
 
1150
      if (col_count < num_blob_cols)
 
1151
        insert_string.append(",", 1);
 
1152
    }
 
1153
 
 
1154
    if (num_blob_cols_size > HUGE_STRING_LENGTH)
 
1155
      free(blob_ptr);
 
1156
  }
 
1157
 
 
1158
  insert_string.append(")", 1);
 
1159
 
 
1160
  if (!(ptr= (statement *)malloc(sizeof(statement))))
 
1161
  {
 
1162
    fprintf(stderr, "Memory Allocation error in creating select\n");
 
1163
    exit(1);
 
1164
  }
 
1165
  memset(ptr, 0, sizeof(statement));
 
1166
  ptr->length= insert_string.length()+1;
 
1167
  if (!(ptr->string= (char *)malloc(ptr->length)))
 
1168
  {
 
1169
    fprintf(stderr, "Memory Allocation error in creating select\n");
 
1170
    exit(1);
 
1171
  }
 
1172
  memset(ptr->string, 0, ptr->length);
 
1173
  ptr->type= INSERT_TYPE;
 
1174
  strcpy(ptr->string, insert_string.c_str());
 
1175
  return(ptr);
 
1176
}
 
1177
 
 
1178
 
 
1179
/*
 
1180
  build_select_string()
 
1181
 
 
1182
  This function builds a query if the user opts to not supply a query
 
1183
  statement or file containing a query statement
 
1184
*/
 
1185
static statement *
 
1186
build_select_string(bool key)
 
1187
{
 
1188
  char       buf[HUGE_STRING_LENGTH];
 
1189
  unsigned int        col_count;
 
1190
  statement *ptr;
 
1191
  string query_string;
 
1192
 
 
1193
  query_string.reserve(HUGE_STRING_LENGTH);
 
1194
 
 
1195
  query_string.append("SELECT ", 7);
 
1196
  if (auto_generate_selected_columns_opt)
 
1197
  {
 
1198
    query_string.append(auto_generate_selected_columns_opt);
 
1199
  }
 
1200
  else
 
1201
  {
 
1202
    for (col_count= 1; col_count <= num_int_cols; col_count++)
 
1203
    {
 
1204
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
 
1205
          > HUGE_STRING_LENGTH)
 
1206
      {
 
1207
        fprintf(stderr, "Memory Allocation error in creating select\n");
 
1208
        exit(1);
 
1209
      }
 
1210
      query_string.append(buf);
 
1211
 
 
1212
      if (col_count < num_int_cols || num_char_cols > 0)
 
1213
        query_string.append(",", 1);
 
1214
 
 
1215
    }
 
1216
    for (col_count= 1; col_count <= num_char_cols; col_count++)
 
1217
    {
 
1218
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
 
1219
          > HUGE_STRING_LENGTH)
 
1220
      {
 
1221
        fprintf(stderr, "Memory Allocation error in creating select\n");
 
1222
        exit(1);
 
1223
      }
 
1224
      query_string.append(buf);
 
1225
 
 
1226
      if (col_count < num_char_cols || num_blob_cols > 0)
 
1227
        query_string.append(",", 1);
 
1228
 
 
1229
    }
 
1230
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
 
1231
    {
 
1232
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
 
1233
          > HUGE_STRING_LENGTH)
 
1234
      {
 
1235
        fprintf(stderr, "Memory Allocation error in creating select\n");
 
1236
        exit(1);
 
1237
      }
 
1238
      query_string.append(buf);
 
1239
 
 
1240
      if (col_count < num_blob_cols)
 
1241
        query_string.append(",", 1);
 
1242
    }
 
1243
  }
 
1244
  query_string.append(" FROM t1");
 
1245
 
 
1246
  if ((key) &&
 
1247
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
 
1248
    query_string.append(" WHERE id = ");
 
1249
 
 
1250
  ptr= (statement *)malloc(sizeof(statement));
 
1251
  if (ptr == NULL)
 
1252
  {
 
1253
    fprintf(stderr, "Memory Allocation error in creating select\n");
 
1254
    exit(1);
 
1255
  }
 
1256
  memset(ptr, 0, sizeof(statement));
 
1257
  ptr->length= query_string.length()+1;
 
1258
  ptr->string= (char *)malloc(ptr->length);
 
1259
  if (ptr->string == NULL)
 
1260
  {
 
1261
    fprintf(stderr, "Memory Allocation error in creating select\n");
 
1262
    exit(1);
 
1263
  }
 
1264
  memset(ptr->string, 0, ptr->length);
 
1265
  if ((key) &&
 
1266
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
 
1267
    ptr->type= SELECT_TYPE_REQUIRES_PREFIX;
 
1268
  else
 
1269
    ptr->type= SELECT_TYPE;
 
1270
  strcpy(ptr->string, query_string.c_str());
 
1271
  return(ptr);
 
1272
}
 
1273
 
 
1274
static int
 
1275
get_options(int *argc,char ***argv)
 
1276
{
 
1277
  int ho_error;
 
1278
  char *tmp_string;
 
1279
  struct stat sbuf;
 
1280
  option_string *sql_type;
 
1281
  unsigned int sql_type_count= 0;
 
1282
  ssize_t bytes_read= 0;
 
1283
 
 
1284
 
 
1285
  if ((ho_error= handle_options(argc, argv, my_long_options, get_one_option)))
 
1286
    exit(ho_error);
 
1287
 
 
1288
  if (!user)
 
1289
    user= (char *)"root";
 
1290
 
 
1291
  /* If something is created we clean it up, otherwise we leave schemas alone */
 
1292
  if (create_string || auto_generate_sql)
 
1293
    opt_preserve= false;
 
1294
 
 
1295
  if (auto_generate_sql && (create_string || user_supplied_query))
 
1296
  {
 
1297
    fprintf(stderr,
 
1298
            "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
 
1299
            internal::my_progname);
 
1300
    exit(1);
 
1301
  }
 
1302
 
 
1303
  if (auto_generate_sql && auto_generate_sql_guid_primary &&
 
1304
      auto_generate_sql_autoincrement)
 
1305
  {
 
1306
    fprintf(stderr,
 
1307
            "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
 
1308
            internal::my_progname);
 
1309
    exit(1);
 
1310
  }
 
1311
 
 
1312
  if (auto_generate_sql && num_of_query && auto_actual_queries)
 
1313
  {
 
1314
    fprintf(stderr,
 
1315
            "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
 
1316
            internal::my_progname);
 
1317
    exit(1);
 
1318
  }
 
1319
 
 
1320
  parse_comma(concurrency_str ? concurrency_str : "1", &concurrency);
 
1321
 
 
1322
  if (opt_csv_str)
 
1323
  {
 
1324
    opt_silent= true;
 
1325
 
 
1326
    if (opt_csv_str[0] == '-')
 
1327
    {
 
1328
      csv_file= fileno(stdout);
 
1329
    }
 
1330
    else
 
1331
    {
 
1332
      if ((csv_file= open(opt_csv_str, O_CREAT|O_WRONLY|O_APPEND, 
 
1333
                          S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
 
1334
      {
 
1335
        fprintf(stderr,"%s: Could not open csv file: %sn\n",
 
1336
                internal::my_progname, opt_csv_str);
 
1337
        exit(1);
 
1338
      }
 
1339
    }
 
1340
  }
 
1341
 
 
1342
  if (opt_only_print)
 
1343
    opt_silent= true;
 
1344
 
 
1345
  if (num_int_cols_opt)
 
1346
  {
 
1347
    option_string *str;
 
1348
    parse_option(num_int_cols_opt, &str, ',');
 
1349
    num_int_cols= atoi(str->string);
 
1350
    if (str->option)
 
1351
      num_int_cols_index= atoi(str->option);
 
1352
    option_cleanup(str);
 
1353
  }
 
1354
 
 
1355
  if (num_char_cols_opt)
 
1356
  {
 
1357
    option_string *str;
 
1358
    parse_option(num_char_cols_opt, &str, ',');
 
1359
    num_char_cols= atoi(str->string);
 
1360
    if (str->option)
 
1361
      num_char_cols_index= atoi(str->option);
 
1362
    else
 
1363
      num_char_cols_index= 0;
 
1364
    option_cleanup(str);
 
1365
  }
 
1366
 
 
1367
  if (num_blob_cols_opt)
 
1368
  {
 
1369
    option_string *str;
 
1370
    parse_option(num_blob_cols_opt, &str, ',');
 
1371
    num_blob_cols= atoi(str->string);
 
1372
    if (str->option)
 
1373
    {
 
1374
      char *sep_ptr;
 
1375
 
 
1376
      if ((sep_ptr= strchr(str->option, '/')))
 
1377
      {
 
1378
        num_blob_cols_size_min= atoi(str->option);
 
1379
        num_blob_cols_size= atoi(sep_ptr+1);
 
1380
      }
 
1381
      else
 
1382
      {
 
1383
        num_blob_cols_size_min= num_blob_cols_size= atoi(str->option);
 
1384
      }
 
1385
    }
 
1386
    else
 
1387
    {
 
1388
      num_blob_cols_size= DEFAULT_BLOB_SIZE;
 
1389
      num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
 
1390
    }
 
1391
    option_cleanup(str);
 
1392
  }
 
1393
 
 
1394
 
 
1395
  if (auto_generate_sql)
 
1396
  {
 
1397
    uint64_t x= 0;
 
1398
    statement *ptr_statement;
 
1399
 
 
1400
    if (verbose >= 2)
 
1401
      printf("Building Create Statements for Auto\n");
 
1402
 
 
1403
    create_statements= build_table_string();
 
1404
    /*
 
1405
      Pre-populate table
 
1406
    */
 
1407
    for (ptr_statement= create_statements, x= 0;
 
1408
         x < auto_generate_sql_unique_write_number;
 
1409
         x++, ptr_statement= ptr_statement->next)
 
1410
    {
 
1411
      ptr_statement->next= build_insert_string();
 
1412
    }
 
1413
 
 
1414
    if (verbose >= 2)
 
1415
      printf("Building Query Statements for Auto\n");
 
1416
 
 
1417
    if (!opt_auto_generate_sql_type)
 
1418
      opt_auto_generate_sql_type= "mixed";
 
1419
 
 
1420
    query_statements_count=
 
1421
      parse_option(opt_auto_generate_sql_type, &query_options, ',');
 
1422
 
 
1423
    query_statements= (statement **)malloc(sizeof(statement *) * query_statements_count);
 
1424
    if (query_statements == NULL)
 
1425
    {
 
1426
      fprintf(stderr, "Memory Allocation error in Building Query Statements\n");
 
1427
      exit(1);
 
1428
    }
 
1429
    memset(query_statements, 0, sizeof(statement *) * query_statements_count);
 
1430
 
 
1431
    sql_type= query_options;
 
1432
    do
 
1433
    {
 
1434
      if (sql_type->string[0] == 'r')
 
1435
      {
 
1436
        if (verbose >= 2)
 
1437
          printf("Generating SELECT Statements for Auto\n");
 
1438
 
 
1439
        query_statements[sql_type_count]= build_select_string(false);
 
1440
        for (ptr_statement= query_statements[sql_type_count], x= 0;
 
1441
             x < auto_generate_sql_unique_query_number;
 
1442
             x++, ptr_statement= ptr_statement->next)
 
1443
        {
 
1444
          ptr_statement->next= build_select_string(false);
 
1445
        }
 
1446
      }
 
1447
      else if (sql_type->string[0] == 'k')
 
1448
      {
 
1449
        if (verbose >= 2)
 
1450
          printf("Generating SELECT for keys Statements for Auto\n");
 
1451
 
 
1452
        if ( auto_generate_sql_autoincrement == false &&
 
1453
             auto_generate_sql_guid_primary == false)
 
1454
        {
 
1455
          fprintf(stderr,
 
1456
                  "%s: Can't perform key test without a primary key!\n",
 
1457
                  internal::my_progname);
 
1458
          exit(1);
 
1459
        }
 
1460
 
 
1461
        query_statements[sql_type_count]= build_select_string(true);
 
1462
        for (ptr_statement= query_statements[sql_type_count], x= 0;
 
1463
             x < auto_generate_sql_unique_query_number;
 
1464
             x++, ptr_statement= ptr_statement->next)
 
1465
        {
 
1466
          ptr_statement->next= build_select_string(true);
 
1467
        }
 
1468
      }
 
1469
      else if (sql_type->string[0] == 'w')
 
1470
      {
 
1471
        /*
 
1472
          We generate a number of strings in case the engine is
 
1473
          Archive (since strings which were identical one after another
 
1474
          would be too easily optimized).
 
1475
        */
 
1476
        if (verbose >= 2)
 
1477
          printf("Generating INSERT Statements for Auto\n");
 
1478
        query_statements[sql_type_count]= build_insert_string();
 
1479
        for (ptr_statement= query_statements[sql_type_count], x= 0;
 
1480
             x < auto_generate_sql_unique_query_number;
 
1481
             x++, ptr_statement= ptr_statement->next)
 
1482
        {
 
1483
          ptr_statement->next= build_insert_string();
 
1484
        }
 
1485
      }
 
1486
      else if (sql_type->string[0] == 'u')
 
1487
      {
 
1488
        if ( auto_generate_sql_autoincrement == false &&
 
1489
             auto_generate_sql_guid_primary == false)
 
1490
        {
 
1491
          fprintf(stderr,
 
1492
                  "%s: Can't perform update test without a primary key!\n",
 
1493
                  internal::my_progname);
 
1494
          exit(1);
 
1495
        }
 
1496
 
 
1497
        query_statements[sql_type_count]= build_update_string();
 
1498
        for (ptr_statement= query_statements[sql_type_count], x= 0;
 
1499
             x < auto_generate_sql_unique_query_number;
 
1500
             x++, ptr_statement= ptr_statement->next)
 
1501
        {
 
1502
          ptr_statement->next= build_update_string();
 
1503
        }
 
1504
      }
 
1505
      else /* Mixed mode is default */
 
1506
      {
 
1507
        int coin= 0;
 
1508
 
 
1509
        query_statements[sql_type_count]= build_insert_string();
 
1510
        /*
 
1511
          This logic should be extended to do a more mixed load,
 
1512
          at the moment it results in "every other".
 
1513
        */
 
1514
        for (ptr_statement= query_statements[sql_type_count], x= 0;
 
1515
             x < auto_generate_sql_unique_query_number;
 
1516
             x++, ptr_statement= ptr_statement->next)
 
1517
        {
 
1518
          if (coin)
 
1519
          {
 
1520
            ptr_statement->next= build_insert_string();
 
1521
            coin= 0;
 
1522
          }
 
1523
          else
 
1524
          {
 
1525
            ptr_statement->next= build_select_string(true);
 
1526
            coin= 1;
 
1527
          }
 
1528
        }
 
1529
      }
 
1530
      sql_type_count++;
 
1531
    } while (sql_type ? (sql_type= sql_type->next) : 0);
 
1532
  }
 
1533
  else
 
1534
  {
 
1535
    if (create_string && !stat(create_string, &sbuf))
 
1536
    {
 
1537
      int data_file;
 
1538
      if (!S_ISREG(sbuf.st_mode))
 
1539
      {
 
1540
        fprintf(stderr,"%s: Create file was not a regular file\n",
 
1541
                internal::my_progname);
 
1542
        exit(1);
 
1543
      }
 
1544
      if ((data_file= open(create_string, O_RDWR)) == -1)
 
1545
      {
 
1546
        fprintf(stderr,"%s: Could not open create file\n", internal::my_progname);
 
1547
        exit(1);
 
1548
      }
 
1549
      if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
 
1550
      {
 
1551
        fprintf(stderr, "Request for more memory than architecture supports\n");
 
1552
        exit(1);
 
1553
      }
 
1554
      tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
 
1555
      if (tmp_string == NULL)
 
1556
      {
 
1557
        fprintf(stderr, "Memory Allocation error in option processing\n");
 
1558
        exit(1);
 
1559
      }
 
1560
      memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
 
1561
      bytes_read= read(data_file, (unsigned char*) tmp_string,
 
1562
                       (size_t)sbuf.st_size);
 
1563
      tmp_string[sbuf.st_size]= '\0';
 
1564
      close(data_file);
 
1565
      if (bytes_read != sbuf.st_size)
 
1566
      {
 
1567
        fprintf(stderr, "Problem reading file: read less bytes than requested\n");
 
1568
      }
 
1569
      parse_delimiter(tmp_string, &create_statements, delimiter[0]);
 
1570
      free(tmp_string);
 
1571
    }
 
1572
    else if (create_string)
 
1573
    {
 
1574
      parse_delimiter(create_string, &create_statements, delimiter[0]);
 
1575
    }
 
1576
 
 
1577
    /* Set this up till we fully support options on user generated queries */
 
1578
    if (user_supplied_query)
 
1579
    {
 
1580
      query_statements_count=
 
1581
        parse_option("default", &query_options, ',');
 
1582
 
 
1583
      query_statements= (statement **)malloc(sizeof(statement *) * query_statements_count);
 
1584
      if (query_statements == NULL)
 
1585
      {
 
1586
        fprintf(stderr, "Memory Allocation error in option processing\n");
 
1587
        exit(1);
 
1588
      }
 
1589
      memset(query_statements, 0, sizeof(statement *) * query_statements_count); 
 
1590
    }
 
1591
 
 
1592
    if (user_supplied_query && !stat(user_supplied_query, &sbuf))
 
1593
    {
 
1594
      int data_file;
 
1595
      if (!S_ISREG(sbuf.st_mode))
 
1596
      {
 
1597
        fprintf(stderr,"%s: User query supplied file was not a regular file\n",
 
1598
                internal::my_progname);
 
1599
        exit(1);
 
1600
      }
 
1601
      if ((data_file= open(user_supplied_query, O_RDWR)) == -1)
 
1602
      {
 
1603
        fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
 
1604
        exit(1);
 
1605
      }
 
1606
      if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
 
1607
      {
 
1608
        fprintf(stderr, "Request for more memory than architecture supports\n");
 
1609
        exit(1);
 
1610
      }
 
1611
      tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
 
1612
      if (tmp_string == NULL)
 
1613
      {
 
1614
        fprintf(stderr, "Memory Allocation error in option processing\n");
 
1615
        exit(1);
 
1616
      }
 
1617
      memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
 
1618
      bytes_read= read(data_file, (unsigned char*) tmp_string,
 
1619
                       (size_t)sbuf.st_size);
 
1620
      tmp_string[sbuf.st_size]= '\0';
 
1621
      close(data_file);
 
1622
      if (bytes_read != sbuf.st_size)
 
1623
      {
 
1624
        fprintf(stderr, "Problem reading file: read less bytes than requested\n");
 
1625
      }
 
1626
      if (user_supplied_query)
 
1627
        actual_queries= parse_delimiter(tmp_string, &query_statements[0],
 
1628
                                        delimiter[0]);
 
1629
      free(tmp_string);
 
1630
    }
 
1631
    else if (user_supplied_query)
 
1632
    {
 
1633
      actual_queries= parse_delimiter(user_supplied_query, &query_statements[0],
 
1634
                                      delimiter[0]);
 
1635
    }
 
1636
  }
 
1637
 
 
1638
  if (user_supplied_pre_statements
 
1639
      && !stat(user_supplied_pre_statements, &sbuf))
 
1640
  {
 
1641
    int data_file;
 
1642
    if (!S_ISREG(sbuf.st_mode))
 
1643
    {
 
1644
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
 
1645
              internal::my_progname);
 
1646
      exit(1);
 
1647
    }
 
1648
    if ((data_file= open(user_supplied_pre_statements, O_RDWR)) == -1)
 
1649
    {
 
1650
      fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
 
1651
      exit(1);
 
1652
    }
 
1653
    if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
 
1654
    {
 
1655
      fprintf(stderr, "Request for more memory than architecture supports\n");
 
1656
      exit(1);
 
1657
    }
 
1658
    tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
 
1659
    if (tmp_string == NULL)
 
1660
    {
 
1661
      fprintf(stderr, "Memory Allocation error in option processing\n");
 
1662
      exit(1);
 
1663
    }
 
1664
    memset(tmp_string, 0, (size_t)(sbuf.st_size + 1));
 
1665
    bytes_read= read(data_file, (unsigned char*) tmp_string,
 
1666
                     (size_t)sbuf.st_size);
 
1667
    tmp_string[sbuf.st_size]= '\0';
 
1668
    close(data_file);
 
1669
    if (bytes_read != sbuf.st_size)
 
1670
    {
 
1671
      fprintf(stderr, "Problem reading file: read less bytes than requested\n");
 
1672
    }
 
1673
    if (user_supplied_pre_statements)
 
1674
      (void)parse_delimiter(tmp_string, &pre_statements,
 
1675
                            delimiter[0]);
 
1676
    free(tmp_string);
 
1677
  }
 
1678
  else if (user_supplied_pre_statements)
 
1679
  {
 
1680
    (void)parse_delimiter(user_supplied_pre_statements,
 
1681
                          &pre_statements,
 
1682
                          delimiter[0]);
 
1683
  }
 
1684
 
 
1685
  if (user_supplied_post_statements
 
1686
      && !stat(user_supplied_post_statements, &sbuf))
 
1687
  {
 
1688
    int data_file;
 
1689
    if (!S_ISREG(sbuf.st_mode))
 
1690
    {
 
1691
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
 
1692
              internal::my_progname);
 
1693
      exit(1);
 
1694
    }
 
1695
    if ((data_file= open(user_supplied_post_statements, O_RDWR)) == -1)
 
1696
    {
 
1697
      fprintf(stderr,"%s: Could not open query supplied file\n", internal::my_progname);
 
1698
      exit(1);
 
1699
    }
 
1700
 
 
1701
    if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
 
1702
    {
 
1703
      fprintf(stderr, "Request for more memory than architecture supports\n");
 
1704
      exit(1);
 
1705
    }
 
1706
    tmp_string= (char *)malloc((size_t)(sbuf.st_size + 1));
 
1707
    if (tmp_string == NULL)
 
1708
    {
 
1709
      fprintf(stderr, "Memory Allocation error in option processing\n");
 
1710
      exit(1);
 
1711
    }
 
1712
    memset(tmp_string, 0, (size_t)(sbuf.st_size+1));
 
1713
 
 
1714
    bytes_read= read(data_file, (unsigned char*) tmp_string,
 
1715
                     (size_t)(sbuf.st_size));
 
1716
    tmp_string[sbuf.st_size]= '\0';
 
1717
    close(data_file);
 
1718
    if (bytes_read != sbuf.st_size)
 
1719
    {
 
1720
      fprintf(stderr, "Problem reading file: read less bytes than requested\n");
 
1721
    }
 
1722
    if (user_supplied_post_statements)
 
1723
      (void)parse_delimiter(tmp_string, &post_statements,
 
1724
                            delimiter[0]);
 
1725
    free(tmp_string);
 
1726
  }
 
1727
  else if (user_supplied_post_statements)
 
1728
  {
 
1729
    (void)parse_delimiter(user_supplied_post_statements, &post_statements,
 
1730
                          delimiter[0]);
 
1731
  }
 
1732
 
 
1733
  if (verbose >= 2)
 
1734
    printf("Parsing engines to use.\n");
 
1735
 
 
1736
  if (default_engine)
 
1737
    parse_option(default_engine, &engine_options, ',');
 
1738
 
 
1739
  if (tty_password)
 
1740
    opt_password= client_get_tty_password(NULL);
 
1741
  return(0);
 
1742
}
 
1743
 
 
1744
 
 
1745
static int run_query(drizzle_con_st *con, drizzle_result_st *result,
 
1746
                     const char *query, int len)
 
1747
{
 
1748
  drizzle_return_t ret;
 
1749
  drizzle_result_st result_buffer;
 
1750
 
 
1751
  if (opt_only_print)
 
1752
  {
 
1753
    printf("%.*s;\n", len, query);
 
1754
    return 0;
 
1755
  }
 
1756
 
 
1757
  if (verbose >= 3)
 
1758
    printf("%.*s;\n", len, query);
 
1759
 
 
1760
  if (result == NULL)
 
1761
    result= &result_buffer;
 
1762
 
 
1763
  result= drizzle_query(con, result, query, len, &ret);
 
1764
 
 
1765
  if (ret == DRIZZLE_RETURN_OK)
 
1766
    ret= drizzle_result_buffer(result);
 
1767
 
 
1768
  if (result == &result_buffer)
 
1769
    drizzle_result_free(result);
 
1770
    
 
1771
  return ret;
 
1772
}
 
1773
 
 
1774
 
 
1775
static int
 
1776
generate_primary_key_list(drizzle_con_st *con, option_string *engine_stmt)
 
1777
{
 
1778
  drizzle_result_st result;
 
1779
  drizzle_row_t row;
 
1780
  uint64_t counter;
 
1781
 
 
1782
 
 
1783
  /*
 
1784
    Blackhole is a special case, this allows us to test the upper end
 
1785
    of the server during load runs.
 
1786
  */
 
1787
  if (opt_only_print || (engine_stmt &&
 
1788
                         strstr(engine_stmt->string, "blackhole")))
 
1789
  {
 
1790
    primary_keys_number_of= 1;
 
1791
    primary_keys= (char **)malloc((sizeof(char *) *
 
1792
                                  primary_keys_number_of));
 
1793
    if (primary_keys == NULL)
 
1794
    {
 
1795
      fprintf(stderr, "Memory Allocation error in option processing\n");
 
1796
      exit(1);
 
1797
    }
 
1798
    
 
1799
    memset(primary_keys, 0, (sizeof(char *) * primary_keys_number_of));
 
1800
    /* Yes, we strdup a const string to simplify the interface */
 
1801
    primary_keys[0]= strdup("796c4422-1d94-102a-9d6d-00e0812d");
 
1802
    if (primary_keys[0] == NULL)
 
1803
    {
 
1804
      fprintf(stderr, "Memory Allocation error in option processing\n");
 
1805
      exit(1);
 
1806
    }
 
1807
  }
 
1808
  else
 
1809
  {
 
1810
    if (run_query(con, &result, "SELECT id from t1", strlen("SELECT id from t1")))
 
1811
    {
 
1812
      fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", internal::my_progname,
 
1813
              drizzle_con_error(con));
 
1814
      exit(1);
 
1815
    }
 
1816
 
 
1817
    uint64_t num_rows_ret= drizzle_result_row_count(&result);
 
1818
    if (num_rows_ret > SIZE_MAX)
 
1819
    {
 
1820
      fprintf(stderr, "More primary keys than than architecture supports\n");
 
1821
      exit(1);
 
1822
    }
 
1823
    primary_keys_number_of= (size_t)num_rows_ret;
 
1824
 
 
1825
    /* So why check this? Blackhole :) */
 
1826
    if (primary_keys_number_of)
 
1827
    {
 
1828
      /*
 
1829
        We create the structure and loop and create the items.
 
1830
      */
 
1831
      primary_keys= (char **)malloc(sizeof(char *) *
 
1832
                                    primary_keys_number_of);
 
1833
      if (primary_keys == NULL)
 
1834
      {
 
1835
        fprintf(stderr, "Memory Allocation error in option processing\n");
 
1836
        exit(1);
 
1837
      }
 
1838
      memset(primary_keys, 0, (size_t)(sizeof(char *) * primary_keys_number_of));
 
1839
      row= drizzle_row_next(&result);
 
1840
      for (counter= 0; counter < primary_keys_number_of;
 
1841
           counter++, row= drizzle_row_next(&result))
 
1842
      {
 
1843
        primary_keys[counter]= strdup(row[0]);
 
1844
        if (primary_keys[counter] == NULL)
 
1845
        {
 
1846
          fprintf(stderr, "Memory Allocation error in option processing\n");
 
1847
          exit(1);
 
1848
        }
 
1849
      }
 
1850
    }
 
1851
 
 
1852
    drizzle_result_free(&result);
 
1853
  }
 
1854
 
 
1855
  return(0);
 
1856
}
 
1857
 
 
1858
static int
 
1859
drop_primary_key_list(void)
 
1860
{
 
1861
  uint64_t counter;
 
1862
 
 
1863
  if (primary_keys_number_of)
 
1864
  {
 
1865
    for (counter= 0; counter < primary_keys_number_of; counter++)
 
1866
      free(primary_keys[counter]);
 
1867
 
 
1868
    free(primary_keys);
 
1869
  }
 
1870
 
 
1871
  return 0;
 
1872
}
 
1873
 
 
1874
static int
 
1875
create_schema(drizzle_con_st *con, const char *db, statement *stmt,
 
1876
              option_string *engine_stmt, stats *sptr)
 
1877
{
 
1878
  char query[HUGE_STRING_LENGTH];
 
1879
  statement *ptr;
 
1880
  statement *after_create;
 
1881
  int len;
 
1882
  uint64_t count;
 
1883
  struct timeval start_time, end_time;
 
1884
 
 
1885
 
 
1886
  gettimeofday(&start_time, NULL);
 
1887
 
 
1888
  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
 
1889
 
 
1890
  if (verbose >= 2)
 
1891
    printf("Loading Pre-data\n");
 
1892
 
 
1893
  if (run_query(con, NULL, query, len))
 
1894
  {
 
1895
    fprintf(stderr,"%s: Cannot create schema %s : %s\n", internal::my_progname, db,
 
1896
            drizzle_con_error(con));
 
1897
    exit(1);
 
1898
  }
 
1899
  else
 
1900
  {
 
1901
    sptr->create_count++;
 
1902
  }
 
1903
 
 
1904
  if (opt_only_print)
 
1905
  {
 
1906
    printf("use %s;\n", db);
 
1907
  }
 
1908
  else
 
1909
  {
 
1910
    drizzle_result_st result;
 
1911
    drizzle_return_t ret;
 
1912
 
 
1913
    if (verbose >= 3)
 
1914
      printf("%s;\n", query);
 
1915
 
 
1916
    if (drizzle_select_db(con,  &result, db, &ret) == NULL ||
 
1917
        ret != DRIZZLE_RETURN_OK)
 
1918
    {
 
1919
      fprintf(stderr,"%s: Cannot select schema '%s': %s\n",internal::my_progname, db,
 
1920
              ret == DRIZZLE_RETURN_ERROR_CODE ?
 
1921
              drizzle_result_error(&result) : drizzle_con_error(con));
 
1922
      exit(1);
 
1923
    }
 
1924
    drizzle_result_free(&result);
 
1925
    sptr->create_count++;
 
1926
  }
 
1927
 
 
1928
  if (engine_stmt)
 
1929
  {
 
1930
    len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
 
1931
                  engine_stmt->string);
 
1932
    if (run_query(con, NULL, query, len))
 
1933
    {
 
1934
      fprintf(stderr,"%s: Cannot set default engine: %s\n", internal::my_progname,
 
1935
              drizzle_con_error(con));
 
1936
      exit(1);
 
1937
    }
 
1938
    sptr->create_count++;
 
1939
  }
 
1940
 
 
1941
  count= 0;
 
1942
  after_create= stmt;
 
1943
 
 
1944
limit_not_met:
 
1945
  for (ptr= after_create; ptr && ptr->length; ptr= ptr->next, count++)
 
1946
  {
 
1947
    if (auto_generate_sql && ( auto_generate_sql_number == count))
 
1948
      break;
 
1949
 
 
1950
    if (engine_stmt && engine_stmt->option && ptr->type == CREATE_TABLE_TYPE)
 
1951
    {
 
1952
      char buffer[HUGE_STRING_LENGTH];
 
1953
 
 
1954
      snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->string,
 
1955
               engine_stmt->option);
 
1956
      if (run_query(con, NULL, buffer, strlen(buffer)))
 
1957
      {
 
1958
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
 
1959
                internal::my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(con));
 
1960
        if (!opt_ignore_sql_errors)
 
1961
          exit(1);
 
1962
      }
 
1963
      sptr->create_count++;
 
1964
    }
 
1965
    else
 
1966
    {
 
1967
      if (run_query(con, NULL, ptr->string, ptr->length))
 
1968
      {
 
1969
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
 
1970
                internal::my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(con));
 
1971
        if (!opt_ignore_sql_errors)
 
1972
          exit(1);
 
1973
      }
 
1974
      sptr->create_count++;
 
1975
    }
 
1976
  }
 
1977
 
 
1978
  if (auto_generate_sql && (auto_generate_sql_number > count ))
 
1979
  {
 
1980
    /* Special case for auto create, we don't want to create tables twice */
 
1981
    after_create= stmt->next;
 
1982
    goto limit_not_met;
 
1983
  }
 
1984
 
 
1985
  gettimeofday(&end_time, NULL);
 
1986
 
 
1987
  sptr->create_timing= timedif(end_time, start_time);
 
1988
 
 
1989
  return(0);
 
1990
}
 
1991
 
 
1992
static int
 
1993
drop_schema(drizzle_con_st *con, const char *db)
 
1994
{
 
1995
  char query[HUGE_STRING_LENGTH];
 
1996
  int len;
 
1997
 
 
1998
  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
 
1999
 
 
2000
  if (run_query(con, NULL, query, len))
 
2001
  {
 
2002
    fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
 
2003
            internal::my_progname, db, drizzle_con_error(con));
 
2004
    exit(1);
 
2005
  }
 
2006
 
 
2007
 
 
2008
 
 
2009
  return(0);
 
2010
}
 
2011
 
 
2012
static int
 
2013
run_statements(drizzle_con_st *con, statement *stmt)
 
2014
{
 
2015
  statement *ptr;
 
2016
 
 
2017
  for (ptr= stmt; ptr && ptr->length; ptr= ptr->next)
 
2018
  {
 
2019
    if (run_query(con, NULL, ptr->string, ptr->length))
 
2020
    {
 
2021
      fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
 
2022
              internal::my_progname, (uint32_t)ptr->length, ptr->string, drizzle_con_error(con));
 
2023
      exit(1);
 
2024
    }
 
2025
  }
 
2026
 
 
2027
  return(0);
 
2028
}
 
2029
 
 
2030
static int
 
2031
run_scheduler(stats *sptr, statement **stmts, uint32_t concur, uint64_t limit)
 
2032
{
 
2033
  uint32_t x;
 
2034
  uint32_t y;
 
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 */
 
2041
 
 
2042
 
 
2043
  pthread_attr_init(&attr);
 
2044
  pthread_attr_setdetachstate(&attr,
 
2045
                              PTHREAD_CREATE_DETACHED);
 
2046
 
 
2047
  pthread_mutex_lock(&counter_mutex);
 
2048
  thread_counter= 0;
 
2049
 
 
2050
  pthread_mutex_lock(&sleeper_mutex);
 
2051
  master_wakeup= 1;
 
2052
  pthread_mutex_unlock(&sleeper_mutex);
 
2053
 
 
2054
  real_concurrency= 0;
 
2055
 
 
2056
  for (y= 0, sql_type= query_options;
 
2057
       y < query_statements_count;
 
2058
       y++, sql_type= sql_type->next)
 
2059
  {
 
2060
    unsigned int options_loop= 1;
 
2061
 
 
2062
    if (sql_type->option)
 
2063
    {
 
2064
      options_loop= strtol(sql_type->option,
 
2065
                           (char **)NULL, 10);
 
2066
      options_loop= options_loop ? options_loop : 1;
 
2067
    }
 
2068
 
 
2069
    while (options_loop--)
 
2070
      for (x= 0; x < concur; x++)
 
2071
      {
 
2072
        con= (thread_context *)malloc(sizeof(thread_context));
 
2073
        if (con == NULL)
 
2074
        {
 
2075
          fprintf(stderr, "Memory Allocation error in scheduler\n");
 
2076
          exit(1);
 
2077
        }
 
2078
        con->stmt= stmts[y];
 
2079
        con->limit= limit;
 
2080
 
 
2081
        real_concurrency++;
 
2082
        /* now you create the thread */
 
2083
        if (pthread_create(&mainthread, &attr, run_task,
 
2084
                           (void *)con) != 0)
 
2085
        {
 
2086
          fprintf(stderr,"%s: Could not create thread\n", internal::my_progname);
 
2087
          exit(1);
 
2088
        }
 
2089
        thread_counter++;
 
2090
      }
 
2091
  }
 
2092
 
 
2093
  /*
 
2094
    The timer_thread belongs to all threads so it too obeys the wakeup
 
2095
    call that run tasks obey.
 
2096
  */
 
2097
  if (opt_timer_length)
 
2098
  {
 
2099
    pthread_mutex_lock(&timer_alarm_mutex);
 
2100
    timer_alarm= true;
 
2101
    pthread_mutex_unlock(&timer_alarm_mutex);
 
2102
 
 
2103
    if (pthread_create(&mainthread, &attr, timer_thread,
 
2104
                       (void *)&opt_timer_length) != 0)
 
2105
    {
 
2106
      fprintf(stderr,"%s: Could not create timer thread\n", internal::my_progname);
 
2107
      exit(1);
 
2108
    }
 
2109
  }
 
2110
 
 
2111
  pthread_mutex_unlock(&counter_mutex);
 
2112
  pthread_attr_destroy(&attr);
 
2113
 
 
2114
  pthread_mutex_lock(&sleeper_mutex);
 
2115
  master_wakeup= 0;
 
2116
  pthread_mutex_unlock(&sleeper_mutex);
 
2117
  pthread_cond_broadcast(&sleep_threshhold);
 
2118
 
 
2119
  gettimeofday(&start_time, NULL);
 
2120
 
 
2121
  /*
 
2122
    We loop until we know that all children have cleaned up.
 
2123
  */
 
2124
  pthread_mutex_lock(&counter_mutex);
 
2125
  while (thread_counter)
 
2126
  {
 
2127
    struct timespec abstime;
 
2128
 
 
2129
    set_timespec(abstime, 3);
 
2130
    pthread_cond_timedwait(&count_threshhold, &counter_mutex, &abstime);
 
2131
  }
 
2132
  pthread_mutex_unlock(&counter_mutex);
 
2133
 
 
2134
  gettimeofday(&end_time, NULL);
 
2135
 
 
2136
 
 
2137
  sptr->timing= timedif(end_time, start_time);
 
2138
  sptr->users= concur;
 
2139
  sptr->real_users= real_concurrency;
 
2140
  sptr->rows= limit;
 
2141
 
 
2142
  return(0);
 
2143
}
 
2144
 
 
2145
 
 
2146
pthread_handler_t timer_thread(void *p)
 
2147
{
 
2148
  uint32_t *timer_length= (uint32_t *)p;
 
2149
  struct timespec abstime;
 
2150
 
 
2151
 
 
2152
  /*
 
2153
    We lock around the initial call in case were we in a loop. This
 
2154
    also keeps the value properly syncronized across call threads.
 
2155
  */
 
2156
  pthread_mutex_lock(&sleeper_mutex);
 
2157
  while (master_wakeup)
 
2158
  {
 
2159
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
 
2160
  }
 
2161
  pthread_mutex_unlock(&sleeper_mutex);
 
2162
 
 
2163
  set_timespec(abstime, *timer_length);
 
2164
 
 
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);
 
2168
 
 
2169
  pthread_mutex_lock(&timer_alarm_mutex);
 
2170
  timer_alarm= false;
 
2171
  pthread_mutex_unlock(&timer_alarm_mutex);
 
2172
 
 
2173
  return(0);
 
2174
}
 
2175
 
 
2176
pthread_handler_t run_task(void *p)
 
2177
{
 
2178
  uint64_t counter= 0, queries;
 
2179
  uint64_t detach_counter;
 
2180
  unsigned int commit_counter;
 
2181
  drizzle_con_st con;
 
2182
  drizzle_result_st result;
 
2183
  drizzle_row_t row;
 
2184
  statement *ptr;
 
2185
  thread_context *ctx= (thread_context *)p;
 
2186
 
 
2187
  pthread_mutex_lock(&sleeper_mutex);
 
2188
  while (master_wakeup)
 
2189
  {
 
2190
    pthread_cond_wait(&sleep_threshhold, &sleeper_mutex);
 
2191
  }
 
2192
  pthread_mutex_unlock(&sleeper_mutex);
 
2193
 
 
2194
  slap_connect(&con, true);
 
2195
 
 
2196
  if (verbose >= 3)
 
2197
    printf("connected!\n");
 
2198
  queries= 0;
 
2199
 
 
2200
  commit_counter= 0;
 
2201
  if (commit_rate)
 
2202
    run_query(&con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
 
2203
 
 
2204
limit_not_met:
 
2205
  for (ptr= ctx->stmt, detach_counter= 0;
 
2206
       ptr && ptr->length;
 
2207
       ptr= ptr->next, detach_counter++)
 
2208
  {
 
2209
    if (!opt_only_print && detach_rate && !(detach_counter % detach_rate))
 
2210
    {
 
2211
      slap_close(&con);
 
2212
      slap_connect(&con, true);
 
2213
    }
 
2214
 
 
2215
    /*
 
2216
      We have to execute differently based on query type. This should become a function.
 
2217
    */
 
2218
    if ((ptr->type == UPDATE_TYPE_REQUIRES_PREFIX) ||
 
2219
        (ptr->type == SELECT_TYPE_REQUIRES_PREFIX))
 
2220
    {
 
2221
      int length;
 
2222
      unsigned int key_val;
 
2223
      char *key;
 
2224
      char buffer[HUGE_STRING_LENGTH];
 
2225
 
 
2226
      /*
 
2227
        This should only happen if some sort of new engine was
 
2228
        implemented that didn't properly handle UPDATEs.
 
2229
 
 
2230
        Just in case someone runs this under an experimental engine we don't
 
2231
        want a crash so the if() is placed here.
 
2232
      */
 
2233
      assert(primary_keys_number_of);
 
2234
      if (primary_keys_number_of)
 
2235
      {
 
2236
        key_val= (unsigned int)(random() % primary_keys_number_of);
 
2237
        key= primary_keys[key_val];
 
2238
 
 
2239
        assert(key);
 
2240
 
 
2241
        length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'",
 
2242
                         (int)ptr->length, ptr->string, key);
 
2243
 
 
2244
        if (run_query(&con, &result, buffer, length))
 
2245
        {
 
2246
          fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
 
2247
                  internal::my_progname, (uint32_t)length, buffer, drizzle_con_error(&con));
 
2248
          exit(1);
 
2249
        }
 
2250
      }
 
2251
    }
 
2252
    else
 
2253
    {
 
2254
      if (run_query(&con, &result, ptr->string, ptr->length))
 
2255
      {
 
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));
 
2258
        exit(1);
 
2259
      }
 
2260
    }
 
2261
 
 
2262
    if (!opt_only_print)
 
2263
    {
 
2264
      while ((row = drizzle_row_next(&result)))
 
2265
        counter++;
 
2266
      drizzle_result_free(&result);
 
2267
    }
 
2268
    queries++;
 
2269
 
 
2270
    if (commit_rate && (++commit_counter == commit_rate))
 
2271
    {
 
2272
      commit_counter= 0;
 
2273
      run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
 
2274
    }
 
2275
 
 
2276
    /* If the timer is set, and the alarm is not active then end */
 
2277
    if (opt_timer_length && timer_alarm == false)
 
2278
      goto end;
 
2279
 
 
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)
 
2282
      goto end;
 
2283
  }
 
2284
 
 
2285
  if (opt_timer_length && timer_alarm == true)
 
2286
    goto limit_not_met;
 
2287
 
 
2288
  if (ctx->limit && queries < ctx->limit)
 
2289
    goto limit_not_met;
 
2290
 
 
2291
 
 
2292
end:
 
2293
  if (commit_rate)
 
2294
    run_query(&con, NULL, "COMMIT", strlen("COMMIT"));
 
2295
 
 
2296
  slap_close(&con);
 
2297
 
 
2298
  pthread_mutex_lock(&counter_mutex);
 
2299
  thread_counter--;
 
2300
  pthread_cond_signal(&count_threshhold);
 
2301
  pthread_mutex_unlock(&counter_mutex);
 
2302
 
 
2303
  free(ctx);
 
2304
 
 
2305
  return(0);
 
2306
}
 
2307
 
 
2308
/*
 
2309
  Parse records from comma seperated string. : is a reserved character and is used for options
 
2310
  on variables.
 
2311
*/
 
2312
uint
 
2313
parse_option(const char *origin, option_string **stmt, char delm)
 
2314
{
 
2315
  char *string;
 
2316
  char *begin_ptr;
 
2317
  char *end_ptr;
 
2318
  option_string **sptr= stmt;
 
2319
  option_string *tmp;
 
2320
  uint32_t length= strlen(origin);
 
2321
  uint32_t count= 0; /* We know that there is always one */
 
2322
 
 
2323
  end_ptr= (char *)origin + length;
 
2324
 
 
2325
  tmp= *sptr= (option_string *)malloc(sizeof(option_string));
 
2326
  if (tmp == NULL)
 
2327
  {
 
2328
    fprintf(stderr,"Error allocating memory while parsing options\n");
 
2329
    exit(1);
 
2330
  }
 
2331
  memset(tmp, 0, sizeof(option_string));
 
2332
 
 
2333
  for (begin_ptr= (char *)origin;
 
2334
       begin_ptr != end_ptr;
 
2335
       tmp= tmp->next)
 
2336
  {
 
2337
    char buffer[HUGE_STRING_LENGTH];
 
2338
    char *buffer_ptr;
 
2339
 
 
2340
    memset(buffer, 0, HUGE_STRING_LENGTH);
 
2341
 
 
2342
    string= strchr(begin_ptr, delm);
 
2343
 
 
2344
    if (string)
 
2345
    {
 
2346
      memcpy(buffer, begin_ptr, string - begin_ptr);
 
2347
      begin_ptr= string+1;
 
2348
    }
 
2349
    else
 
2350
    {
 
2351
      size_t begin_len= strlen(begin_ptr);
 
2352
      memcpy(buffer, begin_ptr, begin_len);
 
2353
      begin_ptr= end_ptr;
 
2354
    }
 
2355
 
 
2356
    if ((buffer_ptr= strchr(buffer, ':')))
 
2357
    {
 
2358
      /* Set a null so that we can get strlen() correct later on */
 
2359
      buffer_ptr[0]= 0;
 
2360
      buffer_ptr++;
 
2361
 
 
2362
      /* Move past the : and the first string */
 
2363
      tmp->option_length= strlen(buffer_ptr);
 
2364
      tmp->option= (char *)malloc(tmp->option_length + 1);
 
2365
      if (tmp->option == NULL)
 
2366
      {
 
2367
        fprintf(stderr,"Error allocating memory while parsing options\n");
 
2368
        exit(1);
 
2369
      }
 
2370
      memcpy(tmp->option, buffer_ptr, tmp->option_length);
 
2371
      tmp->option[tmp->option_length]= 0; 
 
2372
    }
 
2373
 
 
2374
    tmp->length= strlen(buffer);
 
2375
    tmp->string= strdup(buffer);
 
2376
    if (tmp->string == NULL)
 
2377
    {
 
2378
      fprintf(stderr,"Error allocating memory while parsing options\n");
 
2379
      exit(1);
 
2380
    }
 
2381
 
 
2382
    if (isspace(*begin_ptr))
 
2383
      begin_ptr++;
 
2384
 
 
2385
    count++;
 
2386
 
 
2387
    if (begin_ptr != end_ptr)
 
2388
    {
 
2389
      tmp->next= (option_string *)malloc(sizeof(option_string));
 
2390
      if (tmp->next == NULL)
 
2391
      {
 
2392
        fprintf(stderr,"Error allocating memory while parsing options\n");
 
2393
        exit(1);
 
2394
      }
 
2395
      memset(tmp->next, 0, sizeof(option_string));
 
2396
    }
 
2397
    
 
2398
  }
 
2399
 
 
2400
  return count;
 
2401
}
 
2402
 
 
2403
 
 
2404
/*
 
2405
  Raw parsing interface. If you want the slap specific parser look at
 
2406
  parse_option.
 
2407
*/
 
2408
uint
 
2409
parse_delimiter(const char *script, statement **stmt, char delm)
 
2410
{
 
2411
  char *retstr;
 
2412
  char *ptr= (char *)script;
 
2413
  statement **sptr= stmt;
 
2414
  statement *tmp;
 
2415
  uint32_t length= strlen(script);
 
2416
  uint32_t count= 0; /* We know that there is always one */
 
2417
 
 
2418
  for (tmp= *sptr= (statement *)calloc(1, sizeof(statement));
 
2419
       (retstr= strchr(ptr, delm));
 
2420
       tmp->next=  (statement *)calloc(1, sizeof(statement)),
 
2421
       tmp= tmp->next)
 
2422
  {
 
2423
    if (tmp == NULL)
 
2424
    {
 
2425
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
 
2426
      exit(1);
 
2427
    }
 
2428
 
 
2429
    count++;
 
2430
    tmp->length= (size_t)(retstr - ptr);
 
2431
    tmp->string= (char *)malloc(tmp->length + 1);
 
2432
 
 
2433
    if (tmp->string == NULL)
 
2434
    {
 
2435
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
 
2436
      exit(1);
 
2437
    }
 
2438
 
 
2439
    memcpy(tmp->string, ptr, tmp->length);
 
2440
    tmp->string[tmp->length]= 0;
 
2441
    ptr+= retstr - ptr + 1;
 
2442
    if (isspace(*ptr))
 
2443
      ptr++;
 
2444
  }
 
2445
 
 
2446
  if (ptr != script+length)
 
2447
  {
 
2448
    tmp->length= (size_t)((script + length) - ptr);
 
2449
    tmp->string= (char *)malloc(tmp->length + 1);
 
2450
    if (tmp->string == NULL)
 
2451
    {
 
2452
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
 
2453
      exit(1);
 
2454
    }
 
2455
    memcpy(tmp->string, ptr, tmp->length);
 
2456
    tmp->string[tmp->length]= 0;
 
2457
    count++;
 
2458
  }
 
2459
 
 
2460
  return count;
 
2461
}
 
2462
 
 
2463
 
 
2464
/*
 
2465
  Parse comma is different from parse_delimeter in that it parses
 
2466
  number ranges from a comma seperated string.
 
2467
  In restrospect, this is a lousy name from this function.
 
2468
*/
 
2469
uint
 
2470
parse_comma(const char *string, uint32_t **range)
 
2471
{
 
2472
  unsigned int count= 1,x; /* We know that there is always one */
 
2473
  char *retstr;
 
2474
  char *ptr= (char *)string;
 
2475
  unsigned int *nptr;
 
2476
 
 
2477
  for (;*ptr; ptr++)
 
2478
    if (*ptr == ',') count++;
 
2479
 
 
2480
  /* One extra spot for the NULL */
 
2481
  nptr= *range= (uint32_t *)malloc(sizeof(unsigned int) * (count + 1));
 
2482
  memset(nptr, 0, sizeof(unsigned int) * (count + 1));
 
2483
 
 
2484
  ptr= (char *)string;
 
2485
  x= 0;
 
2486
  while ((retstr= strchr(ptr,',')))
 
2487
  {
 
2488
    nptr[x++]= atoi(ptr);
 
2489
    ptr+= retstr - ptr + 1;
 
2490
  }
 
2491
  nptr[x++]= atoi(ptr);
 
2492
 
 
2493
  return count;
 
2494
}
 
2495
 
 
2496
void
 
2497
print_conclusions(conclusions *con)
 
2498
{
 
2499
  printf("Benchmark\n");
 
2500
  if (con->engine)
 
2501
    printf("\tRunning for engine %s\n", con->engine);
 
2502
  if (opt_label || opt_auto_generate_sql_type)
 
2503
  {
 
2504
    const char *ptr= opt_auto_generate_sql_type ? opt_auto_generate_sql_type : "query";
 
2505
    printf("\tLoad: %s\n", opt_label ? opt_label : ptr);
 
2506
  }
 
2507
  printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
 
2508
         con->create_avg_timing / 1000, con->create_avg_timing % 1000);
 
2509
  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
 
2510
         con->avg_timing / 1000, con->avg_timing % 1000);
 
2511
  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
 
2512
         con->min_timing / 1000, con->min_timing % 1000);
 
2513
  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
 
2514
         con->max_timing / 1000, con->max_timing % 1000);
 
2515
  printf("\tTotal time for tests: %ld.%03ld seconds\n",
 
2516
         con->sum_of_time / 1000, con->sum_of_time % 1000);
 
2517
  printf("\tStandard Deviation: %ld.%03ld\n", con->std_dev / 1000, con->std_dev % 1000);
 
2518
  printf("\tNumber of queries in create queries: %"PRIu64"\n", con->create_count);
 
2519
  printf("\tNumber of clients running queries: %u/%u\n",
 
2520
         con->users, con->real_users);
 
2521
  printf("\tNumber of times test was run: %u\n", iterations);
 
2522
  printf("\tAverage number of queries per client: %"PRIu64"\n", con->avg_rows);
 
2523
  printf("\n");
 
2524
}
 
2525
 
 
2526
void
 
2527
print_conclusions_csv(conclusions *con)
 
2528
{
 
2529
  unsigned int x;
 
2530
  char buffer[HUGE_STRING_LENGTH];
 
2531
  char label_buffer[HUGE_STRING_LENGTH];
 
2532
  size_t string_len;
 
2533
 
 
2534
  memset(label_buffer, 0, HUGE_STRING_LENGTH);
 
2535
 
 
2536
  if (opt_label)
 
2537
  {
 
2538
    string_len= strlen(opt_label);
 
2539
 
 
2540
    for (x= 0; x < string_len; x++)
 
2541
    {
 
2542
      if (opt_label[x] == ',')
 
2543
        label_buffer[x]= '-';
 
2544
      else
 
2545
        label_buffer[x]= opt_label[x] ;
 
2546
    }
 
2547
  }
 
2548
  else if (opt_auto_generate_sql_type)
 
2549
  {
 
2550
    string_len= strlen(opt_auto_generate_sql_type);
 
2551
 
 
2552
    for (x= 0; x < string_len; x++)
 
2553
    {
 
2554
      if (opt_auto_generate_sql_type[x] == ',')
 
2555
        label_buffer[x]= '-';
 
2556
      else
 
2557
        label_buffer[x]= opt_auto_generate_sql_type[x] ;
 
2558
    }
 
2559
  }
 
2560
  else
 
2561
    snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
 
2562
 
 
2563
  snprintf(buffer, HUGE_STRING_LENGTH,
 
2564
           "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
 
2565
           "%u,%u,%u,%"PRIu64"\n",
 
2566
           con->engine ? con->engine : "", /* Storage engine we ran against */
 
2567
           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 */
 
2573
           iterations, /* Iterations */
 
2574
           con->users, /* Children used max_timing */
 
2575
           con->real_users, /* Children used max_timing */
 
2576
           con->avg_rows  /* Queries run */
 
2577
           );
 
2578
  internal::my_write(csv_file, (unsigned char*) buffer, (uint32_t)strlen(buffer), MYF(0));
 
2579
}
 
2580
 
 
2581
void
 
2582
generate_stats(conclusions *con, option_string *eng, stats *sptr)
 
2583
{
 
2584
  stats *ptr;
 
2585
  unsigned int x;
 
2586
 
 
2587
  con->min_timing= sptr->timing;
 
2588
  con->max_timing= sptr->timing;
 
2589
  con->min_rows= sptr->rows;
 
2590
  con->max_rows= sptr->rows;
 
2591
 
 
2592
  /* At the moment we assume uniform */
 
2593
  con->users= sptr->users;
 
2594
  con->real_users= sptr->real_users;
 
2595
  con->avg_rows= sptr->rows;
 
2596
 
 
2597
  /* With no next, we know it is the last element that was malloced */
 
2598
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
 
2599
  {
 
2600
    con->avg_timing+= ptr->timing;
 
2601
 
 
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;
 
2606
  }
 
2607
  con->sum_of_time= con->avg_timing;
 
2608
  con->avg_timing= con->avg_timing/iterations;
 
2609
 
 
2610
  if (eng && eng->string)
 
2611
    con->engine= eng->string;
 
2612
  else
 
2613
    con->engine= NULL;
 
2614
 
 
2615
  standard_deviation(con, sptr);
 
2616
 
 
2617
  /* Now we do the create time operations */
 
2618
  con->create_min_timing= sptr->create_timing;
 
2619
  con->create_max_timing= sptr->create_timing;
 
2620
 
 
2621
  /* At the moment we assume uniform */
 
2622
  con->create_count= sptr->create_count;
 
2623
 
 
2624
  /* With no next, we know it is the last element that was malloced */
 
2625
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
 
2626
  {
 
2627
    con->create_avg_timing+= ptr->create_timing;
 
2628
 
 
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;
 
2633
  }
 
2634
  con->create_avg_timing= con->create_avg_timing/iterations;
 
2635
}
 
2636
 
 
2637
void
 
2638
option_cleanup(option_string *stmt)
 
2639
{
 
2640
  option_string *ptr, *nptr;
 
2641
  if (!stmt)
 
2642
    return;
 
2643
 
 
2644
  for (ptr= stmt; ptr; ptr= nptr)
 
2645
  {
 
2646
    nptr= ptr->next;
 
2647
    if (ptr->string)
 
2648
      free(ptr->string);
 
2649
    if (ptr->option)
 
2650
      free(ptr->option);
 
2651
    free(ptr);
 
2652
  }
 
2653
}
 
2654
 
 
2655
void
 
2656
statement_cleanup(statement *stmt)
 
2657
{
 
2658
  statement *ptr, *nptr;
 
2659
  if (!stmt)
 
2660
    return;
 
2661
 
 
2662
  for (ptr= stmt; ptr; ptr= nptr)
 
2663
  {
 
2664
    nptr= ptr->next;
 
2665
    if (ptr->string)
 
2666
      free(ptr->string);
 
2667
    free(ptr);
 
2668
  }
 
2669
}
 
2670
 
 
2671
void
 
2672
slap_close(drizzle_con_st *con)
 
2673
{
 
2674
  if (opt_only_print)
 
2675
    return;
 
2676
 
 
2677
  drizzle_free(drizzle_con_drizzle(con));
 
2678
}
 
2679
 
 
2680
void
 
2681
slap_connect(drizzle_con_st *con, bool connect_to_schema)
 
2682
{
 
2683
  /* Connect to server */
 
2684
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
 
2685
  int x, connect_error= 1;
 
2686
  drizzle_return_t ret;
 
2687
  drizzle_st *drizzle;
 
2688
 
 
2689
  if (opt_only_print)
 
2690
    return;
 
2691
 
 
2692
  if (opt_delayed_start)
 
2693
    usleep(random()%opt_delayed_start);
 
2694
 
 
2695
  if ((drizzle= drizzle_create(NULL)) == NULL ||
 
2696
      drizzle_con_add_tcp(drizzle, con, host, opt_drizzle_port, user,
 
2697
                          opt_password,
 
2698
                          connect_to_schema ? create_schema_string : NULL,
 
2699
                          opt_mysql ? DRIZZLE_CON_MYSQL : DRIZZLE_CON_NONE) == NULL)
 
2700
  {
 
2701
    fprintf(stderr,"%s: Error creating drizzle object\n", internal::my_progname);
 
2702
    exit(1);
 
2703
  }
 
2704
 
 
2705
  for (x= 0; x < 10; x++)
 
2706
  {
 
2707
    if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
 
2708
    {
 
2709
      /* Connect suceeded */
 
2710
      connect_error= 0;
 
2711
      break;
 
2712
    }
 
2713
    usleep(connection_retry_sleep);
 
2714
  }
 
2715
  if (connect_error)
 
2716
  {
 
2717
    fprintf(stderr,"%s: Error when connecting to server: %d %s\n", internal::my_progname,
 
2718
            ret, drizzle_con_error(con));
 
2719
    exit(1);
 
2720
  }
 
2721
 
 
2722
  return;
 
2723
}
 
2724
 
 
2725
void
 
2726
standard_deviation (conclusions *con, stats *sptr)
 
2727
{
 
2728
  unsigned int x;
 
2729
  long int sum_of_squares;
 
2730
  double the_catch;
 
2731
  stats *ptr;
 
2732
 
 
2733
  if (iterations == 1 || iterations == 0)
 
2734
  {
 
2735
    con->std_dev= 0;
 
2736
    return;
 
2737
  }
 
2738
 
 
2739
  for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
 
2740
  {
 
2741
    long int deviation;
 
2742
 
 
2743
    deviation= ptr->timing - con->avg_timing;
 
2744
    sum_of_squares+= deviation*deviation;
 
2745
  }
 
2746
 
 
2747
  the_catch= sqrt((double)(sum_of_squares/(iterations -1)));
 
2748
  con->std_dev= (long int)the_catch;
 
2749
}