~sjamthe/sysbench/latdist

« back to all changes in this revision

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

  • Committer: Alexey Kopytov
  • Date: 2009-05-28 16:12:23 UTC
  • Revision ID: alexey.kopytov@sun.com-20090528161223-p6eu4d5jpb03pepn
Added the old OLTP test back

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