1
/* Copyright (C) 2004 MySQL AB
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.
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.
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
23
#include "db_driver.h"
26
#define GET_RANDOM_ID() ((*rnd_func)())
28
/* How many rows to insert in a single query (used for test DB creation) */
29
#define INSERT_ROWS 10000
31
/* How many rows to insert before COMMITs (used for test DB creation) */
32
#define ROWS_BEFORE_COMMIT 1000
34
/* Maximum query length */
35
#define MAX_QUERY_LEN 1024
37
/* Large prime number to generate unique set of random numbers in delete test */
38
#define LARGE_PRIME 2147483647
40
/* Command line arguments definition */
41
static sb_arg_t oltp_args[] =
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,
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"},
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,
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"},
71
{"oltp-dist-type", "random numbers distribution {uniform,gaussian,special}", SB_ARG_TYPE_STRING,
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"},
79
{NULL, NULL, SB_ARG_TYPE_NULL, NULL}
91
/* Modes for 'non-transactional' test */
95
NONTRX_MODE_UPDATE_KEY,
96
NONTRX_MODE_UPDATE_NOKEY,
101
/* Random numbers distributions */
110
Some code in get_request_*() depends on the order in which the following
111
constants are defined
116
RECONNECT_TRANSACTION,
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;
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;
149
/* Test statements structure */
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;
166
/* Bind buffers for statements */
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 */
182
/* Buffer for the 'pad' table field in insert query */
184
unsigned long pad_len;
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);
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);
203
static sb_test_t oltp_test =
213
oltp_execute_request,
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 */
240
/* Statistic counters */
242
static int write_ops;
243
static int other_ops;
244
static int transactions;
245
static int deadlocks;
247
static sb_timer_t *exec_timers;
248
static sb_timer_t *fetch_timers;
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;
255
/* Variable to pass is_null flag to drivers */
257
static char oltp_is_null = 1;
259
/* Parse command line arguments */
260
static int parse_arguments(void);
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);
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);
274
/* Adds a 'reconnect' request to the list of SQL queries */
275
static inline int add_reconnect_req(sb_list_t *list);
277
/* Get random 'user think' time */
278
static int get_think_time(void);
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);
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 *);
292
/* Close a set of statements */
293
void close_stmt_set(oltp_stmt_set_t *set);
295
int register_test_oltp(sb_list_t *tests)
297
/* Register database API */
301
/* Register OLTP test */
302
SB_LIST_ADD_TAIL(&oltp_test.listitem, tests);
308
int oltp_cmd_help(void)
316
int oltp_cmd_prepare(void)
320
unsigned int query_len;
325
unsigned long commit_cntr = 0;
326
char insert_str[MAX_QUERY_LEN];
328
char *table_options_str;
330
if (parse_arguments())
333
/* Get database capabilites */
334
if (db_describe(driver, &driver_caps, NULL))
336
log_text(LOG_FATAL, "failed to get database capabilities!");
340
/* Create database connection */
341
con = oltp_connect();
345
/* Determine if database supports multiple row inserts */
346
if (driver_caps.multi_rows_insert)
351
/* Prepare statement buffer */
353
snprintf(insert_str, sizeof(insert_str),
354
"(0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')");
356
snprintf(insert_str, sizeof(insert_str),
357
"(%d,0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')",
360
query_len = MAX_QUERY_LEN + nrows * (strlen(insert_str) + 1);
361
query = (char *)malloc(query_len);
364
log_text(LOG_FATAL, "memory allocation failure!");
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,
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, "
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 : ""
386
if (db_query(con, query) == NULL)
388
log_text(LOG_FATAL, "failed to create test table");
392
if (args.auto_inc && !driver_caps.serial && !driver_caps.auto_increment)
394
if (db_query(con, "CREATE SEQUENCE sbtest_seq") == NULL ||
396
"CREATE TRIGGER sbtest_trig BEFORE INSERT ON sbtest "
398
"BEGIN SELECT sbtest_seq.nextval INTO :new.id FROM DUAL; "
402
log_text(LOG_FATAL, "failed to create test table");
407
/* Create secondary index on 'k' */
408
snprintf(query, query_len,
409
"CREATE INDEX k on %s(k)",
411
if (db_query(con, query) == NULL)
413
log_text(LOG_FATAL, "failed to create secondary index on table!");
416
/* Fill test table with data */
417
log_text(LOG_NOTICE, "Creating %d records in table '%s'...", args.table_size,
420
for (i = 0; i < args.table_size; i += nrows)
424
n = snprintf(query, query_len, "INSERT INTO %s(k, c, pad) VALUES ",
427
n = snprintf(query, query_len, "INSERT INTO %s(id, k, c, pad) VALUES ",
431
log_text(LOG_FATAL, "query is too long!");
435
for (j = 0; j < nrows; j++)
437
if ((unsigned)(pos - query) >= query_len)
439
log_text(LOG_FATAL, "query is too long!");
443
/* Form the values string when if are not using auto_inc */
445
snprintf(insert_str, sizeof(insert_str),
446
"(%d,0,' ','qqqqqqqqqqwwwwwwwwwweeeeeeeeeerrrrrrrrrrtttttttttt')",
449
if (j == nrows - 1 || i+j == args.table_size -1)
450
n = snprintf(pos, query_len - (pos - query), "%s", insert_str);
452
n = snprintf(pos, query_len - (pos - query), "%s,", insert_str);
453
if (n >= query_len - (pos - query))
455
log_text(LOG_FATAL, "query is too long!");
458
if (i+j == args.table_size - 1)
464
if (db_query(con, query) == NULL)
466
log_text(LOG_FATAL, "failed to create test table!");
470
if (driver_caps.needs_commit)
472
commit_cntr += nrows;
473
if (commit_cntr >= ROWS_BEFORE_COMMIT)
475
if (db_query(con, "COMMIT") == NULL)
477
log_text(LOG_FATAL, "failed to commit inserted rows!");
480
commit_cntr -= ROWS_BEFORE_COMMIT;
485
if (driver_caps.needs_commit && db_query(con, "COMMIT") == NULL)
487
if (db_query(con, "COMMIT") == NULL)
489
log_text(LOG_FATAL, "failed to commit inserted rows!");
494
oltp_disconnect(con);
499
oltp_disconnect(con);
506
int oltp_cmd_cleanup(void)
511
if (parse_arguments())
514
/* Get database capabilites */
515
if (db_describe(driver, &driver_caps, NULL))
517
log_text(LOG_FATAL, "failed to get database capabilities!");
521
/* Create database connection */
522
con = oltp_connect();
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)
531
oltp_disconnect(con);
535
oltp_disconnect(con);
536
log_text(LOG_INFO, "Done.");
544
unsigned int thread_id;
545
char query[MAX_QUERY_LEN];
547
if (parse_arguments())
550
/* Get database capabilites */
551
if (db_describe(driver, &driver_caps, args.table_name))
553
log_text(LOG_FATAL, "failed to get database capabilities!");
557
/* Truncate table in case of nontrx INSERT test */
558
if (args.test_mode == TEST_MODE_NONTRX && args.nontrx_mode == NONTRX_MODE_INSERT)
560
con = oltp_connect();
563
snprintf(query, sizeof(query), "TRUNCATE TABLE %s", args.table_name);
564
if (db_query(con, query) == NULL)
566
oltp_disconnect(con);
569
/* Allocate database connection pool */
570
connections = (db_conn_t **)malloc(sb_globals.num_threads * sizeof(db_conn_t *));
571
if (connections == NULL)
573
log_text(LOG_FATAL, "failed to allocate DB connection pool!");
577
/* Create database connections */
578
for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
580
connections[thread_id] = oltp_connect();
581
if (connections[thread_id] == NULL)
583
log_text(LOG_FATAL, "thread#%d: failed to connect to database server, aborting...",
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)
594
log_text(LOG_FATAL, "failed to allocate statements pool!");
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++)
604
if (prepare_stmt_set(statements + thread_id, bind_bufs + thread_id,
605
connections[thread_id]))
607
log_text(LOG_FATAL, "thread#%d: failed to prepare statements for test",
613
/* Per-thread reconnect modes */
614
if (!(reconnect_modes = (reconnect_mode_t *)calloc(sb_globals.num_threads,
615
sizeof(reconnect_mode_t))))
618
/* Initialize random seed for non-transactional delete test */
619
if (args.test_mode == TEST_MODE_NONTRX)
621
rnd_seed = LARGE_PRIME;
622
pthread_mutex_init(&rnd_mutex, NULL);
625
/* Initialize internal timers if we are in the debug mode */
626
if (sb_globals.debug)
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++)
632
sb_timer_init(exec_timers + thread_id);
633
sb_timer_init(fetch_timers + thread_id);
643
unsigned int thread_id;
645
if (args.test_mode == TEST_MODE_NONTRX)
646
pthread_mutex_destroy(&rnd_mutex);
648
/* Close statements and database connections */
649
for (thread_id = 0; thread_id < sb_globals.num_threads; thread_id++)
651
close_stmt_set(statements + thread_id);
652
oltp_disconnect(connections[thread_id]);
655
/* Deallocate connection pool */
665
void oltp_print_mode(void)
667
log_text(LOG_NOTICE, "Doing OLTP test.");
669
switch (args.test_mode) {
670
case TEST_MODE_SIMPLE:
671
log_text(LOG_NOTICE, "Running simple OLTP test");
673
case TEST_MODE_COMPLEX:
674
log_text(LOG_NOTICE, "Running mixed OLTP test");
676
case TEST_MODE_NONTRX:
677
log_text(LOG_NOTICE, "Running non-transactional test");
680
log_text(LOG_NOTICE, "Running stored procedure test");
684
log_text(LOG_WARNING, "Unknown OLTP test mode!");
689
log_text(LOG_NOTICE, "Doing read-only test");
691
switch (args.dist_type) {
692
case DIST_TYPE_UNIFORM:
693
log_text(LOG_NOTICE, "Using Uniform distribution");
695
case DIST_TYPE_GAUSSIAN:
696
log_text(LOG_NOTICE, "Using Normal distribution (%d iterations)",
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);
705
log_text(LOG_WARNING, "Unknown distribution!");
710
log_text(LOG_NOTICE, "Skipping BEGIN/COMMIT");
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"));
718
log_text(LOG_NOTICE, "Using auto_inc on the id column");
720
log_text(LOG_NOTICE, "Not using auto_inc on the id column");
722
if (sb_globals.max_requests > 0)
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");
731
sb_request_t oltp_get_request(int tid)
735
if (sb_globals.max_requests > 0 && req_performed >= sb_globals.max_requests)
737
sb_req.type = SB_REQ_TYPE_NULL;
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);
749
return get_request_sp(tid);
751
log_text(LOG_FATAL, "unknown test mode: %d!", args.test_mode);
752
sb_req.type = SB_REQ_TYPE_NULL;
759
inline int add_reconnect_req(sb_list_t *list)
761
sb_sql_query_t *query;
763
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
764
query->num_times = 1;
765
query->type = SB_SQL_QUERY_RECONNECT;
767
query->think_time = get_think_time();
768
SB_LIST_ADD_TAIL(&query->listitem, list);
772
sb_request_t get_request_sp(int tid)
775
sb_sql_request_t *sql_req = &sb_req.u.sql_request;
776
sb_sql_query_t *query;
778
(void)tid; /* unused */
780
sb_req.type = SB_REQ_TYPE_SQL;
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)
786
log_text(LOG_FATAL, "cannot allocate SQL query!");
787
sb_req.type = SB_REQ_TYPE_NULL;
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;
796
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
798
if (args.reconnect_mode == RECONNECT_QUERY ||
799
(args.reconnect_mode == RECONNECT_RANDOM && sb_rnd() % 2))
800
add_reconnect_req(sql_req->queries);
808
sb_request_t get_request_simple(int tid)
811
sb_sql_request_t *sql_req = &sb_req.u.sql_request;
812
sb_sql_query_t *query;
814
(void)tid; /* unused */
816
sb_req.type = SB_REQ_TYPE_SQL;
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)
822
log_text(LOG_FATAL, "cannot allocate SQL query!");
823
sb_req.type = SB_REQ_TYPE_NULL;
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();
833
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
835
if (args.reconnect_mode == RECONNECT_QUERY ||
836
(args.reconnect_mode == RECONNECT_RANDOM && sb_rnd() % 2))
837
add_reconnect_req(sql_req->queries);
845
sb_request_t get_request_complex(int tid)
848
sb_sql_request_t *sql_req = &sb_req.u.sql_request;
849
sb_sql_query_t *query;
854
reconnect_mode_t rmode;
856
sb_req.type = SB_REQ_TYPE_SQL;
858
sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
859
if (sql_req->queries == NULL)
861
log_text(LOG_FATAL, "cannot allocate SQL query!");
862
sb_req.type = SB_REQ_TYPE_NULL;
865
SB_LIST_INIT(sql_req->queries);
867
if (args.reconnect_mode == RECONNECT_RANDOM)
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];
877
rmode = args.reconnect_mode;
881
/* Generate BEGIN statement */
882
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
891
/* Generate set of point selects */
892
for(i = 0; i < args.point_selects; i++)
894
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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();
902
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
903
if (rmode == RECONNECT_QUERY)
904
add_reconnect_req(sql_req->queries);
907
/* Generate range queries */
908
for(i = 0; i < args.simple_ranges; i++)
910
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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;
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);
929
/* Generate sum range queries */
930
for(i = 0; i < args.sum_ranges; i++)
932
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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;
943
query->u.range_query.from = range;
944
query->u.range_query.to = range + args.range_size - 1;
946
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
947
if (rmode == RECONNECT_QUERY)
948
add_reconnect_req(sql_req->queries);
951
/* Generate ordered range queries */
952
for(i = 0; i < args.order_ranges; i++)
954
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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;
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);
973
/* Generate distinct range queries */
974
for(i = 0; i < args.distinct_ranges; i++)
976
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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;
987
query->u.range_query.from = range;
988
query->u.range_query.to = range + args.range_size;
990
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
991
if (rmode == RECONNECT_QUERY)
992
add_reconnect_req(sql_req->queries);
995
/* Skip all write queries for read-only test mode */
999
/* Generate index update */
1000
for (i = 0; i < args.index_updates; i++)
1002
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1014
/* Generate non-index update */
1015
for (i = 0; i < args.non_index_updates; i++)
1017
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1029
/* FIXME: generate one more UPDATE with the same ID as DELETE/INSERT to make
1031
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1041
/* Generate delete */
1042
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1052
/* Generate insert with same value */
1053
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1066
/* Generate commit */
1067
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
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);
1078
/* return request */
1082
/* Handle memory allocation failures */
1084
log_text(LOG_FATAL, "cannot allocate SQL query!");
1085
SB_LIST_FOR_EACH_SAFE(pos, tmp, sql_req->queries)
1087
query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
1090
free(sql_req->queries);
1091
sb_req.type = SB_REQ_TYPE_NULL;
1096
sb_request_t get_request_nontrx(int tid)
1098
sb_request_t sb_req;
1099
sb_sql_request_t *sql_req = &sb_req.u.sql_request;
1100
sb_sql_query_t *query;
1102
(void)tid; /* unused */
1104
sb_req.type = SB_REQ_TYPE_SQL;
1106
sql_req->queries = (sb_list_t *)malloc(sizeof(sb_list_t));
1107
if (sql_req->queries == NULL)
1109
log_text(LOG_FATAL, "cannot allocate SQL query!");
1110
sb_req.type = SB_REQ_TYPE_NULL;
1113
SB_LIST_INIT(sql_req->queries);
1115
query = (sb_sql_query_t *)malloc(sizeof(sb_sql_query_t));
1118
query->num_times = 1;
1119
query->think_time = get_think_time();
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();
1127
case NONTRX_MODE_UPDATE_KEY:
1128
query->type = SB_SQL_QUERY_UPDATE_INDEX;
1129
query->u.update_query.id = GET_RANDOM_ID();
1131
case NONTRX_MODE_UPDATE_NOKEY:
1132
query->type = SB_SQL_QUERY_UPDATE_NON_INDEX;
1133
query->u.update_query.id = GET_RANDOM_ID();
1135
case NONTRX_MODE_INSERT:
1136
query->type = SB_SQL_QUERY_INSERT;
1137
query->u.update_query.id = GET_RANDOM_ID();
1139
case NONTRX_MODE_DELETE:
1140
query->type = SB_SQL_QUERY_DELETE;
1141
query->u.delete_query.id = get_unique_random_id();
1144
log_text(LOG_FATAL, "unknown mode for non-transactional test!");
1146
sb_req.type = SB_REQ_TYPE_NULL;
1150
SB_LIST_ADD_TAIL(&query->listitem, sql_req->queries);
1152
if (args.reconnect_mode == RECONNECT_QUERY ||
1153
(args.reconnect_mode == RECONNECT_RANDOM && sb_rnd() % 2))
1154
add_reconnect_req(sql_req->queries);
1156
/* return request */
1160
/* Handle memory allocation failures */
1162
log_text(LOG_FATAL, "cannot allocate SQL query!");
1165
free(sql_req->queries);
1166
sb_req.type = SB_REQ_TYPE_NULL;
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.
1178
int oltp_execute_request(sb_request_t *sb_req, int thread_id)
1181
sb_sql_request_t *sql_req = &sb_req->u.sql_request;
1183
db_result_set_t *rs;
1184
sb_list_item_t *pos;
1185
sb_list_item_t *tmp;
1186
sb_sql_query_t *query;
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;
1194
log_msg_oper_t op_msg;
1195
unsigned long long nrows;
1197
/* Prepare log message */
1198
msg.type = LOG_MSG_TYPE_OPER;
1201
/* measure the time for transaction */
1202
LOG_EVENT_START(msg, thread_id);
1204
do /* deadlock handling */
1207
SB_LIST_FOR_EACH(pos, sql_req->queries)
1209
query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
1211
for(i = 0; i < query->num_times; i++)
1213
/* emulate user thinking */
1214
if (query->think_time > 0)
1215
usleep(query->think_time);
1217
if (query->type == SB_SQL_QUERY_RECONNECT)
1219
if (oltp_reconnect(thread_id))
1224
/* find prepared statement */
1225
stmt = get_sql_statement(query, thread_id);
1228
log_text(LOG_FATAL, "unknown SQL query type: %d!", query->type);
1229
sb_globals.error = 1;
1233
if (sb_globals.debug)
1234
sb_timer_start(exec_timers + thread_id);
1236
rs = db_execute(stmt);
1238
if (sb_globals.debug)
1239
sb_timer_stop(exec_timers + thread_id);
1243
rc = db_errno(connections[thread_id]);
1244
if (rc != SB_DB_ERROR_DEADLOCK)
1246
log_text(LOG_FATAL, "database error, exiting...");
1247
/* exiting, forget about allocated memory */
1248
sb_globals.error = 1;
1260
if (query->type >= SB_SQL_QUERY_POINT &&
1261
query->type <= SB_SQL_QUERY_RANGE_DISTINCT) /* select query */
1263
if (sb_globals.debug)
1264
sb_timer_start(fetch_timers + thread_id);
1266
rc = db_store_results(rs);
1268
if (sb_globals.debug)
1269
sb_timer_stop(fetch_timers + thread_id);
1272
if (rc == SB_DB_ERROR_DEADLOCK)
1274
db_free_results(rs);
1279
else if (rc != SB_DB_ERROR_NONE)
1281
log_text(LOG_FATAL, "Error fetching result: `%s`", stmt);
1282
/* exiting, forget about allocated memory */
1283
sb_globals.error = 1;
1287
/* Validate the result set if requested */
1288
if (sb_globals.validate && query->nrows > 0)
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);
1298
db_free_results(rs);
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;
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;
1317
local_other_ops += query->num_times;
1320
break; /* break transaction execution if deadlock */
1322
} while(retry); /* retry transaction in case of deadlock */
1324
LOG_EVENT_STOP(msg, thread_id);
1326
SB_THREAD_MUTEX_LOCK();
1327
read_ops += local_read_ops;
1328
write_ops += local_write_ops;
1329
other_ops += local_other_ops;
1331
deadlocks += local_deadlocks;
1332
SB_THREAD_MUTEX_UNLOCK();
1334
/* Free list of queries */
1335
SB_LIST_FOR_EACH_SAFE(pos, tmp, sql_req->queries)
1337
query = SB_LIST_ENTRY(pos, sb_sql_query_t, listitem);
1340
free(sql_req->queries);
1346
void oltp_print_stats(void)
1350
sb_timer_t exec_timer;
1351
sb_timer_t fetch_timer;
1353
total_time = NS2SEC(sb_timer_value(&sb_globals.exec_timer));
1355
log_text(LOG_NOTICE, "OLTP test statistics:");
1356
log_text(LOG_NOTICE, " queries performed:");
1357
log_text(LOG_NOTICE, " read: %d",
1359
log_text(LOG_NOTICE, " write: %d",
1361
log_text(LOG_NOTICE, " other: %d",
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);
1375
if (sb_globals.debug)
1377
sb_timer_init(&exec_timer);
1378
sb_timer_init(&fetch_timer);
1380
for (i = 0; i < sb_globals.num_threads; i++)
1382
exec_timer = merge_timers(&exec_timer, exec_timers + i);
1383
fetch_timer = merge_timers(&fetch_timer, fetch_timers + i);
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)));
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)));
1410
db_conn_t *oltp_connect(void)
1414
con = db_connect(driver);
1417
log_text(LOG_FATAL, "failed to connect to database server!");
1421
if (args.connect_delay > 0)
1422
usleep(args.connect_delay);
1428
int oltp_disconnect(db_conn_t *con)
1430
return db_disconnect(con);
1434
int oltp_reconnect(int thread_id)
1436
close_stmt_set(statements + thread_id);
1437
if (oltp_disconnect(connections[thread_id]))
1439
if (!(connections[thread_id] = oltp_connect()))
1441
if (prepare_stmt_set(statements + thread_id, bind_bufs + thread_id,
1442
connections[thread_id]))
1444
log_text(LOG_FATAL, "thread#%d: failed to prepare statements for test",
1453
/* Parse command line arguments */
1456
int parse_arguments(void)
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;
1471
log_text(LOG_FATAL, "Invalid OLTP test mode: %s.", s);
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;
1486
log_text(LOG_FATAL, "Invalid value for --oltp-reconnect-mode: '%s'", s);
1490
args.sp_name = sb_get_value_string("oltp-sp-name");
1491
if (args.test_mode == TEST_MODE_SP && args.sp_name == NULL)
1493
log_text(LOG_FATAL, "Name of stored procedure must be specified with --oltp-sp-name "
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");
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;
1523
log_text(LOG_FATAL, "Invalid value of oltp-nontrx-mode: %s", s);
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");
1533
s = sb_get_value_string("oltp-dist-type");
1534
if (!strcmp(s, "uniform"))
1536
args.dist_type = DIST_TYPE_UNIFORM;
1537
rnd_func = &rnd_func_uniform;
1539
else if (!strcmp(s, "gaussian"))
1541
args.dist_type = DIST_TYPE_GAUSSIAN;
1542
rnd_func = &rnd_func_gaussian;
1544
else if (!strcmp(s, "special"))
1546
args.dist_type = DIST_TYPE_SPECIAL;
1547
rnd_func = &rnd_func_special;
1551
log_text(LOG_FATAL, "Invalid random numbers distribution: %s.", s);
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");
1559
/* Select driver according to command line arguments */
1560
driver = db_init(NULL);
1563
log_text(LOG_FATAL, "failed to initialize database driver!");
1571
/* Prepare a set of statements for the test */
1574
int prepare_stmt_set(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
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);
1582
return prepare_stmt_set_sp(set, bufs, conn);
1586
/* Close a set of statements for the test */
1588
void close_stmt_set(oltp_stmt_set_t *set)
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));
1606
/* Generate SQL statement from query */
1609
db_stmt_t *get_sql_statement(sb_sql_query_t *query, int thread_id)
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);
1617
return get_sql_statement_sp(query, thread_id);
1621
/* Prepare a set of statements for SP test */
1624
int prepare_stmt_set_sp(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
1626
db_bind_t params[2];
1627
char query[MAX_QUERY_LEN];
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)
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))
1647
/* Prepare a set of statements for transactional test */
1650
int prepare_stmt_set_trx(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
1652
db_bind_t binds[11];
1653
char query[MAX_QUERY_LEN];
1655
/* Prepare the point statement */
1656
snprintf(query, MAX_QUERY_LEN, "SELECT c from %s where id=?",
1658
set->point = db_prepare(conn, query);
1659
if (set->point == NULL)
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))
1668
/* Prepare the range statement */
1669
snprintf(query, MAX_QUERY_LEN, "SELECT c from %s where id between ? and ?",
1671
set->range = db_prepare(conn, query);
1672
if (set->range == NULL)
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))
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)
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))
1702
/* Prepare the range_order statement */
1703
snprintf(query, MAX_QUERY_LEN,
1704
"SELECT c from %s where id between ? and ? order by c",
1706
set->range_order = db_prepare(conn, query);
1707
if (set->range_order == NULL)
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))
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",
1724
set->range_distinct = db_prepare(conn, query);
1725
if (set->range_distinct == NULL)
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))
1738
/* Prepare the update_index statement */
1739
snprintf(query, MAX_QUERY_LEN, "UPDATE %s set k=k+1 where id=?",
1741
set->update_index = db_prepare(conn, query);
1742
if (set->update_index == NULL)
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))
1751
/* Prepare the update_non_index statement */
1752
snprintf(query, MAX_QUERY_LEN,
1753
"UPDATE %s set c=? where id=?",
1755
set->update_non_index = db_prepare(conn, query);
1756
if (set->update_non_index == NULL)
1759
Non-index update statement is re-bound each time because of the string
1763
/* Prepare the delete statement */
1764
snprintf(query, MAX_QUERY_LEN, "DELETE from %s where id=?",
1766
set->delete = db_prepare(conn, query);
1767
if (set->delete == NULL)
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))
1776
/* Prepare the insert statement */
1777
snprintf(query, MAX_QUERY_LEN, "INSERT INTO %s values(?,0,' ',"
1778
"'aaaaaaaaaaffffffffffrrrrrrrrrreeeeeeeeeeyyyyyyyyyy')",
1780
set->insert = db_prepare(conn, query);
1781
if (set->insert == NULL)
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))
1793
/* Prepare the lock statement */
1794
if (driver_caps.transactions)
1795
strncpy(query, "BEGIN", MAX_QUERY_LEN);
1799
snprintf(query, MAX_QUERY_LEN, "LOCK TABLES %s READ", args.table_name);
1801
snprintf(query, MAX_QUERY_LEN, "LOCK TABLES %s WRITE", args.table_name);
1803
set->lock = db_prepare(conn, query);
1804
if (set->lock == NULL)
1807
/* Prepare the unlock statement */
1808
if (driver_caps.transactions)
1809
strncpy(query, "COMMIT", MAX_QUERY_LEN);
1811
strncpy(query, "UNLOCK TABLES", MAX_QUERY_LEN);
1812
set->unlock = db_prepare(conn, query);
1813
if (set->unlock == NULL)
1820
/* Prepare a set of statements for non-transactional test */
1823
int prepare_stmt_set_nontrx(oltp_stmt_set_t *set, oltp_bind_set_t *bufs, db_conn_t *conn)
1825
db_bind_t binds[11];
1826
char query[MAX_QUERY_LEN];
1828
/* Prepare the point statement */
1829
snprintf(query, MAX_QUERY_LEN, "SELECT pad from %s where id=?",
1831
set->point = db_prepare(conn, query);
1832
if (set->point == NULL)
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))
1841
/* Prepare the update_index statement */
1842
snprintf(query, MAX_QUERY_LEN, "UPDATE %s set k=k+1 where id=?",
1844
set->update_index = db_prepare(conn, query);
1845
if (set->update_index == NULL)
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))
1854
/* Prepare the update_non_index statement */
1855
snprintf(query, MAX_QUERY_LEN,
1856
"UPDATE %s set c=? where id=?",
1858
set->update_non_index = db_prepare(conn, query);
1859
if (set->update_non_index == NULL)
1862
Non-index update statement is re-bound each time because of the string
1866
/* Prepare the delete statement */
1867
snprintf(query, MAX_QUERY_LEN, "DELETE from %s where id=?",
1869
set->delete = db_prepare(conn, query);
1870
if (set->delete == NULL)
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))
1879
/* Prepare the insert statement */
1880
snprintf(query, MAX_QUERY_LEN, "INSERT INTO %s values(?,?,?,?)",
1882
set->insert = db_prepare(conn, query);
1884
Insert statement is re-bound each time because of the string
1892
/* Generate SQL statement from query for SP test */
1895
db_stmt_t *get_sql_statement_sp(sb_sql_query_t *query, int thread_id)
1898
oltp_bind_set_t *buf = bind_bufs + thread_id;
1900
(void) query; /* unused */
1902
stmt = statements[thread_id].call;
1903
buf->call.thread_id = thread_id;
1904
buf->call.nthreads = sb_globals.num_threads;
1910
/* Generate SQL statement from query for transactional test */
1913
db_stmt_t *get_sql_statement_trx(sb_sql_query_t *query, int thread_id)
1915
db_stmt_t *stmt = NULL;
1917
oltp_bind_set_t *buf = bind_bufs + thread_id;
1919
switch (query->type) {
1920
case SB_SQL_QUERY_LOCK:
1921
stmt = statements[thread_id].lock;
1924
case SB_SQL_QUERY_UNLOCK:
1925
stmt = statements[thread_id].unlock;
1928
case SB_SQL_QUERY_POINT:
1929
stmt = statements[thread_id].point;
1930
buf->point.id = query->u.point_query.id;
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;
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;
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;
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;
1957
case SB_SQL_QUERY_UPDATE_INDEX:
1958
stmt = statements[thread_id].update_index;
1959
buf->update_index.id = query->u.update_query.id;
1962
case SB_SQL_QUERY_UPDATE_NON_INDEX:
1963
stmt = statements[thread_id].update_non_index;
1965
We have to bind non-index update data each time
1966
because of string parameter
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))
1994
case SB_SQL_QUERY_DELETE:
1995
stmt = statements[thread_id].delete;
1996
buf->delete.id = query->u.delete_query.id;
1999
case SB_SQL_QUERY_INSERT:
2000
stmt = statements[thread_id].insert;
2001
buf->insert.id = query->u.insert_query.id;
2012
/* Generate SQL statement from query for non-transactional test */
2015
db_stmt_t *get_sql_statement_nontrx(sb_sql_query_t *query, int thread_id)
2017
db_stmt_t *stmt = NULL;
2019
oltp_bind_set_t *buf = bind_bufs + thread_id;
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;
2027
case SB_SQL_QUERY_UPDATE_INDEX:
2028
stmt = statements[thread_id].update_index;
2029
buf->update_index.id = query->u.update_query.id;
2032
case SB_SQL_QUERY_UPDATE_NON_INDEX:
2033
stmt = statements[thread_id].update_non_index;
2035
We have to bind non-index update data each time
2036
because of string parameter
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);
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;
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;
2063
if (db_bind_param(statements[thread_id].update_non_index, binds, 2))
2067
case SB_SQL_QUERY_DELETE:
2068
stmt = statements[thread_id].delete;
2069
buf->delete.id = query->u.delete_query.id;
2072
case SB_SQL_QUERY_INSERT:
2073
stmt = statements[thread_id].insert;
2075
We have to bind insert data each time
2076
because of string parameters
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);
2099
/* Use NULL is AUTO_INCREMENT is used, unique id otherwise */
2102
binds[0].is_null = &oltp_is_null;
2106
buf->range.from = get_unique_random_id();
2107
binds[0].buffer = &buf->range.from;
2108
binds[0].is_null = 0;
2111
binds[0].type = DB_TYPE_INT;
2112
binds[0].data_len = 0;
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;
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;
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;
2131
if (db_bind_param(statements[thread_id].insert, binds, 4))
2144
/* uniform distribution */
2147
unsigned int rnd_func_uniform(void)
2149
return 1 + sb_rnd() % args.table_size;
2153
/* gaussian distribution */
2156
unsigned int rnd_func_gaussian(void)
2161
for(i=0, sum=0; i < args.dist_iter; i++)
2162
sum += (1 + sb_rnd() % args.table_size);
2164
return sum / args.dist_iter;
2168
/* 'special' distribution */
2171
unsigned int rnd_func_special(void)
2177
unsigned int range_size;
2179
if (args.table_size == 0)
2182
/* Increase range size for special values. */
2183
range_size = args.table_size * (100 / (100 - args.dist_res));
2185
/* Generate evenly distributed one at this stage */
2186
res = (1 + sb_rnd() % range_size);
2188
/* For first part use gaussian distribution */
2189
if (res <= args.table_size)
2191
for(i = 0; i < args.dist_iter; i++)
2193
sum += (1 + sb_rnd() % args.table_size);
2195
return sum / args.dist_iter;
2199
* For second part use even distribution mapped to few items
2200
* We shall distribute other values near by the center
2202
d = args.table_size * args.dist_pct / 100;
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));
2214
/* Generate unique random id */
2217
unsigned int get_unique_random_id(void)
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);
2230
int get_think_time(void)
2232
int t = args.user_delay_min;
2234
if (args.user_delay_min < args.user_delay_max)
2235
t += sb_rnd() % (args.user_delay_max - args.user_delay_min);