diff options
author | Keith Bostic <keith.bostic@mongodb.com> | 2016-08-31 01:57:46 -0400 |
---|---|---|
committer | Alex Gorrod <alexander.gorrod@mongodb.com> | 2016-08-31 15:57:46 +1000 |
commit | 43e0c3dd822fec07f03091c7d6bcd318911d6c99 (patch) | |
tree | 030febf54e980f6a67217aee3d3b1493bfd770a6 /bench | |
parent | 3dedd2205bdfdcae537172ab9c5a2228b983e808 (diff) | |
download | mongo-43e0c3dd822fec07f03091c7d6bcd318911d6c99.tar.gz |
WT-2842 split wtperf's configuration into per-database and per-run parts (#2971)
Diffstat (limited to 'bench')
-rw-r--r-- | bench/wtperf/config.c | 429 | ||||
-rw-r--r-- | bench/wtperf/config_opt.h | 14 | ||||
-rw-r--r-- | bench/wtperf/doxy.c | 2 | ||||
-rw-r--r-- | bench/wtperf/idle_table_cycle.c | 42 | ||||
-rw-r--r-- | bench/wtperf/misc.c | 15 | ||||
-rw-r--r-- | bench/wtperf/track.c | 17 | ||||
-rw-r--r-- | bench/wtperf/wtperf.c | 745 | ||||
-rw-r--r-- | bench/wtperf/wtperf.h | 58 | ||||
-rw-r--r-- | bench/wtperf/wtperf_opt.i | 8 | ||||
-rw-r--r-- | bench/wtperf/wtperf_truncate.c | 20 |
10 files changed, 714 insertions, 636 deletions
diff --git a/bench/wtperf/config.c b/bench/wtperf/config.c index a2960902ec1..f7718632ae6 100644 --- a/bench/wtperf/config.c +++ b/bench/wtperf/config.c @@ -28,15 +28,19 @@ #include "wtperf.h" -/* All options changeable on command line using -o or -O are listed here. */ -static CONFIG_OPT config_opts[] = { +static CONFIG_OPT config_opts_desc[] = { /* Option descriptions */ #define OPT_DEFINE_DESC #include "wtperf_opt.i" #undef OPT_DEFINE_DESC }; -static int config_opt(CONFIG *, WT_CONFIG_ITEM *, WT_CONFIG_ITEM *); -static void config_opt_usage(void); +static CONFIG_OPTS config_opts_default = { /* Option defaults */ +#define OPT_DEFINE_DEFAULT +#include "wtperf_opt.i" +#undef OPT_DEFINE_DEFAULT + + { NULL, NULL } /* config_head */ +}; /* * STRING_MATCH -- @@ -47,6 +51,68 @@ static void config_opt_usage(void); (strncmp(str, bytes, len) == 0 && (str)[(len)] == '\0') /* + * config_opt_init -- + * Initialize the global configuration options. + */ +void +config_opt_init(CONFIG_OPTS **retp) +{ + CONFIG_OPT *desc; + CONFIG_OPTS *opts; + size_t i; + char **strp; + void *valueloc; + + opts = dmalloc(sizeof(CONFIG_OPTS)); + *opts = config_opts_default; + + TAILQ_INIT(&opts->config_head); + + /* + * Option strings come-and-go as we configure them, so allocate copies + * of the default strings now so that we can always free the string as + * we allocate new versions. + */ + for (i = 0, desc = config_opts_desc; + i < WT_ELEMENTS(config_opts_desc); i++, ++desc) + if (desc->type == CONFIG_STRING_TYPE) { + valueloc = ((uint8_t *)opts + desc->offset); + strp = (char **)valueloc; + *strp = dstrdup(*strp); + } + + *retp = opts; +} + +/* + * config_opt_cleanup -- + * Clean up the global configuration options. + */ +void +config_opt_cleanup(CONFIG_OPTS *opts) +{ + CONFIG_OPT *desc; + CONFIG_QUEUE_ENTRY *config_line; + size_t i; + char **strp; + void *valueloc; + + for (i = 0, desc = config_opts_desc; + i < WT_ELEMENTS(config_opts_desc); i++, ++desc) + if (desc->type == CONFIG_STRING_TYPE) { + valueloc = ((uint8_t *)opts + desc->offset); + strp = (char **)valueloc; + free(*strp); + } + + while ((config_line = TAILQ_FIRST(&opts->config_head)) != NULL) { + TAILQ_REMOVE(&opts->config_head, config_line, q); + free(config_line->string); + free(config_line); + } +} + +/* * config_unescape -- * Modify a string in place, replacing any backslash escape sequences. * The modified string is always shorter. @@ -94,161 +160,6 @@ config_unescape(char *orig) } /* - * config_copy -- - * CONFIG structure initialization, based on a source configuration. - */ -int -config_copy(CONFIG *dest, const CONFIG *src) -{ - CONFIG_QUEUE_ENTRY *conf_line, *tmp_line; - size_t i; - char *newstr, **pstr; - - memcpy(dest, src, sizeof(CONFIG)); - - if (src->home != NULL) - dest->home = dstrdup(src->home); - if (src->monitor_dir != NULL) - dest->monitor_dir = dstrdup(src->monitor_dir); - if (src->partial_config != NULL) - dest->partial_config = dstrdup(src->partial_config); - if (src->reopen_config != NULL) - dest->reopen_config = dstrdup(src->reopen_config); - if (src->base_uri != NULL) - dest->base_uri = dstrdup(src->base_uri); - - if (src->uris != NULL) { - dest->uris = dcalloc(src->table_count, sizeof(char *)); - for (i = 0; i < src->table_count; i++) - dest->uris[i] = dstrdup(src->uris[i]); - } - - if (src->async_config != NULL) - dest->async_config = dstrdup(src->async_config); - - dest->ckptthreads = NULL; - dest->popthreads = NULL; - dest->workers = NULL; - - if (src->workload != NULL) { - dest->workload = dcalloc(WORKLOAD_MAX, sizeof(WORKLOAD)); - memcpy(dest->workload, - src->workload, WORKLOAD_MAX * sizeof(WORKLOAD)); - } - - for (i = 0; i < sizeof(config_opts) / sizeof(config_opts[0]); i++) - if (config_opts[i].type == STRING_TYPE || - config_opts[i].type == CONFIG_STRING_TYPE) { - pstr = (char **) - ((u_char *)dest + config_opts[i].offset); - if (*pstr != NULL) { - newstr = dstrdup(*pstr); - *pstr = newstr; - } - } - - TAILQ_INIT(&dest->stone_head); - TAILQ_INIT(&dest->config_head); - - /* Clone the config string information into the new cfg object */ - TAILQ_FOREACH(conf_line, &src->config_head, c) { - tmp_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1); - tmp_line->string = dstrdup(conf_line->string); - TAILQ_INSERT_TAIL(&dest->config_head, tmp_line, c); - } - return (0); -} - -/* - * config_free -- - * Free any storage allocated in the config struct. - */ -void -config_free(CONFIG *cfg) -{ - CONFIG_QUEUE_ENTRY *config_line; - size_t i; - char **pstr; - - free(cfg->home); - free(cfg->monitor_dir); - free(cfg->partial_config); - free(cfg->reopen_config); - free(cfg->base_uri); - - if (cfg->uris != NULL) { - for (i = 0; i < cfg->table_count; i++) - free(cfg->uris[i]); - free(cfg->uris); - } - - free(cfg->async_config); - - free(cfg->ckptthreads); - free(cfg->popthreads); - - free(cfg->workers); - free(cfg->workload); - - cleanup_truncate_config(cfg); - - while (!TAILQ_EMPTY(&cfg->config_head)) { - config_line = TAILQ_FIRST(&cfg->config_head); - TAILQ_REMOVE(&cfg->config_head, config_line, c); - free(config_line->string); - free(config_line); - } - - for (i = 0; i < sizeof(config_opts) / sizeof(config_opts[0]); i++) - if (config_opts[i].type == STRING_TYPE || - config_opts[i].type == CONFIG_STRING_TYPE) { - pstr = (char **) - ((u_char *)cfg + config_opts[i].offset); - free(*pstr); - *pstr = NULL; - } -} - -/* - * config_compress -- - * Parse the compression configuration. - */ -int -config_compress(CONFIG *cfg) -{ - int ret; - const char *s; - - ret = 0; - s = cfg->compression; - if (strcmp(s, "none") == 0) { - cfg->compress_ext = NULL; - cfg->compress_table = NULL; - } else if (strcmp(s, "lz4") == 0) { -#ifndef HAVE_BUILTIN_EXTENSION_LZ4 - cfg->compress_ext = LZ4_EXT; -#endif - cfg->compress_table = LZ4_BLK; - } else if (strcmp(s, "snappy") == 0) { -#ifndef HAVE_BUILTIN_EXTENSION_SNAPPY - cfg->compress_ext = SNAPPY_EXT; -#endif - cfg->compress_table = SNAPPY_BLK; - } else if (strcmp(s, "zlib") == 0) { -#ifndef HAVE_BUILTIN_EXTENSION_ZLIB - cfg->compress_ext = ZLIB_EXT; -#endif - cfg->compress_table = ZLIB_BLK; - } else { - fprintf(stderr, - "invalid compression configuration: %s\n", s); - ret = EINVAL; - } - return (ret); - -} - -/* * config_threads -- * Parse the thread configuration. */ @@ -428,30 +339,32 @@ err: if (group != NULL) static int config_opt(CONFIG *cfg, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v) { - CONFIG_OPT *popt; + CONFIG_OPTS *opts; + CONFIG_OPT *desc; char *begin, *newstr, **strp; int ret; - size_t i, newlen, nopt; + size_t i, newlen; void *valueloc; - popt = NULL; - nopt = sizeof(config_opts)/sizeof(config_opts[0]); - for (i = 0; i < nopt; i++) - if (strlen(config_opts[i].name) == k->len && - strncmp(config_opts[i].name, k->str, k->len) == 0) { - popt = &config_opts[i]; + opts = cfg->opts; + + desc = NULL; + for (i = 0; i < WT_ELEMENTS(config_opts_desc); i++) + if (strlen(config_opts_desc[i].name) == k->len && + strncmp(config_opts_desc[i].name, k->str, k->len) == 0) { + desc = &config_opts_desc[i]; break; } - if (popt == NULL) { + if (desc == NULL) { fprintf(stderr, "wtperf: Error: " "unknown option \'%.*s\'\n", (int)k->len, k->str); fprintf(stderr, "Options:\n"); - for (i = 0; i < nopt; i++) - fprintf(stderr, "\t%s\n", config_opts[i].name); + for (i = 0; i < WT_ELEMENTS(config_opts_desc); i++) + fprintf(stderr, "\t%s\n", config_opts_desc[i].name); return (EINVAL); } - valueloc = ((u_char *)cfg + popt->offset); - switch (popt->type) { + valueloc = ((uint8_t *)opts + desc->offset); + switch (desc->type) { case BOOL_TYPE: if (v->type != WT_CONFIG_ITEM_BOOL) { fprintf(stderr, "wtperf: Error: " @@ -657,7 +570,7 @@ config_opt_file(CONFIG *cfg, const char *filename) if (contline) optionpos += linelen; else { - if ((ret = config_opt_line(cfg, option)) != 0) { + if ((ret = config_opt_str(cfg, option)) != 0) { fprintf(stderr, "wtperf: %s: %d: parse error\n", filename, linenum); break; @@ -682,19 +595,22 @@ config_opt_file(CONFIG *cfg, const char *filename) } /* - * config_opt_line -- + * config_opt_str -- * Parse a single line of config options. Continued lines have already * been joined. */ int -config_opt_line(CONFIG *cfg, const char *optstr) +config_opt_str(CONFIG *cfg, const char *optstr) { + CONFIG_OPTS *opts; CONFIG_QUEUE_ENTRY *config_line; WT_CONFIG_ITEM k, v; WT_CONFIG_PARSER *scan; size_t len; int ret, t_ret; + opts = cfg->opts; + len = strlen(optstr); if ((ret = wiredtiger_config_parser_open( NULL, optstr, len, &scan)) != 0) { @@ -710,7 +626,7 @@ config_opt_line(CONFIG *cfg, const char *optstr) */ config_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1); config_line->string = dstrdup(optstr); - TAILQ_INSERT_TAIL(&cfg->config_head, config_line, c); + TAILQ_INSERT_TAIL(&opts->config_head, config_line, q); while (ret == 0) { if ((ret = scan->next(scan, &k, &v)) != 0) { @@ -731,11 +647,11 @@ config_opt_line(CONFIG *cfg, const char *optstr) } /* - * config_opt_str -- - * Set a single string config option. + * config_opt_name_value -- + * Set a name/value configuration pair. */ int -config_opt_str(CONFIG *cfg, const char *name, const char *value) +config_opt_name_value(CONFIG *cfg, const char *name, const char *value) { int ret; char *optstr; @@ -743,7 +659,7 @@ config_opt_str(CONFIG *cfg, const char *name, const char *value) /* name="value" */ optstr = dmalloc(strlen(name) + strlen(value) + 4); sprintf(optstr, "%s=\"%s\"", name, value); - ret = config_opt_line(cfg, optstr); + ret = config_opt_str(cfg, optstr); free(optstr); return (ret); } @@ -755,56 +671,59 @@ config_opt_str(CONFIG *cfg, const char *name, const char *value) int config_sanity(CONFIG *cfg) { + CONFIG_OPTS *opts; WORKLOAD *workp; u_int i; + opts = cfg->opts; + /* Various intervals should be less than the run-time. */ - if (cfg->run_time > 0 && - ((cfg->checkpoint_threads != 0 && - cfg->checkpoint_interval > cfg->run_time) || - cfg->report_interval > cfg->run_time || - cfg->sample_interval > cfg->run_time)) { + if (opts->run_time > 0 && + ((opts->checkpoint_threads != 0 && + opts->checkpoint_interval > opts->run_time) || + opts->report_interval > opts->run_time || + opts->sample_interval > opts->run_time)) { fprintf(stderr, "interval value longer than the run-time\n"); return (EINVAL); } /* The maximum is here to keep file name construction simple. */ - if (cfg->table_count < 1 || cfg->table_count > 99999) { + if (opts->table_count < 1 || opts->table_count > 99999) { fprintf(stderr, "invalid table count, less than 1 or greater than 99999\n"); return (EINVAL); } - if (cfg->database_count < 1 || cfg->database_count > 99) { + if (opts->database_count < 1 || opts->database_count > 99) { fprintf(stderr, "invalid database count, less than 1 or greater than 99\n"); return (EINVAL); } - if (cfg->pareto > 100) { + if (opts->pareto > 100) { fprintf(stderr, "Invalid pareto distribution - should be a percentage\n"); return (EINVAL); } - if (cfg->value_sz_max < cfg->value_sz) { + if (opts->value_sz_max < opts->value_sz) { if (F_ISSET(cfg, CFG_GROW)) { fprintf(stderr, "value_sz_max %" PRIu32 " must be greater than or equal to value_sz %" - PRIu32 "\n", cfg->value_sz_max, cfg->value_sz); + PRIu32 "\n", opts->value_sz_max, opts->value_sz); return (EINVAL); } else - cfg->value_sz_max = cfg->value_sz; + opts->value_sz_max = opts->value_sz; } - if (cfg->value_sz_min > cfg->value_sz) { + if (opts->value_sz_min > opts->value_sz) { if (F_ISSET(cfg, CFG_SHRINK)) { fprintf(stderr, "value_sz_min %" PRIu32 " must be less than or equal to value_sz %" - PRIu32 "\n", cfg->value_sz_min, cfg->value_sz); + PRIu32 "\n", opts->value_sz_min, opts->value_sz); return (EINVAL); } else - cfg->value_sz_min = cfg->value_sz; + opts->value_sz_min = opts->value_sz; } - if (cfg->readonly && cfg->workload != NULL) + if (opts->readonly && cfg->workload != NULL) for (i = 0, workp = cfg->workload; i < cfg->workload_cnt; ++i, ++workp) if (workp->insert != 0 || workp->update != 0 || @@ -822,21 +741,21 @@ config_sanity(CONFIG *cfg) * Consolidate repeated configuration settings so that it only appears * once in the configuration output file. */ -void -config_consolidate(CONFIG *cfg) +static void +config_consolidate(CONFIG_OPTS *opts) { CONFIG_QUEUE_ENTRY *conf_line, *test_line, *tmp; char *string_key; /* - * This loop iterates over the config queue and for entry checks if an - * entry later in the queue has the same key. If a match is found then - * the current queue entry is removed and we continue. + * This loop iterates over the config queue and for each entry checks if + * a later queue entry has the same key. If there's a match, the current + * queue entry is removed and we continue. */ - conf_line = TAILQ_FIRST(&cfg->config_head); + conf_line = TAILQ_FIRST(&opts->config_head); while (conf_line != NULL) { string_key = strchr(conf_line->string, '='); - tmp = test_line = TAILQ_NEXT(conf_line, c); + tmp = test_line = TAILQ_NEXT(conf_line, q); while (test_line != NULL) { /* * The + 1 here forces the '=' sign to be matched @@ -847,85 +766,71 @@ config_consolidate(CONFIG *cfg) if (strncmp(conf_line->string, test_line->string, (size_t)((string_key - conf_line->string) + 1)) == 0) { - TAILQ_REMOVE(&cfg->config_head, conf_line, c); + TAILQ_REMOVE(&opts->config_head, conf_line, q); free(conf_line->string); free(conf_line); break; } - test_line = TAILQ_NEXT(test_line, c); + test_line = TAILQ_NEXT(test_line, q); } conf_line = tmp; } } /* - * config_to_file -- + * config_opt_log -- * Write the final config used in this execution to a file. */ void -config_to_file(CONFIG *cfg) +config_opt_log(CONFIG_OPTS *opts, const char *path) { CONFIG_QUEUE_ENTRY *config_line; FILE *fp; - size_t req_len; - char *path; - fp = NULL; + testutil_checkfmt(((fp = fopen(path, "w")) == NULL), "%s", path); - /* Backup the config */ - req_len = strlen(cfg->home) + strlen("/CONFIG.wtperf") + 1; - path = dcalloc(req_len, 1); - snprintf(path, req_len, "%s/CONFIG.wtperf", cfg->home); - if ((fp = fopen(path, "w")) == NULL) { - lprintf(cfg, errno, 0, "%s", path); - goto err; - } + config_consolidate(opts); - /* Print the config dump */ - fprintf(fp,"# Warning. This config includes " + fprintf(fp,"# Warning: This config includes " "unwritten, implicit configuration defaults.\n" "# Changes to those values may cause differences in behavior.\n"); - config_consolidate(cfg); - config_line = TAILQ_FIRST(&cfg->config_head); - while (config_line != NULL) { + TAILQ_FOREACH(config_line, &opts->config_head, q) fprintf(fp, "%s\n", config_line->string); - config_line = TAILQ_NEXT(config_line, c); - } - -err: free(path); - if (fp != NULL) - (void)fclose(fp); + testutil_check(fclose(fp)); } /* - * config_print -- + * config_opt_print -- * Print out the configuration in verbose mode. */ void -config_print(CONFIG *cfg) +config_opt_print(CONFIG *cfg) { + CONFIG_OPTS *opts; WORKLOAD *workp; u_int i; + opts = cfg->opts; + printf("Workload configuration:\n"); printf("\t" "Home: %s\n", cfg->home); - printf("\t" "Table name: %s\n", cfg->table_name); - printf("\t" "Connection configuration: %s\n", cfg->conn_config); - if (cfg->sess_config != NULL) - printf("\t" "Session configuration: %s\n", cfg->sess_config); + printf("\t" "Table name: %s\n", opts->table_name); + printf("\t" "Connection configuration: %s\n", opts->conn_config); + if (opts->sess_config != NULL) + printf("\t" "Session configuration: %s\n", opts->sess_config); printf("\t%s table: %s\n", - cfg->create ? "Creating new" : "Using existing", - cfg->table_config); + opts->create ? "Creating new" : "Using existing", + opts->table_config); printf("\t" "Key size: %" PRIu32 ", value size: %" PRIu32 "\n", - cfg->key_sz, cfg->value_sz); - if (cfg->create) + opts->key_sz, opts->value_sz); + if (opts->create) printf("\t" "Populate threads: %" PRIu32 ", inserting %" PRIu32 " rows\n", - cfg->populate_threads, cfg->icount); + opts->populate_threads, opts->icount); printf("\t" "Workload seconds, operations: %" PRIu32 ", %" PRIu32 "\n", - cfg->run_time, cfg->run_ops); + opts->run_time, opts->run_ops); if (cfg->workload != NULL) { printf("\t" "Workload configuration(s):\n"); for (i = 0, workp = cfg->workload; @@ -939,11 +844,11 @@ config_print(CONFIG *cfg) } printf("\t" "Checkpoint threads, interval: %" PRIu32 ", %" PRIu32 "\n", - cfg->checkpoint_threads, cfg->checkpoint_interval); - printf("\t" "Reporting interval: %" PRIu32 "\n", cfg->report_interval); - printf("\t" "Sampling interval: %" PRIu32 "\n", cfg->sample_interval); + opts->checkpoint_threads, opts->checkpoint_interval); + printf("\t" "Reporting interval: %" PRIu32 "\n", opts->report_interval); + printf("\t" "Sampling interval: %" PRIu32 "\n", opts->sample_interval); - printf("\t" "Verbosity: %" PRIu32 "\n", cfg->verbose); + printf("\t" "Verbosity: %" PRIu32 "\n", opts->verbose); } /* @@ -973,10 +878,10 @@ pretty_print(const char *p, const char *indent) * config_opt_usage -- * Configuration usage error message. */ -static void +void config_opt_usage(void) { - size_t i, nopt; + size_t i; const char *defaultval, *typestr; pretty_print( @@ -986,11 +891,10 @@ config_opt_usage(void) "String values must be enclosed in \" quotes, boolean values must " "be either true or false.\n", NULL); - nopt = sizeof(config_opts)/sizeof(config_opts[0]); - for (i = 0; i < nopt; i++) { - defaultval = config_opts[i].defaultval; + for (i = 0; i < WT_ELEMENTS(config_opts_desc); i++) { + defaultval = config_opts_desc[i].defaultval; typestr = "string"; - switch (config_opts[i].type) { + switch (config_opts_desc[i].type) { case BOOL_TYPE: typestr = "boolean"; if (strcmp(defaultval, "0") == 0) @@ -1009,28 +913,7 @@ config_opt_usage(void) break; } printf("%s (%s, default=%s)\n", - config_opts[i].name, typestr, defaultval); - pretty_print(config_opts[i].description, "\t"); + config_opts_desc[i].name, typestr, defaultval); + pretty_print(config_opts_desc[i].description, "\t"); } } - -/* - * usage -- - * wtperf usage print, no error. - */ -void -usage(void) -{ - printf("wtperf [-C config] " - "[-H mount] [-h home] [-O file] [-o option] [-T config]\n"); - printf("\t-C <string> additional connection configuration\n"); - printf("\t (added to option conn_config)\n"); - printf("\t-H <mount> configure Helium volume mount point\n"); - printf("\t-h <string> Wired Tiger home must exist, default WT_TEST\n"); - printf("\t-O <file> file contains options as listed below\n"); - printf("\t-o option=val[,option=val,...] set options listed below\n"); - printf("\t-T <string> additional table configuration\n"); - printf("\t (added to option table_config)\n"); - printf("\n"); - config_opt_usage(); -} diff --git a/bench/wtperf/config_opt.h b/bench/wtperf/config_opt.h index b7eff8e143f..3f1ab642227 100644 --- a/bench/wtperf/config_opt.h +++ b/bench/wtperf/config_opt.h @@ -37,3 +37,17 @@ typedef struct { CONFIG_OPT_TYPE type; size_t offset; } CONFIG_OPT; + +typedef struct __config_queue_entry { + char *string; + TAILQ_ENTRY(__config_queue_entry) q; +} CONFIG_QUEUE_ENTRY; + +typedef struct { /* Option structure */ +#define OPT_DECLARE_STRUCT +#include "wtperf_opt.i" +#undef OPT_DECLARE_STRUCT + + /* Queue head to save a copy of the config to be output */ + TAILQ_HEAD(__config_qh, __config_queue_entry) config_head; +} CONFIG_OPTS; diff --git a/bench/wtperf/doxy.c b/bench/wtperf/doxy.c index 26d73168ef2..4a9426da123 100644 --- a/bench/wtperf/doxy.c +++ b/bench/wtperf/doxy.c @@ -26,9 +26,11 @@ * OTHER DEALINGS IN THE SOFTWARE. */ +#include <sys/types.h> #include <string.h> #include <stdio.h> +#include "queue.h" #include "config_opt.h" static const CONFIG_OPT config_opts[] = { diff --git a/bench/wtperf/idle_table_cycle.c b/bench/wtperf/idle_table_cycle.c index 3c079bb560f..ad6b075be77 100644 --- a/bench/wtperf/idle_table_cycle.c +++ b/bench/wtperf/idle_table_cycle.c @@ -32,25 +32,28 @@ static int check_timing(CONFIG *cfg, const char *name, struct timespec start, struct timespec *stop) { + CONFIG_OPTS *opts; uint64_t last_interval; int ret; + opts = cfg->opts; + if ((ret = __wt_epoch(NULL, stop)) != 0) { lprintf(cfg, ret, 0, "Get time failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (ret); } last_interval = (uint64_t)(WT_TIMEDIFF_SEC(*stop, start)); - if (last_interval > cfg->idle_table_cycle) { + if (last_interval > opts->idle_table_cycle) { lprintf(cfg, ret, 0, "Cycling idle table failed because %s took %" PRIu64 " seconds which is longer than configured acceptable" " maximum of %" PRIu32 ".", - name, last_interval, cfg->idle_table_cycle); - cfg->error = ETIMEDOUT; + name, last_interval, opts->idle_table_cycle); + cfg->error = true; return (ETIMEDOUT); } return (0); @@ -65,16 +68,18 @@ cycle_idle_tables(void *arg) { struct timespec start, stop; CONFIG *cfg; - WT_SESSION *session; + CONFIG_OPTS *opts; WT_CURSOR *cursor; + WT_SESSION *session; int cycle_count, ret; char uri[512]; cfg = (CONFIG *)arg; + opts = cfg->opts; cycle_count = 0; if ((ret = cfg->conn->open_session( - cfg->conn, NULL, cfg->sess_config, &session)) != 0) { + cfg->conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "Error opening a session on %s", cfg->home); return (NULL); @@ -89,18 +94,18 @@ cycle_idle_tables(void *arg) if ((ret = __wt_epoch(NULL, &start)) != 0) { lprintf(cfg, ret, 0, "Get time failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (NULL); } /* Create a table. */ if ((ret = session->create( - session, uri, cfg->table_config)) != 0) { + session, uri, opts->table_config)) != 0) { if (ret == EBUSY) continue; lprintf(cfg, ret, 0, "Table create failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (NULL); } if (check_timing(cfg, "create", start, &stop) != 0) @@ -112,13 +117,13 @@ cycle_idle_tables(void *arg) session, uri, NULL, NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, "Cursor open failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (NULL); } if ((ret = cursor->close(cursor)) != 0) { lprintf(cfg, ret, 0, "Cursor close failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (NULL); } if (check_timing(cfg, "cursor", start, &stop) != 0) @@ -136,7 +141,7 @@ cycle_idle_tables(void *arg) if (ret != 0 && ret != EBUSY) { lprintf(cfg, ret, 0, "Table drop failed in cycle_idle_tables."); - cfg->error = ret; + cfg->error = true; return (NULL); } if (check_timing(cfg, "drop", start, &stop) != 0) @@ -156,17 +161,19 @@ cycle_idle_tables(void *arg) int start_idle_table_cycle(CONFIG *cfg, pthread_t *idle_table_cycle_thread) { + CONFIG_OPTS *opts; pthread_t thread_id; int ret; - if (cfg->idle_table_cycle == 0) + opts = cfg->opts; + + if (opts->idle_table_cycle == 0) return (0); cfg->idle_cycle_run = true; if ((ret = pthread_create( &thread_id, NULL, cycle_idle_tables, cfg)) != 0) { - lprintf( - cfg, ret, 0, "Error creating idle table cycle thread."); + lprintf(cfg, ret, 0, "Error creating idle table cycle thread."); cfg->idle_cycle_run = false; return (ret); } @@ -178,9 +185,12 @@ start_idle_table_cycle(CONFIG *cfg, pthread_t *idle_table_cycle_thread) int stop_idle_table_cycle(CONFIG *cfg, pthread_t idle_table_cycle_thread) { + CONFIG_OPTS *opts; int ret; - if (cfg->idle_table_cycle == 0 || !cfg->idle_cycle_run) + opts = cfg->opts; + + if (opts->idle_table_cycle == 0 || !cfg->idle_cycle_run) return (0); cfg->idle_cycle_run = false; diff --git a/bench/wtperf/misc.c b/bench/wtperf/misc.c index 2821216f240..14a6610f5bc 100644 --- a/bench/wtperf/misc.c +++ b/bench/wtperf/misc.c @@ -32,18 +32,20 @@ int setup_log_file(CONFIG *cfg) { + CONFIG_OPTS *opts; int ret; char *fname; + opts = cfg->opts; ret = 0; - if (cfg->verbose < 1) + if (opts->verbose < 1) return (0); fname = dcalloc(strlen(cfg->monitor_dir) + - strlen(cfg->table_name) + strlen(".stat") + 2, 1); + strlen(opts->table_name) + strlen(".stat") + 2, 1); - sprintf(fname, "%s/%s.stat", cfg->monitor_dir, cfg->table_name); + sprintf(fname, "%s/%s.stat", cfg->monitor_dir, opts->table_name); cfg->logf = fopen(fname, "w"); if (cfg->logf == NULL) { ret = errno; @@ -64,15 +66,18 @@ setup_log_file(CONFIG *cfg) void lprintf(const CONFIG *cfg, int err, uint32_t level, const char *fmt, ...) { + CONFIG_OPTS *opts; va_list ap; - if (err == 0 && level <= cfg->verbose) { + opts = cfg->opts; + + if (err == 0 && level <= opts->verbose) { va_start(ap, fmt); vfprintf(cfg->logf, fmt, ap); va_end(ap); fprintf(cfg->logf, "\n"); - if (level < cfg->verbose) { + if (level < opts->verbose) { va_start(ap, fmt); vprintf(fmt, ap); va_end(ap); diff --git a/bench/wtperf/track.c b/bench/wtperf/track.c index b3f4847d9d0..0464d22fb79 100644 --- a/bench/wtperf/track.c +++ b/bench/wtperf/track.c @@ -34,14 +34,16 @@ uint64_t sum_pop_ops(CONFIG *cfg) { + CONFIG_OPTS *opts; CONFIG_THREAD *thread; uint64_t total; u_int i; + opts = cfg->opts; total = 0; for (i = 0, thread = cfg->popthreads; - thread != NULL && i < cfg->populate_threads; ++i, ++thread) + thread != NULL && i < opts->populate_threads; ++i, ++thread) total += thread->insert.ops; return (total); } @@ -52,14 +54,16 @@ sum_pop_ops(CONFIG *cfg) uint64_t sum_ckpt_ops(CONFIG *cfg) { + CONFIG_OPTS *opts; CONFIG_THREAD *thread; uint64_t total; u_int i; + opts = cfg->opts; total = 0; for (i = 0, thread = cfg->ckptthreads; - thread != NULL && i < cfg->checkpoint_threads; ++i, ++thread) + thread != NULL && i < opts->checkpoint_threads; ++i, ++thread) total += thread->ckpt.ops; return (total); } @@ -70,17 +74,20 @@ sum_ckpt_ops(CONFIG *cfg) static uint64_t sum_ops(CONFIG *cfg, size_t field_offset) { + CONFIG_OPTS *opts; CONFIG_THREAD *thread; uint64_t total; int64_t i, th_cnt; + opts = cfg->opts; total = 0; + if (cfg->popthreads == NULL) { thread = cfg->workers; th_cnt = cfg->workers_cnt; } else { thread = cfg->popthreads; - th_cnt = cfg->populate_threads; + th_cnt = opts->populate_threads; } for (i = 0; thread != NULL && i < th_cnt; ++i, ++thread) total += ((TRACK *)((uint8_t *)thread + field_offset))->ops; @@ -117,12 +124,14 @@ static void latency_op(CONFIG *cfg, size_t field_offset, uint32_t *avgp, uint32_t *minp, uint32_t *maxp) { + CONFIG_OPTS *opts; CONFIG_THREAD *thread; TRACK *track; uint64_t ops, latency, tmp; int64_t i, th_cnt; uint32_t max, min; + opts = cfg->opts; ops = latency = 0; max = 0; min = UINT32_MAX; @@ -132,7 +141,7 @@ latency_op(CONFIG *cfg, th_cnt = cfg->workers_cnt; } else { thread = cfg->popthreads; - th_cnt = cfg->populate_threads; + th_cnt = opts->populate_threads; } for (i = 0; thread != NULL && i < th_cnt; ++i, ++thread) { track = (TRACK *)((uint8_t *)thread + field_offset); diff --git a/bench/wtperf/wtperf.c b/bench/wtperf/wtperf.c index c689fca80f7..a628f847476 100644 --- a/bench/wtperf/wtperf.c +++ b/bench/wtperf/wtperf.c @@ -31,44 +31,6 @@ /* Default values. */ #define DEFAULT_HOME "WT_TEST" #define DEFAULT_MONITOR_DIR "WT_TEST" -static const CONFIG default_cfg = { - NULL, /* home */ - NULL, /* monitor dir */ - NULL, /* partial logging */ - NULL, /* reopen config */ - NULL, /* base_uri */ - NULL, /* uris */ - NULL, /* conn */ - NULL, /* logf */ - NULL, /* async */ - NULL, NULL, /* compressor ext, blk */ - NULL, NULL, /* populate, checkpoint threads */ - - NULL, /* worker threads */ - 0, /* worker thread count */ - NULL, /* workloads */ - 0, /* workload count */ - 0, /* use_asyncops */ - 0, /* checkpoint operations */ - 0, /* insert operations */ - 0, /* read operations */ - 0, /* truncate operations */ - 0, /* update operations */ - 0, /* insert key */ - 0, /* checkpoint in progress */ - 0, /* thread error */ - 0, /* notify threads to stop */ - 0, /* in warmup phase */ - false, /* Signal for idle cycle thread */ - 0, /* total seconds running */ - 0, /* flags */ - {NULL, NULL}, /* the truncate queue */ - {NULL, NULL}, /* the config queue */ - -#define OPT_DEFINE_DEFAULT -#include "wtperf_opt.i" -#undef OPT_DEFINE_DEFAULT -}; static const char * const debug_cconfig = ""; static const char * const debug_tconfig = ""; @@ -110,9 +72,12 @@ get_next_incr(CONFIG *cfg) static void randomize_value(CONFIG_THREAD *thread, char *value_buf) { + CONFIG_OPTS *opts; uint8_t *vb; uint32_t i, max_range, rand_val; + opts = thread->cfg->opts; + /* * Limit how much of the buffer we validate for length, this means * that only threads that do growing updates will ever make changes to @@ -121,11 +86,11 @@ randomize_value(CONFIG_THREAD *thread, char *value_buf) * in this performance sensitive function. */ if (thread->workload == NULL || thread->workload->update_delta == 0) - max_range = thread->cfg->value_sz; + max_range = opts->value_sz; else if (thread->workload->update_delta > 0) - max_range = thread->cfg->value_sz_max; + max_range = opts->value_sz_max; else - max_range = thread->cfg->value_sz_min; + max_range = opts->value_sz_min; /* * Generate a single random value and re-use it. We generally only @@ -157,15 +122,19 @@ randomize_value(CONFIG_THREAD *thread, char *value_buf) static uint32_t map_key_to_table(CONFIG *cfg, uint64_t k) { - if (cfg->range_partition) { + CONFIG_OPTS *opts; + + opts = cfg->opts; + + if (opts->range_partition) { /* Take care to return a result in [0..table_count-1]. */ - if (k > cfg->icount + cfg->random_range) + if (k > opts->icount + opts->random_range) return (0); return ((uint32_t)((k - 1) / - ((cfg->icount + cfg->random_range + cfg->table_count - 1) / - cfg->table_count))); + ((opts->icount + opts->random_range + + opts->table_count - 1) / opts->table_count))); } else - return ((uint32_t)(k % cfg->table_count)); + return ((uint32_t)(k % opts->table_count)); } /* @@ -177,23 +146,25 @@ static inline void update_value_delta(CONFIG_THREAD *thread) { CONFIG *cfg; + CONFIG_OPTS *opts; char * value; int64_t delta, len, new_len; cfg = thread->cfg; + opts = cfg->opts; value = thread->value_buf; delta = thread->workload->update_delta; len = (int64_t)strlen(value); if (delta == INT64_MAX) delta = __wt_random(&thread->rnd) % - (cfg->value_sz_max - cfg->value_sz); + (opts->value_sz_max - opts->value_sz); /* Ensure we aren't changing across boundaries */ - if (delta > 0 && len + delta > cfg->value_sz_max) - delta = cfg->value_sz_max - len; - else if (delta < 0 && len + delta < cfg->value_sz_min) - delta = cfg->value_sz_min - len; + if (delta > 0 && len + delta > opts->value_sz_max) + delta = opts->value_sz_max - len; + else if (delta < 0 && len + delta < opts->value_sz_min) + delta = opts->value_sz_min - len; /* Bail if there isn't anything to do */ if (delta == 0) @@ -204,7 +175,7 @@ update_value_delta(CONFIG_THREAD *thread) else { /* Extend the value by the configured amount. */ for (new_len = len; - new_len < cfg->value_sz_max && new_len - len < delta; + new_len < opts->value_sz_max && new_len - len < delta; new_len++) value[new_len] = 'a'; } @@ -279,7 +250,7 @@ err: /* Panic if error */ lprintf(cfg, ret, 0, "Error in op %" PRIu64, op->get_id(op)); - cfg->error = cfg->stop = 1; + cfg->error = cfg->stop = true; return (1); } @@ -352,6 +323,7 @@ static void * worker_async(void *arg) { CONFIG *cfg; + CONFIG_OPTS *opts; CONFIG_THREAD *thread; WT_ASYNC_OP *asyncop; WT_CONNECTION *conn; @@ -362,6 +334,7 @@ worker_async(void *arg) thread = (CONFIG_THREAD *)arg; cfg = thread->cfg; + opts = cfg->opts; conn = cfg->conn; key_buf = thread->key_buf; @@ -378,10 +351,10 @@ worker_async(void *arg) switch (*op) { case WORKER_INSERT: case WORKER_INSERT_RMW: - if (cfg->random_range) + if (opts->random_range) next_val = wtperf_rand(thread); else - next_val = cfg->icount + get_next_incr(cfg); + next_val = opts->icount + get_next_incr(cfg); break; case WORKER_READ: case WORKER_UPDATE: @@ -422,14 +395,14 @@ worker_async(void *arg) break; goto op_err; case WORKER_INSERT: - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); asyncop->set_value(asyncop, value_buf); if ((ret = asyncop->insert(asyncop)) == 0) break; goto op_err; case WORKER_UPDATE: - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); asyncop->set_value(asyncop, value_buf); if ((ret = asyncop->update(asyncop)) == 0) @@ -452,7 +425,7 @@ op_err: lprintf(cfg, ret, 0, /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } return (NULL); } @@ -465,15 +438,17 @@ err: cfg->error = cfg->stop = 1; static int do_range_reads(CONFIG *cfg, WT_CURSOR *cursor) { + CONFIG_OPTS *opts; size_t range; uint64_t next_val, prev_val; char *range_key_buf; char buf[512]; int ret; + opts = cfg->opts; ret = 0; - if (cfg->read_range == 0) + if (opts->read_range == 0) return (0); memset(&buf[0], 0, 512 * sizeof(char)); @@ -483,7 +458,7 @@ do_range_reads(CONFIG *cfg, WT_CURSOR *cursor) testutil_check(cursor->get_key(cursor, &range_key_buf)); extract_key(range_key_buf, &next_val); - for (range = 0; range < cfg->read_range; ++range) { + for (range = 0; range < opts->read_range; ++range) { prev_val = next_val; ret = cursor->next(cursor); /* We are done if we reach the end. */ @@ -509,6 +484,7 @@ worker(void *arg) { struct timespec start, stop; CONFIG *cfg; + CONFIG_OPTS *opts; CONFIG_THREAD *thread; TRACK *trk; WT_CONNECTION *conn; @@ -524,6 +500,7 @@ worker(void *arg) thread = (CONFIG_THREAD *)arg; cfg = thread->cfg; + opts = cfg->opts; conn = cfg->conn; cursors = NULL; ops = 0; @@ -532,12 +509,12 @@ worker(void *arg) trk = NULL; if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &session)) != 0) { + conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "worker: WT_CONNECTION.open_session"); goto err; } - cursors = dcalloc(cfg->table_count, sizeof(WT_CURSOR *)); - for (i = 0; i < cfg->table_count_idle; i++) { + cursors = dcalloc(opts->table_count, sizeof(WT_CURSOR *)); + for (i = 0; i < opts->table_count_idle; i++) { snprintf(buf, 512, "%s_idle%05d", cfg->uris[0], (int)i); if ((ret = session->open_cursor( session, buf, NULL, NULL, &tmp_cursor)) != 0) { @@ -551,7 +528,7 @@ worker(void *arg) goto err; } } - for (i = 0; i < cfg->table_count; i++) { + for (i = 0; i < opts->table_count; i++) { if ((ret = session->open_cursor(session, cfg->uris[i], NULL, NULL, &cursors[i])) != 0) { lprintf(cfg, ret, 0, @@ -590,10 +567,10 @@ worker(void *arg) case WORKER_INSERT: case WORKER_INSERT_RMW: trk = &thread->insert; - if (cfg->random_range) + if (opts->random_range) next_val = wtperf_rand(thread); else - next_val = cfg->icount + get_next_incr(cfg); + next_val = opts->icount + get_next_incr(cfg); break; case WORKER_READ: trk = &thread->read; @@ -631,8 +608,8 @@ worker(void *arg) * is 0, to avoid first time latency spikes. */ measure_latency = - cfg->sample_interval != 0 && trk != NULL && - trk->ops != 0 && (trk->ops % cfg->sample_rate == 0); + opts->sample_interval != 0 && trk != NULL && + trk->ops != 0 && (trk->ops % opts->sample_rate == 0); if (measure_latency && (ret = __wt_epoch(NULL, &start)) != 0) { lprintf(cfg, ret, 0, "Get time call failed"); goto err; @@ -677,7 +654,7 @@ worker(void *arg) /* FALLTHROUGH */ case WORKER_INSERT: - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); cursor->set_value(cursor, value_buf); if ((ret = cursor->insert(cursor)) == 0) @@ -708,14 +685,14 @@ worker(void *arg) * safe, and be sure to NUL-terminate. */ strncpy(value_buf, - value, cfg->value_sz_max - 1); + value, opts->value_sz_max - 1); if (thread->workload->update_delta != 0) update_value_delta(thread); if (value_buf[0] == 'a') value_buf[0] = 'b'; else value_buf[0] = 'a'; - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); cursor->set_value(cursor, value_buf); if ((ret = cursor->update(cursor)) == 0) @@ -769,7 +746,7 @@ op_err: if (ret == WT_ROLLBACK && ops_per_txn != 0) { } /* Release the cursor, if we have multiple tables. */ - if (cfg->table_count > 1 && ret == 0 && + if (opts->table_count > 1 && ret == 0 && *op != WORKER_INSERT && *op != WORKER_INSERT_RMW) { if ((ret = cursor->reset(cursor)) != 0) { lprintf(cfg, ret, 0, "Cursor reset failed"); @@ -828,7 +805,7 @@ op_err: if (ret == WT_ROLLBACK && ops_per_txn != 0) { /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } free(cursors); @@ -883,8 +860,11 @@ run_mix_schedule_op(WORKLOAD *workp, int op, int64_t op_cnt) static int run_mix_schedule(CONFIG *cfg, WORKLOAD *workp) { + CONFIG_OPTS *opts; int64_t pct; + opts = cfg->opts; + /* Confirm reads, inserts, truncates and updates cannot all be zero. */ if (workp->insert == 0 && workp->read == 0 && workp->truncate == 0 && workp->update == 0) { @@ -915,7 +895,7 @@ run_mix_schedule(CONFIG *cfg, WORKLOAD *workp) */ if (workp->insert != 0 && workp->read == 0 && workp->update == 0) { memset(workp->ops, - cfg->insert_rmw ? WORKER_INSERT_RMW : WORKER_INSERT, + opts->insert_rmw ? WORKER_INSERT_RMW : WORKER_INSERT, sizeof(workp->ops)); return (0); } @@ -947,7 +927,7 @@ run_mix_schedule(CONFIG *cfg, WORKLOAD *workp) (workp->insert + workp->read + workp->update); if (pct != 0) run_mix_schedule_op(workp, - cfg->insert_rmw ? WORKER_INSERT_RMW : WORKER_INSERT, pct); + opts->insert_rmw ? WORKER_INSERT_RMW : WORKER_INSERT, pct); pct = (workp->update * 100) / (workp->insert + workp->read + workp->update); if (pct != 0) @@ -960,6 +940,7 @@ populate_thread(void *arg) { struct timespec start, stop; CONFIG *cfg; + CONFIG_OPTS *opts; CONFIG_THREAD *thread; TRACK *trk; WT_CONNECTION *conn; @@ -974,6 +955,7 @@ populate_thread(void *arg) thread = (CONFIG_THREAD *)arg; cfg = thread->cfg; + opts = cfg->opts; conn = cfg->conn; session = NULL; cursors = NULL; @@ -984,17 +966,17 @@ populate_thread(void *arg) value_buf = thread->value_buf; if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &session)) != 0) { + conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "populate: WT_CONNECTION.open_session"); goto err; } /* Do bulk loads if populate is single-threaded. */ cursor_config = - (cfg->populate_threads == 1 && !cfg->index) ? "bulk" : NULL; + (opts->populate_threads == 1 && !opts->index) ? "bulk" : NULL; /* Create the cursors. */ - cursors = dcalloc(cfg->table_count, sizeof(WT_CURSOR *)); - for (i = 0; i < cfg->table_count; i++) { + cursors = dcalloc(opts->table_count, sizeof(WT_CURSOR *)); + for (i = 0; i < opts->table_count; i++) { if ((ret = session->open_cursor( session, cfg->uris[i], NULL, cursor_config, &cursors[i])) != 0) { @@ -1008,12 +990,12 @@ populate_thread(void *arg) /* Populate the databases. */ for (intxn = 0, opcount = 0;;) { op = get_next_incr(cfg); - if (op > cfg->icount) + if (op > opts->icount) break; - if (cfg->populate_ops_per_txn != 0 && !intxn) { + if (opts->populate_ops_per_txn != 0 && !intxn) { if ((ret = session->begin_transaction( - session, cfg->transaction_config)) != 0) { + session, opts->transaction_config)) != 0) { lprintf(cfg, ret, 0, "Failed starting transaction."); goto err; @@ -1026,14 +1008,14 @@ populate_thread(void *arg) cursor = cursors[map_key_to_table(cfg, op)]; generate_key(cfg, key_buf, op); measure_latency = - cfg->sample_interval != 0 && - trk->ops != 0 && (trk->ops % cfg->sample_rate == 0); + opts->sample_interval != 0 && + trk->ops != 0 && (trk->ops % opts->sample_rate == 0); if (measure_latency && (ret = __wt_epoch(NULL, &start)) != 0) { lprintf(cfg, ret, 0, "Get time call failed"); goto err; } cursor->set_key(cursor, key_buf); - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); cursor->set_value(cursor, value_buf); if ((ret = cursor->insert(cursor)) == WT_ROLLBACK) { @@ -1067,12 +1049,12 @@ populate_thread(void *arg) } ++thread->insert.ops; /* Same as trk->ops */ - if (cfg->checkpoint_stress_rate != 0 && - (op % cfg->checkpoint_stress_rate) == 0) + if (opts->checkpoint_stress_rate != 0 && + (op % opts->checkpoint_stress_rate) == 0) stress_checkpoint_due = 1; - if (cfg->populate_ops_per_txn != 0) { - if (++opcount < cfg->populate_ops_per_txn) + if (opts->populate_ops_per_txn != 0) { + if (++opcount < opts->populate_ops_per_txn) continue; opcount = 0; @@ -1103,7 +1085,7 @@ populate_thread(void *arg) /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } free(cursors); @@ -1115,6 +1097,7 @@ populate_async(void *arg) { struct timespec start, stop; CONFIG *cfg; + CONFIG_OPTS *opts; CONFIG_THREAD *thread; TRACK *trk; WT_ASYNC_OP *asyncop; @@ -1126,6 +1109,7 @@ populate_async(void *arg) thread = (CONFIG_THREAD *)arg; cfg = thread->cfg; + opts = cfg->opts; conn = cfg->conn; session = NULL; ret = 0; @@ -1135,7 +1119,7 @@ populate_async(void *arg) value_buf = thread->value_buf; if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &session)) != 0) { + conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "populate: WT_CONNECTION.open_session"); goto err; } @@ -1146,8 +1130,8 @@ populate_async(void *arg) * the time to process by workers. */ measure_latency = - cfg->sample_interval != 0 && - trk->ops != 0 && (trk->ops % cfg->sample_rate == 0); + opts->sample_interval != 0 && + trk->ops != 0 && (trk->ops % opts->sample_rate == 0); if (measure_latency && (ret = __wt_epoch(NULL, &start)) != 0) { lprintf(cfg, ret, 0, "Get time call failed"); goto err; @@ -1155,7 +1139,7 @@ populate_async(void *arg) /* Populate the databases. */ for (;;) { op = get_next_incr(cfg); - if (op > cfg->icount) + if (op > opts->icount) break; /* * Allocate an async op for whichever table. @@ -1170,7 +1154,7 @@ populate_async(void *arg) asyncop->app_private = thread; generate_key(cfg, key_buf, op); asyncop->set_key(asyncop, key_buf); - if (cfg->random_value) + if (opts->random_value) randomize_value(thread, value_buf); asyncop->set_value(asyncop, value_buf); if ((ret = asyncop->insert(asyncop)) != 0) { @@ -1204,7 +1188,7 @@ populate_async(void *arg) /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } return (NULL); } @@ -1215,6 +1199,7 @@ monitor(void *arg) struct timespec t; struct tm *tm, _tm; CONFIG *cfg; + CONFIG_OPTS *opts; FILE *fp; size_t len; uint64_t min_thr, reads, inserts, updates; @@ -1230,12 +1215,14 @@ monitor(void *arg) char buf[64], *path; cfg = (CONFIG *)arg; - assert(cfg->sample_interval != 0); + opts = cfg->opts; + assert(opts->sample_interval != 0); + fp = NULL; path = NULL; - min_thr = (uint64_t)cfg->min_throughput; - latency_max = (uint32_t)ms_to_us(cfg->max_latency); + min_thr = (uint64_t)opts->min_throughput; + latency_max = (uint32_t)ms_to_us(opts->max_latency); /* Open the logging file. */ len = strlen(cfg->monitor_dir) + 100; @@ -1266,7 +1253,7 @@ monitor(void *arg) "\n"); last_reads = last_inserts = last_updates = 0; while (!cfg->stop) { - for (i = 0; i < cfg->sample_interval; i++) { + for (i = 0; i < opts->sample_interval; i++) { sleep(1); if (cfg->stop) break; @@ -1291,8 +1278,8 @@ monitor(void *arg) latency_insert(cfg, &insert_avg, &insert_min, &insert_max); latency_update(cfg, &update_avg, &update_min, &update_max); - cur_reads = (reads - last_reads) / cfg->sample_interval; - cur_updates = (updates - last_updates) / cfg->sample_interval; + cur_reads = (reads - last_reads) / opts->sample_interval; + cur_updates = (updates - last_updates) / opts->sample_interval; /* * For now the only item we need to worry about changing is * inserts when we transition from the populate phase to @@ -1302,7 +1289,7 @@ monitor(void *arg) cur_inserts = 0; else cur_inserts = - (inserts - last_inserts) / cfg->sample_interval; + (inserts - last_inserts) / opts->sample_interval; (void)fprintf(fp, "%s,%" PRIu32 @@ -1322,7 +1309,7 @@ monitor(void *arg) if (latency_max != 0 && (read_max > latency_max || insert_max > latency_max || update_max > latency_max)) { - if (cfg->max_latency_fatal) { + if (opts->max_latency_fatal) { level = 1; msg_err = WT_PANIC; str = "ERROR"; @@ -1341,7 +1328,7 @@ monitor(void *arg) ((cur_reads != 0 && cur_reads < min_thr) || (cur_inserts != 0 && cur_inserts < min_thr) || (cur_updates != 0 && cur_updates < min_thr))) { - if (cfg->min_throughput_fatal) { + if (opts->min_throughput_fatal) { level = 1; msg_err = WT_PANIC; str = "ERROR"; @@ -1363,7 +1350,7 @@ monitor(void *arg) /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } if (fp != NULL) @@ -1377,6 +1364,7 @@ static void * checkpoint_worker(void *arg) { CONFIG *cfg; + CONFIG_OPTS *opts; CONFIG_THREAD *thread; WT_CONNECTION *conn; WT_SESSION *session; @@ -1386,11 +1374,12 @@ checkpoint_worker(void *arg) thread = (CONFIG_THREAD *)arg; cfg = thread->cfg; + opts = cfg->opts; conn = cfg->conn; session = NULL; if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &session)) != 0) { + conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "open_session failed in checkpoint thread."); goto err; @@ -1398,7 +1387,7 @@ checkpoint_worker(void *arg) while (!cfg->stop) { /* Break the sleep up, so we notice interrupts faster. */ - for (i = 0; i < cfg->checkpoint_interval; i++) { + for (i = 0; i < opts->checkpoint_interval; i++) { sleep(1); if (cfg->stop) break; @@ -1411,12 +1400,12 @@ checkpoint_worker(void *arg) lprintf(cfg, ret, 0, "Get time failed in checkpoint."); goto err; } - cfg->ckpt = 1; + cfg->ckpt = true; if ((ret = session->checkpoint(session, NULL)) != 0) { lprintf(cfg, ret, 0, "Checkpoint failed."); goto err; } - cfg->ckpt = 0; + cfg->ckpt = false; ++thread->ckpt.ops; if ((ret = __wt_epoch(NULL, &e)) != 0) { @@ -1434,7 +1423,7 @@ checkpoint_worker(void *arg) /* Notify our caller we failed and shut the system down. */ if (0) { -err: cfg->error = cfg->stop = 1; +err: cfg->error = cfg->stop = true; } return (NULL); @@ -1444,6 +1433,7 @@ static int execute_populate(CONFIG *cfg) { struct timespec start, stop; + CONFIG_OPTS *opts; CONFIG_THREAD *popth; WT_ASYNC_OP *asyncop; pthread_t idle_table_cycle_thread; @@ -1454,10 +1444,12 @@ execute_populate(CONFIG *cfg) int elapsed, ret; void *(*pfunc)(void *); + opts = cfg->opts; + lprintf(cfg, 0, 1, "Starting %" PRIu32 " populate thread(s) for %" PRIu32 " items", - cfg->populate_threads, cfg->icount); + opts->populate_threads, opts->icount); /* Start cycling idle tables if configured. */ if ((ret = start_idle_table_cycle(cfg, &idle_table_cycle_thread)) != 0) @@ -1465,15 +1457,16 @@ execute_populate(CONFIG *cfg) cfg->insert_key = 0; - cfg->popthreads = dcalloc(cfg->populate_threads, sizeof(CONFIG_THREAD)); - if (cfg->use_asyncops > 0) { + cfg->popthreads = + dcalloc(opts->populate_threads, sizeof(CONFIG_THREAD)); + if (cfg->use_asyncops) { lprintf(cfg, 0, 1, "Starting %" PRIu32 " async thread(s)", - cfg->async_threads); + opts->async_threads); pfunc = populate_async; } else pfunc = populate_thread; if ((ret = start_threads(cfg, NULL, - cfg->popthreads, cfg->populate_threads, pfunc)) != 0) + cfg->popthreads, opts->populate_threads, pfunc)) != 0) return (ret); if ((ret = __wt_epoch(NULL, &start)) != 0) { @@ -1481,26 +1474,26 @@ execute_populate(CONFIG *cfg) return (ret); } for (elapsed = 0, interval = 0, last_ops = 0; - cfg->insert_key < cfg->icount && cfg->error == 0;) { + cfg->insert_key < opts->icount && !cfg->error;) { /* * Sleep for 100th of a second, report_interval is in second * granularity, each 100th increment of elapsed is a single * increment of interval. */ (void)usleep(10000); - if (cfg->report_interval == 0 || ++elapsed < 100) + if (opts->report_interval == 0 || ++elapsed < 100) continue; elapsed = 0; - if (++interval < cfg->report_interval) + if (++interval < opts->report_interval) continue; interval = 0; - cfg->totalsec += cfg->report_interval; + cfg->totalsec += opts->report_interval; cfg->insert_ops = sum_pop_ops(cfg); lprintf(cfg, 0, 1, "%" PRIu64 " populate inserts (%" PRIu64 " of %" PRIu32 ") in %" PRIu32 " secs (%" PRIu32 " total secs)", cfg->insert_ops - last_ops, cfg->insert_ops, - cfg->icount, cfg->report_interval, cfg->totalsec); + opts->icount, opts->report_interval, cfg->totalsec); last_ops = cfg->insert_ops; } if ((ret = __wt_epoch(NULL, &stop)) != 0) { @@ -1516,19 +1509,19 @@ execute_populate(CONFIG *cfg) */ popth = cfg->popthreads; cfg->popthreads = NULL; - ret = stop_threads(cfg, cfg->populate_threads, popth); + ret = stop_threads(cfg, opts->populate_threads, popth); free(popth); if (ret != 0) return (ret); /* Report if any worker threads didn't finish. */ - if (cfg->error != 0) { + if (cfg->error) { lprintf(cfg, WT_ERROR, 0, "Populate thread(s) exited without finishing."); return (WT_ERROR); } - lprintf(cfg, 0, 1, "Finished load of %" PRIu32 " items", cfg->icount); + lprintf(cfg, 0, 1, "Finished load of %" PRIu32 " items", opts->icount); msecs = WT_TIMEDIFF_MS(stop, start); /* @@ -1540,7 +1533,7 @@ execute_populate(CONFIG *cfg) print_ops_sec = 0; } else { print_secs = (double)msecs / (double)MSEC_PER_SEC; - print_ops_sec = (uint64_t)(cfg->icount / print_secs); + print_ops_sec = (uint64_t)(opts->icount / print_secs); } lprintf(cfg, 0, 1, "Load time: %.2f\n" "load ops/sec: %" PRIu64, @@ -1551,15 +1544,15 @@ execute_populate(CONFIG *cfg) * set an unlimited timeout because if we close the connection * then any in-progress compact/merge is aborted. */ - if (cfg->compact) { - assert(cfg->async_threads > 0); + if (opts->compact) { + assert(opts->async_threads > 0); lprintf(cfg, 0, 1, "Compact after populate"); if ((ret = __wt_epoch(NULL, &start)) != 0) { lprintf(cfg, ret, 0, "Get time failed in populate."); return (ret); } - tables = cfg->table_count; - for (i = 0; i < cfg->table_count; i++) { + tables = opts->table_count; + for (i = 0; i < opts->table_count; i++) { /* * If no ops are available, retry. Any other error, * return. @@ -1600,9 +1593,12 @@ execute_populate(CONFIG *cfg) static int close_reopen(CONFIG *cfg) { + CONFIG_OPTS *opts; int ret; - if (!cfg->readonly && !cfg->reopen_connection) + opts = cfg->opts; + + if (!opts->readonly && !opts->reopen_connection) return (0); /* * Reopen the connection. We do this so that the workload phase always @@ -1628,7 +1624,7 @@ close_reopen(CONFIG *cfg) * threads looking for work that will never arrive don't affect * performance. */ - if (cfg->compact && cfg->use_asyncops == 0) { + if (opts->compact && !cfg->use_asyncops) { if ((ret = cfg->conn->reconfigure( cfg->conn, "async=(enabled=false)")) != 0) { lprintf(cfg, ret, 0, "Reconfigure async off failed"); @@ -1641,6 +1637,7 @@ close_reopen(CONFIG *cfg) static int execute_workload(CONFIG *cfg) { + CONFIG_OPTS *opts; CONFIG_THREAD *threads; WORKLOAD *workp; WT_CONNECTION *conn; @@ -1653,6 +1650,8 @@ execute_workload(CONFIG *cfg) int ret, t_ret; void *(*pfunc)(void *); + opts = cfg->opts; + cfg->insert_key = 0; cfg->insert_ops = cfg->read_ops = cfg->truncate_ops = 0; cfg->update_ops = 0; @@ -1667,26 +1666,26 @@ execute_workload(CONFIG *cfg) if ((ret = start_idle_table_cycle(cfg, &idle_table_cycle_thread)) != 0) return (ret); - if (cfg->warmup != 0) - cfg->in_warmup = 1; + if (opts->warmup != 0) + cfg->in_warmup = true; /* Allocate memory for the worker threads. */ cfg->workers = dcalloc((size_t)cfg->workers_cnt, sizeof(CONFIG_THREAD)); - if (cfg->use_asyncops > 0) { + if (cfg->use_asyncops) { lprintf(cfg, 0, 1, "Starting %" PRIu32 " async thread(s)", - cfg->async_threads); + opts->async_threads); pfunc = worker_async; } else pfunc = worker; - if (cfg->session_count_idle != 0) { - sessions = dcalloc((size_t)cfg->session_count_idle, + if (opts->session_count_idle != 0) { + sessions = dcalloc((size_t)opts->session_count_idle, sizeof(WT_SESSION *)); conn = cfg->conn; - for (i = 0; i < cfg->session_count_idle; ++i) - if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &sessions[i])) != 0) { + for (i = 0; i < opts->session_count_idle; ++i) + if ((ret = conn->open_session(conn, + NULL, opts->sess_config, &sessions[i])) != 0) { lprintf(cfg, ret, 0, "execute_workload: idle open_session"); goto err; @@ -1714,15 +1713,15 @@ execute_workload(CONFIG *cfg) threads += workp->threads; } - if (cfg->warmup != 0) { + if (opts->warmup != 0) { lprintf(cfg, 0, 1, - "Waiting for warmup duration of %" PRIu32, cfg->warmup); - sleep(cfg->warmup); - cfg->in_warmup = 0; + "Waiting for warmup duration of %" PRIu32, opts->warmup); + sleep(opts->warmup); + cfg->in_warmup = false; } - for (interval = cfg->report_interval, run_time = cfg->run_time, - run_ops = cfg->run_ops; cfg->error == 0;) { + for (interval = opts->report_interval, + run_time = opts->run_time, run_ops = opts->run_ops; !cfg->error;) { /* * Sleep for one second at a time. * If we are tracking run time, check to see if we're done, and @@ -1751,8 +1750,8 @@ execute_workload(CONFIG *cfg) /* If writing out throughput information, see if it's time. */ if (interval == 0 || --interval > 0) continue; - interval = cfg->report_interval; - cfg->totalsec += cfg->report_interval; + interval = opts->report_interval; + cfg->totalsec += opts->report_interval; lprintf(cfg, 0, 1, "%" PRIu64 " reads, %" PRIu64 " inserts, %" PRIu64 @@ -1763,7 +1762,7 @@ execute_workload(CONFIG *cfg) cfg->update_ops - last_updates, cfg->truncate_ops - last_truncates, cfg->ckpt_ops - last_ckpts, - cfg->report_interval, cfg->totalsec); + opts->report_interval, cfg->totalsec); last_reads = cfg->read_ops; last_inserts = cfg->insert_ops; last_updates = cfg->update_ops; @@ -1772,7 +1771,7 @@ execute_workload(CONFIG *cfg) } /* Notify the worker threads they are done. */ -err: cfg->stop = 1; +err: cfg->stop = true; /* Stop cycling idle tables. */ if ((ret = stop_idle_table_cycle(cfg, idle_table_cycle_thread)) != 0) @@ -1783,12 +1782,12 @@ err: cfg->stop = 1; ret = t_ret; /* Drop tables if configured to and this isn't an error path */ - if (ret == 0 && cfg->drop_tables && (ret = drop_all_tables(cfg)) != 0) + if (ret == 0 && opts->drop_tables && (ret = drop_all_tables(cfg)) != 0) lprintf(cfg, ret, 0, "Drop tables failed."); free(sessions); /* Report if any worker threads didn't finish. */ - if (cfg->error != 0) { + if (cfg->error) { lprintf(cfg, WT_ERROR, 0, "Worker thread(s) exited without finishing."); if (ret == 0) @@ -1804,6 +1803,7 @@ err: cfg->stop = 1; static int find_table_count(CONFIG *cfg) { + CONFIG_OPTS *opts; WT_CONNECTION *conn; WT_CURSOR *cursor; WT_SESSION *session; @@ -1811,16 +1811,17 @@ find_table_count(CONFIG *cfg) int ret, t_ret; char *key; + opts = cfg->opts; conn = cfg->conn; max_icount = 0; if ((ret = conn->open_session( - conn, NULL, cfg->sess_config, &session)) != 0) { + conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "find_table_count: open_session failed"); goto out; } - for (i = 0; i < cfg->table_count; i++) { + for (i = 0; i < opts->table_count; i++) { if ((ret = session->open_cursor(session, cfg->uris[i], NULL, NULL, &cursor)) != 0) { lprintf(cfg, ret, 0, @@ -1853,61 +1854,65 @@ err: if ((t_ret = session->close(session, NULL)) != 0) { lprintf(cfg, ret, 0, "find_table_count: session close failed"); } - cfg->icount = max_icount; + opts->icount = max_icount; out: return (ret); } /* - * Populate the uri array if more than one table is being used. + * Populate the uri array. */ static void create_uris(CONFIG *cfg) { - size_t base_uri_len; + CONFIG_OPTS *opts; + size_t len; uint32_t i; - char *uri; - base_uri_len = strlen(cfg->base_uri); - cfg->uris = dcalloc(cfg->table_count, sizeof(char *)); - for (i = 0; i < cfg->table_count; i++) { - uri = cfg->uris[i] = dcalloc(base_uri_len + 6, 1); - /* - * If there is only one table, just use base name. - */ - if (cfg->table_count == 1) - memcpy(uri, cfg->base_uri, base_uri_len); + opts = cfg->opts; + + cfg->uris = dcalloc(opts->table_count, sizeof(char *)); + len = strlen("table:") + strlen(opts->table_name) + 20; + for (i = 0; i < opts->table_count; i++) { + /* If there is only one table, just use the base name. */ + cfg->uris[i] = dmalloc(len); + if (opts->table_count == 1) + sprintf(cfg->uris[i], "table:%s", opts->table_name); else - sprintf(uri, "%s%05d", cfg->base_uri, i); + sprintf( + cfg->uris[i], "table:%s%05d", opts->table_name, i); } } static int create_tables(CONFIG *cfg) { + CONFIG_OPTS *opts; WT_SESSION *session; size_t i; int ret; char buf[512]; + opts = cfg->opts; + if ((ret = cfg->conn->open_session( - cfg->conn, NULL, cfg->sess_config, &session)) != 0) { + cfg->conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "Error opening a session on %s", cfg->home); return (ret); } - for (i = 0; i < cfg->table_count_idle; i++) { + for (i = 0; i < opts->table_count_idle; i++) { snprintf(buf, 512, "%s_idle%05d", cfg->uris[0], (int)i); if ((ret = session->create( - session, buf, cfg->table_config)) != 0) { + session, buf, opts->table_config)) != 0) { lprintf(cfg, ret, 0, "Error creating idle table %s", buf); return (ret); } } - for (i = 0; i < cfg->table_count; i++) { - if (cfg->log_partial && i > 0) { + for (i = 0; i < opts->table_count; i++) { + if (opts->log_partial && i > 0) { if (((ret = session->create(session, cfg->uris[i], cfg->partial_config)) != 0)) { lprintf(cfg, ret, 0, @@ -1915,12 +1920,12 @@ create_tables(CONFIG *cfg) return (ret); } } else if ((ret = session->create( - session, cfg->uris[i], cfg->table_config)) != 0) { + session, cfg->uris[i], opts->table_config)) != 0) { lprintf(cfg, ret, 0, "Error creating table %s", cfg->uris[i]); return (ret); } - if (cfg->index) { + if (opts->index) { snprintf(buf, 512, "index:%s:val_idx", cfg->uris[i] + strlen("table:")); if ((ret = session->create( @@ -1940,48 +1945,172 @@ create_tables(CONFIG *cfg) return (0); } +/* + * config_copy -- + * Create a new CONFIG structure as a duplicate of a previous one. + */ +static int +config_copy(const CONFIG *src, CONFIG **retp) +{ + CONFIG *dest; + CONFIG_OPTS *opts; + size_t i; + + opts = src->opts; + + dest = dcalloc(1, sizeof(CONFIG)); + + if (src->home != NULL) + dest->home = dstrdup(src->home); + if (src->monitor_dir != NULL) + dest->monitor_dir = dstrdup(src->monitor_dir); + if (src->partial_config != NULL) + dest->partial_config = dstrdup(src->partial_config); + if (src->reopen_config != NULL) + dest->reopen_config = dstrdup(src->reopen_config); + + if (src->uris != NULL) { + dest->uris = dcalloc(opts->table_count, sizeof(char *)); + for (i = 0; i < opts->table_count; i++) + dest->uris[i] = dstrdup(src->uris[i]); + } + + if (src->async_config != NULL) + dest->async_config = dstrdup(src->async_config); + + dest->ckptthreads = NULL; + dest->popthreads = NULL; + dest->workers = NULL; + + if (src->workload != NULL) { + dest->workload = dcalloc(WORKLOAD_MAX, sizeof(WORKLOAD)); + memcpy(dest->workload, + src->workload, WORKLOAD_MAX * sizeof(WORKLOAD)); + } + + TAILQ_INIT(&dest->stone_head); + + dest->opts = src->opts; + + *retp = dest; + return (0); +} + +/* + * config_free -- + * Free any storage allocated in the CONFIG structure. + */ +static void +config_free(CONFIG *cfg) +{ + CONFIG_OPTS *opts; + size_t i; + + opts = cfg->opts; + + free(cfg->home); + free(cfg->monitor_dir); + free(cfg->partial_config); + free(cfg->reopen_config); + + if (cfg->uris != NULL) { + for (i = 0; i < opts->table_count; i++) + free(cfg->uris[i]); + free(cfg->uris); + } + + free(cfg->async_config); + + free(cfg->ckptthreads); + free(cfg->popthreads); + + free(cfg->workers); + free(cfg->workload); + + cleanup_truncate_config(cfg); +} + +/* + * config_compress -- + * Parse the compression configuration. + */ +static int +config_compress(CONFIG *cfg) +{ + CONFIG_OPTS *opts; + int ret; + const char *s; + + opts = cfg->opts; + ret = 0; + + s = opts->compression; + if (strcmp(s, "none") == 0) { + cfg->compress_ext = NULL; + cfg->compress_table = NULL; + } else if (strcmp(s, "lz4") == 0) { +#ifndef HAVE_BUILTIN_EXTENSION_LZ4 + cfg->compress_ext = LZ4_EXT; +#endif + cfg->compress_table = LZ4_BLK; + } else if (strcmp(s, "snappy") == 0) { +#ifndef HAVE_BUILTIN_EXTENSION_SNAPPY + cfg->compress_ext = SNAPPY_EXT; +#endif + cfg->compress_table = SNAPPY_BLK; + } else if (strcmp(s, "zlib") == 0) { +#ifndef HAVE_BUILTIN_EXTENSION_ZLIB + cfg->compress_ext = ZLIB_EXT; +#endif + cfg->compress_table = ZLIB_BLK; + } else { + fprintf(stderr, + "invalid compression configuration: %s\n", s); + ret = EINVAL; + } + return (ret); + +} + static int start_all_runs(CONFIG *cfg) { CONFIG *next_cfg, **configs; + CONFIG_OPTS *opts; pthread_t *threads; - size_t home_len, i; + size_t i, len; int ret, t_ret; - char *new_home; - ret = 0; + opts = cfg->opts; configs = NULL; + ret = 0; - if (cfg->database_count == 1) + if (opts->database_count == 1) return (start_run(cfg)); /* Allocate an array to hold our config struct copies. */ - configs = dcalloc(cfg->database_count, sizeof(CONFIG *)); + configs = dcalloc(opts->database_count, sizeof(CONFIG *)); /* Allocate an array to hold our thread IDs. */ - threads = dcalloc(cfg->database_count, sizeof(pthread_t)); + threads = dcalloc(opts->database_count, sizeof(pthread_t)); - home_len = strlen(cfg->home); - for (i = 0; i < cfg->database_count; i++) { - next_cfg = dcalloc(1, sizeof(CONFIG)); - configs[i] = next_cfg; - if ((ret = config_copy(next_cfg, cfg)) != 0) + len = strlen(cfg->home); + for (i = 0; i < opts->database_count; i++) { + if ((ret = config_copy(cfg, &next_cfg)) != 0) goto err; + configs[i] = next_cfg; /* Setup a unique home directory for each database. */ - new_home = dmalloc(home_len + 5); - snprintf(new_home, home_len + 5, "%s/D%02d", cfg->home, (int)i); - free(next_cfg->home); - next_cfg->home = new_home; + next_cfg->home = dmalloc(len + 5); + snprintf(next_cfg->home, + len + 5, "%s/D%02d", cfg->home, (int)i); /* If the monitor dir is default, update it too. */ - if (strcmp(cfg->monitor_dir, cfg->home) == 0) { - free(next_cfg->monitor_dir); - next_cfg->monitor_dir = dstrdup(new_home); - } + if (strcmp(cfg->monitor_dir, cfg->home) == 0) + next_cfg->monitor_dir = dstrdup(next_cfg->home); /* If creating the sub-database, recreate its home */ - if (cfg->create != 0) + if (opts->create != 0) recreate_dir(next_cfg->home); if ((ret = pthread_create( @@ -1992,14 +2121,14 @@ start_all_runs(CONFIG *cfg) } /* Wait for threads to finish. */ - for (i = 0; i < cfg->database_count; i++) + for (i = 0; i < opts->database_count; i++) if ((t_ret = pthread_join(threads[i], NULL)) != 0) { lprintf(cfg, ret, 0, "Error joining thread"); if (ret == 0) ret = t_ret; } -err: for (i = 0; i < cfg->database_count && configs[i] != NULL; i++) { +err: for (i = 0; i < opts->database_count && configs[i] != NULL; i++) { config_free(configs[i]); free(configs[i]); } @@ -2025,11 +2154,13 @@ thread_run_wtperf(void *arg) static int start_run(CONFIG *cfg) { + CONFIG_OPTS *opts; pthread_t monitor_thread; uint64_t total_ops; uint32_t run_time; int monitor_created, ret, t_ret; + opts = cfg->opts; monitor_created = ret = 0; /* [-Wconditional-uninitialized] */ memset(&monitor_thread, 0, sizeof(monitor_thread)); @@ -2038,7 +2169,7 @@ start_run(CONFIG *cfg) goto err; if ((ret = wiredtiger_open( /* Open the real connection. */ - cfg->home, NULL, cfg->conn_config, &cfg->conn)) != 0) { + cfg->home, NULL, opts->conn_config, &cfg->conn)) != 0) { lprintf(cfg, ret, 0, "Error connecting to %s", cfg->home); goto err; } @@ -2046,27 +2177,26 @@ start_run(CONFIG *cfg) create_uris(cfg); /* If creating, create the tables. */ - if (cfg->create != 0 && (ret = create_tables(cfg)) != 0) + if (opts->create != 0 && (ret = create_tables(cfg)) != 0) goto err; /* Start the monitor thread. */ - if (cfg->sample_interval != 0) { + if (opts->sample_interval != 0) { if ((ret = pthread_create( &monitor_thread, NULL, monitor, cfg)) != 0) { - lprintf( - cfg, ret, 0, "Error creating monitor thread."); + lprintf(cfg, ret, 0, "Error creating monitor thread."); goto err; } monitor_created = 1; } /* If creating, populate the table. */ - if (cfg->create != 0 && execute_populate(cfg) != 0) + if (opts->create != 0 && execute_populate(cfg) != 0) goto err; /* Optional workload. */ if (cfg->workers_cnt != 0 && - (cfg->run_time != 0 || cfg->run_ops != 0)) { + (opts->run_time != 0 || opts->run_ops != 0)) { /* * If we have a workload, close and reopen the connection so * that LSM can detect read-only workloads. @@ -2075,18 +2205,18 @@ start_run(CONFIG *cfg) goto err; /* Didn't create, set insert count. */ - if (cfg->create == 0 && cfg->random_range == 0 && - find_table_count(cfg) != 0) + if (opts->create == 0 && + opts->random_range == 0 && find_table_count(cfg) != 0) goto err; /* Start the checkpoint thread. */ - if (cfg->checkpoint_threads != 0) { + if (opts->checkpoint_threads != 0) { lprintf(cfg, 0, 1, "Starting %" PRIu32 " checkpoint thread(s)", - cfg->checkpoint_threads); + opts->checkpoint_threads); cfg->ckptthreads = dcalloc( - cfg->checkpoint_threads, sizeof(CONFIG_THREAD)); + opts->checkpoint_threads, sizeof(CONFIG_THREAD)); if (start_threads(cfg, NULL, cfg->ckptthreads, - cfg->checkpoint_threads, checkpoint_worker) != 0) + opts->checkpoint_threads, checkpoint_worker) != 0) goto err; } /* Execute the workload. */ @@ -2101,7 +2231,7 @@ start_run(CONFIG *cfg) cfg->ckpt_ops = sum_ckpt_ops(cfg); total_ops = cfg->read_ops + cfg->insert_ops + cfg->update_ops; - run_time = cfg->run_time == 0 ? 1 : cfg->run_time; + run_time = opts->run_time == 0 ? 1 : opts->run_time; lprintf(cfg, 0, 1, "Executed %" PRIu64 " read operations (%" PRIu64 "%%) %" PRIu64 " ops/sec", @@ -2135,7 +2265,7 @@ err: if (ret == 0) } /* Notify the worker threads they are done. */ - cfg->stop = 1; + cfg->stop = true; if ((t_ret = stop_threads(cfg, 1, cfg->ckptthreads)) != 0) if (ret == 0) @@ -2157,12 +2287,13 @@ err: if (ret == 0) } if (ret == 0) { - if (cfg->run_time == 0 && cfg->run_ops == 0) + if (opts->run_time == 0 && opts->run_ops == 0) lprintf(cfg, 0, 1, "Run completed"); else lprintf(cfg, 0, 1, "Run completed: %" PRIu32 " %s", - cfg->run_time == 0 ? cfg->run_ops : cfg->run_time, - cfg->run_time == 0 ? "operations" : "seconds"); + opts->run_time == 0 ? + opts->run_ops : opts->run_time, + opts->run_time == 0 ? "operations" : "seconds"); } if (cfg->logf != NULL) { @@ -2178,32 +2309,55 @@ extern int __wt_optind, __wt_optreset; extern char *__wt_optarg; void (*custom_die)(void) = NULL; +/* + * usage -- + * wtperf usage print, no error. + */ +static void +usage(void) +{ + printf("wtperf [-C config] " + "[-H mount] [-h home] [-O file] [-o option] [-T config]\n"); + printf("\t-C <string> additional connection configuration\n"); + printf("\t (added to option conn_config)\n"); + printf("\t-H <mount> configure Helium volume mount point\n"); + printf("\t-h <string> Wired Tiger home must exist, default WT_TEST\n"); + printf("\t-O <file> file contains options as listed below\n"); + printf("\t-o option=val[,option=val,...] set options listed below\n"); + printf("\t-T <string> additional table configuration\n"); + printf("\t (added to option table_config)\n"); + printf("\n"); + config_opt_usage(); +} + int main(int argc, char *argv[]) { CONFIG *cfg, _cfg; + CONFIG_OPTS *opts; size_t req_len, sreq_len; bool monitor_set; int ch, ret; - const char *opts = "C:h:m:O:o:T:"; + const char *cmdflags = "C:h:m:O:o:T:"; const char *config_opts; - char *cc_buf, *sess_cfg, *tc_buf, *user_cconfig, *user_tconfig; - - monitor_set = false; - ret = 0; - config_opts = NULL; - cc_buf = sess_cfg = tc_buf = user_cconfig = user_tconfig = NULL; + char *cc_buf, *path, *sess_cfg, *tc_buf, *user_cconfig, *user_tconfig; - /* Setup the default configuration values. */ + /* The first CONFIG structure (from which all others are derived). */ cfg = &_cfg; memset(cfg, 0, sizeof(*cfg)); - if (config_copy(cfg, &default_cfg)) - goto err; cfg->home = dstrdup(DEFAULT_HOME); cfg->monitor_dir = dstrdup(DEFAULT_MONITOR_DIR); + TAILQ_INIT(&cfg->stone_head); + config_opt_init(&cfg->opts); + + opts = cfg->opts; + monitor_set = false; + ret = 0; + config_opts = NULL; + cc_buf = sess_cfg = tc_buf = user_cconfig = user_tconfig = NULL; /* Do a basic validation of options, and home is needed before open. */ - while ((ch = __wt_getopt("wtperf", argc, argv, opts)) != EOF) + while ((ch = __wt_getopt("wtperf", argc, argv, cmdflags)) != EOF) switch (ch) { case 'C': if (user_cconfig == NULL) @@ -2259,16 +2413,16 @@ main(int argc, char *argv[]) /* Parse options that override values set via a configuration file. */ __wt_optreset = __wt_optind = 1; - while ((ch = __wt_getopt("wtperf", argc, argv, opts)) != EOF) + while ((ch = __wt_getopt("wtperf", argc, argv, cmdflags)) != EOF) switch (ch) { case 'o': /* Allow -o key=value */ - if (config_opt_line(cfg, __wt_optarg) != 0) + if (config_opt_str(cfg, __wt_optarg) != 0) goto einval; break; } - if (cfg->populate_threads == 0 && cfg->icount != 0) { + if (opts->populate_threads == 0 && opts->icount != 0) { lprintf(cfg, 1, 0, "Cannot have 0 populate threads when icount is set\n"); goto err; @@ -2280,16 +2434,16 @@ main(int argc, char *argv[]) * If the user wants compaction, then we also enable async for * the compact operation, but not for the workloads. */ - if (cfg->async_threads > 0) { + if (opts->async_threads > 0) { if (F_ISSET(cfg, CFG_TRUNCATE)) { lprintf(cfg, 1, 0, "Cannot run truncate and async\n"); goto err; } - cfg->use_asyncops = 1; + cfg->use_asyncops = true; } - if (cfg->compact && cfg->async_threads == 0) - cfg->async_threads = 2; - if (cfg->async_threads > 0) { + if (opts->compact && opts->async_threads == 0) + opts->async_threads = 2; + if (opts->async_threads > 0) { /* * The maximum number of async threads is two digits, so just * use that to compute the space we need. Assume the default @@ -2300,34 +2454,29 @@ main(int argc, char *argv[]) cfg->async_config = dmalloc(req_len); snprintf(cfg->async_config, req_len, ",async=(enabled=true,threads=%" PRIu32 ")", - cfg->async_threads); + opts->async_threads); } if ((ret = config_compress(cfg)) != 0) goto err; /* You can't have truncate on a random collection. */ - if (F_ISSET(cfg, CFG_TRUNCATE) && cfg->random_range) { + if (F_ISSET(cfg, CFG_TRUNCATE) && opts->random_range) { lprintf(cfg, 1, 0, "Cannot run truncate and random_range\n"); goto err; } /* We can't run truncate with more than one table. */ - if (F_ISSET(cfg, CFG_TRUNCATE) && cfg->table_count > 1) { + if (F_ISSET(cfg, CFG_TRUNCATE) && opts->table_count > 1) { lprintf(cfg, 1, 0, "Cannot truncate more than 1 table\n"); goto err; } - /* Build the URI from the table name. */ - req_len = strlen("table:") + strlen(cfg->table_name) + 2; - cfg->base_uri = dmalloc(req_len); - snprintf(cfg->base_uri, req_len, "table:%s", cfg->table_name); - /* Make stdout line buffered, so verbose output appears quickly. */ __wt_stream_set_line_buffer(stdout); /* Concatenate non-default configuration strings. */ - if (cfg->verbose > 1 || user_cconfig != NULL || - cfg->session_count_idle > 0 || cfg->compress_ext != NULL || + if (opts->verbose > 1 || user_cconfig != NULL || + opts->session_count_idle > 0 || cfg->compress_ext != NULL || cfg->async_config != NULL) { req_len = strlen(debug_cconfig) + 3; if (user_cconfig != NULL) @@ -2336,14 +2485,14 @@ main(int argc, char *argv[]) req_len += strlen(cfg->async_config); if (cfg->compress_ext != NULL) req_len += strlen(cfg->compress_ext); - if (cfg->session_count_idle > 0) { + if (opts->session_count_idle > 0) { sreq_len = strlen(",session_max=") + 6; req_len += sreq_len; sess_cfg = dmalloc(sreq_len); snprintf(sess_cfg, sreq_len, ",session_max=%" PRIu32, - cfg->session_count_idle + cfg->workers_cnt + - cfg->populate_threads + 10); + opts->session_count_idle + + cfg->workers_cnt + opts->populate_threads + 10); } cc_buf = dmalloc(req_len); /* @@ -2352,81 +2501,82 @@ main(int argc, char *argv[]) snprintf(cc_buf, req_len, "%s%s%s%s%s%s%s", cfg->async_config ? cfg->async_config : "", cfg->compress_ext ? cfg->compress_ext : "", - cfg->verbose > 1 && strlen(debug_cconfig) ? ",": "", - cfg->verbose > 1 && + opts->verbose > 1 && strlen(debug_cconfig) ? ",": "", + opts->verbose > 1 && strlen(debug_cconfig) ? debug_cconfig : "", sess_cfg ? sess_cfg : "", user_cconfig ? ",": "", user_cconfig ? user_cconfig : ""); - if (strlen(cc_buf)) - if ((ret = config_opt_str( - cfg, "conn_config", cc_buf)) != 0) - goto err; + if (strlen(cc_buf) && (ret = + config_opt_name_value(cfg, "conn_config", cc_buf)) != 0) + goto err; } - if (cfg->verbose > 1 || cfg->index || + if (opts->verbose > 1 || opts->index || user_tconfig != NULL || cfg->compress_table != NULL) { req_len = strlen(debug_tconfig) + 3; if (user_tconfig != NULL) req_len += strlen(user_tconfig); if (cfg->compress_table != NULL) req_len += strlen(cfg->compress_table); - if (cfg->index) + if (opts->index) req_len += strlen(INDEX_COL_NAMES); tc_buf = dmalloc(req_len); /* * This is getting hard to parse. */ snprintf(tc_buf, req_len, "%s%s%s%s%s%s", - cfg->index ? INDEX_COL_NAMES : "", + opts->index ? INDEX_COL_NAMES : "", cfg->compress_table ? cfg->compress_table : "", - cfg->verbose > 1 && strlen(debug_tconfig) ? ",": "", - cfg->verbose > 1 && + opts->verbose > 1 && strlen(debug_tconfig) ? ",": "", + opts->verbose > 1 && strlen(debug_tconfig) ? debug_tconfig : "", user_tconfig ? ",": "", user_tconfig ? user_tconfig : ""); - if (strlen(tc_buf)) - if ((ret = config_opt_str( - cfg, "table_config", tc_buf)) != 0) - goto err; + if (strlen(tc_buf) && (ret = + config_opt_name_value(cfg, "table_config", tc_buf)) != 0) + goto err; } - if (cfg->log_partial && cfg->table_count > 1) { - req_len = strlen(cfg->table_config) + + if (opts->log_partial && opts->table_count > 1) { + req_len = strlen(opts->table_config) + strlen(LOG_PARTIAL_CONFIG) + 1; cfg->partial_config = dmalloc(req_len); snprintf(cfg->partial_config, req_len, "%s%s", - cfg->table_config, LOG_PARTIAL_CONFIG); + opts->table_config, LOG_PARTIAL_CONFIG); } /* * Set the config for reopen. If readonly add in that string. * If not readonly then just copy the original conn_config. */ - if (cfg->readonly) - req_len = strlen(cfg->conn_config) + + if (opts->readonly) + req_len = strlen(opts->conn_config) + strlen(READONLY_CONFIG) + 1; else - req_len = strlen(cfg->conn_config) + 1; + req_len = strlen(opts->conn_config) + 1; cfg->reopen_config = dmalloc(req_len); - if (cfg->readonly) + if (opts->readonly) snprintf(cfg->reopen_config, req_len, "%s%s", - cfg->conn_config, READONLY_CONFIG); + opts->conn_config, READONLY_CONFIG); else - snprintf(cfg->reopen_config, req_len, "%s", - cfg->conn_config); + snprintf(cfg->reopen_config, req_len, "%s", opts->conn_config); /* Sanity-check the configuration. */ if ((ret = config_sanity(cfg)) != 0) goto err; /* If creating, remove and re-create the home directory. */ - if (cfg->create != 0) + if (opts->create != 0) recreate_dir(cfg->home); /* Write a copy of the config. */ - config_to_file(cfg); + req_len = strlen(cfg->home) + strlen("/CONFIG.wtperf") + 1; + path = dmalloc(req_len); + snprintf(path, req_len, "%s/CONFIG.wtperf", cfg->home); + config_opt_log(opts, path); + free(path); /* Display the configuration. */ - if (cfg->verbose > 1) - config_print(cfg); + if (opts->verbose > 1) + config_opt_print(cfg); if ((ret = start_all_runs(cfg)) != 0) goto err; @@ -2436,6 +2586,8 @@ einval: ret = EINVAL; } err: config_free(cfg); + config_opt_cleanup(opts); + free(cc_buf); free(sess_cfg); free(tc_buf); @@ -2449,10 +2601,13 @@ static int start_threads(CONFIG *cfg, WORKLOAD *workp, CONFIG_THREAD *base, u_int num, void *(*func)(void *)) { + CONFIG_OPTS *opts; CONFIG_THREAD *thread; u_int i; int ret; + opts = cfg->opts; + /* Initialize the threads. */ for (i = 0, thread = base; i < num; ++i, ++thread) { thread->cfg = cfg; @@ -2473,14 +2628,14 @@ start_threads(CONFIG *cfg, * don't, it's not enough memory to bother. These buffers hold * strings: trailing NUL is included in the size. */ - thread->key_buf = dcalloc(cfg->key_sz, 1); - thread->value_buf = dcalloc(cfg->value_sz_max, 1); + thread->key_buf = dcalloc(opts->key_sz, 1); + thread->value_buf = dcalloc(opts->value_sz_max, 1); /* * Initialize and then toss in a bit of random values if needed. */ - memset(thread->value_buf, 'a', cfg->value_sz - 1); - if (cfg->random_value) + memset(thread->value_buf, 'a', opts->value_sz - 1); + if (opts->random_value) randomize_value(thread, thread->value_buf); /* @@ -2552,22 +2707,24 @@ static int drop_all_tables(CONFIG *cfg) { struct timespec start, stop; + CONFIG_OPTS *opts; WT_SESSION *session; size_t i; uint64_t msecs; int ret, t_ret; + opts = cfg->opts; + /* Drop any tables. */ if ((ret = cfg->conn->open_session( - cfg->conn, NULL, cfg->sess_config, &session)) != 0) { + cfg->conn, NULL, opts->sess_config, &session)) != 0) { lprintf(cfg, ret, 0, "Error opening a session on %s", cfg->home); return (ret); } testutil_check(__wt_epoch(NULL, &start)); - for (i = 0; i < cfg->table_count; i++) { - if ((ret = session->drop( - session, cfg->uris[i], NULL)) != 0) { + for (i = 0; i < opts->table_count; i++) { + if ((ret = session->drop(session, cfg->uris[i], NULL)) != 0) { lprintf(cfg, ret, 0, "Error dropping table %s", cfg->uris[i]); goto err; @@ -2577,7 +2734,7 @@ drop_all_tables(CONFIG *cfg) msecs = WT_TIMEDIFF_MS(stop, start); lprintf(cfg, 0, 1, "Executed %" PRIu32 " drop operations average time %" PRIu64 "ms", - cfg->table_count, msecs / cfg->table_count); + opts->table_count, msecs / opts->table_count); err: if ((t_ret = session->close(session, NULL)) != 0 && ret == 0) ret = t_ret; @@ -2587,25 +2744,31 @@ err: if ((t_ret = session->close(session, NULL)) != 0 && ret == 0) static uint64_t wtperf_value_range(CONFIG *cfg) { - if (cfg->random_range) - return (cfg->icount + cfg->random_range); + CONFIG_OPTS *opts; + + opts = cfg->opts; + + if (opts->random_range) + return (opts->icount + opts->random_range); /* * It is legal to configure a zero size populate phase, hide that * from other code by pretending the range is 1 in that case. */ - if (cfg->icount + cfg->insert_key == 0) + if (opts->icount + cfg->insert_key == 0) return (1); - return (cfg->icount + cfg->insert_key - (u_int)(cfg->workers_cnt + 1)); + return (opts->icount + cfg->insert_key - (u_int)(cfg->workers_cnt + 1)); } static uint64_t wtperf_rand(CONFIG_THREAD *thread) { CONFIG *cfg; + CONFIG_OPTS *opts; double S1, S2, U; uint64_t rval; cfg = thread->cfg; + opts = cfg->opts; /* * Use WiredTiger's random number routine: it's lock-free and fairly @@ -2614,11 +2777,11 @@ wtperf_rand(CONFIG_THREAD *thread) rval = __wt_random(&thread->rnd); /* Use Pareto distribution to give 80/20 hot/cold values. */ - if (cfg->pareto != 0) { + if (opts->pareto != 0) { #define PARETO_SHAPE 1.5 S1 = (-1 / PARETO_SHAPE); S2 = wtperf_value_range(cfg) * - (cfg->pareto / 100.0) * (PARETO_SHAPE - 1); + (opts->pareto / 100.0) * (PARETO_SHAPE - 1); U = 1 - (double)rval / (double)UINT32_MAX; rval = (uint64_t)((pow(U, S1) - 1) * S2); /* diff --git a/bench/wtperf/wtperf.h b/bench/wtperf/wtperf.h index 9d6ef2f56ea..b3e173eb37e 100644 --- a/bench/wtperf/wtperf.h +++ b/bench/wtperf/wtperf.h @@ -95,12 +95,6 @@ struct __truncate_queue_entry { TAILQ_ENTRY(__truncate_queue_entry) q; }; -struct __config_queue_entry { - char *string; - TAILQ_ENTRY(__config_queue_entry) c; -}; -typedef struct __config_queue_entry CONFIG_QUEUE_ENTRY; - /* Steering for the throttle configuration */ typedef struct { struct timespec last_increment; /* Time that we last added more ops */ @@ -120,14 +114,14 @@ struct __config { /* Configuration structure */ char *monitor_dir; /* Monitor output dir */ char *partial_config; /* Config string for partial logging */ char *reopen_config; /* Config string for conn reopen */ - char *base_uri; /* Object URI */ - char **uris; /* URIs if multiple tables */ + char **uris; /* URIs */ WT_CONNECTION *conn; /* Database connection */ FILE *logf; /* Logging handle */ - char *async_config; /* Config string for async */ + char *async_config; /* Config string for async */ + bool use_asyncops; /* Use async operations */ const char *compress_ext; /* Compression extension for conn */ const char *compress_table; /* Compression arg to table create */ @@ -141,9 +135,7 @@ struct __config { /* Configuration structure */ WORKLOAD *workload; /* Workloads */ u_int workload_cnt; - uint32_t use_asyncops; /* Use async operations */ /* State tracking variables. */ - uint64_t ckpt_ops; /* checkpoint operations */ uint64_t insert_ops; /* insert operations */ uint64_t read_ops; /* read operations */ @@ -152,10 +144,10 @@ struct __config { /* Configuration structure */ uint64_t insert_key; /* insert key */ - volatile int ckpt; /* checkpoint in progress */ - volatile int error; /* thread error */ - volatile int stop; /* notify threads to stop */ - volatile int in_warmup; /* Running warmup phase */ + volatile bool ckpt; /* checkpoint in progress */ + volatile bool error; /* thread error */ + volatile bool stop; /* notify threads to stop */ + volatile bool in_warmup; /* running warmup phase */ volatile bool idle_cycle_run; /* Signal for idle cycle thread */ @@ -169,13 +161,7 @@ struct __config { /* Configuration structure */ /* Queue head for use with the Truncate Logic */ TAILQ_HEAD(__truncate_qh, __truncate_queue_entry) stone_head; - /* Queue head to save a copy of the config to be output */ - TAILQ_HEAD(__config_qh, __config_queue_entry) config_head; - - /* Fields changeable on command line are listed in wtperf_opt.i */ -#define OPT_DECLARE_STRUCT -#include "wtperf_opt.i" -#undef OPT_DECLARE_STRUCT + CONFIG_OPTS *opts; /* Global configuration */ }; #define ELEMENTS(a) (sizeof(a) / sizeof(a[0])) @@ -259,35 +245,33 @@ struct __config_thread { /* Per-thread structure */ }; void cleanup_truncate_config(CONFIG *); -int config_compress(CONFIG *); -void config_free(CONFIG *); -int config_copy(CONFIG *, const CONFIG *); int config_opt_file(CONFIG *, const char *); -int config_opt_line(CONFIG *, const char *); -int config_opt_str(CONFIG *, const char *, const char *); -void config_to_file(CONFIG *); -void config_consolidate(CONFIG *); -void config_print(CONFIG *); +void config_opt_cleanup(CONFIG_OPTS *); +void config_opt_init(CONFIG_OPTS **); +void config_opt_log(CONFIG_OPTS *, const char *); +int config_opt_name_value(CONFIG *, const char *, const char *); +void config_opt_print(CONFIG *); +int config_opt_str(CONFIG *, const char *); +void config_opt_usage(void); int config_sanity(CONFIG *); void latency_insert(CONFIG *, uint32_t *, uint32_t *, uint32_t *); +void latency_print(CONFIG *); void latency_read(CONFIG *, uint32_t *, uint32_t *, uint32_t *); void latency_update(CONFIG *, uint32_t *, uint32_t *, uint32_t *); -void latency_print(CONFIG *); int run_truncate( - CONFIG *, CONFIG_THREAD *, WT_CURSOR *, WT_SESSION *, int *); + CONFIG *, CONFIG_THREAD *, WT_CURSOR *, WT_SESSION *, int *); int setup_log_file(CONFIG *); void setup_throttle(CONFIG_THREAD*); int setup_truncate(CONFIG *, CONFIG_THREAD *, WT_SESSION *); int start_idle_table_cycle(CONFIG *, pthread_t *); int stop_idle_table_cycle(CONFIG *, pthread_t); +void worker_throttle(CONFIG_THREAD*); uint64_t sum_ckpt_ops(CONFIG *); uint64_t sum_insert_ops(CONFIG *); uint64_t sum_pop_ops(CONFIG *); uint64_t sum_read_ops(CONFIG *); uint64_t sum_truncate_ops(CONFIG *); uint64_t sum_update_ops(CONFIG *); -void usage(void); -void worker_throttle(CONFIG_THREAD*); void lprintf(const CONFIG *, int err, uint32_t, const char *, ...) #if defined(__GNUC__) @@ -298,10 +282,14 @@ __attribute__((format (printf, 4, 5))) static inline void generate_key(CONFIG *cfg, char *key_buf, uint64_t keyno) { + CONFIG_OPTS *opts; + + opts = cfg->opts; + /* * Don't change to snprintf, sprintf is faster in some tests. */ - sprintf(key_buf, "%0*" PRIu64, cfg->key_sz - 1, keyno); + sprintf(key_buf, "%0*" PRIu64, opts->key_sz - 1, keyno); } static inline void diff --git a/bench/wtperf/wtperf_opt.i b/bench/wtperf/wtperf_opt.i index f1f26bd0d01..9db71f5dd69 100644 --- a/bench/wtperf/wtperf_opt.i +++ b/bench/wtperf/wtperf_opt.i @@ -38,14 +38,14 @@ #ifdef OPT_DEFINE_DESC #define DEF_OPT_AS_BOOL(name, initval, desc) \ - { #name, desc, #initval, BOOL_TYPE, offsetof(CONFIG, name) }, + { #name, desc, #initval, BOOL_TYPE, offsetof(CONFIG_OPTS, name) }, #define DEF_OPT_AS_CONFIG_STRING(name, initval, desc) \ { #name, desc, initval, CONFIG_STRING_TYPE, \ - offsetof(CONFIG, name) }, + offsetof(CONFIG_OPTS, name) }, #define DEF_OPT_AS_STRING(name, initval, desc) \ - { #name, desc, initval, STRING_TYPE, offsetof(CONFIG, name) }, + { #name, desc, initval, STRING_TYPE, offsetof(CONFIG_OPTS, name) }, #define DEF_OPT_AS_UINT32(name, initval, desc) \ - { #name, desc, #initval, UINT32_TYPE, offsetof(CONFIG, name) }, + { #name, desc, #initval, UINT32_TYPE, offsetof(CONFIG_OPTS, name) }, #endif #ifdef OPT_DEFINE_DEFAULT diff --git a/bench/wtperf/wtperf_truncate.c b/bench/wtperf/wtperf_truncate.c index e6ebc83c681..aac79b4b96d 100644 --- a/bench/wtperf/wtperf_truncate.c +++ b/bench/wtperf/wtperf_truncate.c @@ -35,8 +35,9 @@ decode_key(char *key_buf) } int -setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { - +setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) +{ + CONFIG_OPTS *opts; TRUNCATE_CONFIG *trunc_cfg; TRUNCATE_QUEUE_ENTRY *truncate_item; WORKLOAD *workload; @@ -45,6 +46,7 @@ setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { int ret; uint64_t end_point, final_stone_gap, i, start_point; + opts = cfg->opts; end_point = final_stone_gap = start_point = 0; trunc_cfg = &thread->trunc_cfg; workload = thread->workload; @@ -104,7 +106,7 @@ setup_truncate(CONFIG *cfg, CONFIG_THREAD *thread, WT_SESSION *session) { for (i = 1; i <= trunc_cfg->needed_stones; i++) { truncate_item = dcalloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); - truncate_item->key = dcalloc(cfg->key_sz, 1); + truncate_item->key = dcalloc(opts->key_sz, 1); generate_key( cfg, truncate_item->key, trunc_cfg->stone_gap * i); truncate_item->diff = @@ -124,16 +126,18 @@ err: if ((ret = cursor->close(cursor)) != 0) { int run_truncate(CONFIG *cfg, CONFIG_THREAD *thread, - WT_CURSOR *cursor, WT_SESSION *session, int *truncatedp) { - + WT_CURSOR *cursor, WT_SESSION *session, int *truncatedp) +{ + CONFIG_OPTS *opts; TRUNCATE_CONFIG *trunc_cfg; TRUNCATE_QUEUE_ENTRY *truncate_item; char *next_key; int ret, t_ret; uint64_t used_stone_gap; - ret = 0; + opts = cfg->opts; trunc_cfg = &thread->trunc_cfg; + ret = 0; *truncatedp = 0; /* Update the total inserts */ @@ -170,7 +174,7 @@ run_truncate(CONFIG *cfg, CONFIG_THREAD *thread, while (trunc_cfg->num_stones < trunc_cfg->needed_stones) { trunc_cfg->last_key += used_stone_gap; truncate_item = dcalloc(sizeof(TRUNCATE_QUEUE_ENTRY), 1); - truncate_item->key = dcalloc(cfg->key_sz, 1); + truncate_item->key = dcalloc(opts->key_sz, 1); generate_key(cfg, truncate_item->key, trunc_cfg->last_key); truncate_item->diff = used_stone_gap; TAILQ_INSERT_TAIL(&cfg->stone_head, truncate_item, q); @@ -190,7 +194,7 @@ run_truncate(CONFIG *cfg, CONFIG_THREAD *thread, * Truncate the content via a single truncate call or a cursor walk * depending on the configuration. */ - if (cfg->truncate_single_ops) { + if (opts->truncate_single_ops) { while ((ret = cursor->next(cursor)) == 0) { testutil_check(cursor->get_key(cursor, &next_key)); if (strcmp(next_key, truncate_item->key) == 0) |