~xnox/ubuntu/saucy/drizzle/merge

« back to all changes in this revision

Viewing changes to .pc/boost-time-utc.patch/client/drizzleslap.cc

  • Committer: Dmitrijs Ledkovs
  • Date: 2013-07-17 01:13:45 UTC
  • mfrom: (2.1.18 sid)
  • Revision ID: dmitrijs.ledkovs@canonical.com-20130717011345-4rbneu4ti33ke12w
* Merge from debian, remaining changes:
  - Link against boost_system because of boost_thread.
* Fix "FTBFS: autoreconf: automake failed with exit status: 1" by fixing
  pandora (new patch pandora_fixforautomake1.13.patch) (Closes: #711199)
* Add Slovak po-debconf translation (Closes: #709089)
* Bump S-V, no changes required
* Overriding linitian error regarding embedded code copy (libjson) until
  upstream gives feedback/reasons about it
* Add verbosity to the build to make build log check compiler-flags-hidden
  happy
* New patch boost-1.49.patch due to a boost problem showed with gcc >4.7
  (Closes: #701269)
* Adding Japanese (Closes: #692842) and Brazilian (Closes: #685770)
  translations
* Do not build undocumented commands drizzle_passwordhash and
  drizzlebackup.innobase (no man pages are available.) This is handled
  in the new patches donotbuild_drizzlepasswordhash.patch and
  donotbuild_drizzlebackup.innobase.patch
* Switch from hardening-wrapper to dpkg-buildflags
* Add patch ftbfs-bison-2.7.patch to fix a FTBS with recent bison.
  (cherry-picked from upstream)
* Remove extra space in drizzle.init and prepare /var/run/drizzle
  (Closes: #678702)
* Building mysql-protocol-plugin and and mysql-socket-protocol-plugin
  (Closes: #678963)
* New patch: Changing default path for the mysql.socket to /var/run/drizzle
* Remove linitian warning regarding d/copyright.
* Targeting experimental during the freeze.

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) 2010 Vijay Samuel
5
 
 *  Copyright (C) 2008 MySQL
6
 
 *
7
 
 *  This program is free software; you can redistribute it and/or modify
8
 
 *  it under the terms of the GNU General Public License as published by
9
 
 *  the Free Software Foundation; either version 2 of the License, or
10
 
 *  (at your option) any later version.
11
 
 *
12
 
 *  This program is distributed in the hope that it will be useful,
13
 
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 
 *  GNU General Public License for more details.
16
 
 *
17
 
 *  You should have received a copy of the GNU General Public License
18
 
 *  along with this program; if not, write to the Free Software
19
 
 *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
20
 
 */
21
 
 
22
 
 
23
 
/*
24
 
  Drizzle Slap
25
 
 
26
 
  A simple program designed to work as if multiple clients querying the database,
27
 
  then reporting the timing of each stage.
28
 
 
29
 
  Drizzle slap runs three stages:
30
 
  1) Create schema,table, and optionally any SP or data you want to beign
31
 
  the test with. (single client)
32
 
  2) Load test (many clients)
33
 
  3) Cleanup (disconnection, drop table if specified, single client)
34
 
 
35
 
  Examples:
36
 
 
37
 
  Supply your own create and query SQL statements, with 50 clients
38
 
  querying (200 selects for each):
39
 
 
40
 
  drizzleslap --delimiter=";" \
41
 
  --create="CREATE TABLE A (a int);INSERT INTO A VALUES (23)" \
42
 
  --query="SELECT * FROM A" --concurrency=50 --iterations=200
43
 
 
44
 
  Let the program build the query SQL statement with a table of two int
45
 
  columns, three varchar columns, five clients querying (20 times each),
46
 
  don't create the table or insert the data (using the previous test's
47
 
  schema and data):
48
 
 
49
 
  drizzleslap --concurrency=5 --iterations=20 \
50
 
  --number-int-cols=2 --number-char-cols=3 \
51
 
  --auto-generate-sql
52
 
 
53
 
  Tell the program to load the create, insert and query SQL statements from
54
 
  the specified files, where the create.sql file has multiple table creation
55
 
  statements delimited by ';' and multiple insert statements delimited by ';'.
56
 
  The --query file will have multiple queries delimited by ';', run all the
57
 
  load statements, and then run all the queries in the query file
58
 
  with five clients (five times each):
59
 
 
60
 
  drizzleslap --concurrency=5 \
61
 
  --iterations=5 --query=query.sql --create=create.sql \
62
 
  --delimiter=";"
63
 
 
64
 
  @todo
65
 
  Add language for better tests
66
 
  String length for files and those put on the command line are not
67
 
  setup to handle binary data.
68
 
  More stats
69
 
  Break up tests and run them on multiple hosts at once.
70
 
  Allow output to be fed into a database directly.
71
 
 
72
 
*/
73
 
 
74
 
#include <config.h>
75
 
#include "client/client_priv.h"
76
 
 
77
 
#include "client/option_string.h"
78
 
#include "client/stats.h"
79
 
#include "client/thread_context.h"
80
 
#include "client/conclusions.h"
81
 
#include "client/wakeup.h"
82
 
 
83
 
#include <signal.h>
84
 
#include <stdarg.h>
85
 
#include <sys/types.h>
86
 
#include <sys/wait.h>
87
 
#ifdef HAVE_SYS_STAT_H
88
 
# include <sys/stat.h>
89
 
#endif
90
 
#include <fcntl.h>
91
 
#include <math.h>
92
 
#include <cassert>
93
 
#include <cstdlib>
94
 
#include <string>
95
 
#include <iostream>
96
 
#include <fstream>
97
 
#include <drizzled/configmake.h>
98
 
#include <memory>
99
 
 
100
 
/* Added this for string translation. */
101
 
#include <drizzled/gettext.h>
102
 
 
103
 
#include <boost/algorithm/string.hpp>
104
 
#include <boost/thread.hpp>
105
 
#include <boost/thread/mutex.hpp>
106
 
#include <boost/thread/condition_variable.hpp>
107
 
#include <boost/program_options.hpp>
108
 
#include <boost/scoped_ptr.hpp>
109
 
#include <drizzled/atomics.h>
110
 
 
111
 
#define SLAP_NAME "drizzleslap"
112
 
#define SLAP_VERSION "1.5"
113
 
 
114
 
#define HUGE_STRING_LENGTH 8196
115
 
#define RAND_STRING_SIZE 126
116
 
#define DEFAULT_BLOB_SIZE 1024
117
 
 
118
 
using namespace std;
119
 
using namespace drizzled;
120
 
namespace po= boost::program_options;
121
 
 
122
 
#ifdef HAVE_SMEM
123
 
static char *shared_memory_base_name=0;
124
 
#endif
125
 
 
126
 
client::Wakeup master_wakeup;
127
 
 
128
 
/* Global Thread timer */
129
 
static bool timer_alarm= false;
130
 
boost::mutex timer_alarm_mutex;
131
 
boost::condition_variable_any timer_alarm_threshold;
132
 
 
133
 
std::vector < std::string > primary_keys;
134
 
 
135
 
drizzled::atomic<size_t> connection_count;
136
 
drizzled::atomic<uint64_t> failed_update_for_transaction;
137
 
 
138
 
static string host, 
139
 
  opt_password, 
140
 
  user,
141
 
  user_supplied_query,
142
 
  user_supplied_pre_statements,
143
 
  user_supplied_post_statements,
144
 
  default_engine,
145
 
  pre_system,
146
 
  post_system;
147
 
 
148
 
static vector<string> user_supplied_queries;
149
 
static string opt_verbose;
150
 
std::string opt_protocol;
151
 
string delimiter;
152
 
 
153
 
string create_schema_string;
154
 
 
155
 
static bool use_drizzle_protocol= false;
156
 
static bool opt_preserve= true;
157
 
static bool opt_only_print;
158
 
static bool opt_burnin;
159
 
static bool opt_ignore_sql_errors= false;
160
 
static bool opt_silent,
161
 
  auto_generate_sql_autoincrement,
162
 
  auto_generate_sql_guid_primary,
163
 
  auto_generate_sql;
164
 
std::string opt_auto_generate_sql_type;
165
 
 
166
 
static int32_t verbose= 0;
167
 
static uint32_t delimiter_length;
168
 
static uint32_t commit_rate;
169
 
static uint32_t detach_rate;
170
 
static uint32_t opt_timer_length;
171
 
static uint32_t opt_delayed_start;
172
 
string num_blob_cols_opt,
173
 
  num_char_cols_opt,
174
 
  num_int_cols_opt;
175
 
string opt_label;
176
 
static uint32_t opt_set_random_seed;
177
 
 
178
 
string auto_generate_selected_columns_opt;
179
 
 
180
 
/* Yes, we do set defaults here */
181
 
static uint32_t num_int_cols= 1;
182
 
static uint32_t num_char_cols= 1;
183
 
static uint32_t num_blob_cols= 0;
184
 
static uint32_t num_blob_cols_size;
185
 
static uint32_t num_blob_cols_size_min;
186
 
static uint32_t num_int_cols_index= 0;
187
 
static uint32_t num_char_cols_index= 0;
188
 
static uint32_t iterations;
189
 
static uint64_t actual_queries= 0;
190
 
static uint64_t auto_actual_queries;
191
 
static uint64_t auto_generate_sql_unique_write_number;
192
 
static uint64_t auto_generate_sql_unique_query_number;
193
 
static uint32_t auto_generate_sql_secondary_indexes;
194
 
static uint64_t num_of_query;
195
 
static uint64_t auto_generate_sql_number;
196
 
string concurrency_str;
197
 
string create_string;
198
 
std::vector <uint32_t> concurrency;
199
 
 
200
 
std::string opt_csv_str;
201
 
int csv_file;
202
 
 
203
 
static int process_options(void);
204
 
static uint32_t opt_drizzle_port= 0;
205
 
 
206
 
static OptionString *engine_options= NULL;
207
 
static OptionString *query_options= NULL;
208
 
static Statement *pre_statements= NULL;
209
 
static Statement *post_statements= NULL;
210
 
static Statement *create_statements= NULL;
211
 
 
212
 
static std::vector <Statement *> query_statements;
213
 
static uint32_t query_statements_count;
214
 
 
215
 
 
216
 
/* Prototypes */
217
 
void print_conclusions(Conclusions &con);
218
 
void print_conclusions_csv(Conclusions &con);
219
 
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr);
220
 
uint32_t parse_comma(const char *string, std::vector <uint32_t> &range);
221
 
uint32_t parse_delimiter(const char *script, Statement **stmt, char delm);
222
 
uint32_t parse_option(const char *origin, OptionString **stmt, char delm);
223
 
static void drop_schema(drizzle_con_st &con, const char *db);
224
 
uint32_t get_random_string(char *buf, size_t size);
225
 
static Statement *build_table_string(void);
226
 
static Statement *build_insert_string(void);
227
 
static Statement *build_update_string(void);
228
 
static Statement * build_select_string(bool key);
229
 
static int generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt);
230
 
static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr);
231
 
static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit);
232
 
void statement_cleanup(Statement *stmt);
233
 
void option_cleanup(OptionString *stmt);
234
 
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr);
235
 
static void run_statements(drizzle_con_st &con, Statement *stmt);
236
 
drizzle_con_st *slap_connect(bool connect_to_schema);
237
 
void slap_close(drizzle_con_st *con);
238
 
static int run_query(drizzle_con_st &con, drizzle_result_st *result, const char *query, int len);
239
 
void standard_deviation(Conclusions &con, Stats *sptr);
240
 
 
241
 
static const char ALPHANUMERICS[]=
242
 
"0123456789ABCDEFGHIJKLMNOPQRSTWXYZabcdefghijklmnopqrstuvwxyz";
243
 
 
244
 
#define ALPHANUMERICS_SIZE (sizeof(ALPHANUMERICS)-1)
245
 
 
246
 
 
247
 
static long int timedif(struct timeval a, struct timeval b)
248
 
{
249
 
  int us, s;
250
 
 
251
 
  us = a.tv_usec - b.tv_usec;
252
 
  us /= 1000;
253
 
  s = a.tv_sec - b.tv_sec;
254
 
  s *= 1000;
255
 
  return s + us;
256
 
}
257
 
 
258
 
static void combine_queries(vector<string> queries)
259
 
{
260
 
  user_supplied_query.erase();
261
 
  for (vector<string>::iterator it= queries.begin();
262
 
       it != queries.end();
263
 
       ++it)
264
 
  {
265
 
    user_supplied_query.append(*it);
266
 
    user_supplied_query.append(delimiter);
267
 
  }
268
 
}
269
 
 
270
 
 
271
 
static void run_task(ThreadContext *ctx)
272
 
{
273
 
  uint64_t counter= 0, queries;
274
 
  uint64_t detach_counter;
275
 
  uint32_t commit_counter;
276
 
  drizzle_result_st result;
277
 
  drizzle_row_t row;
278
 
  Statement *ptr;
279
 
 
280
 
  master_wakeup.wait();
281
 
 
282
 
  drizzle_con_st *con= slap_connect(true);
283
 
 
284
 
  if (verbose >= 3)
285
 
  {
286
 
    printf("connected!\n");
287
 
  }
288
 
  queries= 0;
289
 
 
290
 
  commit_counter= 0;
291
 
  if (commit_rate)
292
 
  {
293
 
    run_query(*con, NULL, "SET AUTOCOMMIT=0", strlen("SET AUTOCOMMIT=0"));
294
 
  }
295
 
 
296
 
limit_not_met:
297
 
  for (ptr= ctx->getStmt(), detach_counter= 0;
298
 
       ptr && ptr->getLength();
299
 
       ptr= ptr->getNext(), detach_counter++)
300
 
  {
301
 
    if (not opt_only_print && detach_rate && !(detach_counter % detach_rate))
302
 
    {
303
 
      slap_close(con);
304
 
      con= slap_connect(true);
305
 
    }
306
 
 
307
 
    /*
308
 
      We have to execute differently based on query type. This should become a function.
309
 
    */
310
 
    bool is_failed_update= false;
311
 
    if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) ||
312
 
        (ptr->getType() == SELECT_TYPE_REQUIRES_PREFIX))
313
 
    {
314
 
      uint32_t key_val;
315
 
      char buffer[HUGE_STRING_LENGTH];
316
 
 
317
 
      /*
318
 
        This should only happen if some sort of new engine was
319
 
        implemented that didn't properly handle UPDATEs.
320
 
 
321
 
        Just in case someone runs this under an experimental engine we don't
322
 
        want a crash so the if() is placed here.
323
 
      */
324
 
      assert(primary_keys.size());
325
 
      if (primary_keys.size())
326
 
      {
327
 
        key_val= (uint32_t)(random() % primary_keys.size());
328
 
        const char *key= primary_keys[key_val].c_str();
329
 
 
330
 
        assert(key);
331
 
 
332
 
        int length= snprintf(buffer, HUGE_STRING_LENGTH, "%.*s '%s'", (int)ptr->getLength(), ptr->getString(), key);
333
 
 
334
 
        if (run_query(*con, &result, buffer, length))
335
 
        {
336
 
          if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
337
 
          {
338
 
            // Expand to check to see if Innodb, if so we should restart the
339
 
            // transaction.  
340
 
 
341
 
            is_failed_update= true;
342
 
            failed_update_for_transaction.fetch_and_increment();
343
 
          }
344
 
          else
345
 
          {
346
 
            fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
347
 
                    SLAP_NAME, (uint32_t)length, buffer, drizzle_con_error(con));
348
 
            abort();
349
 
          }
350
 
        }
351
 
      }
352
 
    }
353
 
    else
354
 
    {
355
 
      if (run_query(*con, &result, ptr->getString(), ptr->getLength()))
356
 
      {
357
 
        if ((ptr->getType() == UPDATE_TYPE_REQUIRES_PREFIX) and commit_rate)
358
 
        {
359
 
          // Expand to check to see if Innodb, if so we should restart the
360
 
          // transaction.
361
 
 
362
 
          is_failed_update= true;
363
 
          failed_update_for_transaction.fetch_and_increment();
364
 
        }
365
 
        else
366
 
        {
367
 
          fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
368
 
                  SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(con));
369
 
          abort();
370
 
        }
371
 
      }
372
 
    }
373
 
 
374
 
    if (not opt_only_print and not is_failed_update)
375
 
    {
376
 
      while ((row = drizzle_row_next(&result)))
377
 
        counter++;
378
 
      drizzle_result_free(&result);
379
 
    }
380
 
    queries++;
381
 
 
382
 
    if (commit_rate && (++commit_counter == commit_rate) and not is_failed_update)
383
 
    {
384
 
      commit_counter= 0;
385
 
      run_query(*con, NULL, "COMMIT", strlen("COMMIT"));
386
 
    }
387
 
 
388
 
    /* If the timer is set, and the alarm is not active then end */
389
 
    if (opt_timer_length && timer_alarm == false)
390
 
      goto end;
391
 
 
392
 
    /* If limit has been reached, and we are not in a timer_alarm just end */
393
 
    if (ctx->getLimit() && queries == ctx->getLimit() && timer_alarm == false)
394
 
      goto end;
395
 
  }
396
 
 
397
 
  if (opt_timer_length && timer_alarm == true)
398
 
    goto limit_not_met;
399
 
 
400
 
  if (ctx->getLimit() && queries < ctx->getLimit())
401
 
    goto limit_not_met;
402
 
 
403
 
 
404
 
end:
405
 
  if (commit_rate)
406
 
  {
407
 
    run_query(*con, NULL, "COMMIT", strlen("COMMIT"));
408
 
  }
409
 
 
410
 
  slap_close(con);
411
 
  con= NULL;
412
 
 
413
 
  delete ctx;
414
 
}
415
 
 
416
 
/**
417
 
 * commandline_options is the set of all options that can only be called via the command line.
418
 
 
419
 
 * client_options is the set of all options that can be defined via both command line and via
420
 
 * the configuration file client.cnf
421
 
 
422
 
 * slap_options is the set of all drizzleslap specific options which behave in a manner 
423
 
 * similar to that of client_options. It's configuration file is drizzleslap.cnf
424
 
 
425
 
 * long_options is the union of commandline_options, slap_options and client_options.
426
 
 
427
 
 * There are two configuration files per set of options, one which is defined by the user
428
 
 * which is found at either $XDG_CONFIG_HOME/drizzle or ~/.config/drizzle directory and the other which 
429
 
 * is the system configuration file which is found in the SYSCONFDIR/drizzle directory.
430
 
 
431
 
 * The system configuration file is over ridden by the user's configuration file which
432
 
 * in turn is over ridden by the command line.
433
 
 */
434
 
int main(int argc, char **argv)
435
 
{
436
 
  char *password= NULL;
437
 
  try
438
 
  {
439
 
    po::options_description commandline_options("Options used only in command line");
440
 
    commandline_options.add_options()
441
 
      ("help,?","Display this help and exit")
442
 
      ("info","Gives information and exit")
443
 
      ("burnin",po::value<bool>(&opt_burnin)->default_value(false)->zero_tokens(),
444
 
       "Run full test case in infinite loop")
445
 
      ("ignore-sql-errors", po::value<bool>(&opt_ignore_sql_errors)->default_value(false)->zero_tokens(),
446
 
       "Ignore SQL errors in query run")
447
 
      ("create-schema",po::value<string>(&create_schema_string)->default_value("drizzleslap"),
448
 
       "Schema to run tests in")
449
 
      ("create",po::value<string>(&create_string)->default_value(""),
450
 
       "File or string to use to create tables")
451
 
      ("detach",po::value<uint32_t>(&detach_rate)->default_value(0),
452
 
       "Detach (close and re open) connections after X number of requests")
453
 
      ("iterations,i",po::value<uint32_t>(&iterations)->default_value(1),
454
 
       "Number of times to run the tests")
455
 
      ("label",po::value<string>(&opt_label)->default_value(""),
456
 
       "Label to use for print and csv")
457
 
      ("number-blob-cols",po::value<string>(&num_blob_cols_opt)->default_value(""),
458
 
       "Number of BLOB columns to create table with if specifying --auto-generate-sql. Example --number-blob-cols=3:1024/2048 would give you 3 blobs with a random size between 1024 and 2048. ")
459
 
      ("number-char-cols,x",po::value<string>(&num_char_cols_opt)->default_value(""),
460
 
       "Number of VARCHAR columns to create in table if specifying --auto-generate-sql.")
461
 
      ("number-int-cols,y",po::value<string>(&num_int_cols_opt)->default_value(""),
462
 
       "Number of INT columns to create in table if specifying --auto-generate-sql.")
463
 
      ("number-of-queries",
464
 
       po::value<uint64_t>(&num_of_query)->default_value(0),
465
 
       "Limit each client to this number of queries(this is not exact)") 
466
 
      ("only-print",po::value<bool>(&opt_only_print)->default_value(false)->zero_tokens(),
467
 
       "This causes drizzleslap to not connect to the database instead print out what it would have done instead")
468
 
      ("post-query", po::value<string>(&user_supplied_post_statements)->default_value(""),
469
 
       "Query to run or file containing query to execute after tests have completed.")
470
 
      ("post-system",po::value<string>(&post_system)->default_value(""),
471
 
       "system() string to execute after tests have completed")
472
 
      ("pre-query",
473
 
       po::value<string>(&user_supplied_pre_statements)->default_value(""),
474
 
       "Query to run or file containing query to execute before running tests.")
475
 
      ("pre-system",po::value<string>(&pre_system)->default_value(""),
476
 
       "system() string to execute before running tests.")
477
 
      ("query,q",po::value<vector<string> >(&user_supplied_queries)->composing()->notifier(&combine_queries),
478
 
       "Query to run or file containing query")
479
 
      ("verbose,v", po::value<string>(&opt_verbose)->default_value("v"), "Increase verbosity level by one.")
480
 
      ("version,V","Output version information and exit") 
481
 
      ;
482
 
 
483
 
    po::options_description slap_options("Options specific to drizzleslap");
484
 
    slap_options.add_options()
485
 
      ("auto-generate-sql-select-columns",
486
 
       po::value<string>(&auto_generate_selected_columns_opt)->default_value(""),
487
 
       "Provide a string to use for the select fields used in auto tests")
488
 
      ("auto-generate-sql,a",po::value<bool>(&auto_generate_sql)->default_value(false)->zero_tokens(),
489
 
       "Generate SQL where not supplied by file or command line")  
490
 
      ("auto-generate-sql-add-autoincrement",
491
 
       po::value<bool>(&auto_generate_sql_autoincrement)->default_value(false)->zero_tokens(),
492
 
       "Add an AUTO_INCREMENT column to auto-generated tables")
493
 
      ("auto-generate-sql-execute-number",
494
 
       po::value<uint64_t>(&auto_actual_queries)->default_value(0),
495
 
       "See this number and generate a set of queries to run")
496
 
      ("auto-generate-sql-guid-primary",
497
 
       po::value<bool>(&auto_generate_sql_guid_primary)->default_value(false)->zero_tokens(),
498
 
       "Add GUID based primary keys to auto-generated tables")
499
 
      ("auto-generate-sql-load-type",
500
 
       po::value<string>(&opt_auto_generate_sql_type)->default_value("mixed"),
501
 
       "Specify test load type: mixed, update, write, key or read; default is mixed")  
502
 
      ("auto-generate-sql-secondary-indexes",
503
 
       po::value<uint32_t>(&auto_generate_sql_secondary_indexes)->default_value(0),
504
 
       "Number of secondary indexes to add to auto-generated tables")
505
 
      ("auto-generated-sql-unique-query-number",
506
 
       po::value<uint64_t>(&auto_generate_sql_unique_query_number)->default_value(10),
507
 
       "Number of unique queries to generate for automatic tests")
508
 
      ("auto-generate-sql-unique-write-number",
509
 
       po::value<uint64_t>(&auto_generate_sql_unique_write_number)->default_value(10),
510
 
       "Number of unique queries to generate for auto-generate-sql-write-number")
511
 
      ("auto-generate-sql-write-number",
512
 
       po::value<uint64_t>(&auto_generate_sql_number)->default_value(100),
513
 
       "Number of row inserts to perform for each thread (default is 100).")
514
 
      ("commit",po::value<uint32_t>(&commit_rate)->default_value(0),
515
 
       "Commit records every X number of statements")
516
 
      ("concurrency,c",po::value<string>(&concurrency_str)->default_value(""),
517
 
       "Number of clients to simulate for query to run")
518
 
      ("csv",po::value<std::string>(&opt_csv_str)->default_value(""),
519
 
       "Generate CSV output to named file or to stdout if no file is name.")
520
 
      ("delayed-start",po::value<uint32_t>(&opt_delayed_start)->default_value(0),
521
 
       "Delay the startup of threads by a random number of microsends (the maximum of the delay")
522
 
      ("delimiter,F",po::value<string>(&delimiter)->default_value("\n"),
523
 
       "Delimiter to use in SQL statements supplied in file or command line")
524
 
      ("engine,e",po::value<string>(&default_engine)->default_value(""),
525
 
       "Storage engine to use for creating the table")
526
 
      ("set-random-seed",
527
 
       po::value<uint32_t>(&opt_set_random_seed)->default_value(0), 
528
 
       "Seed for random number generator (srandom(3)) ") 
529
 
      ("silent,s",po::value<bool>(&opt_silent)->default_value(false)->zero_tokens(),
530
 
       "Run program in silent mode - no output. ") 
531
 
      ("timer-length",po::value<uint32_t>(&opt_timer_length)->default_value(0),
532
 
       "Require drizzleslap to run each specific test a certain amount of time in seconds")  
533
 
      ;
534
 
 
535
 
    po::options_description client_options("Options specific to the client");
536
 
    client_options.add_options()
537
 
      ("host,h",po::value<string>(&host)->default_value("localhost"),"Connect to the host")
538
 
      ("password,P",po::value<char *>(&password),
539
 
       "Password to use when connecting to server. If password is not given it's asked from the tty")
540
 
      ("port,p",po::value<uint32_t>(), "Port number to use for connection")
541
 
      ("protocol",po::value<string>(&opt_protocol)->default_value("mysql"),
542
 
       "The protocol of connection (mysql or drizzle).")
543
 
      ("user,u",po::value<string>(&user)->default_value(""),
544
 
       "User for login if not current user")  
545
 
      ;
546
 
 
547
 
    po::options_description long_options("Allowed Options");
548
 
    long_options.add(commandline_options).add(slap_options).add(client_options);
549
 
 
550
 
    std::string system_config_dir_slap(SYSCONFDIR); 
551
 
    system_config_dir_slap.append("/drizzle/drizzleslap.cnf");
552
 
 
553
 
    std::string system_config_dir_client(SYSCONFDIR); 
554
 
    system_config_dir_client.append("/drizzle/client.cnf");
555
 
 
556
 
    std::string user_config_dir((getenv("XDG_CONFIG_HOME")? getenv("XDG_CONFIG_HOME"):"~/.config"));
557
 
 
558
 
    if (user_config_dir.compare(0, 2, "~/") == 0)
559
 
    {
560
 
      char *homedir;
561
 
      homedir= getenv("HOME");
562
 
      if (homedir != NULL)
563
 
        user_config_dir.replace(0, 1, homedir);
564
 
    }
565
 
 
566
 
    uint64_t temp_drizzle_port= 0;
567
 
    boost::scoped_ptr<drizzle_con_st> con_ap(new drizzle_con_st);
568
 
    OptionString *eptr;
569
 
 
570
 
    // Disable allow_guessing
571
 
    int style = po::command_line_style::default_style & ~po::command_line_style::allow_guessing;
572
 
 
573
 
    po::variables_map vm;
574
 
    po::store(po::command_line_parser(argc, argv).options(long_options).
575
 
              style(style).extra_parser(parse_password_arg).run(), vm);
576
 
 
577
 
    std::string user_config_dir_slap(user_config_dir);
578
 
    user_config_dir_slap.append("/drizzle/drizzleslap.cnf"); 
579
 
 
580
 
    std::string user_config_dir_client(user_config_dir);
581
 
    user_config_dir_client.append("/drizzle/client.cnf");
582
 
 
583
 
    ifstream user_slap_ifs(user_config_dir_slap.c_str());
584
 
    po::store(parse_config_file(user_slap_ifs, slap_options), vm);
585
 
 
586
 
    ifstream user_client_ifs(user_config_dir_client.c_str());
587
 
    po::store(parse_config_file(user_client_ifs, client_options), vm);
588
 
 
589
 
    ifstream system_slap_ifs(system_config_dir_slap.c_str());
590
 
    store(parse_config_file(system_slap_ifs, slap_options), vm);
591
 
 
592
 
    ifstream system_client_ifs(system_config_dir_client.c_str());
593
 
    store(parse_config_file(system_client_ifs, client_options), vm);
594
 
 
595
 
    po::notify(vm);
596
 
 
597
 
    if (process_options())
598
 
      abort();
599
 
 
600
 
    if ( vm.count("help") || vm.count("info"))
601
 
    {
602
 
      printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
603
 
          drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
604
 
      puts("Copyright (C) 2008 Sun Microsystems");
605
 
      puts("This software comes with ABSOLUTELY NO WARRANTY. "
606
 
           "This is free software,\n"
607
 
           "and you are welcome to modify and redistribute it under the GPL "
608
 
           "license\n");
609
 
      puts("Run a query multiple times against the server\n");
610
 
      cout << long_options << endl;
611
 
      abort();
612
 
    }   
613
 
 
614
 
    if (vm.count("protocol"))
615
 
    {
616
 
      boost::to_lower(opt_protocol);
617
 
      if (not opt_protocol.compare("mysql"))
618
 
        use_drizzle_protocol=false;
619
 
      else if (not opt_protocol.compare("drizzle"))
620
 
        use_drizzle_protocol=true;
621
 
      else
622
 
      {
623
 
        cout << _("Error: Unknown protocol") << " '" << opt_protocol << "'" << endl;
624
 
        abort();
625
 
      }
626
 
    }
627
 
    if (vm.count("port")) 
628
 
    {
629
 
      temp_drizzle_port= vm["port"].as<uint32_t>();
630
 
 
631
 
      if ((temp_drizzle_port == 0) || (temp_drizzle_port > 65535))
632
 
      {
633
 
        fprintf(stderr, _("Value supplied for port is not valid.\n"));
634
 
        abort();
635
 
      }
636
 
      else
637
 
      {
638
 
        opt_drizzle_port= (uint32_t) temp_drizzle_port;
639
 
      }
640
 
    }
641
 
 
642
 
  if ( vm.count("password") )
643
 
  {
644
 
    if (not opt_password.empty())
645
 
      opt_password.erase();
646
 
    if (password == PASSWORD_SENTINEL)
647
 
    {
648
 
      opt_password= "";
649
 
    }
650
 
    else
651
 
    {
652
 
      opt_password= password;
653
 
      tty_password= false;
654
 
    }
655
 
  }
656
 
  else
657
 
  {
658
 
      tty_password= true;
659
 
  }
660
 
 
661
 
 
662
 
 
663
 
    if ( vm.count("version") )
664
 
    {
665
 
      printf("%s  Ver %s Distrib %s, for %s-%s (%s)\n",SLAP_NAME, SLAP_VERSION,
666
 
          drizzle_version(),HOST_VENDOR,HOST_OS,HOST_CPU);
667
 
      abort();
668
 
    }
669
 
 
670
 
    /* Seed the random number generator if we will be using it. */
671
 
    if (auto_generate_sql)
672
 
    {
673
 
      if (opt_set_random_seed == 0)
674
 
        opt_set_random_seed= (uint32_t)time(NULL);
675
 
      srandom(opt_set_random_seed);
676
 
    }
677
 
 
678
 
    /* globals? Yes, so we only have to run strlen once */
679
 
    delimiter_length= delimiter.length();
680
 
 
681
 
    drizzle_con_st *con= slap_connect(false);
682
 
 
683
 
    /* Main iterations loop */
684
 
burnin:
685
 
    eptr= engine_options;
686
 
    do
687
 
    {
688
 
      /* For the final stage we run whatever queries we were asked to run */
689
 
      uint32_t *current;
690
 
 
691
 
      if (verbose >= 2)
692
 
        printf("Starting Concurrency Test\n");
693
 
 
694
 
      if (concurrency.size())
695
 
      {
696
 
        for (current= &concurrency[0]; current && *current; current++)
697
 
          concurrency_loop(*con, *current, eptr);
698
 
      }
699
 
      else
700
 
      {
701
 
        uint32_t infinite= 1;
702
 
        do {
703
 
          concurrency_loop(*con, infinite, eptr);
704
 
        }
705
 
        while (infinite++);
706
 
      }
707
 
 
708
 
      if (not opt_preserve)
709
 
        drop_schema(*con, create_schema_string.c_str());
710
 
 
711
 
    } while (eptr ? (eptr= eptr->getNext()) : 0);
712
 
 
713
 
    if (opt_burnin)
714
 
    {
715
 
      goto burnin;
716
 
    }
717
 
 
718
 
    slap_close(con);
719
 
 
720
 
    /* now free all the strings we created */
721
 
    if (not opt_password.empty())
722
 
      opt_password.erase();
723
 
 
724
 
    concurrency.clear();
725
 
 
726
 
    statement_cleanup(create_statements);
727
 
    for (uint32_t x= 0; x < query_statements_count; x++)
728
 
      statement_cleanup(query_statements[x]);
729
 
    query_statements.clear();
730
 
    statement_cleanup(pre_statements);
731
 
    statement_cleanup(post_statements);
732
 
    option_cleanup(engine_options);
733
 
    option_cleanup(query_options);
734
 
 
735
 
#ifdef HAVE_SMEM
736
 
    free(shared_memory_base_name);
737
 
#endif
738
 
 
739
 
  }
740
 
 
741
 
  catch(std::exception &err)
742
 
  {
743
 
    cerr<<"Error:"<<err.what()<<endl;
744
 
  }
745
 
 
746
 
  if (csv_file != fileno(stdout))
747
 
    close(csv_file);
748
 
 
749
 
  return 0;
750
 
}
751
 
 
752
 
void concurrency_loop(drizzle_con_st &con, uint32_t current, OptionString *eptr)
753
 
{
754
 
  Stats *head_sptr;
755
 
  Stats *sptr;
756
 
  Conclusions conclusion;
757
 
  uint64_t client_limit;
758
 
 
759
 
  head_sptr= new Stats[iterations];
760
 
  if (head_sptr == NULL)
761
 
  {
762
 
    fprintf(stderr,"Error allocating memory in concurrency_loop\n");
763
 
    abort();
764
 
  }
765
 
 
766
 
  if (auto_actual_queries)
767
 
    client_limit= auto_actual_queries;
768
 
  else if (num_of_query)
769
 
    client_limit=  num_of_query / current;
770
 
  else
771
 
    client_limit= actual_queries;
772
 
 
773
 
  uint32_t x;
774
 
  for (x= 0, sptr= head_sptr; x < iterations; x++, sptr++)
775
 
  {
776
 
    /*
777
 
      We might not want to load any data, such as when we are calling
778
 
      a stored_procedure that doesn't use data, or we know we already have
779
 
      data in the table.
780
 
    */
781
 
    if (opt_preserve == false)
782
 
      drop_schema(con, create_schema_string.c_str());
783
 
 
784
 
    /* First we create */
785
 
    if (create_statements)
786
 
      create_schema(con, create_schema_string.c_str(), create_statements, eptr, sptr);
787
 
 
788
 
    /*
789
 
      If we generated GUID we need to build a list of them from creation that
790
 
      we can later use.
791
 
    */
792
 
    if (verbose >= 2)
793
 
      printf("Generating primary key list\n");
794
 
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
795
 
      generate_primary_key_list(con, eptr);
796
 
 
797
 
    if (not pre_system.empty())
798
 
    {
799
 
      int ret= system(pre_system.c_str());
800
 
      assert(ret != -1);
801
 
    }
802
 
 
803
 
    /*
804
 
      Pre statements are always run after all other logic so they can
805
 
      correct/adjust any item that they want.
806
 
    */
807
 
    if (pre_statements)
808
 
      run_statements(con, pre_statements);
809
 
 
810
 
    run_scheduler(sptr, &query_statements[0], current, client_limit);
811
 
 
812
 
    if (post_statements)
813
 
      run_statements(con, post_statements);
814
 
 
815
 
    if (not post_system.empty())
816
 
    {
817
 
      int ret=  system(post_system.c_str());
818
 
      assert(ret !=-1);
819
 
    }
820
 
 
821
 
    /* We are finished with this run */
822
 
    if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
823
 
      primary_keys.clear();
824
 
  }
825
 
 
826
 
  if (verbose >= 2)
827
 
    printf("Generating stats\n");
828
 
 
829
 
  generate_stats(&conclusion, eptr, head_sptr);
830
 
 
831
 
  if (not opt_silent)
832
 
    print_conclusions(conclusion);
833
 
  if (not opt_csv_str.empty())
834
 
    print_conclusions_csv(conclusion);
835
 
 
836
 
  delete[] head_sptr;
837
 
}
838
 
 
839
 
 
840
 
uint32_t get_random_string(char *buf, size_t size)
841
 
{
842
 
  char *buf_ptr= buf;
843
 
 
844
 
  for (size_t x= size; x > 0; x--)
845
 
    *buf_ptr++= ALPHANUMERICS[random() % ALPHANUMERICS_SIZE];
846
 
  return(buf_ptr - buf);
847
 
}
848
 
 
849
 
 
850
 
/*
851
 
  build_table_string
852
 
 
853
 
  This function builds a create table query if the user opts to not supply
854
 
  a file or string containing a create table statement
855
 
*/
856
 
static Statement *
857
 
build_table_string(void)
858
 
{
859
 
  char       buf[HUGE_STRING_LENGTH];
860
 
  uint32_t        col_count;
861
 
  Statement *ptr;
862
 
  string table_string;
863
 
 
864
 
  table_string.reserve(HUGE_STRING_LENGTH);
865
 
 
866
 
  table_string= "CREATE TABLE `t1` (";
867
 
 
868
 
  if (auto_generate_sql_autoincrement)
869
 
  {
870
 
    table_string.append("id serial");
871
 
 
872
 
    if (num_int_cols || num_char_cols)
873
 
      table_string.append(",");
874
 
  }
875
 
 
876
 
  if (auto_generate_sql_guid_primary)
877
 
  {
878
 
    table_string.append("id varchar(128) primary key");
879
 
 
880
 
    if (num_int_cols || num_char_cols || auto_generate_sql_guid_primary)
881
 
      table_string.append(",");
882
 
  }
883
 
 
884
 
  if (auto_generate_sql_secondary_indexes)
885
 
  {
886
 
    for (uint32_t count= 0; count < auto_generate_sql_secondary_indexes; count++)
887
 
    {
888
 
      if (count) /* Except for the first pass we add a comma */
889
 
        table_string.append(",");
890
 
 
891
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "id%d varchar(32) unique key", count)
892
 
          > HUGE_STRING_LENGTH)
893
 
      {
894
 
        fprintf(stderr, "Memory Allocation error in create table\n");
895
 
        abort();
896
 
      }
897
 
      table_string.append(buf);
898
 
    }
899
 
 
900
 
    if (num_int_cols || num_char_cols)
901
 
      table_string.append(",");
902
 
  }
903
 
 
904
 
  if (num_int_cols)
905
 
    for (col_count= 1; col_count <= num_int_cols; col_count++)
906
 
    {
907
 
      if (num_int_cols_index)
908
 
      {
909
 
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT, INDEX(intcol%d)",
910
 
                     col_count, col_count) > HUGE_STRING_LENGTH)
911
 
        {
912
 
          fprintf(stderr, "Memory Allocation error in create table\n");
913
 
          abort();
914
 
        }
915
 
      }
916
 
      else
917
 
      {
918
 
        if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d INT ", col_count)
919
 
            > HUGE_STRING_LENGTH)
920
 
        {
921
 
          fprintf(stderr, "Memory Allocation error in create table\n");
922
 
          abort();
923
 
        }
924
 
      }
925
 
      table_string.append(buf);
926
 
 
927
 
      if (col_count < num_int_cols || num_char_cols > 0)
928
 
        table_string.append(",");
929
 
    }
930
 
 
931
 
  if (num_char_cols)
932
 
    for (col_count= 1; col_count <= num_char_cols; col_count++)
933
 
    {
934
 
      if (num_char_cols_index)
935
 
      {
936
 
        if (snprintf(buf, HUGE_STRING_LENGTH,
937
 
                     "charcol%d VARCHAR(128), INDEX(charcol%d) ",
938
 
                     col_count, col_count) > HUGE_STRING_LENGTH)
939
 
        {
940
 
          fprintf(stderr, "Memory Allocation error in creating table\n");
941
 
          abort();
942
 
        }
943
 
      }
944
 
      else
945
 
      {
946
 
        if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d VARCHAR(128)",
947
 
                     col_count) > HUGE_STRING_LENGTH)
948
 
        {
949
 
          fprintf(stderr, "Memory Allocation error in creating table\n");
950
 
          abort();
951
 
        }
952
 
      }
953
 
      table_string.append(buf);
954
 
 
955
 
      if (col_count < num_char_cols || num_blob_cols > 0)
956
 
        table_string.append(",");
957
 
    }
958
 
 
959
 
  if (num_blob_cols)
960
 
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
961
 
    {
962
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d blob",
963
 
                   col_count) > HUGE_STRING_LENGTH)
964
 
      {
965
 
        fprintf(stderr, "Memory Allocation error in creating table\n");
966
 
        abort();
967
 
      }
968
 
      table_string.append(buf);
969
 
 
970
 
      if (col_count < num_blob_cols)
971
 
        table_string.append(",");
972
 
    }
973
 
 
974
 
  table_string.append(")");
975
 
  ptr= new Statement;
976
 
  ptr->setString(table_string.length());
977
 
  if (ptr->getString()==NULL)
978
 
  {
979
 
    fprintf(stderr, "Memory Allocation error in creating table\n");
980
 
    abort();
981
 
  }
982
 
  ptr->setType(CREATE_TABLE_TYPE);
983
 
  strcpy(ptr->getString(), table_string.c_str());
984
 
  return(ptr);
985
 
}
986
 
 
987
 
/*
988
 
  build_update_string()
989
 
 
990
 
  This function builds insert statements when the user opts to not supply
991
 
  an insert file or string containing insert data
992
 
*/
993
 
static Statement *
994
 
build_update_string(void)
995
 
{
996
 
  char       buf[HUGE_STRING_LENGTH];
997
 
  uint32_t        col_count;
998
 
  Statement *ptr;
999
 
  string update_string;
1000
 
 
1001
 
  update_string.reserve(HUGE_STRING_LENGTH);
1002
 
 
1003
 
  update_string= "UPDATE t1 SET ";
1004
 
 
1005
 
  if (num_int_cols)
1006
 
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1007
 
    {
1008
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d = %ld", col_count,
1009
 
                   random()) > HUGE_STRING_LENGTH)
1010
 
      {
1011
 
        fprintf(stderr, "Memory Allocation error in creating update\n");
1012
 
        abort();
1013
 
      }
1014
 
      update_string.append(buf);
1015
 
 
1016
 
      if (col_count < num_int_cols || num_char_cols > 0)
1017
 
        update_string.append(",", 1);
1018
 
    }
1019
 
 
1020
 
  if (num_char_cols)
1021
 
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1022
 
    {
1023
 
      char rand_buffer[RAND_STRING_SIZE];
1024
 
      int buf_len= get_random_string(rand_buffer, RAND_STRING_SIZE);
1025
 
 
1026
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d = '%.*s'", col_count,
1027
 
                   buf_len, rand_buffer)
1028
 
          > HUGE_STRING_LENGTH)
1029
 
      {
1030
 
        fprintf(stderr, "Memory Allocation error in creating update\n");
1031
 
        abort();
1032
 
      }
1033
 
      update_string.append(buf);
1034
 
 
1035
 
      if (col_count < num_char_cols)
1036
 
        update_string.append(",", 1);
1037
 
    }
1038
 
 
1039
 
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1040
 
    update_string.append(" WHERE id = ");
1041
 
 
1042
 
 
1043
 
  ptr= new Statement;
1044
 
 
1045
 
  ptr->setString(update_string.length());
1046
 
  if (ptr->getString() == NULL)
1047
 
  {
1048
 
    fprintf(stderr, "Memory Allocation error in creating update\n");
1049
 
    abort();
1050
 
  }
1051
 
  if (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary)
1052
 
    ptr->setType(UPDATE_TYPE_REQUIRES_PREFIX);
1053
 
  else
1054
 
    ptr->setType(UPDATE_TYPE);
1055
 
  strncpy(ptr->getString(), update_string.c_str(), ptr->getLength());
1056
 
  return(ptr);
1057
 
}
1058
 
 
1059
 
 
1060
 
/*
1061
 
  build_insert_string()
1062
 
 
1063
 
  This function builds insert statements when the user opts to not supply
1064
 
  an insert file or string containing insert data
1065
 
*/
1066
 
static Statement *
1067
 
build_insert_string(void)
1068
 
{
1069
 
  char       buf[HUGE_STRING_LENGTH];
1070
 
  uint32_t        col_count;
1071
 
  Statement *ptr;
1072
 
  string insert_string;
1073
 
 
1074
 
  insert_string.reserve(HUGE_STRING_LENGTH);
1075
 
 
1076
 
  insert_string= "INSERT INTO t1 VALUES (";
1077
 
 
1078
 
  if (auto_generate_sql_autoincrement)
1079
 
  {
1080
 
    insert_string.append("NULL");
1081
 
 
1082
 
    if (num_int_cols || num_char_cols)
1083
 
      insert_string.append(",");
1084
 
  }
1085
 
 
1086
 
  if (auto_generate_sql_guid_primary)
1087
 
  {
1088
 
    insert_string.append("uuid()");
1089
 
 
1090
 
    if (num_int_cols || num_char_cols)
1091
 
      insert_string.append(",");
1092
 
  }
1093
 
 
1094
 
  if (auto_generate_sql_secondary_indexes)
1095
 
  {
1096
 
    uint32_t count;
1097
 
 
1098
 
    for (count= 0; count < auto_generate_sql_secondary_indexes; count++)
1099
 
    {
1100
 
      if (count) /* Except for the first pass we add a comma */
1101
 
        insert_string.append(",");
1102
 
 
1103
 
      insert_string.append("uuid()");
1104
 
    }
1105
 
 
1106
 
    if (num_int_cols || num_char_cols)
1107
 
      insert_string.append(",");
1108
 
  }
1109
 
 
1110
 
  if (num_int_cols)
1111
 
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1112
 
    {
1113
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "%ld", random()) > HUGE_STRING_LENGTH)
1114
 
      {
1115
 
        fprintf(stderr, "Memory Allocation error in creating insert\n");
1116
 
        abort();
1117
 
      }
1118
 
      insert_string.append(buf);
1119
 
 
1120
 
      if (col_count < num_int_cols || num_char_cols > 0)
1121
 
        insert_string.append(",");
1122
 
    }
1123
 
 
1124
 
  if (num_char_cols)
1125
 
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1126
 
    {
1127
 
      int buf_len= get_random_string(buf, RAND_STRING_SIZE);
1128
 
      insert_string.append("'", 1);
1129
 
      insert_string.append(buf, buf_len);
1130
 
      insert_string.append("'", 1);
1131
 
 
1132
 
      if (col_count < num_char_cols || num_blob_cols > 0)
1133
 
        insert_string.append(",", 1);
1134
 
    }
1135
 
 
1136
 
  if (num_blob_cols)
1137
 
  {
1138
 
    vector <char> blob_ptr;
1139
 
 
1140
 
    blob_ptr.resize(num_blob_cols_size);
1141
 
 
1142
 
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1143
 
    {
1144
 
      uint32_t buf_len;
1145
 
      uint32_t size;
1146
 
      uint32_t difference= num_blob_cols_size - num_blob_cols_size_min;
1147
 
 
1148
 
      size= difference ? (num_blob_cols_size_min + (random() % difference)) :
1149
 
        num_blob_cols_size;
1150
 
 
1151
 
      buf_len= get_random_string(&blob_ptr[0], size);
1152
 
 
1153
 
      insert_string.append("'", 1);
1154
 
      insert_string.append(&blob_ptr[0], buf_len);
1155
 
      insert_string.append("'", 1);
1156
 
 
1157
 
      if (col_count < num_blob_cols)
1158
 
        insert_string.append(",", 1);
1159
 
    }
1160
 
  }
1161
 
 
1162
 
  insert_string.append(")", 1);
1163
 
 
1164
 
  ptr= new Statement;
1165
 
  ptr->setString(insert_string.length());
1166
 
  if (ptr->getString()==NULL)
1167
 
  {
1168
 
    fprintf(stderr, "Memory Allocation error in creating select\n");
1169
 
    abort();
1170
 
  }
1171
 
  ptr->setType(INSERT_TYPE);
1172
 
  strcpy(ptr->getString(), insert_string.c_str());
1173
 
  return(ptr);
1174
 
}
1175
 
 
1176
 
 
1177
 
/*
1178
 
  build_select_string()
1179
 
 
1180
 
  This function builds a query if the user opts to not supply a query
1181
 
  statement or file containing a query statement
1182
 
*/
1183
 
static Statement *
1184
 
build_select_string(bool key)
1185
 
{
1186
 
  char       buf[HUGE_STRING_LENGTH];
1187
 
  uint32_t        col_count;
1188
 
  Statement *ptr;
1189
 
  string query_string;
1190
 
 
1191
 
  query_string.reserve(HUGE_STRING_LENGTH);
1192
 
 
1193
 
  query_string.append("SELECT ", 7);
1194
 
  if (not auto_generate_selected_columns_opt.empty())
1195
 
  {
1196
 
    query_string.append(auto_generate_selected_columns_opt.c_str());
1197
 
  }
1198
 
  else
1199
 
  {
1200
 
    for (col_count= 1; col_count <= num_int_cols; col_count++)
1201
 
    {
1202
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "intcol%d", col_count)
1203
 
          > HUGE_STRING_LENGTH)
1204
 
      {
1205
 
        fprintf(stderr, "Memory Allocation error in creating select\n");
1206
 
        abort();
1207
 
      }
1208
 
      query_string.append(buf);
1209
 
 
1210
 
      if (col_count < num_int_cols || num_char_cols > 0)
1211
 
        query_string.append(",", 1);
1212
 
 
1213
 
    }
1214
 
    for (col_count= 1; col_count <= num_char_cols; col_count++)
1215
 
    {
1216
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "charcol%d", col_count)
1217
 
          > HUGE_STRING_LENGTH)
1218
 
      {
1219
 
        fprintf(stderr, "Memory Allocation error in creating select\n");
1220
 
        abort();
1221
 
      }
1222
 
      query_string.append(buf);
1223
 
 
1224
 
      if (col_count < num_char_cols || num_blob_cols > 0)
1225
 
        query_string.append(",", 1);
1226
 
 
1227
 
    }
1228
 
    for (col_count= 1; col_count <= num_blob_cols; col_count++)
1229
 
    {
1230
 
      if (snprintf(buf, HUGE_STRING_LENGTH, "blobcol%d", col_count)
1231
 
          > HUGE_STRING_LENGTH)
1232
 
      {
1233
 
        fprintf(stderr, "Memory Allocation error in creating select\n");
1234
 
        abort();
1235
 
      }
1236
 
      query_string.append(buf);
1237
 
 
1238
 
      if (col_count < num_blob_cols)
1239
 
        query_string.append(",", 1);
1240
 
    }
1241
 
  }
1242
 
  query_string.append(" FROM t1");
1243
 
 
1244
 
  if ((key) &&
1245
 
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1246
 
    query_string.append(" WHERE id = ");
1247
 
 
1248
 
  ptr= new Statement;
1249
 
  ptr->setString(query_string.length());
1250
 
  if (ptr->getString() == NULL)
1251
 
  {
1252
 
    fprintf(stderr, "Memory Allocation error in creating select\n");
1253
 
    abort();
1254
 
  }
1255
 
  if ((key) &&
1256
 
      (auto_generate_sql_autoincrement || auto_generate_sql_guid_primary))
1257
 
    ptr->setType(SELECT_TYPE_REQUIRES_PREFIX);
1258
 
  else
1259
 
    ptr->setType(SELECT_TYPE);
1260
 
  strcpy(ptr->getString(), query_string.c_str());
1261
 
  return(ptr);
1262
 
}
1263
 
 
1264
 
static int
1265
 
process_options(void)
1266
 
{
1267
 
  struct stat sbuf;
1268
 
  ssize_t bytes_read= 0;
1269
 
  
1270
 
  if (user.empty())
1271
 
    user= "root";
1272
 
 
1273
 
  verbose= opt_verbose.length();
1274
 
 
1275
 
  /* If something is created we clean it up, otherwise we leave schemas alone */
1276
 
  if ( (not create_string.empty()) || auto_generate_sql)
1277
 
    opt_preserve= false;
1278
 
 
1279
 
  if (auto_generate_sql && (not create_string.empty() || !user_supplied_query.empty()))
1280
 
  {
1281
 
    fprintf(stderr,
1282
 
            "%s: Can't use --auto-generate-sql when create and query strings are specified!\n",
1283
 
            SLAP_NAME);
1284
 
    abort();
1285
 
  }
1286
 
 
1287
 
  if (auto_generate_sql && auto_generate_sql_guid_primary &&
1288
 
      auto_generate_sql_autoincrement)
1289
 
  {
1290
 
    fprintf(stderr,
1291
 
            "%s: Either auto-generate-sql-guid-primary or auto-generate-sql-add-autoincrement can be used!\n",
1292
 
            SLAP_NAME);
1293
 
    abort();
1294
 
  }
1295
 
 
1296
 
  if (auto_generate_sql && num_of_query && auto_actual_queries)
1297
 
  {
1298
 
    fprintf(stderr,
1299
 
            "%s: Either auto-generate-sql-execute-number or number-of-queries can be used!\n",
1300
 
            SLAP_NAME);
1301
 
    abort();
1302
 
  }
1303
 
 
1304
 
  parse_comma(not concurrency_str.empty() ? concurrency_str.c_str() : "1", concurrency);
1305
 
 
1306
 
  if (not opt_csv_str.empty())
1307
 
  {
1308
 
    opt_silent= true;
1309
 
 
1310
 
    if (opt_csv_str[0] == '-')
1311
 
    {
1312
 
      csv_file= fileno(stdout);
1313
 
    }
1314
 
    else
1315
 
    {
1316
 
      if ((csv_file= open(opt_csv_str.c_str(), O_CREAT|O_WRONLY|O_APPEND, 
1317
 
                          S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)) == -1)
1318
 
      {
1319
 
        fprintf(stderr,"%s: Could not open csv file: %sn\n",
1320
 
                SLAP_NAME, opt_csv_str.c_str());
1321
 
        abort();
1322
 
      }
1323
 
    }
1324
 
  }
1325
 
 
1326
 
  if (opt_only_print)
1327
 
    opt_silent= true;
1328
 
 
1329
 
  if (not num_int_cols_opt.empty())
1330
 
  {
1331
 
    OptionString *str;
1332
 
    parse_option(num_int_cols_opt.c_str(), &str, ',');
1333
 
    num_int_cols= atoi(str->getString());
1334
 
    if (str->getOption())
1335
 
      num_int_cols_index= atoi(str->getOption());
1336
 
    option_cleanup(str);
1337
 
  }
1338
 
 
1339
 
  if (not num_char_cols_opt.empty())
1340
 
  {
1341
 
    OptionString *str;
1342
 
    parse_option(num_char_cols_opt.c_str(), &str, ',');
1343
 
    num_char_cols= atoi(str->getString());
1344
 
    if (str->getOption())
1345
 
      num_char_cols_index= atoi(str->getOption());
1346
 
    else
1347
 
      num_char_cols_index= 0;
1348
 
    option_cleanup(str);
1349
 
  }
1350
 
 
1351
 
  uint32_t sql_type_count= 0;
1352
 
  if (not num_blob_cols_opt.empty())
1353
 
  {
1354
 
    OptionString *str;
1355
 
    parse_option(num_blob_cols_opt.c_str(), &str, ',');
1356
 
    num_blob_cols= atoi(str->getString());
1357
 
    if (str->getOption())
1358
 
    {
1359
 
      char *sep_ptr;
1360
 
 
1361
 
      if ((sep_ptr= strchr(str->getOption(), '/')))
1362
 
      {
1363
 
        num_blob_cols_size_min= atoi(str->getOption());
1364
 
        num_blob_cols_size= atoi(sep_ptr+1);
1365
 
      }
1366
 
      else
1367
 
      {
1368
 
        num_blob_cols_size_min= num_blob_cols_size= atoi(str->getOption());
1369
 
      }
1370
 
    }
1371
 
    else
1372
 
    {
1373
 
      num_blob_cols_size= DEFAULT_BLOB_SIZE;
1374
 
      num_blob_cols_size_min= DEFAULT_BLOB_SIZE;
1375
 
    }
1376
 
    option_cleanup(str);
1377
 
  }
1378
 
 
1379
 
 
1380
 
  if (auto_generate_sql)
1381
 
  {
1382
 
    uint64_t x= 0;
1383
 
    Statement *ptr_statement;
1384
 
 
1385
 
    if (verbose >= 2)
1386
 
      printf("Building Create Statements for Auto\n");
1387
 
 
1388
 
    create_statements= build_table_string();
1389
 
    /*
1390
 
      Pre-populate table
1391
 
    */
1392
 
    for (ptr_statement= create_statements, x= 0;
1393
 
         x < auto_generate_sql_unique_write_number;
1394
 
         x++, ptr_statement= ptr_statement->getNext())
1395
 
    {
1396
 
      ptr_statement->setNext(build_insert_string());
1397
 
    }
1398
 
 
1399
 
    if (verbose >= 2)
1400
 
      printf("Building Query Statements for Auto\n");
1401
 
 
1402
 
    if (opt_auto_generate_sql_type.empty())
1403
 
      opt_auto_generate_sql_type= "mixed";
1404
 
 
1405
 
    query_statements_count=
1406
 
      parse_option(opt_auto_generate_sql_type.c_str(), &query_options, ',');
1407
 
 
1408
 
    query_statements.resize(query_statements_count);
1409
 
 
1410
 
    OptionString* sql_type= query_options;
1411
 
    do
1412
 
    {
1413
 
      if (sql_type->getString()[0] == 'r')
1414
 
      {
1415
 
        if (verbose >= 2)
1416
 
          printf("Generating SELECT Statements for Auto\n");
1417
 
 
1418
 
        query_statements[sql_type_count]= build_select_string(false);
1419
 
        for (ptr_statement= query_statements[sql_type_count], x= 0;
1420
 
             x < auto_generate_sql_unique_query_number;
1421
 
             x++, ptr_statement= ptr_statement->getNext())
1422
 
        {
1423
 
          ptr_statement->setNext(build_select_string(false));
1424
 
        }
1425
 
      }
1426
 
      else if (sql_type->getString()[0] == 'k')
1427
 
      {
1428
 
        if (verbose >= 2)
1429
 
          printf("Generating SELECT for keys Statements for Auto\n");
1430
 
 
1431
 
        if ( auto_generate_sql_autoincrement == false &&
1432
 
             auto_generate_sql_guid_primary == false)
1433
 
        {
1434
 
          fprintf(stderr,
1435
 
                  "%s: Can't perform key test without a primary key!\n",
1436
 
                  SLAP_NAME);
1437
 
          abort();
1438
 
        }
1439
 
 
1440
 
        query_statements[sql_type_count]= build_select_string(true);
1441
 
        for (ptr_statement= query_statements[sql_type_count], x= 0;
1442
 
             x < auto_generate_sql_unique_query_number;
1443
 
             x++, ptr_statement= ptr_statement->getNext())
1444
 
        {
1445
 
          ptr_statement->setNext(build_select_string(true));
1446
 
        }
1447
 
      }
1448
 
      else if (sql_type->getString()[0] == 'w')
1449
 
      {
1450
 
        /*
1451
 
          We generate a number of strings in case the engine is
1452
 
          Archive (since strings which were identical one after another
1453
 
          would be too easily optimized).
1454
 
        */
1455
 
        if (verbose >= 2)
1456
 
          printf("Generating INSERT Statements for Auto\n");
1457
 
        query_statements[sql_type_count]= build_insert_string();
1458
 
        for (ptr_statement= query_statements[sql_type_count], x= 0;
1459
 
             x < auto_generate_sql_unique_query_number;
1460
 
             x++, ptr_statement= ptr_statement->getNext())
1461
 
        {
1462
 
          ptr_statement->setNext(build_insert_string());
1463
 
        }
1464
 
      }
1465
 
      else if (sql_type->getString()[0] == 'u')
1466
 
      {
1467
 
        if ( auto_generate_sql_autoincrement == false &&
1468
 
             auto_generate_sql_guid_primary == false)
1469
 
        {
1470
 
          fprintf(stderr,
1471
 
                  "%s: Can't perform update test without a primary key!\n",
1472
 
                  SLAP_NAME);
1473
 
          abort();
1474
 
        }
1475
 
 
1476
 
        query_statements[sql_type_count]= build_update_string();
1477
 
        for (ptr_statement= query_statements[sql_type_count], x= 0;
1478
 
             x < auto_generate_sql_unique_query_number;
1479
 
             x++, ptr_statement= ptr_statement->getNext())
1480
 
        {
1481
 
          ptr_statement->setNext(build_update_string());
1482
 
        }
1483
 
      }
1484
 
      else /* Mixed mode is default */
1485
 
      {
1486
 
        int coin= 0;
1487
 
 
1488
 
        query_statements[sql_type_count]= build_insert_string();
1489
 
        /*
1490
 
          This logic should be extended to do a more mixed load,
1491
 
          at the moment it results in "every other".
1492
 
        */
1493
 
        for (ptr_statement= query_statements[sql_type_count], x= 0;
1494
 
             x < auto_generate_sql_unique_query_number;
1495
 
             x++, ptr_statement= ptr_statement->getNext())
1496
 
        {
1497
 
          if (coin)
1498
 
          {
1499
 
            ptr_statement->setNext(build_insert_string());
1500
 
            coin= 0;
1501
 
          }
1502
 
          else
1503
 
          {
1504
 
            ptr_statement->setNext(build_select_string(true));
1505
 
            coin= 1;
1506
 
          }
1507
 
        }
1508
 
      }
1509
 
      sql_type_count++;
1510
 
    } while (sql_type ? (sql_type= sql_type->getNext()) : 0);
1511
 
  }
1512
 
  else
1513
 
  {
1514
 
    if (not create_string.empty() && !stat(create_string.c_str(), &sbuf))
1515
 
    {
1516
 
      int data_file;
1517
 
      std::vector<char> tmp_string;
1518
 
      if (not S_ISREG(sbuf.st_mode))
1519
 
      {
1520
 
        fprintf(stderr,"%s: Create file was not a regular file\n",
1521
 
                SLAP_NAME);
1522
 
        abort();
1523
 
      }
1524
 
      if ((data_file= open(create_string.c_str(), O_RDWR)) == -1)
1525
 
      {
1526
 
        fprintf(stderr,"%s: Could not open create file\n", SLAP_NAME);
1527
 
        abort();
1528
 
      }
1529
 
      if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1530
 
      {
1531
 
        fprintf(stderr, "Request for more memory than architecture supports\n");
1532
 
        abort();
1533
 
      }
1534
 
      tmp_string.resize(sbuf.st_size + 1);
1535
 
      bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1536
 
                       (size_t)sbuf.st_size);
1537
 
      close(data_file);
1538
 
      if (bytes_read != sbuf.st_size)
1539
 
      {
1540
 
        fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1541
 
      }
1542
 
      parse_delimiter(&tmp_string[0], &create_statements, delimiter[0]);
1543
 
    }
1544
 
    else if (not create_string.empty())
1545
 
    {
1546
 
      parse_delimiter(create_string.c_str(), &create_statements, delimiter[0]);
1547
 
    }
1548
 
 
1549
 
    /* Set this up till we fully support options on user generated queries */
1550
 
    if (not user_supplied_query.empty())
1551
 
    {
1552
 
      query_statements_count=
1553
 
        parse_option("default", &query_options, ',');
1554
 
 
1555
 
      query_statements.resize(query_statements_count);
1556
 
    }
1557
 
 
1558
 
    if (not user_supplied_query.empty() && !stat(user_supplied_query.c_str(), &sbuf))
1559
 
    {
1560
 
      int data_file;
1561
 
      std::vector<char> tmp_string;
1562
 
 
1563
 
      if (not S_ISREG(sbuf.st_mode))
1564
 
      {
1565
 
        fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1566
 
                SLAP_NAME);
1567
 
        abort();
1568
 
      }
1569
 
      if ((data_file= open(user_supplied_query.c_str(), O_RDWR)) == -1)
1570
 
      {
1571
 
        fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1572
 
        abort();
1573
 
      }
1574
 
      if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1575
 
      {
1576
 
        fprintf(stderr, "Request for more memory than architecture supports\n");
1577
 
        abort();
1578
 
      }
1579
 
      tmp_string.resize((size_t)(sbuf.st_size + 1));
1580
 
      bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1581
 
                       (size_t)sbuf.st_size);
1582
 
      close(data_file);
1583
 
      if (bytes_read != sbuf.st_size)
1584
 
      {
1585
 
        fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1586
 
      }
1587
 
      if (not user_supplied_query.empty())
1588
 
        actual_queries= parse_delimiter(&tmp_string[0], &query_statements[0],
1589
 
                                        delimiter[0]);
1590
 
    }
1591
 
    else if (not user_supplied_query.empty())
1592
 
    {
1593
 
      actual_queries= parse_delimiter(user_supplied_query.c_str(), &query_statements[0],
1594
 
                                      delimiter[0]);
1595
 
    }
1596
 
  }
1597
 
 
1598
 
  if (not user_supplied_pre_statements.empty()
1599
 
      && !stat(user_supplied_pre_statements.c_str(), &sbuf))
1600
 
  {
1601
 
    int data_file;
1602
 
    std::vector<char> tmp_string;
1603
 
 
1604
 
    if (not S_ISREG(sbuf.st_mode))
1605
 
    {
1606
 
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1607
 
              SLAP_NAME);
1608
 
      abort();
1609
 
    }
1610
 
    if ((data_file= open(user_supplied_pre_statements.c_str(), O_RDWR)) == -1)
1611
 
    {
1612
 
      fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1613
 
      abort();
1614
 
    }
1615
 
    if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1616
 
    {
1617
 
      fprintf(stderr, "Request for more memory than architecture supports\n");
1618
 
      abort();
1619
 
    }
1620
 
    tmp_string.resize((size_t)(sbuf.st_size + 1));
1621
 
    bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1622
 
                     (size_t)sbuf.st_size);
1623
 
    close(data_file);
1624
 
    if (bytes_read != sbuf.st_size)
1625
 
    {
1626
 
      fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1627
 
    }
1628
 
    if (not user_supplied_pre_statements.empty())
1629
 
      (void)parse_delimiter(&tmp_string[0], &pre_statements,
1630
 
                            delimiter[0]);
1631
 
  }
1632
 
  else if (not user_supplied_pre_statements.empty())
1633
 
  {
1634
 
    (void)parse_delimiter(user_supplied_pre_statements.c_str(),
1635
 
                          &pre_statements,
1636
 
                          delimiter[0]);
1637
 
  }
1638
 
 
1639
 
  if (not user_supplied_post_statements.empty()
1640
 
      && !stat(user_supplied_post_statements.c_str(), &sbuf))
1641
 
  {
1642
 
    int data_file;
1643
 
    std::vector<char> tmp_string;
1644
 
 
1645
 
    if (not S_ISREG(sbuf.st_mode))
1646
 
    {
1647
 
      fprintf(stderr,"%s: User query supplied file was not a regular file\n",
1648
 
              SLAP_NAME);
1649
 
      abort();
1650
 
    }
1651
 
    if ((data_file= open(user_supplied_post_statements.c_str(), O_RDWR)) == -1)
1652
 
    {
1653
 
      fprintf(stderr,"%s: Could not open query supplied file\n", SLAP_NAME);
1654
 
      abort();
1655
 
    }
1656
 
 
1657
 
    if ((uint64_t)(sbuf.st_size + 1) > SIZE_MAX)
1658
 
    {
1659
 
      fprintf(stderr, "Request for more memory than architecture supports\n");
1660
 
      abort();
1661
 
    }
1662
 
    tmp_string.resize((size_t)(sbuf.st_size + 1));
1663
 
 
1664
 
    bytes_read= read(data_file, (unsigned char*) &tmp_string[0],
1665
 
                     (size_t)(sbuf.st_size));
1666
 
    close(data_file);
1667
 
    if (bytes_read != sbuf.st_size)
1668
 
    {
1669
 
      fprintf(stderr, "Problem reading file: read less bytes than requested\n");
1670
 
    }
1671
 
    if (not user_supplied_post_statements.empty())
1672
 
      (void)parse_delimiter(&tmp_string[0], &post_statements,
1673
 
                            delimiter[0]);
1674
 
  }
1675
 
  else if (not user_supplied_post_statements.empty())
1676
 
  {
1677
 
    (void)parse_delimiter(user_supplied_post_statements.c_str(), &post_statements,
1678
 
                          delimiter[0]);
1679
 
  }
1680
 
 
1681
 
  if (verbose >= 2)
1682
 
    printf("Parsing engines to use.\n");
1683
 
 
1684
 
  if (not default_engine.empty())
1685
 
    parse_option(default_engine.c_str(), &engine_options, ',');
1686
 
 
1687
 
  if (tty_password)
1688
 
    opt_password= client_get_tty_password(NULL);
1689
 
  return(0);
1690
 
}
1691
 
 
1692
 
 
1693
 
static int run_query(drizzle_con_st &con, drizzle_result_st *result,
1694
 
                     const char *query, int len)
1695
 
{
1696
 
  drizzle_return_t ret;
1697
 
  drizzle_result_st result_buffer;
1698
 
 
1699
 
  if (opt_only_print)
1700
 
  {
1701
 
    printf("/* CON: %" PRIu64 " */ %.*s;\n",
1702
 
           (uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1703
 
           len, query);
1704
 
    return 0;
1705
 
  }
1706
 
 
1707
 
  if (verbose >= 3)
1708
 
    printf("%.*s;\n", len, query);
1709
 
 
1710
 
  if (result == NULL)
1711
 
    result= &result_buffer;
1712
 
 
1713
 
  result= drizzle_query(&con, result, query, len, &ret);
1714
 
 
1715
 
  if (ret == DRIZZLE_RETURN_OK)
1716
 
    ret= drizzle_result_buffer(result);
1717
 
 
1718
 
  if (result == &result_buffer)
1719
 
    drizzle_result_free(result);
1720
 
    
1721
 
  return ret;
1722
 
}
1723
 
 
1724
 
 
1725
 
static int
1726
 
generate_primary_key_list(drizzle_con_st &con, OptionString *engine_stmt)
1727
 
{
1728
 
  drizzle_result_st result;
1729
 
  drizzle_row_t row;
1730
 
  uint64_t counter;
1731
 
 
1732
 
 
1733
 
  /*
1734
 
    Blackhole is a special case, this allows us to test the upper end
1735
 
    of the server during load runs.
1736
 
  */
1737
 
  if (opt_only_print || (engine_stmt &&
1738
 
                         strstr(engine_stmt->getString(), "blackhole")))
1739
 
  {
1740
 
    /* Yes, we strdup a const string to simplify the interface */
1741
 
    primary_keys.push_back("796c4422-1d94-102a-9d6d-00e0812d");
1742
 
  }
1743
 
  else
1744
 
  {
1745
 
    if (run_query(con, &result, "SELECT id from t1", strlen("SELECT id from t1")))
1746
 
    {
1747
 
      fprintf(stderr,"%s: Cannot select GUID primary keys. (%s)\n", SLAP_NAME,
1748
 
              drizzle_con_error(&con));
1749
 
      abort();
1750
 
    }
1751
 
 
1752
 
    uint64_t num_rows_ret= drizzle_result_row_count(&result);
1753
 
    if (num_rows_ret > SIZE_MAX)
1754
 
    {
1755
 
      fprintf(stderr, "More primary keys than than architecture supports\n");
1756
 
      abort();
1757
 
    }
1758
 
    size_t primary_keys_number_of;
1759
 
    primary_keys_number_of= (size_t)num_rows_ret;
1760
 
 
1761
 
    /* So why check this? Blackhole :) */
1762
 
    if (primary_keys_number_of)
1763
 
    {
1764
 
      /*
1765
 
        We create the structure and loop and create the items.
1766
 
      */
1767
 
      row= drizzle_row_next(&result);
1768
 
      for (counter= 0; counter < primary_keys_number_of;
1769
 
           counter++, row= drizzle_row_next(&result))
1770
 
      {
1771
 
        primary_keys.push_back(row[0]);
1772
 
      }
1773
 
    }
1774
 
 
1775
 
    drizzle_result_free(&result);
1776
 
  }
1777
 
 
1778
 
  return(0);
1779
 
}
1780
 
 
1781
 
static void create_schema(drizzle_con_st &con, const char *db, Statement *stmt, OptionString *engine_stmt, Stats *sptr)
1782
 
{
1783
 
  char query[HUGE_STRING_LENGTH];
1784
 
  Statement *ptr;
1785
 
  Statement *after_create;
1786
 
  int len;
1787
 
  struct timeval start_time, end_time;
1788
 
 
1789
 
 
1790
 
  gettimeofday(&start_time, NULL);
1791
 
 
1792
 
  len= snprintf(query, HUGE_STRING_LENGTH, "CREATE SCHEMA `%s`", db);
1793
 
 
1794
 
  if (verbose >= 2)
1795
 
    printf("Loading Pre-data\n");
1796
 
 
1797
 
  if (run_query(con, NULL, query, len))
1798
 
  {
1799
 
    fprintf(stderr,"%s: Cannot create schema %s : %s\n", SLAP_NAME, db,
1800
 
            drizzle_con_error(&con));
1801
 
    abort();
1802
 
  }
1803
 
  else
1804
 
  {
1805
 
    sptr->setCreateCount(sptr->getCreateCount()+1);
1806
 
  }
1807
 
 
1808
 
  if (opt_only_print)
1809
 
  {
1810
 
    printf("/* CON: %" PRIu64 " */ use %s;\n",
1811
 
           (uint64_t)drizzle_context(drizzle_con_drizzle(&con)),
1812
 
           db);
1813
 
  }
1814
 
  else
1815
 
  {
1816
 
    drizzle_result_st result;
1817
 
    drizzle_return_t ret;
1818
 
 
1819
 
    if (verbose >= 3)
1820
 
      printf("%s;\n", query);
1821
 
 
1822
 
    if (drizzle_select_db(&con,  &result, db, &ret) == NULL ||
1823
 
        ret != DRIZZLE_RETURN_OK)
1824
 
    {
1825
 
      fprintf(stderr,"%s: Cannot select schema '%s': %s\n",SLAP_NAME, db,
1826
 
              ret == DRIZZLE_RETURN_ERROR_CODE ?
1827
 
              drizzle_result_error(&result) : drizzle_con_error(&con));
1828
 
      abort();
1829
 
    }
1830
 
    drizzle_result_free(&result);
1831
 
    sptr->setCreateCount(sptr->getCreateCount()+1);
1832
 
  }
1833
 
 
1834
 
  if (engine_stmt)
1835
 
  {
1836
 
    len= snprintf(query, HUGE_STRING_LENGTH, "set storage_engine=`%s`",
1837
 
                  engine_stmt->getString());
1838
 
    if (run_query(con, NULL, query, len))
1839
 
    {
1840
 
      fprintf(stderr,"%s: Cannot set default engine: %s\n", SLAP_NAME,
1841
 
              drizzle_con_error(&con));
1842
 
      abort();
1843
 
    }
1844
 
    sptr->setCreateCount(sptr->getCreateCount()+1);
1845
 
  }
1846
 
 
1847
 
  uint64_t count= 0;
1848
 
  after_create= stmt;
1849
 
 
1850
 
limit_not_met:
1851
 
  for (ptr= after_create; ptr && ptr->getLength(); ptr= ptr->getNext(), count++)
1852
 
  {
1853
 
    if (auto_generate_sql && ( auto_generate_sql_number == count))
1854
 
      break;
1855
 
 
1856
 
    if (engine_stmt && engine_stmt->getOption() && ptr->getType() == CREATE_TABLE_TYPE)
1857
 
    {
1858
 
      char buffer[HUGE_STRING_LENGTH];
1859
 
 
1860
 
      snprintf(buffer, HUGE_STRING_LENGTH, "%s %s", ptr->getString(),
1861
 
               engine_stmt->getOption());
1862
 
      if (run_query(con, NULL, buffer, strlen(buffer)))
1863
 
      {
1864
 
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1865
 
                SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1866
 
        if (not opt_ignore_sql_errors)
1867
 
          abort();
1868
 
      }
1869
 
      sptr->setCreateCount(sptr->getCreateCount()+1);
1870
 
    }
1871
 
    else
1872
 
    {
1873
 
      if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1874
 
      {
1875
 
        fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1876
 
                SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1877
 
        if (not opt_ignore_sql_errors)
1878
 
          abort();
1879
 
      }
1880
 
      sptr->setCreateCount(sptr->getCreateCount()+1);
1881
 
    }
1882
 
  }
1883
 
 
1884
 
  if (auto_generate_sql && (auto_generate_sql_number > count ))
1885
 
  {
1886
 
    /* Special case for auto create, we don't want to create tables twice */
1887
 
    after_create= stmt->getNext();
1888
 
    goto limit_not_met;
1889
 
  }
1890
 
 
1891
 
  gettimeofday(&end_time, NULL);
1892
 
 
1893
 
  sptr->setCreateTiming(timedif(end_time, start_time));
1894
 
}
1895
 
 
1896
 
static void drop_schema(drizzle_con_st &con, const char *db)
1897
 
{
1898
 
  char query[HUGE_STRING_LENGTH];
1899
 
  int len;
1900
 
 
1901
 
  len= snprintf(query, HUGE_STRING_LENGTH, "DROP SCHEMA IF EXISTS `%s`", db);
1902
 
 
1903
 
  if (run_query(con, NULL, query, len))
1904
 
  {
1905
 
    fprintf(stderr,"%s: Cannot drop database '%s' ERROR : %s\n",
1906
 
            SLAP_NAME, db, drizzle_con_error(&con));
1907
 
    abort();
1908
 
  }
1909
 
}
1910
 
 
1911
 
static void run_statements(drizzle_con_st &con, Statement *stmt)
1912
 
{
1913
 
  for (Statement *ptr= stmt; ptr && ptr->getLength(); ptr= ptr->getNext())
1914
 
  {
1915
 
    if (run_query(con, NULL, ptr->getString(), ptr->getLength()))
1916
 
    {
1917
 
      fprintf(stderr,"%s: Cannot run query %.*s ERROR : %s\n",
1918
 
              SLAP_NAME, (uint32_t)ptr->getLength(), ptr->getString(), drizzle_con_error(&con));
1919
 
      abort();
1920
 
    }
1921
 
  }
1922
 
}
1923
 
 
1924
 
 
1925
 
static void timer_thread()
1926
 
{
1927
 
  /*
1928
 
    We lock around the initial call in case were we in a loop. This
1929
 
    also keeps the value properly syncronized across call threads.
1930
 
  */
1931
 
  master_wakeup.wait();
1932
 
 
1933
 
  {
1934
 
    boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1935
 
 
1936
 
    boost::xtime xt; 
1937
 
    xtime_get(&xt, boost::TIME_UTC); 
1938
 
    xt.sec += opt_timer_length; 
1939
 
 
1940
 
    (void)timer_alarm_threshold.timed_wait(scopedLock, xt);
1941
 
  }
1942
 
 
1943
 
  {
1944
 
    boost::mutex::scoped_lock scopedLock(timer_alarm_mutex);
1945
 
    timer_alarm= false;
1946
 
  }
1947
 
}
1948
 
 
1949
 
typedef boost::shared_ptr<boost::thread> Thread;
1950
 
typedef std::vector <Thread> Threads;
1951
 
static void run_scheduler(Stats *sptr, Statement **stmts, uint32_t concur, uint64_t limit)
1952
 
{
1953
 
  uint32_t real_concurrency;
1954
 
  struct timeval start_time, end_time;
1955
 
 
1956
 
  Threads threads;
1957
 
 
1958
 
  {
1959
 
    OptionString *sql_type;
1960
 
 
1961
 
    master_wakeup.reset();
1962
 
 
1963
 
    real_concurrency= 0;
1964
 
 
1965
 
    uint32_t y;
1966
 
    for (y= 0, sql_type= query_options;
1967
 
         y < query_statements_count;
1968
 
         y++, sql_type= sql_type->getNext())
1969
 
    {
1970
 
      uint32_t options_loop= 1;
1971
 
 
1972
 
      if (sql_type->getOption())
1973
 
      {
1974
 
        options_loop= strtol(sql_type->getOption(),
1975
 
                             (char **)NULL, 10);
1976
 
        options_loop= options_loop ? options_loop : 1;
1977
 
      }
1978
 
 
1979
 
      while (options_loop--)
1980
 
      {
1981
 
        for (uint32_t x= 0; x < concur; x++)
1982
 
        {
1983
 
          ThreadContext *con;
1984
 
          con= new ThreadContext;
1985
 
          if (con == NULL)
1986
 
          {
1987
 
            fprintf(stderr, "Memory Allocation error in scheduler\n");
1988
 
            abort();
1989
 
          }
1990
 
          con->setStmt(stmts[y]);
1991
 
          con->setLimit(limit);
1992
 
 
1993
 
          real_concurrency++;
1994
 
 
1995
 
          /* now you create the thread */
1996
 
          Thread thread;
1997
 
          thread= Thread(new boost::thread(boost::bind(&run_task, con)));
1998
 
          threads.push_back(thread);
1999
 
 
2000
 
        }
2001
 
      }
2002
 
    }
2003
 
 
2004
 
    /*
2005
 
      The timer_thread belongs to all threads so it too obeys the wakeup
2006
 
      call that run tasks obey.
2007
 
    */
2008
 
    if (opt_timer_length)
2009
 
    {
2010
 
      {
2011
 
        boost::mutex::scoped_lock alarmLock(timer_alarm_mutex);
2012
 
        timer_alarm= true;
2013
 
      }
2014
 
 
2015
 
      Thread thread;
2016
 
      thread= Thread(new boost::thread(&timer_thread));
2017
 
      threads.push_back(thread);
2018
 
    }
2019
 
  }
2020
 
 
2021
 
  master_wakeup.start();
2022
 
 
2023
 
  gettimeofday(&start_time, NULL);
2024
 
 
2025
 
  /*
2026
 
    We loop until we know that all children have cleaned up.
2027
 
  */
2028
 
  for (Threads::iterator iter= threads.begin(); iter != threads.end(); iter++)
2029
 
  {
2030
 
    (*iter)->join();
2031
 
  }
2032
 
 
2033
 
  gettimeofday(&end_time, NULL);
2034
 
 
2035
 
  sptr->setTiming(timedif(end_time, start_time));
2036
 
  sptr->setUsers(concur);
2037
 
  sptr->setRealUsers(real_concurrency);
2038
 
  sptr->setRows(limit);
2039
 
}
2040
 
 
2041
 
/*
2042
 
  Parse records from comma seperated string. : is a reserved character and is used for options
2043
 
  on variables.
2044
 
*/
2045
 
uint32_t parse_option(const char *origin, OptionString **stmt, char delm)
2046
 
{
2047
 
  char *string;
2048
 
  char *begin_ptr;
2049
 
  char *end_ptr;
2050
 
  uint32_t length= strlen(origin);
2051
 
  uint32_t count= 0; /* We know that there is always one */
2052
 
 
2053
 
  end_ptr= (char *)origin + length;
2054
 
 
2055
 
  OptionString *tmp;
2056
 
  *stmt= tmp= new OptionString;
2057
 
 
2058
 
  for (begin_ptr= (char *)origin;
2059
 
       begin_ptr != end_ptr;
2060
 
       tmp= tmp->getNext())
2061
 
  {
2062
 
    char buffer[HUGE_STRING_LENGTH];
2063
 
    char *buffer_ptr;
2064
 
 
2065
 
    memset(buffer, 0, HUGE_STRING_LENGTH);
2066
 
 
2067
 
    string= strchr(begin_ptr, delm);
2068
 
 
2069
 
    if (string)
2070
 
    {
2071
 
      memcpy(buffer, begin_ptr, string - begin_ptr);
2072
 
      begin_ptr= string+1;
2073
 
    }
2074
 
    else
2075
 
    {
2076
 
      size_t begin_len= strlen(begin_ptr);
2077
 
      memcpy(buffer, begin_ptr, begin_len);
2078
 
      begin_ptr= end_ptr;
2079
 
    }
2080
 
 
2081
 
    if ((buffer_ptr= strchr(buffer, ':')))
2082
 
    {
2083
 
      /* Set a null so that we can get strlen() correct later on */
2084
 
      buffer_ptr[0]= 0;
2085
 
      buffer_ptr++;
2086
 
 
2087
 
      /* Move past the : and the first string */
2088
 
      tmp->setOption(buffer_ptr);
2089
 
    }
2090
 
 
2091
 
    tmp->setString(strdup(buffer));
2092
 
    if (tmp->getString() == NULL)
2093
 
    {
2094
 
      fprintf(stderr,"Error allocating memory while parsing options\n");
2095
 
      abort();
2096
 
    }
2097
 
 
2098
 
    if (isspace(*begin_ptr))
2099
 
      begin_ptr++;
2100
 
 
2101
 
    count++;
2102
 
 
2103
 
    if (begin_ptr != end_ptr)
2104
 
    {
2105
 
      tmp->setNext( new OptionString);
2106
 
    }
2107
 
    
2108
 
  }
2109
 
 
2110
 
  return count;
2111
 
}
2112
 
 
2113
 
 
2114
 
/*
2115
 
  Raw parsing interface. If you want the slap specific parser look at
2116
 
  parse_option.
2117
 
*/
2118
 
uint32_t parse_delimiter(const char *script, Statement **stmt, char delm)
2119
 
{
2120
 
  char *retstr;
2121
 
  char *ptr= (char *)script;
2122
 
  Statement **sptr= stmt;
2123
 
  Statement *tmp;
2124
 
  uint32_t length= strlen(script);
2125
 
  uint32_t count= 0; /* We know that there is always one */
2126
 
 
2127
 
  for (tmp= *sptr= new Statement;
2128
 
       (retstr= strchr(ptr, delm));
2129
 
       tmp->setNext(new Statement),
2130
 
       tmp= tmp->getNext())
2131
 
  {
2132
 
    if (tmp == NULL)
2133
 
    {
2134
 
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2135
 
      abort();
2136
 
    }
2137
 
 
2138
 
    count++;
2139
 
    tmp->setString((size_t)(retstr - ptr));
2140
 
 
2141
 
    if (tmp->getString() == NULL)
2142
 
    {
2143
 
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2144
 
      abort();
2145
 
    }
2146
 
 
2147
 
    memcpy(tmp->getString(), ptr, tmp->getLength());
2148
 
    ptr+= retstr - ptr + 1;
2149
 
    if (isspace(*ptr))
2150
 
      ptr++;
2151
 
  }
2152
 
 
2153
 
  if (ptr != script+length)
2154
 
  {
2155
 
    tmp->setString((size_t)((script + length) - ptr));
2156
 
    if (tmp->getString() == NULL)
2157
 
    {
2158
 
      fprintf(stderr,"Error allocating memory while parsing delimiter\n");
2159
 
      abort();
2160
 
    }
2161
 
    memcpy(tmp->getString(), ptr, tmp->getLength());
2162
 
    count++;
2163
 
  }
2164
 
 
2165
 
  return count;
2166
 
}
2167
 
 
2168
 
 
2169
 
/*
2170
 
  Parse comma is different from parse_delimeter in that it parses
2171
 
  number ranges from a comma seperated string.
2172
 
  In restrospect, this is a lousy name from this function.
2173
 
*/
2174
 
uint32_t parse_comma(const char *string, std::vector <uint32_t> &range)
2175
 
{
2176
 
  uint32_t count= 1; /* We know that there is always one */
2177
 
  char *retstr;
2178
 
  char *ptr= (char *)string;
2179
 
  uint32_t *nptr;
2180
 
 
2181
 
  for (;*ptr; ptr++)
2182
 
    if (*ptr == ',') count++;
2183
 
 
2184
 
  /* One extra spot for the NULL */
2185
 
  range.resize(count +1);
2186
 
  nptr= &range[0];
2187
 
 
2188
 
  ptr= (char *)string;
2189
 
  uint32_t x= 0;
2190
 
  while ((retstr= strchr(ptr,',')))
2191
 
  {
2192
 
    nptr[x++]= atoi(ptr);
2193
 
    ptr+= retstr - ptr + 1;
2194
 
  }
2195
 
  nptr[x++]= atoi(ptr);
2196
 
 
2197
 
  return count;
2198
 
}
2199
 
 
2200
 
void print_conclusions(Conclusions &con)
2201
 
{
2202
 
  printf("Benchmark\n");
2203
 
  if (con.getEngine())
2204
 
    printf("\tRunning for engine %s\n", con.getEngine());
2205
 
 
2206
 
  if (not opt_label.empty() || !opt_auto_generate_sql_type.empty())
2207
 
  {
2208
 
    const char *ptr= opt_auto_generate_sql_type.c_str() ? opt_auto_generate_sql_type.c_str() : "query";
2209
 
    printf("\tLoad: %s\n", !opt_label.empty() ? opt_label.c_str() : ptr);
2210
 
  }
2211
 
  printf("\tAverage Time took to generate schema and initial data: %ld.%03ld seconds\n",
2212
 
         con.getCreateAvgTiming() / 1000, con.getCreateAvgTiming() % 1000);
2213
 
  printf("\tAverage number of seconds to run all queries: %ld.%03ld seconds\n",
2214
 
         con.getAvgTiming() / 1000, con.getAvgTiming() % 1000);
2215
 
  printf("\tMinimum number of seconds to run all queries: %ld.%03ld seconds\n",
2216
 
         con.getMinTiming() / 1000, con.getMinTiming() % 1000);
2217
 
  printf("\tMaximum number of seconds to run all queries: %ld.%03ld seconds\n",
2218
 
         con.getMaxTiming() / 1000, con.getMaxTiming() % 1000);
2219
 
  printf("\tTotal time for tests: %ld.%03ld seconds\n",
2220
 
         con.getSumOfTime() / 1000, con.getSumOfTime() % 1000);
2221
 
  printf("\tStandard Deviation: %ld.%03ld\n", con.getStdDev() / 1000, con.getStdDev() % 1000);
2222
 
  printf("\tNumber of queries in create queries: %"PRIu64"\n", con.getCreateCount());
2223
 
  printf("\tNumber of clients running queries: %u/%u\n",
2224
 
         con.getUsers(), con.getRealUsers());
2225
 
  printf("\tNumber of times test was run: %u\n", iterations);
2226
 
  printf("\tAverage number of queries per client: %"PRIu64"\n", con.getAvgRows());
2227
 
 
2228
 
  uint64_t temp_val= failed_update_for_transaction; 
2229
 
  if (temp_val)
2230
 
    printf("\tFailed number of updates %"PRIu64"\n", temp_val);
2231
 
 
2232
 
  printf("\n");
2233
 
}
2234
 
 
2235
 
void print_conclusions_csv(Conclusions &con)
2236
 
{
2237
 
  char buffer[HUGE_STRING_LENGTH];
2238
 
  char label_buffer[HUGE_STRING_LENGTH];
2239
 
  size_t string_len;
2240
 
  const char *temp_label= opt_label.c_str();
2241
 
 
2242
 
  memset(label_buffer, 0, sizeof(label_buffer));
2243
 
 
2244
 
  if (not opt_label.empty())
2245
 
  {
2246
 
    string_len= opt_label.length();
2247
 
 
2248
 
    for (uint32_t x= 0; x < string_len; x++)
2249
 
    {
2250
 
      if (temp_label[x] == ',')
2251
 
        label_buffer[x]= '-';
2252
 
      else
2253
 
        label_buffer[x]= temp_label[x] ;
2254
 
    }
2255
 
  }
2256
 
  else if (not opt_auto_generate_sql_type.empty())
2257
 
  {
2258
 
    string_len= opt_auto_generate_sql_type.length();
2259
 
 
2260
 
    for (uint32_t x= 0; x < string_len; x++)
2261
 
    {
2262
 
      if (opt_auto_generate_sql_type[x] == ',')
2263
 
        label_buffer[x]= '-';
2264
 
      else
2265
 
        label_buffer[x]= opt_auto_generate_sql_type[x] ;
2266
 
    }
2267
 
  }
2268
 
  else
2269
 
  {
2270
 
    snprintf(label_buffer, HUGE_STRING_LENGTH, "query");
2271
 
  }
2272
 
 
2273
 
  snprintf(buffer, HUGE_STRING_LENGTH,
2274
 
           "%s,%s,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,%ld.%03ld,"
2275
 
           "%u,%u,%u,%"PRIu64"\n",
2276
 
           con.getEngine() ? con.getEngine() : "", /* Storage engine we ran against */
2277
 
           label_buffer, /* Load type */
2278
 
           con.getAvgTiming() / 1000, con.getAvgTiming() % 1000, /* Time to load */
2279
 
           con.getMinTiming() / 1000, con.getMinTiming() % 1000, /* Min time */
2280
 
           con.getMaxTiming() / 1000, con.getMaxTiming() % 1000, /* Max time */
2281
 
           con.getSumOfTime() / 1000, con.getSumOfTime() % 1000, /* Total time */
2282
 
           con.getStdDev() / 1000, con.getStdDev() % 1000, /* Standard Deviation */
2283
 
           iterations, /* Iterations */
2284
 
           con.getUsers(), /* Children used max_timing */
2285
 
           con.getRealUsers(), /* Children used max_timing */
2286
 
           con.getAvgRows()  /* Queries run */
2287
 
           );
2288
 
  size_t buff_len= strlen(buffer);
2289
 
  ssize_t write_ret= write(csv_file, (unsigned char*) buffer, buff_len);
2290
 
  if (write_ret != (ssize_t)buff_len)
2291
 
  {
2292
 
    fprintf(stderr, _("Unable to fully write %"PRIu64" bytes. "
2293
 
                      "Could only write %"PRId64"."), (uint64_t)write_ret,
2294
 
                      (int64_t)buff_len);
2295
 
    exit(-1);
2296
 
  }
2297
 
}
2298
 
 
2299
 
void generate_stats(Conclusions *con, OptionString *eng, Stats *sptr)
2300
 
{
2301
 
  Stats *ptr;
2302
 
  uint32_t x;
2303
 
 
2304
 
  con->setMinTiming(sptr->getTiming());
2305
 
  con->setMaxTiming(sptr->getTiming());
2306
 
  con->setMinRows(sptr->getRows());
2307
 
  con->setMaxRows(sptr->getRows());
2308
 
 
2309
 
  /* At the moment we assume uniform */
2310
 
  con->setUsers(sptr->getUsers());
2311
 
  con->setRealUsers(sptr->getRealUsers());
2312
 
  con->setAvgRows(sptr->getRows());
2313
 
 
2314
 
  /* With no next, we know it is the last element that was malloced */
2315
 
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2316
 
  {
2317
 
    con->setAvgTiming(ptr->getTiming()+con->getAvgTiming());
2318
 
 
2319
 
    if (ptr->getTiming() > con->getMaxTiming())
2320
 
      con->setMaxTiming(ptr->getTiming());
2321
 
    if (ptr->getTiming() < con->getMinTiming())
2322
 
      con->setMinTiming(ptr->getTiming());
2323
 
  }
2324
 
  con->setSumOfTime(con->getAvgTiming());
2325
 
  con->setAvgTiming(con->getAvgTiming()/iterations);
2326
 
 
2327
 
  if (eng && eng->getString())
2328
 
    con->setEngine(eng->getString());
2329
 
  else
2330
 
    con->setEngine(NULL);
2331
 
 
2332
 
  standard_deviation(*con, sptr);
2333
 
 
2334
 
  /* Now we do the create time operations */
2335
 
  con->setCreateMinTiming(sptr->getCreateTiming());
2336
 
  con->setCreateMaxTiming(sptr->getCreateTiming());
2337
 
 
2338
 
  /* At the moment we assume uniform */
2339
 
  con->setCreateCount(sptr->getCreateCount());
2340
 
 
2341
 
  /* With no next, we know it is the last element that was malloced */
2342
 
  for (ptr= sptr, x= 0; x < iterations; ptr++, x++)
2343
 
  {
2344
 
    con->setCreateAvgTiming(ptr->getCreateTiming()+con->getCreateAvgTiming());
2345
 
 
2346
 
    if (ptr->getCreateTiming() > con->getCreateMaxTiming())
2347
 
      con->setCreateMaxTiming(ptr->getCreateTiming());
2348
 
    if (ptr->getCreateTiming() < con->getCreateMinTiming())
2349
 
      con->setCreateMinTiming(ptr->getCreateTiming());
2350
 
  }
2351
 
  con->setCreateAvgTiming(con->getCreateAvgTiming()/iterations);
2352
 
}
2353
 
 
2354
 
void
2355
 
option_cleanup(OptionString *stmt)
2356
 
{
2357
 
  OptionString *ptr, *nptr;
2358
 
  if (not stmt)
2359
 
    return;
2360
 
 
2361
 
  for (ptr= stmt; ptr; ptr= nptr)
2362
 
  {
2363
 
    nptr= ptr->getNext();
2364
 
    delete ptr;
2365
 
  }
2366
 
}
2367
 
 
2368
 
void statement_cleanup(Statement *stmt)
2369
 
{
2370
 
  Statement *ptr, *nptr;
2371
 
  if (not stmt)
2372
 
    return;
2373
 
 
2374
 
  for (ptr= stmt; ptr; ptr= nptr)
2375
 
  {
2376
 
    nptr= ptr->getNext();
2377
 
    delete ptr;
2378
 
  }
2379
 
}
2380
 
 
2381
 
void slap_close(drizzle_con_st *con)
2382
 
{
2383
 
  drizzle_free(drizzle_con_drizzle(con));
2384
 
}
2385
 
 
2386
 
drizzle_con_st* slap_connect(bool connect_to_schema)
2387
 
{
2388
 
  /* Connect to server */
2389
 
  static uint32_t connection_retry_sleep= 100000; /* Microseconds */
2390
 
  int connect_error= 1;
2391
 
  drizzle_return_t ret;
2392
 
  drizzle_st *drizzle;
2393
 
 
2394
 
  if (opt_delayed_start)
2395
 
    usleep(random()%opt_delayed_start);
2396
 
 
2397
 
  drizzle_con_st* con;
2398
 
  if ((drizzle= drizzle_create()) == NULL or
2399
 
      (con= drizzle_con_add_tcp(drizzle,
2400
 
                                host.c_str(), opt_drizzle_port,
2401
 
                                user.c_str(), opt_password.c_str(),
2402
 
                                connect_to_schema ? create_schema_string.c_str() : NULL,
2403
 
                                use_drizzle_protocol ? DRIZZLE_CON_EXPERIMENTAL : DRIZZLE_CON_MYSQL)) == NULL)
2404
 
  {
2405
 
    fprintf(stderr,"%s: Error creating drizzle object\n", SLAP_NAME);
2406
 
    abort();
2407
 
  }
2408
 
 
2409
 
  drizzle_set_context(drizzle, (void*)(connection_count.fetch_and_increment()));
2410
 
 
2411
 
  if (opt_only_print)
2412
 
  {
2413
 
    return con;
2414
 
  }
2415
 
 
2416
 
  for (uint32_t x= 0; x < 10; x++)
2417
 
  {
2418
 
    if ((ret= drizzle_con_connect(con)) == DRIZZLE_RETURN_OK)
2419
 
    {
2420
 
      /* Connect suceeded */
2421
 
      connect_error= 0;
2422
 
      break;
2423
 
    }
2424
 
    usleep(connection_retry_sleep);
2425
 
  }
2426
 
  if (connect_error)
2427
 
  {
2428
 
    fprintf(stderr,"%s: Error when connecting to server: %d %s\n", SLAP_NAME,
2429
 
            ret, drizzle_con_error(con));
2430
 
    abort();
2431
 
  }
2432
 
 
2433
 
  return con;
2434
 
}
2435
 
 
2436
 
void standard_deviation(Conclusions &con, Stats *sptr)
2437
 
{
2438
 
  long int sum_of_squares;
2439
 
  double the_catch;
2440
 
  Stats *ptr;
2441
 
 
2442
 
  if (iterations == 1 || iterations == 0)
2443
 
  {
2444
 
    con.setStdDev(0);
2445
 
    return;
2446
 
  }
2447
 
 
2448
 
  uint32_t x;
2449
 
  for (ptr= sptr, x= 0, sum_of_squares= 0; x < iterations; ptr++, x++)
2450
 
  {
2451
 
    long int deviation;
2452
 
 
2453
 
    deviation= ptr->getTiming() - con.getAvgTiming();
2454
 
    sum_of_squares+= deviation*deviation;
2455
 
  }
2456
 
 
2457
 
  the_catch= sqrt((double)(sum_of_squares/(iterations -1)));
2458
 
  con.setStdDev((long int)the_catch);
2459
 
}