~ubuntu-branches/debian/jessie/sysbench/jessie

« back to all changes in this revision

Viewing changes to sysbench/tests/oltp/sb_oltp.c

  • Committer: Bazaar Package Importer
  • Author(s): Hendrik Frenzel
  • Date: 2009-02-23 00:32:52 UTC
  • Revision ID: james.westby@ubuntu.com-20090223003252-u6psmnqbivepsj0n
Tags: upstream-0.4.10
ImportĀ upstreamĀ versionĀ 0.4.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2004 MySQL AB
 
2
 
 
3
   This program is free software; you can redistribute it and/or modify
 
4
   it under the terms of the GNU General Public License as published by
 
5
   the Free Software Foundation; either version 2 of the License, or
 
6
   (at your option) any later version.
 
7
 
 
8
   This program is distributed in the hope that it will be useful,
 
9
   but WITHOUT ANY WARRANTY; without even the implied warranty of
 
10
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
11
   GNU General Public License for more details.
 
12
 
 
13
   You should have received a copy of the GNU General Public License
 
14
   along with this program; if not, write to the Free Software
 
15
   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 
16
*/
 
17
 
 
18
#ifdef HAVE_CONFIG_H
 
19
# include "config.h"
 
20
#endif
 
21
 
 
22
#include "sysbench.h"
 
23
#include "db_driver.h"
 
24
#include "sb_oltp.h"
 
25
 
 
26
#define GET_RANDOM_ID() ((*rnd_func)())
 
27
 
 
28
/* How many rows to insert in a single query (used for test DB creation) */
 
29
#define INSERT_ROWS 10000
 
30
 
 
31
/* How many rows to insert before COMMITs (used for test DB creation) */
 
32
#define ROWS_BEFORE_COMMIT 1000
 
33
 
 
34
/* Maximum query length */
 
35
#define MAX_QUERY_LEN 1024
 
36
 
 
37
/* Large prime number to generate unique set of random numbers in delete test */
 
38
#define LARGE_PRIME 2147483647
 
39
 
 
40
/* Command line arguments definition */
 
41
static sb_arg_t oltp_args[] =
 
42
{
 
43
  {"oltp-test-mode", "test type to use {simple,complex,nontrx,sp}", SB_ARG_TYPE_STRING, "complex"},
 
44
  {"oltp-sp-name", "name of store procedure to call in SP test mode", SB_ARG_TYPE_STRING, ""},
 
45
  {"oltp-read-only", "generate only 'read' queries (do not modify database)", SB_ARG_TYPE_FLAG, "off"},
 
46
  {"oltp-skip-trx", "skip BEGIN/COMMIT statements", SB_ARG_TYPE_FLAG, "off"},
 
47
  {"oltp-range-size", "range size for range queries", SB_ARG_TYPE_INT, "100"},
 
48
  {"oltp-point-selects", "number of point selects", SB_ARG_TYPE_INT, "10"},
 
49
  {"oltp-simple-ranges", "number of simple ranges", SB_ARG_TYPE_INT, "1"},
 
50
  {"oltp-sum-ranges", "number of sum ranges", SB_ARG_TYPE_INT, "1"},
 
51
  {"oltp-order-ranges", "number of ordered ranges", SB_ARG_TYPE_INT, "1"},
 
52
  {"oltp-distinct-ranges", "number of distinct ranges", SB_ARG_TYPE_INT, "1"},
 
53
  {"oltp-index-updates", "number of index update", SB_ARG_TYPE_INT, "1"},
 
54
  {"oltp-non-index-updates", "number of non-index updates", SB_ARG_TYPE_INT, "1"},
 
55
  {"oltp-nontrx-mode",
 
56
   "mode for non-transactional test {select, update_key, update_nokey, insert, delete}",
 
57
   SB_ARG_TYPE_STRING, "select"},
 
58
  {"oltp-auto-inc", "whether AUTO_INCREMENT (or equivalent) should be used on id column",
 
59
   SB_ARG_TYPE_FLAG, "on"},
 
60
  {"oltp-connect-delay", "time in microseconds to sleep after connection to database", SB_ARG_TYPE_INT,
 
61
   "10000"},
 
62
  {"oltp-user-delay-min", "minimum time in microseconds to sleep after each request",
 
63
   SB_ARG_TYPE_INT, "0"},
 
64
  {"oltp-user-delay-max", "maximum time in microseconds to sleep after each request",
 
65
   SB_ARG_TYPE_INT, "0"},
 
66
  {"oltp-table-name", "name of test table", SB_ARG_TYPE_STRING, "sbtest"},
 
67
  {"oltp-table-size", "number of records in test table", SB_ARG_TYPE_INT, "10000"},
 
68
 
 
69
  {"oltp-dist-type", "random numbers distribution {uniform,gaussian,special}", SB_ARG_TYPE_STRING,
 
70
   "special"},
 
71
  {"oltp-dist-iter", "number of iterations used for numbers generation", SB_ARG_TYPE_INT, "12"},
 
72
  {"oltp-dist-pct", "percentage of values to be treated as 'special' (for special distribution)",
 
73
   SB_ARG_TYPE_INT, "1"},
 
74
  {"oltp-dist-res", "percentage of 'special' values to use (for special distribution)",
 
75
   SB_ARG_TYPE_INT, "75"},
 
76
  
 
77
  {NULL, NULL, SB_ARG_TYPE_NULL, NULL}
 
78
};
 
79
 
 
80
/* Test modes */
 
81
typedef enum
 
82
{
 
83
  TEST_MODE_SIMPLE,
 
84
  TEST_MODE_COMPLEX,
 
85
  TEST_MODE_NONTRX,
 
86
  TEST_MODE_SP
 
87
} oltp_mode_t;
 
88
 
 
89
/* Modes for 'non-transactional' test */
 
90
typedef enum
 
91
{
 
92
  NONTRX_MODE_SELECT,
 
93
  NONTRX_MODE_UPDATE_KEY,
 
94
  NONTRX_MODE_UPDATE_NOKEY,
 
95
  NONTRX_MODE_INSERT,
 
96
  NONTRX_MODE_DELETE
 
97
} nontrx_mode_t;
 
98
 
 
99
/* Random numbers distributions */
 
100
typedef enum
 
101
{
 
102
  DIST_TYPE_UNIFORM,
 
103
  DIST_TYPE_GAUSSIAN,
 
104
  DIST_TYPE_SPECIAL
 
105
} oltp_dist_t;
 
106
 
 
107
typedef struct
 
108
{
 
109
  oltp_mode_t   test_mode;
 
110
  unsigned int  read_only;
 
111
  unsigned int  skip_trx;
 
112
  unsigned int  auto_inc;
 
113
  unsigned int  range_size;
 
114
  unsigned int  point_selects;
 
115
  unsigned int  simple_ranges;
 
116
  unsigned int  sum_ranges;
 
117
  unsigned int  order_ranges;
 
118
  unsigned int  distinct_ranges;
 
119
  unsigned int  index_updates;
 
120
  unsigned int  non_index_updates;
 
121
  nontrx_mode_t nontrx_mode;
 
122
  unsigned int  connect_delay;
 
123
  unsigned int  user_delay_min;
 
124
  unsigned int  user_delay_max;
 
125
  char          *table_name;
 
126
  char          *sp_name;
 
127
  unsigned int  table_size;
 
128
  oltp_dist_t   dist_type;
 
129
  unsigned int  dist_iter;
 
130
  unsigned int  dist_pct;
 
131
  unsigned int  dist_res;
 
132
} oltp_args_t;
 
133
 
 
134
/* Test statements structure */
 
135
typedef struct
 
136
{
 
137
  db_stmt_t *lock;
 
138
  db_stmt_t *unlock;
 
139
  db_stmt_t *point;
 
140
  db_stmt_t *call;
 
141
  db_stmt_t *range;
 
142
  db_stmt_t *range_sum;
 
143
  db_stmt_t *range_order;
 
144
  db_stmt_t *range_distinct;
 
145
  db_stmt_t *update_index;
 
146
  db_stmt_t *update_non_index;
 
147
  db_stmt_t *delete;
 
148
  db_stmt_t *insert;
 
149
} oltp_stmt_set_t;
 
150
 
 
151
/* Bind buffers for statements */
 
152
typedef struct
 
153
{
 
154
  sb_sql_query_point_t  point;
 
155
  sb_sql_query_range_t  range;
 
156
  sb_sql_query_range_t  range_sum;
 
157
  sb_sql_query_range_t  range_order;
 
158
  sb_sql_query_range_t  range_distinct;
 
159
  sb_sql_query_update_t update_index;
 
160
  sb_sql_query_update_t update_non_index;
 
161
  sb_sql_query_delete_t delete;
 
162
  sb_sql_query_insert_t insert;
 
163
  sb_sql_query_call_t   call;
 
164
  /* Buffer for the 'c' table field in update_non_index and insert queries */
 
165
  char                  c[120];
 
166
  unsigned long         c_len;
 
167
  /* Buffer for the 'pad' table field in insert query */
 
168
  char                  pad[60];
 
169
  unsigned long         pad_len;
 
170
} oltp_bind_set_t;
 
171
 
 
172
/* OLTP test commands */
 
173
static int oltp_cmd_help(void);
 
174
static int oltp_cmd_prepare(void);
 
175
static int oltp_cmd_cleanup(void);
 
176
 
 
177
/* OLTP test operations */
 
178
static int oltp_init(void);
 
179
static void oltp_print_mode(void);
 
180
static sb_request_t oltp_get_request(int);
 
181
static int oltp_execute_request(sb_request_t *, int);
 
182
static void oltp_print_stats(void);
 
183
static db_conn_t *oltp_connect(void);
 
184
static int oltp_disconnect(db_conn_t *);
 
185
static int oltp_done(void);
 
186
 
 
187
static sb_test_t oltp_test =
 
188
{
 
189
  .sname = "oltp",
 
190
  .lname = "OLTP test",
 
191
  .ops = {
 
192
    .init = oltp_init,
 
193
    .prepare = NULL,
 
194
    .thread_init = NULL,
 
195
    .thread_done = NULL,
 
196
    .cleanup = NULL,
 
197
    .print_mode = oltp_print_mode,
 
198
    .get_request = oltp_get_request,
 
199
    .execute_request = oltp_execute_request,
 
200
    .print_stats = oltp_print_stats,
 
201
    .done = oltp_done
 
202
  },
 
203
  .cmds = {
 
204
    .help = oltp_cmd_help,
 
205
    .prepare = oltp_cmd_prepare,
 
206
    .run = NULL,
 
207
    .cleanup = oltp_cmd_cleanup
 
208
  },
 
209
  .args = oltp_args,
 
210
  {NULL, NULL}
 
211
};
 
212
 
 
213
/* Global variables */
 
214
static oltp_args_t args;               /* test args */
 
215
static unsigned int (*rnd_func)(void); /* pointer to random numbers generator */
 
216
static unsigned int req_performed;     /* number of requests done */
 
217
static db_conn_t **connections;        /* database connection pool */
 
218
static oltp_stmt_set_t *statements;    /* prepared statements pool */
 
219
static oltp_bind_set_t *bind_bufs;     /* bind buffers pool */
 
220
static db_driver_t *driver;            /* current database driver */
 
221
static drv_caps_t driver_caps;         /* driver capabilities */
 
222
 
 
223
/* Statistic counters */
 
224
static int read_ops;
 
225
static int write_ops;
 
226
static int other_ops;
 
227
static int transactions;
 
228
static int deadlocks;
 
229
 
 
230
static sb_timer_t *exec_timers;
 
231
static sb_timer_t *fetch_timers;
 
232
 
 
233
/* Random seed used to generate unique random numbers */
 
234
static unsigned long long rnd_seed;
 
235
/* Mutex to protect random seed */
 
236
static pthread_mutex_t    rnd_mutex;
 
237
 
 
238
/* Variable to pass is_null flag to drivers */
 
239
 
 
240
static char oltp_is_null = 1;
 
241
 
 
242
/* Parse command line arguments */
 
243
static int parse_arguments(void);
 
244
 
 
245
/* Random number generators */
 
246
static unsigned int rnd_func_uniform(void);
 
247
static unsigned int rnd_func_gaussian(void);
 
248
static unsigned int rnd_func_special(void);
 
249
static unsigned int get_unique_random_id(void);
 
250
 
 
251
/* SQL request generators */
 
252
static sb_request_t get_request_simple(void);
 
253
static sb_request_t get_request_complex(void);
 
254
static sb_request_t get_request_nontrx(void);
 
255
static sb_request_t get_request_sp(void);
 
256
 
 
257
/* Get random 'user think' time */
 
258
static int get_think_time(void);
 
259
 
 
260
/* Generate SQL statement from query */
 
261
static db_stmt_t *get_sql_statement(sb_sql_query_t *, int);
 
262
static db_stmt_t *get_sql_statement_trx(sb_sql_query_t *, int);
 
263
static db_stmt_t *get_sql_statement_nontrx(sb_sql_query_t *, int);
 
264
static db_stmt_t *get_sql_statement_sp(sb_sql_query_t *, int);
 
265
 
 
266
/* Prepare a set of statements for test */
 
267
static int prepare_stmt_set(oltp_stmt_set_t *, oltp_bind_set_t *, db_conn_t *);
 
268
static int prepare_stmt_set_trx(oltp_stmt_set_t *, oltp_bind_set_t *, db_conn_t *);
 
269
static int prepare_stmt_set_nontrx(oltp_stmt_set_t *, oltp_bind_set_t *, db_conn_t *);
 
270
static int prepare_stmt_set_sp(oltp_stmt_set_t *, oltp_bind_set_t *, db_conn_t *);
 
271
 
 
272
/* Close a set of statements */
 
273
void close_stmt_set(oltp_stmt_set_t *set);
 
274
 
 
275
int register_test_oltp(sb_list_t *tests)
 
276
{
 
277
  /* Register database API */
 
278
  if (db_register())
 
279
    return 1;
 
280
  
 
281
  /* Register OLTP test */
 
282
  SB_LIST_ADD_TAIL(&oltp_test.listitem, tests);
 
283
  
 
284
  return 0;
 
285
}
 
286
 
 
287
 
 
288
int oltp_cmd_help(void)
 
289
{
 
290
  db_print_help();
 
291
  
 
292
  return 0;
 
293
}
 
294
 
 
295
 
 
296
int oltp_cmd_prepare(void)
 
297
{
 
298
  db_conn_t      *con;
 
299
  char           *query = NULL;
 
300
  unsigned int   query_len;
 
301
  unsigned int   i;
 
302
  unsigned int   j;
 
303
  unsigned int   n;
 
304
  unsigned long  nrows;
 
305
  unsigned long  commit_cntr = 0;
 
306
  char           insert_str[MAX_QUERY_LEN];
 
307
  char           *pos;
 
308
  char           *table_options_str;
 
309
  
 
310
  if (parse_arguments())
 
311
    return 1;
 
312
 
 
313
  /* Get database capabilites */
 
314
  if (db_describe(driver, &driver_caps, NULL))
 
315
  {
 
316
    log_text(LOG_FATAL, "failed to get database capabilities!");
 
317
    return 1;
 
318
  }
 
319
  
 
320
  /* Create database connection */
 
321
  con = oltp_connect();
 
322
  if (con == NULL)
 
323
    return 1;
 
324
 
 
325
  /* Determine if database supports multiple row inserts */
 
326
  if (driver_caps.multi_rows_insert)
 
327
    nrows = INSERT_ROWS;
 
328
  else
 
329
    nrows = 1;
 
330
  
 
331
  /* Prepare statement buffer */
 
332
  if (args.auto_inc)
 
333
    snprintf(insert_str, sizeof(insert_str),
 
334
             "(0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')");
 
335
  else
 
336
    snprintf(insert_str, sizeof(insert_str),
 
337
             "(%d,0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')",
 
338
             args.table_size);
 
339
  
 
340
  query_len = MAX_QUERY_LEN + nrows * (strlen(insert_str) + 1);
 
341
  query = (char *)malloc(query_len);
 
342
  if (query == NULL)
 
343
  {
 
344
    log_text(LOG_FATAL, "memory allocation failure!");
 
345
    goto error;
 
346
  }
 
347
  
 
348
  /* Create test table */
 
349
  log_text(LOG_NOTICE, "Creating table '%s'...", args.table_name);
 
350
  table_options_str = driver_caps.table_options_str;
 
351
  snprintf(query, query_len,
 
352
           "CREATE TABLE %s ("
 
353
           "id %s %s NOT NULL %s, "
 
354
           "k integer %s DEFAULT '0' NOT NULL, "
 
355
           "c char(120) DEFAULT '' NOT NULL, "
 
356
           "pad char(60) DEFAULT '' NOT NULL, "
 
357
           "PRIMARY KEY  (id) "
 
358
           ") %s",
 
359
           args.table_name,
 
360
           (args.auto_inc && driver_caps.serial) ? "SERIAL" : "INTEGER",
 
361
           driver_caps.unsigned_int ? "UNSIGNED" : "",
 
362
           (args.auto_inc && driver_caps.auto_increment) ? "AUTO_INCREMENT" : "",
 
363
           driver_caps.unsigned_int ? "UNSIGNED" : "",
 
364
           (table_options_str != NULL) ? table_options_str : ""
 
365
           );
 
366
  if (db_query(con, query) == NULL)
 
367
  {
 
368
    log_text(LOG_FATAL, "failed to create test table");
 
369
    goto error;
 
370
  }  
 
371
 
 
372
  if (args.auto_inc && !driver_caps.serial && !driver_caps.auto_increment)
 
373
  {
 
374
    if (db_query(con, "CREATE SEQUENCE sbtest_seq") == NULL ||
 
375
        db_query(con,
 
376
                 "CREATE TRIGGER sbtest_trig BEFORE INSERT ON sbtest "
 
377
                 "FOR EACH ROW "
 
378
                 "BEGIN SELECT sbtest_seq.nextval INTO :new.id FROM DUAL; "
 
379
                 "END;")
 
380
        == NULL)
 
381
    {
 
382
      log_text(LOG_FATAL, "failed to create test table");
 
383
      goto error;
 
384
    }
 
385
  }
 
386
  
 
387
  /* Create secondary index on 'k' */
 
388
  snprintf(query, query_len,
 
389
           "CREATE INDEX k on %s(k)",
 
390
           args.table_name);
 
391
  if (db_query(con, query) == NULL)
 
392
  {
 
393
    log_text(LOG_FATAL, "failed to create secondary index on table!");
 
394
    goto error;
 
395
  }
 
396
  /* Fill test table with data */
 
397
  log_text(LOG_NOTICE, "Creating %d records in table '%s'...", args.table_size,
 
398
         args.table_name);
 
399
 
 
400
  for (i = 0; i < args.table_size; i += nrows)
 
401
  {
 
402
    /* Build query */
 
403
    if (args.auto_inc)
 
404
      n = snprintf(query, query_len, "INSERT INTO %s(k, c, pad) VALUES ",
 
405
                   args.table_name);
 
406
    else
 
407
      n = snprintf(query, query_len, "INSERT INTO %s(id, k, c, pad) VALUES ",
 
408
                   args.table_name);
 
409
    if (n >= query_len)
 
410
    {
 
411
      log_text(LOG_FATAL, "query is too long!");
 
412
      goto error;
 
413
    }
 
414
    pos = query + n;
 
415
    for (j = 0; j < nrows; j++)
 
416
    {
 
417
      if ((unsigned)(pos - query) >= query_len)
 
418
      {
 
419
        log_text(LOG_FATAL, "query is too long!");
 
420
        goto error;
 
421
      }
 
422
 
 
423
      /* Form the values string when if are not using auto_inc */
 
424
      if (!args.auto_inc)
 
425
        snprintf(insert_str, sizeof(insert_str),
 
426
                 "(%d,0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')",
 
427
                 i + j + 1);
 
428
      
 
429
      if (j == nrows - 1 || i+j == args.table_size -1)
 
430
        n = snprintf(pos, query_len - (pos - query), "%s", insert_str);
 
431
      else
 
432
        n = snprintf(pos, query_len - (pos - query), "%s,", insert_str);
 
433
      if (n >= query_len - (pos - query))
 
434
      {
 
435
        log_text(LOG_FATAL, "query is too long!");
 
436
        goto error;
 
437
      }
 
438
      if (i+j == args.table_size - 1)
 
439
        break;
 
440
      pos += n;
 
441
    }
 
442
    
 
443
    /* Execute query */
 
444
    if (db_query(con, query) == NULL)
 
445
    {
 
446
      log_text(LOG_FATAL, "failed to create test table!");
 
447
      goto error;
 
448
    }
 
449
 
 
450
    if (driver_caps.needs_commit)
 
451
    {
 
452
      commit_cntr += nrows;
 
453
      if (commit_cntr >= ROWS_BEFORE_COMMIT)
 
454
      {
 
455
        if (db_query(con, "COMMIT") == NULL)
 
456
        {
 
457
          log_text(LOG_FATAL, "failed to commit inserted rows!");
 
458
          goto error;
 
459
        }
 
460
        commit_cntr -= ROWS_BEFORE_COMMIT;
 
461
      }
 
462
    }
 
463
  }
 
464
 
 
465
  if (driver_caps.needs_commit && db_query(con, "COMMIT") == NULL)
 
466
  {
 
467
    if (db_query(con, "COMMIT") == NULL)
 
468
    {
 
469
      log_text(LOG_FATAL, "failed to commit inserted rows!");
 
470
      return 1;
 
471
    }
 
472
  }
 
473
 
 
474
  oltp_disconnect(con);
 
475
  
 
476
  return 0;
 
477
 
 
478
 error:
 
479
  oltp_disconnect(con);
 
480
  if (query != NULL)
 
481
    free(query);
 
482
 
 
483
  return 1;
 
484
}
 
485
 
 
486
int oltp_cmd_cleanup(void)
 
487
{
 
488
  db_conn_t *con;
 
489
  char      query[256];
 
490
  
 
491
  if (parse_arguments())
 
492
    return 1;
 
493
 
 
494
  /* Get database capabilites */
 
495
  if (db_describe(driver, &driver_caps, NULL))
 
496
  {
 
497
    log_text(LOG_FATAL, "failed to get database capabilities!");
 
498
    return 1;
 
499
  }
 
500
 
 
501
  /* Create database connection */
 
502
  con = oltp_connect();
 
503
  if (con == NULL)
 
504
    return 1;
 
505
 
 
506
  /* Drop the test table */
 
507
  log_text(LOG_NOTICE, "Dropping table '%s'...", args.table_name);
 
508
  snprintf(query, sizeof(query), "DROP TABLE %s", args.table_name);
 
509
  if (db_query(con, query) == NULL)
 
510
  {
 
511
    oltp_disconnect(con);
 
512
    return 1;
 
513
  }
 
514
 
 
515
  oltp_disconnect(con);
 
516
  log_text(LOG_INFO, "Done.");
 
517
  
 
518
  return 0;
 
519
}
 
520
 
 
521
int oltp_init(void)
 
522
{
 
523
  db_conn_t    *con;
 
524
  unsigned int thread_id;
 
525
  char         query[MAX_QUERY_LEN];
 
526
 
 
527
  if (parse_arguments())
 
528
    return 1;
 
529
  
 
530
  /* Get database capabilites */
 
531
  if (db_describe(driver, &driver_caps, args.table_name))
 
532
  {
 
533
    log_text(LOG_FATAL, "failed to get database capabilities!");
 
534
    return 1;
 
535
  }
 
536
  
 
537
  /* Truncate table in case of nontrx INSERT test */
 
538
  if (args.test_mode == TEST_MODE_NONTRX && args.nontrx_mode == NONTRX_MODE_INSERT)
 
539
  {
 
540
    con = oltp_connect();
 
541
    if (con == NULL)
 
542
      return 1;
 
543
    snprintf(query, sizeof(query), "TRUNCATE TABLE %s", args.table_name);
 
544
    if (db_query(con, query) == NULL)
 
545
      return 1;
 
546
    oltp_disconnect(con);
 
547
  }
 
548
  
 
549
  /* Allocate database connection pool */
 
550
  connections = (db_conn_t **)malloc(sb_globals.num_threads * sizeof(db_conn_t *));
 
551
  if (connections == NULL)
 
552
  {
 
553
    log_text(LOG_FATAL, "failed to allocate DB connection pool!");
 
554
    return 1;
 
555
  }
 
556
 
 
557
  /* Create database connections */
 
558
  for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
 
559
  {
 
560
    connections[thread_id] = oltp_connect();
 
561
    if (connections[thread_id] == NULL)
 
562
    {
 
563
      log_text(LOG_FATAL, "thread#%d: failed to connect to database server, aborting...",
 
564
             thread_id);
 
565
      return 1;
 
566
    }
 
567
  }
 
568
 
 
569
  /* Allocate statements pool */
 
570
  statements = (oltp_stmt_set_t *)calloc(sb_globals.num_threads,
 
571
                                          sizeof(oltp_stmt_set_t));
 
572
  if (statements == NULL)
 
573
  {
 
574
    log_text(LOG_FATAL, "failed to allocate statements pool!");
 
575
    return 1;
 
576
  }
 
577
  
 
578
  /* Allocate bind buffers for each thread */
 
579
  bind_bufs = (oltp_bind_set_t *)calloc(sb_globals.num_threads,
 
580
                                        sizeof(oltp_bind_set_t));
 
581
  /* Prepare statements for each thread */
 
582
  for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
 
583
  {
 
584
    if (prepare_stmt_set(statements + thread_id, bind_bufs + thread_id,
 
585
                         connections[thread_id]))
 
586
    {
 
587
      log_text(LOG_FATAL, "thread#%d: failed to prepare statements for test",
 
588
             thread_id);
 
589
      return 1;
 
590
    }
 
591
  }
 
592
 
 
593
  /* Initialize random seed for non-transactional delete test */
 
594
  if (args.test_mode == TEST_MODE_NONTRX)
 
595
  {
 
596
    rnd_seed = LARGE_PRIME;
 
597
    pthread_mutex_init(&rnd_mutex, NULL);
 
598
  }
 
599
 
 
600
  /* Initialize internal timers if we are in the debug mode */
 
601
  if (sb_globals.debug)
 
602
  {
 
603
    exec_timers = (sb_timer_t *)malloc(sb_globals.num_threads * sizeof(sb_timer_t));
 
604
    fetch_timers = (sb_timer_t *)malloc(sb_globals.num_threads * sizeof(sb_timer_t));
 
605
    for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
 
606
    {
 
607
      sb_timer_init(exec_timers + thread_id);
 
608
      sb_timer_init(fetch_timers + thread_id);
 
609
    }
 
610
  }
 
611
  
 
612
  return 0;
 
613
}
 
614
 
 
615
 
 
616
int oltp_done(void)
 
617
{
 
618
  unsigned int thread_id;
 
619
 
 
620
  if (args.test_mode == TEST_MODE_NONTRX)
 
621
    pthread_mutex_destroy(&rnd_mutex);
 
622
 
 
623
  /* Close statements and database connections */
 
624
  for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
 
625
  {
 
626
    close_stmt_set(statements + thread_id);
 
627
    oltp_disconnect(connections[thread_id]);
 
628
  }
 
629
 
 
630
  /* Deallocate connection pool */
 
631
  free(connections);
 
632
 
 
633
  free(bind_bufs);
 
634
  free(statements);
 
635
  
 
636
  return 0;
 
637
}
 
638
 
 
639
 
 
640
void oltp_print_mode(void)
 
641
{
 
642
  log_text(LOG_NOTICE, "Doing OLTP test.");
 
643
  
 
644
  switch (args.test_mode) {
 
645
    case TEST_MODE_SIMPLE:
 
646
      log_text(LOG_NOTICE, "Running simple OLTP test");
 
647
      break;
 
648
    case TEST_MODE_COMPLEX:
 
649
      log_text(LOG_NOTICE, "Running mixed OLTP test");
 
650
      break;
 
651
    case TEST_MODE_NONTRX:
 
652
      log_text(LOG_NOTICE, "Running non-transactional test");
 
653
      break;
 
654
    case TEST_MODE_SP:
 
655
      log_text(LOG_NOTICE, "Running stored procedure test");
 
656
      return;
 
657
      break;
 
658
    default:
 
659
      log_text(LOG_WARNING, "Unknown OLTP test mode!");
 
660
      break;
 
661
  }
 
662
 
 
663
  if (args.read_only)
 
664
    log_text(LOG_NOTICE, "Doing read-only test");
 
665
  
 
666
  switch (args.dist_type) {
 
667
    case DIST_TYPE_UNIFORM:
 
668
      log_text(LOG_NOTICE, "Using Uniform distribution");
 
669
      break;
 
670
    case DIST_TYPE_GAUSSIAN:
 
671
      log_text(LOG_NOTICE, "Using Normal distribution (%d iterations)",
 
672
               args.dist_iter);
 
673
      break;
 
674
    case DIST_TYPE_SPECIAL:
 
675
      log_text(LOG_NOTICE, "Using Special distribution (%d iterations,  "
 
676
               "%d pct of values are returned in %d pct cases)",
 
677
               args.dist_iter, args.dist_pct, args.dist_res);
 
678
      break;
 
679
    default:
 
680
      log_text(LOG_WARNING, "Unknown distribution!");
 
681
      break;
 
682
  }
 
683
 
 
684
  if (args.skip_trx)
 
685
    log_text(LOG_NOTICE, "Skipping BEGIN/COMMIT");
 
686
  else
 
687
    log_text(LOG_NOTICE, "Using \"%s%s\" for starting transactions",
 
688
             driver_caps.transactions ? "BEGIN" : "LOCK TABLES",
 
689
             (driver_caps.transactions) ? "" :
 
690
             ((args.read_only) ? " READ" : " WRITE"));
 
691
 
 
692
  if (args.auto_inc)
 
693
    log_text(LOG_NOTICE, "Using auto_inc on the id column");
 
694
  else
 
695
    log_text(LOG_NOTICE, "Not using auto_inc on the id column");
 
696
  
 
697
  if (sb_globals.max_requests > 0)
 
698
    log_text(LOG_NOTICE,
 
699
             "Maximum number of requests for OLTP test is limited to %d",
 
700
             sb_globals.max_requests);
 
701
  if (sb_globals.validate)
 
702
    log_text(LOG_NOTICE, "Validation mode enabled");
 
703
}
 
704
 
 
705
 
 
706
sb_request_t oltp_get_request(int tid)
 
707
{
 
708
  sb_request_t sb_req;
 
709
 
 
710
  (void)tid; /* unused */
 
711
  
 
712
  if (sb_globals.max_requests > 0 && req_performed >= sb_globals.max_requests)
 
713
  {
 
714
    sb_req.type = SB_REQ_TYPE_NULL;
 
715
    return sb_req;
 
716
  }
 
717
  
 
718
  switch (args.test_mode) {
 
719
    case TEST_MODE_SIMPLE:
 
720
      return get_request_simple();
 
721
    case TEST_MODE_COMPLEX:
 
722
      return get_request_complex();
 
723
    case TEST_MODE_NONTRX:
 
724
      return get_request_nontrx();
 
725
    case TEST_MODE_SP:
 
726
      return get_request_sp();
 
727
    default:
 
728
      log_text(LOG_FATAL, "unknown test mode: %d!", args.test_mode);
 
729
      sb_req.type = SB_REQ_TYPE_NULL;
 
730
  }
 
731
  
 
732
  return sb_req;
 
733
}
 
734
 
 
735
 
 
736
sb_request_t get_request_sp(void)
 
737
{
 
738
  sb_request_t     sb_req;
 
739
  sb_sql_request_t *sql_req = &sb_req.u.sql_request;
 
740
  sb_sql_query_t   *query;
 
741
  
 
742
  sb_req.type = SB_REQ_TYPE_SQL;
 
743
  
 
744
  sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
 
745
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
746
  if (sql_req->queries == NULL || query == NULL)
 
747
  {
 
748
    log_text(LOG_FATAL, "cannot allocate SQL query!");
 
749
    sb_req.type = SB_REQ_TYPE_NULL;
 
750
    return sb_req;
 
751
  }
 
752
  
 
753
  SB_LIST_INIT(sql_req->queries);
 
754
  query->num_times = 1;
 
755
  query->think_time = get_think_time();
 
756
  query->type = SB_SQL_QUERY_CALL;
 
757
  query->nrows = 0;
 
758
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
759
 
 
760
  req_performed++;
 
761
 
 
762
  return sb_req;
 
763
}
 
764
 
 
765
 
 
766
sb_request_t get_request_simple(void)
 
767
{
 
768
  sb_request_t        sb_req;
 
769
  sb_sql_request_t    *sql_req = &sb_req.u.sql_request;
 
770
  sb_sql_query_t      *query;
 
771
  
 
772
  sb_req.type = SB_REQ_TYPE_SQL;
 
773
  
 
774
  sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
 
775
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
776
  if (sql_req->queries == NULL || query == NULL)
 
777
  {
 
778
    log_text(LOG_FATAL, "cannot allocate SQL query!");
 
779
    sb_req.type = SB_REQ_TYPE_NULL;
 
780
    return sb_req;
 
781
  }
 
782
 
 
783
  SB_LIST_INIT(sql_req->queries);
 
784
  query->num_times = 1;
 
785
  query->think_time = get_think_time();
 
786
  query->type = SB_SQL_QUERY_POINT;
 
787
  query->u.point_query.id = GET_RANDOM_ID();
 
788
  query->nrows = 1;
 
789
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
790
  
 
791
  req_performed++;
 
792
  
 
793
  return sb_req;
 
794
}
 
795
 
 
796
 
 
797
sb_request_t get_request_complex(void)
 
798
{
 
799
  sb_request_t        sb_req;
 
800
  sb_sql_request_t    *sql_req = &sb_req.u.sql_request;
 
801
  sb_sql_query_t      *query;
 
802
  sb_list_item_t      *pos;
 
803
  sb_list_item_t      *tmp;
 
804
  unsigned int        i;
 
805
  unsigned int        range;
 
806
  
 
807
  sb_req.type = SB_REQ_TYPE_SQL;
 
808
 
 
809
  sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
 
810
  if (sql_req->queries == NULL)
 
811
  {
 
812
    log_text(LOG_FATAL, "cannot allocate SQL query!");
 
813
    sb_req.type = SB_REQ_TYPE_NULL;
 
814
    return sb_req;
 
815
  }
 
816
  SB_LIST_INIT(sql_req->queries);
 
817
 
 
818
  if (!args.skip_trx)
 
819
  {
 
820
    /* Generate BEGIN statement */
 
821
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
822
    if (query == NULL)
 
823
      goto memfail;
 
824
    query->type = SB_SQL_QUERY_LOCK;
 
825
    query->num_times = 1;
 
826
    query->think_time = 0;
 
827
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
828
  }
 
829
  
 
830
  /* Generate set of point selects */
 
831
  for(i = 0; i < args.point_selects; i++)
 
832
  {
 
833
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
834
    if (query == NULL)
 
835
      goto memfail;
 
836
    query->num_times = 1;
 
837
    query->think_time = get_think_time();
 
838
    query->type = SB_SQL_QUERY_POINT;
 
839
    query->u.point_query.id = GET_RANDOM_ID();
 
840
    query->nrows = 1;
 
841
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
842
  }
 
843
  
 
844
  /* Generate range queries */
 
845
  for(i = 0; i < args.simple_ranges; i++)
 
846
  {
 
847
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
848
    if (query == NULL)
 
849
      goto memfail;
 
850
    query->num_times = 1;
 
851
    query->think_time = get_think_time();
 
852
    query->type = SB_SQL_QUERY_RANGE;
 
853
    range = GET_RANDOM_ID();
 
854
    if (range + args.range_size > args.table_size)
 
855
      range = args.table_size - args.range_size;
 
856
    if (range < 1)
 
857
      range = 1;     
 
858
    query->u.range_query.from = range;
 
859
    query->u.range_query.to = range + args.range_size - 1;
 
860
    query->nrows = args.range_size;
 
861
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
862
  }
 
863
  
 
864
  /* Generate sum range queries */
 
865
  for(i = 0; i < args.sum_ranges; i++)
 
866
  {
 
867
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
868
    if (query == NULL)
 
869
      goto memfail;
 
870
    query->num_times = 1;
 
871
    query->think_time = get_think_time();
 
872
    query->type = SB_SQL_QUERY_RANGE_SUM;
 
873
    range = GET_RANDOM_ID();
 
874
    if (range + args.range_size > args.table_size)
 
875
      range = args.table_size - args.range_size;
 
876
    if (range < 1)
 
877
      range = 1;
 
878
    query->u.range_query.from = range;
 
879
    query->u.range_query.to = range + args.range_size - 1;
 
880
    query->nrows = 1;
 
881
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
882
  }
 
883
 
 
884
  /* Generate ordered range queries */
 
885
  for(i = 0; i < args.order_ranges; i++)
 
886
  {
 
887
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
888
    if (query == NULL)
 
889
      goto memfail;
 
890
    query->num_times = 1;
 
891
    query->think_time = get_think_time();
 
892
    query->type = SB_SQL_QUERY_RANGE_ORDER;
 
893
    range = GET_RANDOM_ID();
 
894
    if (range + args.range_size > args.table_size)
 
895
      range = args.table_size - args.range_size;
 
896
    if (range < 1)
 
897
      range = 1;
 
898
    query->u.range_query.from = range;
 
899
    query->u.range_query.to = range + args.range_size - 1;
 
900
    query->nrows = args.range_size;
 
901
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
902
  }
 
903
 
 
904
  /* Generate distinct range queries */
 
905
  for(i = 0; i < args.distinct_ranges; i++)
 
906
  {
 
907
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
908
    if (query == NULL)
 
909
      goto memfail;
 
910
    query->num_times = 1;
 
911
    query->think_time = get_think_time();
 
912
    query->type = SB_SQL_QUERY_RANGE_DISTINCT;
 
913
    range = GET_RANDOM_ID();
 
914
    if (range + args.range_size > args.table_size)
 
915
      range = args.table_size - args.range_size;
 
916
    if (range < 1)
 
917
      range = 1;     
 
918
    query->u.range_query.from = range;
 
919
    query->u.range_query.to = range + args.range_size;
 
920
    query->nrows = 0;
 
921
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
922
  }
 
923
 
 
924
  /* Skip all write queries for read-only test mode */
 
925
  if (args.read_only)
 
926
    goto readonly;
 
927
  
 
928
  /* Generate index update */
 
929
  for (i = 0; i < args.index_updates; i++)
 
930
  {
 
931
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
932
    if (query == NULL)
 
933
      goto memfail;
 
934
    query->num_times = 1;
 
935
    query->think_time = get_think_time();
 
936
    query->type = SB_SQL_QUERY_UPDATE_INDEX;
 
937
    query->u.update_query.id = GET_RANDOM_ID();
 
938
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
939
  }
 
940
  
 
941
  /* Generate non-index update */
 
942
  for (i = 0; i < args.non_index_updates; i++)
 
943
  {
 
944
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
945
    if (query == NULL)
 
946
      goto memfail;
 
947
    query->num_times = 1;
 
948
    query->think_time = get_think_time();
 
949
    query->type = SB_SQL_QUERY_UPDATE_NON_INDEX;
 
950
    query->u.update_query.id = GET_RANDOM_ID();
 
951
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
952
  }
 
953
  
 
954
  /* FIXME: generate one more UPDATE with the same ID as DELETE/INSERT to make
 
955
     PostgreSQL work */
 
956
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
957
  if (query == NULL)
 
958
    goto memfail;
 
959
  query->num_times = 1;
 
960
  query->think_time = get_think_time();
 
961
  query->type = SB_SQL_QUERY_UPDATE_INDEX;
 
962
  range = GET_RANDOM_ID();
 
963
  query->u.update_query.id = range;
 
964
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
965
  
 
966
  /* Generate delete */
 
967
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
968
  if (query == NULL)
 
969
    goto memfail;
 
970
  query->num_times = 1;
 
971
  query->think_time = get_think_time();
 
972
  query->type = SB_SQL_QUERY_DELETE;
 
973
  /* FIXME  range = GET_RANDOM_ID(); */
 
974
  query->u.delete_query.id = range;
 
975
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
976
 
 
977
  /* Generate insert with same value */
 
978
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
979
  if (query == NULL)
 
980
    goto memfail;
 
981
  query->num_times = 1;
 
982
  query->think_time = get_think_time();
 
983
  query->type = SB_SQL_QUERY_INSERT;
 
984
  query->u.insert_query.id = range;
 
985
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
986
 
 
987
 readonly:
 
988
  
 
989
  if (!args.skip_trx)
 
990
  {
 
991
    /* Generate commit */
 
992
    query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
993
    if (query == NULL)
 
994
      goto memfail;
 
995
    query->type = SB_SQL_QUERY_UNLOCK;
 
996
    query->num_times = 1;
 
997
    query->think_time = 0;
 
998
    SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
999
  }
 
1000
  
 
1001
  /* return request */
 
1002
  req_performed++;
 
1003
  return sb_req;
 
1004
 
 
1005
  /* Handle memory allocation failures */
 
1006
 memfail:
 
1007
  log_text(LOG_FATAL, "cannot allocate SQL query!");
 
1008
  SB_LIST_FOR_EACH_SAFE(pos, tmp, sql_req->queries)
 
1009
  {
 
1010
    query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
 
1011
    free(query);
 
1012
  }
 
1013
  free(sql_req->queries);
 
1014
  sb_req.type = SB_REQ_TYPE_NULL;
 
1015
  return sb_req;
 
1016
}
 
1017
 
 
1018
 
 
1019
sb_request_t get_request_nontrx(void)
 
1020
{
 
1021
  sb_request_t        sb_req;
 
1022
  sb_sql_request_t    *sql_req = &sb_req.u.sql_request;
 
1023
  sb_sql_query_t      *query;
 
1024
  
 
1025
  sb_req.type = SB_REQ_TYPE_SQL;
 
1026
 
 
1027
  sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
 
1028
  if (sql_req->queries == NULL)
 
1029
  {
 
1030
    log_text(LOG_FATAL, "cannot allocate SQL query!");
 
1031
    sb_req.type = SB_REQ_TYPE_NULL;
 
1032
    return sb_req;
 
1033
  }
 
1034
  SB_LIST_INIT(sql_req->queries);
 
1035
 
 
1036
  query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
 
1037
  if (query == NULL)
 
1038
    goto memfail;
 
1039
  query->num_times = 1;
 
1040
  query->think_time = get_think_time();
 
1041
  
 
1042
  switch (args.nontrx_mode) {
 
1043
    case NONTRX_MODE_SELECT:
 
1044
      query->type = SB_SQL_QUERY_POINT;
 
1045
      query->u.point_query.id = GET_RANDOM_ID();
 
1046
      query->nrows = 1;
 
1047
      break;
 
1048
    case NONTRX_MODE_UPDATE_KEY:
 
1049
      query->type = SB_SQL_QUERY_UPDATE_INDEX;
 
1050
      query->u.update_query.id = GET_RANDOM_ID();
 
1051
      break;
 
1052
    case NONTRX_MODE_UPDATE_NOKEY:
 
1053
      query->type = SB_SQL_QUERY_UPDATE_NON_INDEX;
 
1054
      query->u.update_query.id = GET_RANDOM_ID();
 
1055
      break;
 
1056
    case NONTRX_MODE_INSERT:
 
1057
      query->type = SB_SQL_QUERY_INSERT;
 
1058
      query->u.update_query.id = GET_RANDOM_ID();
 
1059
      break;
 
1060
    case NONTRX_MODE_DELETE:
 
1061
      query->type = SB_SQL_QUERY_DELETE;
 
1062
      query->u.delete_query.id = get_unique_random_id();
 
1063
      break;
 
1064
    default:
 
1065
      log_text(LOG_FATAL, "unknown mode for non-transactional test!");
 
1066
      free(query);
 
1067
      sb_req.type = SB_REQ_TYPE_NULL;
 
1068
      break;
 
1069
  }
 
1070
 
 
1071
  SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
 
1072
 
 
1073
  /* return request */
 
1074
  req_performed++;
 
1075
  return sb_req;
 
1076
 
 
1077
  /* Handle memory allocation failures */
 
1078
 memfail:
 
1079
  log_text(LOG_FATAL, "cannot allocate SQL query!");
 
1080
  if (query)
 
1081
    free(query);
 
1082
  free(sql_req->queries);
 
1083
  sb_req.type = SB_REQ_TYPE_NULL;
 
1084
  return sb_req;
 
1085
}
 
1086
 
 
1087
 
 
1088
/*
 
1089
 * We measure read operations, write operations and transactions
 
1090
 * performance. The time is counted for atomic operations as user might sleep
 
1091
 * before some of them.
 
1092
 */
 
1093
 
 
1094
 
 
1095
int oltp_execute_request(sb_request_t *sb_req, int thread_id)
 
1096
{
 
1097
  db_stmt_t           *stmt;
 
1098
  sb_sql_request_t    *sql_req = &sb_req->u.sql_request;
 
1099
  db_error_t          rc;
 
1100
  db_result_set_t     *rs;
 
1101
  sb_list_item_t      *pos;
 
1102
  sb_list_item_t      *tmp;
 
1103
  sb_sql_query_t      *query;
 
1104
  unsigned int        i;
 
1105
  unsigned int        local_read_ops=0;
 
1106
  unsigned int        local_write_ops=0;
 
1107
  unsigned int        local_other_ops=0;
 
1108
  unsigned int        local_deadlocks=0;
 
1109
  int                 retry;
 
1110
  log_msg_t           msg;
 
1111
  log_msg_oper_t      op_msg;
 
1112
  unsigned long long  nrows;
 
1113
  
 
1114
  /* Prepare log message */
 
1115
  msg.type = LOG_MSG_TYPE_OPER;
 
1116
  msg.data = &op_msg;
 
1117
 
 
1118
  /* measure the time for transaction */
 
1119
  LOG_EVENT_START(msg, thread_id);
 
1120
 
 
1121
  do  /* deadlock handling */
 
1122
  {
 
1123
    retry = 0;
 
1124
    SB_LIST_FOR_EACH(pos, sql_req->queries)
 
1125
    {
 
1126
      query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
 
1127
 
 
1128
      for(i = 0; i < query->num_times; i++)
 
1129
      {
 
1130
        /* emulate user thinking */
 
1131
        if (query->think_time > 0)
 
1132
          usleep(query->think_time); 
 
1133
 
 
1134
        /* find prepared statement */
 
1135
        stmt = get_sql_statement(query, thread_id);
 
1136
        if (stmt == NULL)
 
1137
        {
 
1138
          log_text(LOG_FATAL, "unknown SQL query type: %d!", query->type);
 
1139
          sb_globals.error = 1;
 
1140
          return 1;
 
1141
        }
 
1142
 
 
1143
        if (sb_globals.debug)
 
1144
          sb_timer_start(exec_timers + thread_id);
 
1145
 
 
1146
        rs = db_execute(stmt);
 
1147
 
 
1148
        if (sb_globals.debug)
 
1149
          sb_timer_stop(exec_timers + thread_id);
 
1150
          
 
1151
        if (rs == NULL)
 
1152
        {
 
1153
          rc = db_errno(connections[thread_id]);
 
1154
          if (rc != SB_DB_ERROR_DEADLOCK)
 
1155
          {
 
1156
            log_text(LOG_FATAL, "database error, exiting...");
 
1157
            /* exiting, forget about allocated memory */
 
1158
            sb_globals.error = 1;
 
1159
            return 1; 
 
1160
          }  
 
1161
          else
 
1162
          {
 
1163
            local_deadlocks++;
 
1164
            retry = 1;
 
1165
            /* exit for loop */
 
1166
            break;  
 
1167
          }
 
1168
        }
 
1169
        
 
1170
        if (query->type >= SB_SQL_QUERY_POINT &&
 
1171
          query->type <= SB_SQL_QUERY_RANGE_DISTINCT) /* select query */
 
1172
        {
 
1173
          if (sb_globals.debug)
 
1174
            sb_timer_start(fetch_timers + thread_id);
 
1175
          
 
1176
          rc = db_store_results(rs);
 
1177
 
 
1178
          if (sb_globals.debug)
 
1179
            sb_timer_stop(fetch_timers + thread_id);
 
1180
          
 
1181
          
 
1182
          if (rc == SB_DB_ERROR_DEADLOCK)
 
1183
          {
 
1184
            db_free_results(rs);
 
1185
            local_deadlocks++;
 
1186
            retry = 1;
 
1187
            break;  
 
1188
          }
 
1189
          else if (rc != SB_DB_ERROR_NONE)
 
1190
          {
 
1191
            log_text(LOG_FATAL, "Error fetching result: `%s`", stmt);
 
1192
            /* exiting, forget about allocated memory */
 
1193
            sb_globals.error = 1;
 
1194
            return 1; 
 
1195
          }
 
1196
 
 
1197
          /* Validate the result set if requested */
 
1198
          if (sb_globals.validate && query->nrows > 0)
 
1199
          {
 
1200
            nrows = db_num_rows(rs);
 
1201
            if (nrows != query->nrows)
 
1202
              log_text(LOG_WARNING,
 
1203
                       "Number of received rows mismatch, expected: %ld, actual: %ld",
 
1204
                       (long )query->nrows, (long)nrows);
 
1205
          }
 
1206
          
 
1207
        }
 
1208
        db_free_results(rs);
 
1209
      }
 
1210
      
 
1211
      /* count operation statistics */
 
1212
      switch(query->type) {
 
1213
        case SB_SQL_QUERY_POINT:
 
1214
        case SB_SQL_QUERY_RANGE:
 
1215
        case SB_SQL_QUERY_RANGE_SUM:
 
1216
        case SB_SQL_QUERY_RANGE_ORDER:
 
1217
        case SB_SQL_QUERY_RANGE_DISTINCT:
 
1218
          local_read_ops += query->num_times;
 
1219
          break;
 
1220
        case SB_SQL_QUERY_UPDATE_INDEX:
 
1221
        case SB_SQL_QUERY_UPDATE_NON_INDEX:
 
1222
        case SB_SQL_QUERY_DELETE:
 
1223
        case SB_SQL_QUERY_INSERT:
 
1224
          local_write_ops += query->num_times;
 
1225
          break;
 
1226
        default: 
 
1227
          local_other_ops += query->num_times;
 
1228
      }   
 
1229
      if (retry)
 
1230
        break;  /* break transaction execution if deadlock */
 
1231
    }
 
1232
  } while(retry); /* retry transaction in case of deadlock */
 
1233
 
 
1234
  LOG_EVENT_STOP(msg, thread_id);
 
1235
  
 
1236
  SB_THREAD_MUTEX_LOCK();
 
1237
  read_ops += local_read_ops;
 
1238
  write_ops += local_write_ops;
 
1239
  other_ops += local_other_ops;
 
1240
  transactions++;
 
1241
  deadlocks += local_deadlocks;
 
1242
  SB_THREAD_MUTEX_UNLOCK();
 
1243
 
 
1244
  /* Free list of queries */
 
1245
  SB_LIST_FOR_EACH_SAFE(pos, tmp, sql_req->queries)
 
1246
  {
 
1247
    query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
 
1248
    free(query);
 
1249
  }
 
1250
  free(sql_req->queries);
 
1251
  
 
1252
  return 0;
 
1253
}
 
1254
 
 
1255
 
 
1256
void oltp_print_stats(void)
 
1257
{
 
1258
  double       total_time;
 
1259
  unsigned int i;
 
1260
  sb_timer_t   exec_timer;
 
1261
  sb_timer_t   fetch_timer;
 
1262
 
 
1263
  total_time = NS2SEC(sb_timer_value(&sb_globals.exec_timer));
 
1264
  
 
1265
  log_text(LOG_NOTICE, "OLTP test statistics:");
 
1266
  log_text(LOG_NOTICE, "    queries performed:");
 
1267
  log_text(LOG_NOTICE, "        read:                            %d",
 
1268
           read_ops);
 
1269
  log_text(LOG_NOTICE, "        write:                           %d",
 
1270
           write_ops);
 
1271
  log_text(LOG_NOTICE, "        other:                           %d",
 
1272
           other_ops);
 
1273
  log_text(LOG_NOTICE, "        total:                           %d",
 
1274
           read_ops + write_ops + other_ops);
 
1275
  log_text(LOG_NOTICE, "    transactions:                        %-6d"
 
1276
           " (%.2f per sec.)", transactions, transactions / total_time);
 
1277
  log_text(LOG_NOTICE, "    deadlocks:                           %-6d"
 
1278
           " (%.2f per sec.)", deadlocks, deadlocks / total_time);
 
1279
  log_text(LOG_NOTICE, "    read/write requests:                 %-6d"
 
1280
           " (%.2f per sec.)", read_ops + write_ops,
 
1281
           (read_ops + write_ops) / total_time);  
 
1282
  log_text(LOG_NOTICE, "    other operations:                    %-6d"
 
1283
           " (%.2f per sec.)", other_ops, other_ops / total_time);
 
1284
 
 
1285
  if (sb_globals.debug)
 
1286
  {
 
1287
    sb_timer_init(&exec_timer);
 
1288
    sb_timer_init(&fetch_timer);
 
1289
 
 
1290
    for (i = 0; i < sb_globals.num_threads; i++)
 
1291
    {
 
1292
      exec_timer = merge_timers(&exec_timer, exec_timers + i);
 
1293
      fetch_timer = merge_timers(&fetch_timer, fetch_timers + i);
 
1294
    }
 
1295
 
 
1296
    log_text(LOG_DEBUG, "");
 
1297
    log_text(LOG_DEBUG, "Query execution statistics:");
 
1298
    log_text(LOG_DEBUG, "    min:                                %.4fs",
 
1299
             NS2SEC(get_min_time(&exec_timer)));
 
1300
    log_text(LOG_DEBUG, "    avg:                                %.4fs",
 
1301
             NS2SEC(get_avg_time(&exec_timer)));
 
1302
    log_text(LOG_DEBUG, "    max:                                %.4fs",
 
1303
             NS2SEC(get_max_time(&exec_timer)));
 
1304
    log_text(LOG_DEBUG, "  total:                                %.4fs",
 
1305
             NS2SEC(get_sum_time(&exec_timer)));
 
1306
 
 
1307
    log_text(LOG_DEBUG, "Results fetching statistics:");
 
1308
    log_text(LOG_DEBUG, "    min:                                %.4fs",
 
1309
             NS2SEC(get_min_time(&fetch_timer)));
 
1310
    log_text(LOG_DEBUG, "    avg:                                %.4fs",
 
1311
             NS2SEC(get_avg_time(&fetch_timer)));
 
1312
    log_text(LOG_DEBUG, "    max:                                %.4fs",
 
1313
             NS2SEC(get_max_time(&fetch_timer)));
 
1314
    log_text(LOG_DEBUG, "  total:                                %.4fs",
 
1315
             NS2SEC(get_sum_time(&fetch_timer)));
 
1316
  }
 
1317
}
 
1318
 
 
1319
 
 
1320
db_conn_t *oltp_connect(void)
 
1321
{
 
1322
  db_conn_t *con;
 
1323
 
 
1324
  con = db_connect(driver);
 
1325
  if (con == NULL)
 
1326
  {
 
1327
    log_text(LOG_FATAL, "failed to connect to database server!");
 
1328
    return NULL;
 
1329
  }
 
1330
  
 
1331
  if (args.connect_delay > 0)
 
1332
    usleep(args.connect_delay);
 
1333
  
 
1334
  return con;
 
1335
}
 
1336
 
 
1337
 
 
1338
int oltp_disconnect(db_conn_t *con)
 
1339
{
 
1340
  return db_disconnect(con);
 
1341
}
 
1342
 
 
1343
 
 
1344
/* Parse command line arguments */
 
1345
 
 
1346
 
 
1347
int parse_arguments(void)
 
1348
{
 
1349
  char           *s;
 
1350
  
 
1351
  s = sb_get_value_string("oltp-test-mode");
 
1352
  if (!strcmp(s, "simple"))
 
1353
    args.test_mode = TEST_MODE_SIMPLE;
 
1354
  else if (!strcmp(s, "complex"))
 
1355
    args.test_mode = TEST_MODE_COMPLEX;
 
1356
  else if (!strcmp(s, "nontrx"))
 
1357
    args.test_mode = TEST_MODE_NONTRX;
 
1358
  else if (!strcmp(s, "sp"))
 
1359
    args.test_mode = TEST_MODE_SP;
 
1360
  else
 
1361
  {
 
1362
    log_text(LOG_FATAL, "Invalid OLTP test mode: %s.", s);
 
1363
    return 1;
 
1364
  }
 
1365
 
 
1366
  args.sp_name = sb_get_value_string("oltp-sp-name");
 
1367
  if (args.test_mode == TEST_MODE_SP && args.sp_name == NULL)
 
1368
  {
 
1369
    log_text(LOG_FATAL, "Name of stored procedure must be specified with --oltp-sp-name "
 
1370
             "in SP test mode");
 
1371
    return 1;
 
1372
  }
 
1373
 
 
1374
  args.read_only = sb_get_value_flag("oltp-read-only");
 
1375
  args.skip_trx = sb_get_value_flag("oltp-skip-trx");
 
1376
  args.auto_inc = sb_get_value_flag("oltp-auto-inc");
 
1377
  args.range_size = sb_get_value_int("oltp-range-size");
 
1378
  args.point_selects = sb_get_value_int("oltp-point-selects");
 
1379
  args.simple_ranges = sb_get_value_int("oltp-simple-ranges");
 
1380
  args.sum_ranges = sb_get_value_int("oltp-sum-ranges");
 
1381
  args.order_ranges = sb_get_value_int("oltp-order-ranges");
 
1382
  args.distinct_ranges = sb_get_value_int("oltp-distinct-ranges");
 
1383
  args.index_updates = sb_get_value_int("oltp-index-updates");
 
1384
  args.non_index_updates = sb_get_value_int("oltp-non-index-updates");
 
1385
 
 
1386
  s = sb_get_value_string("oltp-nontrx-mode");
 
1387
  if (!strcmp(s, "select"))
 
1388
    args.nontrx_mode = NONTRX_MODE_SELECT;
 
1389
  else if (!strcmp(s, "update_key"))
 
1390
    args.nontrx_mode = NONTRX_MODE_UPDATE_KEY;
 
1391
  else if (!strcmp(s, "update_nokey"))
 
1392
    args.nontrx_mode = NONTRX_MODE_UPDATE_NOKEY;
 
1393
  else if (!strcmp(s, "insert"))
 
1394
    args.nontrx_mode = NONTRX_MODE_INSERT;
 
1395
  else if (!strcmp(s, "delete"))
 
1396
    args.nontrx_mode = NONTRX_MODE_DELETE;
 
1397
  else
 
1398
  {
 
1399
    log_text(LOG_FATAL, "Invalid value of oltp-nontrx-mode: %s", s);
 
1400
    return 1;
 
1401
  }
 
1402
  
 
1403
  args.connect_delay = sb_get_value_int("oltp-connect-delay");
 
1404
  args.user_delay_min = sb_get_value_int("oltp-user-delay-min");
 
1405
  args.user_delay_max = sb_get_value_int("oltp-user-delay-max");
 
1406
  args.table_name = sb_get_value_string("oltp-table-name");
 
1407
  args.table_size = sb_get_value_int("oltp-table-size");
 
1408
 
 
1409
  s = sb_get_value_string("oltp-dist-type");
 
1410
  if (!strcmp(s, "uniform"))
 
1411
  {
 
1412
    args.dist_type = DIST_TYPE_UNIFORM;
 
1413
    rnd_func = &rnd_func_uniform;
 
1414
  }
 
1415
  else if (!strcmp(s, "gaussian"))
 
1416
  {
 
1417
    args.dist_type = DIST_TYPE_GAUSSIAN;
 
1418
    rnd_func = &rnd_func_gaussian;
 
1419
  }
 
1420
  else if (!strcmp(s, "special"))
 
1421
  {
 
1422
    args.dist_type = DIST_TYPE_SPECIAL;
 
1423
    rnd_func = &rnd_func_special;
 
1424
  }
 
1425
  else
 
1426
  {
 
1427
    log_text(LOG_FATAL, "Invalid random numbers distribution: %s.", s);
 
1428
    return 1;
 
1429
  }
 
1430
  
 
1431
  args.dist_iter = sb_get_value_int("oltp-dist-iter");
 
1432
  args.dist_pct = sb_get_value_int("oltp-dist-pct");
 
1433
  args.dist_res = sb_get_value_int("oltp-dist-res");
 
1434
 
 
1435
  /* Select driver according to command line arguments */
 
1436
  driver = db_init(NULL);
 
1437
  if (driver == NULL)
 
1438
  {
 
1439
    log_text(LOG_FATAL, "failed to initialize database driver!");
 
1440
    return 1;
 
1441
  }
 
1442
  
 
1443
  return 0;
 
1444
}
 
1445
 
 
1446
 
 
1447
/* Prepare a set of statements for the test */
 
1448
 
 
1449
 
 
1450
int prepare_stmt_set(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
 
1451
{
 
1452
  if (args.test_mode == TEST_MODE_NONTRX)
 
1453
    return prepare_stmt_set_nontrx(set, bufs, conn);
 
1454
  else if (args.test_mode == TEST_MODE_COMPLEX ||
 
1455
           args.test_mode == TEST_MODE_SIMPLE)
 
1456
    return prepare_stmt_set_trx(set, bufs, conn);
 
1457
 
 
1458
  return prepare_stmt_set_sp(set, bufs, conn);
 
1459
}
 
1460
 
 
1461
 
 
1462
/* Close a set of statements for the test */
 
1463
 
 
1464
void close_stmt_set(oltp_stmt_set_t *set)
 
1465
{
 
1466
  db_close(set->lock);
 
1467
  db_close(set->unlock);
 
1468
  db_close(set->point);
 
1469
  db_close(set->call);
 
1470
  db_close(set->range);
 
1471
  db_close(set->range_sum);
 
1472
  db_close(set->range_order);
 
1473
  db_close(set->range_distinct);
 
1474
  db_close(set->update_index);
 
1475
  db_close(set->update_non_index);
 
1476
  db_close(set->delete);
 
1477
  db_close(set->insert);
 
1478
}
 
1479
 
 
1480
 
 
1481
/* Generate SQL statement from query */
 
1482
 
 
1483
 
 
1484
db_stmt_t *get_sql_statement(sb_sql_query_t *query, int thread_id)
 
1485
{
 
1486
  if (args.test_mode == TEST_MODE_NONTRX)
 
1487
    return get_sql_statement_nontrx(query, thread_id);
 
1488
  else if (args.test_mode == TEST_MODE_COMPLEX ||
 
1489
           args.test_mode == TEST_MODE_SIMPLE)
 
1490
    return get_sql_statement_trx(query, thread_id);
 
1491
 
 
1492
  return get_sql_statement_sp(query, thread_id);
 
1493
}
 
1494
 
 
1495
 
 
1496
/* Prepare a set of statements for SP test */
 
1497
 
 
1498
 
 
1499
int prepare_stmt_set_sp(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
 
1500
{
 
1501
  db_bind_t params[2];
 
1502
  char      query[MAX_QUERY_LEN];
 
1503
  
 
1504
  /* Prepare CALL statement */
 
1505
  snprintf(query, MAX_QUERY_LEN, "CALL %s(?,?)", args.sp_name);
 
1506
  set->call = db_prepare(conn, query);
 
1507
  if (set->call == NULL)
 
1508
    return 1;
 
1509
  params[0].type = DB_TYPE_INT;
 
1510
  params[0].buffer = &bufs->call.thread_id;
 
1511
  params[0].is_null = 0;
 
1512
  params[0].data_len = 0;
 
1513
  params[1].type = DB_TYPE_INT;
 
1514
  params[1].buffer = &bufs->call.nthreads;
 
1515
  params[1].is_null = 0;
 
1516
  params[1].data_len = 0;
 
1517
  if (db_bind_param(set->call, params, 2))
 
1518
    return 1;
 
1519
  return 0;
 
1520
}
 
1521
 
 
1522
/* Prepare a set of statements for transactional test */
 
1523
 
 
1524
 
 
1525
int prepare_stmt_set_trx(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
 
1526
{
 
1527
  db_bind_t binds[11];
 
1528
  char      query[MAX_QUERY_LEN];
 
1529
 
 
1530
  /* Prepare the point statement */
 
1531
  snprintf(query, MAX_QUERY_LEN, "SELECT c from %s where id=?",
 
1532
           args.table_name);
 
1533
  set->point = db_prepare(conn, query);
 
1534
  if (set->point == NULL)
 
1535
    return 1;
 
1536
  binds[0].type = DB_TYPE_INT;
 
1537
  binds[0].buffer = &bufs->point.id;
 
1538
  binds[0].is_null = 0;
 
1539
  binds[0].data_len = 0;
 
1540
  if (db_bind_param(set->point, binds, 1))
 
1541
    return 1;
 
1542
 
 
1543
  /* Prepare the range statement */
 
1544
  snprintf(query, MAX_QUERY_LEN, "SELECT c from %s where id between ? and ?",
 
1545
           args.table_name);
 
1546
  set->range = db_prepare(conn, query);
 
1547
  if (set->range == NULL)
 
1548
    return 1;
 
1549
  binds[0].type = DB_TYPE_INT;
 
1550
  binds[0].buffer = &bufs->range.from;
 
1551
  binds[0].is_null = 0;
 
1552
  binds[0].data_len = 0;
 
1553
  binds[1].type = DB_TYPE_INT;
 
1554
  binds[1].buffer = &bufs->range.to;
 
1555
  binds[1].is_null = 0;
 
1556
  binds[1].data_len = 0;
 
1557
  if (db_bind_param(set->range, binds, 2))
 
1558
    return 1;
 
1559
 
 
1560
  /* Prepare the range_sum statement */
 
1561
  snprintf(query, MAX_QUERY_LEN,
 
1562
           "SELECT SUM(K) from %s where id between ? and ?", args.table_name);
 
1563
  set->range_sum = db_prepare(conn, query);
 
1564
  if (set->range_sum == NULL)
 
1565
    return 1;
 
1566
  binds[0].type = DB_TYPE_INT;
 
1567
  binds[0].buffer = &bufs->range_sum.from;
 
1568
  binds[0].is_null = 0;
 
1569
  binds[0].data_len = 0;
 
1570
  binds[1].type = DB_TYPE_INT;
 
1571
  binds[1].buffer = &bufs->range_sum.to;
 
1572
  binds[1].is_null = 0;
 
1573
  binds[1].data_len = 0;
 
1574
  if (db_bind_param(set->range_sum, binds, 2))
 
1575
    return 1;
 
1576
 
 
1577
  /* Prepare the range_order statement */
 
1578
  snprintf(query, MAX_QUERY_LEN,
 
1579
           "SELECT c from %s where id between ? and ? order by c",
 
1580
           args.table_name);
 
1581
  set->range_order = db_prepare(conn, query);
 
1582
  if (set->range_order == NULL)
 
1583
    return 1;
 
1584
  binds[0].type = DB_TYPE_INT;
 
1585
  binds[0].buffer = &bufs->range_order.from;
 
1586
  binds[0].is_null = 0;
 
1587
  binds[0].data_len = 0;
 
1588
  binds[1].type = DB_TYPE_INT;
 
1589
  binds[1].buffer = &bufs->range_order.to;
 
1590
  binds[1].is_null = 0;
 
1591
  binds[1].data_len = 0;
 
1592
  if (db_bind_param(set->range_order, binds, 2))
 
1593
    return 1;
 
1594
 
 
1595
  /* Prepare the range_distinct statement */
 
1596
  snprintf(query, MAX_QUERY_LEN,
 
1597
           "SELECT DISTINCT c from %s where id between ? and ? order by c",
 
1598
           args.table_name);
 
1599
  set->range_distinct = db_prepare(conn, query);
 
1600
  if (set->range_distinct == NULL)
 
1601
    return 1;
 
1602
  binds[0].type = DB_TYPE_INT;
 
1603
  binds[0].buffer = &bufs->range_distinct.from;
 
1604
  binds[0].is_null = 0;
 
1605
  binds[0].data_len = 0;
 
1606
  binds[1].type = DB_TYPE_INT;
 
1607
  binds[1].buffer = &bufs->range_distinct.to;
 
1608
  binds[1].is_null = 0;
 
1609
  binds[1].data_len = 0;
 
1610
  if (db_bind_param(set->range_distinct, binds, 2))
 
1611
    return 1;
 
1612
 
 
1613
  /* Prepare the update_index statement */
 
1614
  snprintf(query, MAX_QUERY_LEN, "UPDATE %s set k=k+1 where id=?",
 
1615
           args.table_name);
 
1616
  set->update_index = db_prepare(conn, query);
 
1617
  if (set->update_index == NULL)
 
1618
    return 1;
 
1619
  binds[0].type = DB_TYPE_INT;
 
1620
  binds[0].buffer = &bufs->update_index.id;
 
1621
  binds[0].is_null = 0;
 
1622
  binds[0].data_len = 0;
 
1623
  if (db_bind_param(set->update_index, binds, 1))
 
1624
    return 1;
 
1625
 
 
1626
  /* Prepare the update_non_index statement */
 
1627
  snprintf(query, MAX_QUERY_LEN,
 
1628
           "UPDATE %s set c=? where id=?",
 
1629
           args.table_name);
 
1630
  set->update_non_index = db_prepare(conn, query);
 
1631
  if (set->update_non_index == NULL)
 
1632
    return 1;
 
1633
  /*
 
1634
    Non-index update statement is re-bound each time because of the string
 
1635
    parameter
 
1636
  */
 
1637
  
 
1638
  /* Prepare the delete statement */
 
1639
  snprintf(query, MAX_QUERY_LEN, "DELETE from %s where id=?",
 
1640
           args.table_name);
 
1641
  set->delete = db_prepare(conn, query);
 
1642
  if (set->delete == NULL)
 
1643
    return 1;
 
1644
  binds[0].type = DB_TYPE_INT;
 
1645
  binds[0].buffer = &bufs->delete.id;
 
1646
  binds[0].is_null = 0;
 
1647
  binds[0].data_len = 0;
 
1648
  if (db_bind_param(set->delete, binds, 1))
 
1649
    return 1;
 
1650
 
 
1651
  /* Prepare the insert statement */
 
1652
  snprintf(query, MAX_QUERY_LEN, "INSERT INTO %s values(?,0,' ',"
 
1653
           "'aaaaaaaaaaffffffffffrrrrrrrrrreeeeeeeeeeyyyyyyyyyy')",
 
1654
           args.table_name);
 
1655
  set->insert = db_prepare(conn, query);
 
1656
  if (set->insert == NULL)
 
1657
    return 1;
 
1658
  binds[0].type = DB_TYPE_INT;
 
1659
  binds[0].buffer = &bufs->insert.id;
 
1660
  binds[0].is_null = 0;
 
1661
  binds[0].data_len = 0;
 
1662
  if (db_bind_param(set->insert, binds, 1))
 
1663
    return 1;
 
1664
 
 
1665
  if (args.skip_trx)
 
1666
    return 0;
 
1667
  
 
1668
  /* Prepare the lock statement */
 
1669
  if (driver_caps.transactions)
 
1670
    strncpy(query, "BEGIN", MAX_QUERY_LEN);
 
1671
  else
 
1672
  {
 
1673
    if (args.read_only)
 
1674
      snprintf(query, MAX_QUERY_LEN, "LOCK TABLES %s READ", args.table_name);
 
1675
    else
 
1676
      snprintf(query, MAX_QUERY_LEN, "LOCK TABLES %s WRITE", args.table_name);
 
1677
  }
 
1678
  set->lock = db_prepare(conn, query);
 
1679
  if (set->lock == NULL)
 
1680
    return 1;
 
1681
 
 
1682
  /* Prepare the unlock statement */
 
1683
  if (driver_caps.transactions)
 
1684
    strncpy(query, "COMMIT", MAX_QUERY_LEN);
 
1685
  else
 
1686
    strncpy(query, "UNLOCK TABLES", MAX_QUERY_LEN);
 
1687
  set->unlock = db_prepare(conn, query);
 
1688
  if (set->unlock == NULL)
 
1689
    return 1;
 
1690
 
 
1691
  return 0;
 
1692
}
 
1693
 
 
1694
 
 
1695
/* Prepare a set of statements for non-transactional test */
 
1696
 
 
1697
 
 
1698
int prepare_stmt_set_nontrx(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
 
1699
{
 
1700
  db_bind_t binds[11];
 
1701
  char      query[MAX_QUERY_LEN];
 
1702
 
 
1703
  /* Prepare the point statement */
 
1704
  snprintf(query, MAX_QUERY_LEN, "SELECT pad from %s where id=?",
 
1705
           args.table_name);
 
1706
  set->point = db_prepare(conn, query);
 
1707
  if (set->point == NULL)
 
1708
    return 1;
 
1709
  binds[0].type = DB_TYPE_INT;
 
1710
  binds[0].buffer = &bufs->point.id;
 
1711
  binds[0].is_null = 0;
 
1712
  binds[0].data_len = 0;
 
1713
  if (db_bind_param(set->point, binds, 1))
 
1714
    return 1;
 
1715
 
 
1716
  /* Prepare the update_index statement */
 
1717
  snprintf(query, MAX_QUERY_LEN, "UPDATE %s set k=k+1 where id=?",
 
1718
           args.table_name);
 
1719
  set->update_index = db_prepare(conn, query);
 
1720
  if (set->update_index == NULL)
 
1721
    return 1;
 
1722
  binds[0].type = DB_TYPE_INT;
 
1723
  binds[0].buffer = &bufs->update_index.id;
 
1724
  binds[0].is_null = 0;
 
1725
  binds[0].data_len = 0;
 
1726
  if (db_bind_param(set->update_index, binds, 1))
 
1727
    return 1;
 
1728
 
 
1729
  /* Prepare the update_non_index statement */
 
1730
  snprintf(query, MAX_QUERY_LEN,
 
1731
           "UPDATE %s set c=? where id=?",
 
1732
           args.table_name);
 
1733
  set->update_non_index = db_prepare(conn, query);
 
1734
  if (set->update_non_index == NULL)
 
1735
    return 1;
 
1736
  /*
 
1737
    Non-index update statement is re-bound each time because of the string
 
1738
    parameter
 
1739
  */
 
1740
  
 
1741
  /* Prepare the delete statement */
 
1742
  snprintf(query, MAX_QUERY_LEN, "DELETE from %s where id=?",
 
1743
           args.table_name);
 
1744
  set->delete = db_prepare(conn, query);
 
1745
  if (set->delete == NULL)
 
1746
    return 1;
 
1747
  binds[0].type = DB_TYPE_INT;
 
1748
  binds[0].buffer = &bufs->delete.id;
 
1749
  binds[0].is_null = 0;
 
1750
  binds[0].data_len = 0;
 
1751
  if (db_bind_param(set->delete, binds, 1))
 
1752
    return 1;
 
1753
 
 
1754
  /* Prepare the insert statement */
 
1755
  snprintf(query, MAX_QUERY_LEN, "INSERT INTO %s values(?,?,?,?)",
 
1756
           args.table_name);
 
1757
  set->insert = db_prepare(conn, query);
 
1758
  /*
 
1759
    Insert statement is re-bound each time because of the string
 
1760
    parameters
 
1761
  */
 
1762
  
 
1763
  return 0;
 
1764
}
 
1765
 
 
1766
 
 
1767
/* Generate SQL statement from query for SP test */
 
1768
 
 
1769
 
 
1770
db_stmt_t *get_sql_statement_sp(sb_sql_query_t *query, int thread_id)
 
1771
{
 
1772
  db_stmt_t       *stmt;
 
1773
  oltp_bind_set_t  *buf = bind_bufs + thread_id;
 
1774
 
 
1775
  (void) query; /* unused */
 
1776
  
 
1777
  stmt = statements[thread_id].call;
 
1778
  buf->call.thread_id = thread_id;
 
1779
  buf->call.nthreads = sb_globals.num_threads;
 
1780
  
 
1781
  return stmt;
 
1782
}
 
1783
 
 
1784
 
 
1785
/* Generate SQL statement from query for transactional test */
 
1786
 
 
1787
 
 
1788
db_stmt_t *get_sql_statement_trx(sb_sql_query_t *query, int thread_id)
 
1789
{
 
1790
  db_stmt_t       *stmt = NULL;
 
1791
  db_bind_t       binds[2];
 
1792
  oltp_bind_set_t *buf = bind_bufs + thread_id;
 
1793
  
 
1794
  switch (query->type) {
 
1795
    case SB_SQL_QUERY_LOCK:
 
1796
      stmt = statements[thread_id].lock;
 
1797
      break;
 
1798
 
 
1799
    case SB_SQL_QUERY_UNLOCK:
 
1800
      stmt = statements[thread_id].unlock;
 
1801
      break;
 
1802
 
 
1803
    case SB_SQL_QUERY_POINT:
 
1804
      stmt = statements[thread_id].point;
 
1805
      buf->point.id = query->u.point_query.id;
 
1806
      break;
 
1807
 
 
1808
    case SB_SQL_QUERY_RANGE:
 
1809
      stmt = statements[thread_id].range;
 
1810
      buf->range.from = query->u.range_query.from;
 
1811
      buf->range.to = query->u.range_query.to;
 
1812
      break;
 
1813
 
 
1814
    case SB_SQL_QUERY_RANGE_SUM:
 
1815
      stmt = statements[thread_id].range_sum;
 
1816
      buf->range_sum.from = query->u.range_query.from;
 
1817
      buf->range_sum.to = query->u.range_query.to;
 
1818
      break;
 
1819
 
 
1820
    case SB_SQL_QUERY_RANGE_ORDER:
 
1821
      stmt = statements[thread_id].range_order;
 
1822
      buf->range_order.from = query->u.range_query.from;
 
1823
      buf->range_order.to = query->u.range_query.to;
 
1824
      break;
 
1825
 
 
1826
    case SB_SQL_QUERY_RANGE_DISTINCT:
 
1827
      stmt = statements[thread_id].range_distinct;
 
1828
      buf->range_distinct.from = query->u.range_query.from;
 
1829
      buf->range_distinct.to = query->u.range_query.to;
 
1830
      break;
 
1831
 
 
1832
    case SB_SQL_QUERY_UPDATE_INDEX:
 
1833
      stmt = statements[thread_id].update_index;
 
1834
      buf->update_index.id = query->u.update_query.id;
 
1835
      break;
 
1836
 
 
1837
    case SB_SQL_QUERY_UPDATE_NON_INDEX:
 
1838
      stmt = statements[thread_id].update_non_index;
 
1839
      /*
 
1840
        We have to bind non-index update data each time
 
1841
        because of string parameter
 
1842
      */
 
1843
      snprintf(buf->c, 120, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
 
1844
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(),
 
1845
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd());
 
1846
      buf->update_non_index.id = query->u.update_query.id;
 
1847
      buf->c_len = strlen(buf->c);
 
1848
      binds[0].type = DB_TYPE_CHAR;
 
1849
      binds[0].buffer = buf->c;
 
1850
      binds[0].data_len = &buf->c_len;
 
1851
      binds[0].is_null = 0;
 
1852
      binds[0].max_len = 120;
 
1853
      binds[1].type = DB_TYPE_INT;
 
1854
      binds[1].buffer = &buf->update_non_index.id;
 
1855
      binds[1].data_len = 0;
 
1856
      binds[1].is_null = 0;
 
1857
      if (db_bind_param(statements[thread_id].update_non_index, binds, 2))
 
1858
        return NULL;
 
1859
      break;
 
1860
 
 
1861
    case SB_SQL_QUERY_DELETE:
 
1862
      stmt = statements[thread_id].delete;
 
1863
      buf->delete.id = query->u.delete_query.id;
 
1864
      break;
 
1865
 
 
1866
    case SB_SQL_QUERY_INSERT:
 
1867
      stmt = statements[thread_id].insert;
 
1868
      buf->insert.id = query->u.insert_query.id;
 
1869
      break;
 
1870
 
 
1871
    default:
 
1872
      return NULL;
 
1873
  }
 
1874
 
 
1875
  return stmt;
 
1876
}
 
1877
 
 
1878
 
 
1879
/* Generate SQL statement from query for non-transactional test */
 
1880
 
 
1881
 
 
1882
db_stmt_t *get_sql_statement_nontrx(sb_sql_query_t *query, int thread_id)
 
1883
{
 
1884
  db_stmt_t       *stmt = NULL;
 
1885
  db_bind_t       binds[4];
 
1886
  oltp_bind_set_t *buf = bind_bufs + thread_id;
 
1887
  
 
1888
  switch (query->type) {
 
1889
    case SB_SQL_QUERY_POINT:
 
1890
      stmt = statements[thread_id].point;
 
1891
      buf->point.id = query->u.point_query.id;
 
1892
      break;
 
1893
 
 
1894
    case SB_SQL_QUERY_UPDATE_INDEX:
 
1895
      stmt = statements[thread_id].update_index;
 
1896
      buf->update_index.id = query->u.update_query.id;
 
1897
      break;
 
1898
 
 
1899
    case SB_SQL_QUERY_UPDATE_NON_INDEX:
 
1900
      stmt = statements[thread_id].update_non_index;
 
1901
      /*
 
1902
        We have to bind non-index update data each time
 
1903
        because of string parameter
 
1904
      */
 
1905
      snprintf(buf->c, 120, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
 
1906
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(),
 
1907
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd());
 
1908
      buf->update_non_index.id = query->u.update_query.id;
 
1909
      buf->c_len = strlen(buf->c);
 
1910
 
 
1911
      binds[0].type = DB_TYPE_CHAR;
 
1912
      binds[0].buffer = buf->c;
 
1913
      binds[0].data_len = &buf->c_len;
 
1914
      binds[0].is_null = 0;
 
1915
      binds[0].max_len = 120;
 
1916
 
 
1917
      binds[1].type = DB_TYPE_INT;
 
1918
      binds[1].buffer = &buf->update_non_index.id;
 
1919
      binds[1].data_len = 0;
 
1920
      binds[1].is_null = 0;
 
1921
 
 
1922
      if (db_bind_param(statements[thread_id].update_non_index, binds, 2))
 
1923
        return NULL;
 
1924
      break;
 
1925
 
 
1926
    case SB_SQL_QUERY_DELETE:
 
1927
      stmt = statements[thread_id].delete;
 
1928
      buf->delete.id = query->u.delete_query.id;
 
1929
      break;
 
1930
 
 
1931
    case SB_SQL_QUERY_INSERT:
 
1932
      stmt = statements[thread_id].insert;
 
1933
      /*
 
1934
        We have to bind insert data each time
 
1935
        because of string parameters
 
1936
      */
 
1937
      buf->range.to = query->u.insert_query.id;
 
1938
      snprintf(buf->c, 120, "%d-%d-%d-%d-%d-%d-%d-%d-%d-%d",
 
1939
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(),
 
1940
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd());
 
1941
      buf->c_len = strlen(buf->c);
 
1942
      snprintf(buf->pad, 60, "%d-%d-%d-%d-%d",
 
1943
               sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd(), sb_rnd());
 
1944
      buf->pad_len = strlen(buf->pad);
 
1945
 
 
1946
      /* Use NULL is AUTO_INCREMENT is used, unique id otherwise */
 
1947
      if (args.auto_inc)
 
1948
      {
 
1949
        binds[0].is_null = &oltp_is_null;
 
1950
      }
 
1951
      else
 
1952
      {
 
1953
        buf->range.from = get_unique_random_id();
 
1954
        binds[0].buffer = &buf->range.from;
 
1955
        binds[0].is_null = 0;
 
1956
      }
 
1957
      
 
1958
      binds[0].type = DB_TYPE_INT;
 
1959
      binds[0].data_len = 0;
 
1960
 
 
1961
      binds[1].type = DB_TYPE_INT;
 
1962
      binds[1].buffer = &buf->range.to;
 
1963
      binds[1].data_len = 0;
 
1964
      binds[1].is_null = 0;
 
1965
 
 
1966
      binds[2].type = DB_TYPE_CHAR;
 
1967
      binds[2].buffer = buf->c;
 
1968
      binds[2].data_len = &buf->c_len;
 
1969
      binds[2].is_null = 0;
 
1970
      binds[2].max_len = 120;
 
1971
 
 
1972
      binds[3].type = DB_TYPE_CHAR;
 
1973
      binds[3].buffer = buf->pad;
 
1974
      binds[3].data_len = &buf->pad_len;
 
1975
      binds[3].is_null = 0;
 
1976
      binds[3].max_len = 60;
 
1977
 
 
1978
      if (db_bind_param(statements[thread_id].insert, binds, 4))
 
1979
        return NULL;
 
1980
      
 
1981
      break;
 
1982
 
 
1983
    default:
 
1984
      return NULL;
 
1985
  }
 
1986
 
 
1987
  return stmt;
 
1988
}
 
1989
 
 
1990
 
 
1991
/* uniform distribution */
 
1992
 
 
1993
 
 
1994
unsigned int rnd_func_uniform(void)
 
1995
{
 
1996
  return 1 + sb_rnd() % args.table_size;
 
1997
}
 
1998
 
 
1999
 
 
2000
/* gaussian distribution */
 
2001
 
 
2002
 
 
2003
unsigned int rnd_func_gaussian(void)
 
2004
{
 
2005
  int          sum;
 
2006
  unsigned int i;
 
2007
 
 
2008
  for(i=0, sum=0; i < args.dist_iter; i++)
 
2009
    sum += (1 + sb_rnd() % args.table_size);
 
2010
  
 
2011
  return sum / args.dist_iter;
 
2012
}
 
2013
 
 
2014
 
 
2015
/* 'special' distribution */
 
2016
 
 
2017
 
 
2018
unsigned int rnd_func_special(void)
 
2019
{
 
2020
  int          sum = 0;
 
2021
  unsigned int i;
 
2022
  unsigned int d;
 
2023
  unsigned int res;
 
2024
  unsigned int range_size;
 
2025
  
 
2026
  if (args.table_size == 0)
 
2027
    return 0;
 
2028
  
 
2029
  /* Increase range size for special values. */
 
2030
  range_size = args.table_size * (100 / (100 - args.dist_res));
 
2031
  
 
2032
  /* Generate evenly distributed one at this stage  */
 
2033
  res = (1 + sb_rnd() % range_size);
 
2034
  
 
2035
  /* For first part use gaussian distribution */
 
2036
  if (res <= args.table_size)
 
2037
  {
 
2038
    for(i = 0; i < args.dist_iter; i++)
 
2039
    {
 
2040
      sum += (1 + sb_rnd() % args.table_size);
 
2041
    }
 
2042
    return sum / args.dist_iter;  
 
2043
  }
 
2044
 
 
2045
  /*
 
2046
   * For second part use even distribution mapped to few items 
 
2047
   * We shall distribute other values near by the center
 
2048
   */
 
2049
  d = args.table_size * args.dist_pct / 100;
 
2050
  if (d < 1)
 
2051
    d = 1;
 
2052
  res %= d;
 
2053
   
 
2054
  /* Now we have res values in SPECIAL_PCT range of the data */
 
2055
  res += (args.table_size / 2 - args.table_size * args.dist_pct / (100 * 2));
 
2056
   
 
2057
  return res;
 
2058
}
 
2059
 
 
2060
 
 
2061
/* Generate unique random id */
 
2062
 
 
2063
 
 
2064
unsigned int get_unique_random_id(void)
 
2065
{
 
2066
  unsigned int res;
 
2067
 
 
2068
  pthread_mutex_lock(&rnd_mutex);
 
2069
  res = (unsigned int) (rnd_seed % args.table_size) + 1;
 
2070
  rnd_seed += LARGE_PRIME;
 
2071
  pthread_mutex_unlock(&rnd_mutex);
 
2072
 
 
2073
  return res;
 
2074
}
 
2075
 
 
2076
 
 
2077
int get_think_time(void)
 
2078
{
 
2079
  int t = args.user_delay_min;
 
2080
 
 
2081
  if (args.user_delay_min < args.user_delay_max)
 
2082
    t += sb_rnd() % (args.user_delay_max - args.user_delay_min);
 
2083
 
 
2084
  return t; 
 
2085
}
 
2086