diff options
author | Keith Bostic <keith@wiredtiger.com> | 2013-11-20 08:57:55 -0500 |
---|---|---|
committer | Keith Bostic <keith@wiredtiger.com> | 2013-11-20 08:57:55 -0500 |
commit | 3e5ad346eaf0a8eaf8d2461f7ccbcacfae7e68c5 (patch) | |
tree | bdf45c879933dff522964b74afb3a326689bfe4a | |
parent | aac0acc84db32f53aa25a91a1b1e03874c577795 (diff) | |
download | mongo-3e5ad346eaf0a8eaf8d2461f7ccbcacfae7e68c5.tar.gz |
Split wtperf up by moving configuration functions into their own file.
-rw-r--r-- | bench/wtperf/Makefile.am | 4 | ||||
-rw-r--r-- | bench/wtperf/config.c | 442 | ||||
-rw-r--r-- | bench/wtperf/misc.c | 110 | ||||
-rw-r--r-- | bench/wtperf/wtperf.c | 686 | ||||
-rw-r--r-- | bench/wtperf/wtperf.h | 103 |
5 files changed, 705 insertions, 640 deletions
diff --git a/bench/wtperf/Makefile.am b/bench/wtperf/Makefile.am index e4ff8f11059..6e22be13a91 100644 --- a/bench/wtperf/Makefile.am +++ b/bench/wtperf/Makefile.am @@ -4,6 +4,8 @@ LDADD = $(top_builddir)/libwiredtiger.la -lm noinst_PROGRAMS = wtperf wtperf_LDFLAGS = -static +wtperf_SOURCES =\ + config.c misc.c wtperf.c wtperf.h wtperf_opt.i # The benchmark can be run with no arguments as simple smoke tests TESTS = $(noinst_PROGRAMS) @@ -11,4 +13,4 @@ TESTS = $(noinst_PROGRAMS) TESTS_ENVIRONMENT = rm -rf WT_TEST ; mkdir WT_TEST ; clean-local: - rm -rf WT_TEST + rm -rf WT_TEST *.core diff --git a/bench/wtperf/config.c b/bench/wtperf/config.c new file mode 100644 index 00000000000..2bad1cf7b16 --- /dev/null +++ b/bench/wtperf/config.c @@ -0,0 +1,442 @@ +/*- + * Public Domain 2008-2013 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "wtperf.h" + +/* All options changeable on command line using -o or -O are listed here. */ +static CONFIG_OPT config_opts[] = { +#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); + +/* Assign the src config to the dest. + * Any storage allocated in dest is freed as a result. + */ +int +config_assign(CONFIG *dest, const CONFIG *src) +{ + size_t i, len; + char *newstr, **pstr; + + config_free(dest); + memcpy(dest, src, sizeof(CONFIG)); + + 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) { + len = strlen(*pstr) + 1; + if ((newstr = malloc(len)) == NULL) + return (enomem(src)); + strncpy(newstr, *pstr, len); + *pstr = newstr; + } + } + return (0); +} + +/* Free any storage allocated in the config struct. + */ +void +config_free(CONFIG *cfg) +{ + size_t i; + char **pstr; + + 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 **) + ((unsigned char *)cfg + config_opts[i].offset); + if (*pstr != NULL) { + free(*pstr); + *pstr = NULL; + } + } + + free(cfg->uri); +} + +/* + * Check a single key=value returned by the config parser + * against our table of valid keys, along with the expected type. + * If everything is okay, set the value. + */ +static int +config_opt(CONFIG *cfg, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v) +{ + CONFIG_OPT *popt; + char *newstr, **strp; + size_t i, nopt; + uint64_t 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]; + break; + } + if (popt == 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); + return (EINVAL); + } + valueloc = ((unsigned char *)cfg + popt->offset); + switch (popt->type) { + case BOOL_TYPE: + if (v->type != WT_CONFIG_ITEM_BOOL) { + fprintf(stderr, "wtperf: Error: " + "bad bool value for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + *(int *)valueloc = (int)v->val; + break; + case INT_TYPE: + if (v->type != WT_CONFIG_ITEM_NUM) { + fprintf(stderr, "wtperf: Error: " + "bad int value for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + if (v->val > INT_MAX) { + fprintf(stderr, "wtperf: Error: " + "int value out of range for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + *(int *)valueloc = (int)v->val; + break; + case UINT32_TYPE: + if (v->type != WT_CONFIG_ITEM_NUM) { + fprintf(stderr, "wtperf: Error: " + "bad uint32 value for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + if (v->val < 0 || v->val > UINT_MAX) { + fprintf(stderr, "wtperf: Error: " + "uint32 value out of range for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + *(uint32_t *)valueloc = (uint32_t)v->val; + break; + case CONFIG_STRING_TYPE: + if (v->type != WT_CONFIG_ITEM_STRING) { + fprintf(stderr, "wtperf: Error: " + "bad string value for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + strp = (char **)valueloc; + newlen = v->len + 1; + if (*strp == NULL) { + if ((newstr = calloc(newlen, sizeof(char))) == NULL) + return (enomem(cfg)); + strncpy(newstr, v->str, v->len); + } else { + newlen += (strlen(*strp) + 1); + if ((newstr = calloc(newlen, sizeof(char))) == NULL) + return (enomem(cfg)); + snprintf(newstr, newlen, + "%s,%*s", *strp, (int)v->len, v->str); + /* Free the old value now we've copied it. */ + free(*strp); + } + *strp = newstr; + break; + case STRING_TYPE: + if (v->type != WT_CONFIG_ITEM_STRING) { + fprintf(stderr, "wtperf: Error: " + "bad string value for \'%.*s=%.*s\'\n", + (int)k->len, k->str, (int)v->len, v->str); + return (EINVAL); + } + strp = (char **)valueloc; + free(*strp); + if ((newstr = malloc(v->len + 1)) == NULL) + return (enomem(cfg)); + strncpy(newstr, v->str, v->len); + newstr[v->len] = '\0'; + *strp = newstr; + break; + } + return (0); +} + +/* Parse a configuration file. + * We recognize comments '#' and continuation via lines ending in '\'. + */ +int +config_opt_file(CONFIG *cfg, WT_SESSION *parse_session, const char *filename) +{ + FILE *fp; + size_t linelen, optionpos; + int contline, linenum, ret; + char line[256], option[1024]; + char *comment, *ltrim, *rtrim; + + if ((fp = fopen(filename, "r")) == NULL) { + fprintf(stderr, "wtperf: %s: %s\n", filename, strerror(errno)); + return (errno); + } + + ret = 0; + optionpos = 0; + linenum = 0; + while (fgets(line, sizeof(line), fp) != NULL) { + linenum++; + /* trim the line */ + for (ltrim = line; *ltrim && isspace(*ltrim); ltrim++) + ; + rtrim = <rim[strlen(ltrim)]; + if (rtrim > ltrim && rtrim[-1] == '\n') + rtrim--; + + contline = (rtrim > ltrim && rtrim[-1] == '\\'); + if (contline) + rtrim--; + + comment = strchr(ltrim, '#'); + if (comment != NULL && comment < rtrim) + rtrim = comment; + while (rtrim > ltrim && isspace(rtrim[-1])) + rtrim--; + + linelen = (size_t)(rtrim - ltrim); + if (linelen == 0) + continue; + + if (linelen + optionpos + 1 > sizeof(option)) { + fprintf(stderr, "wtperf: %s: %d: line overflow\n", + filename, linenum); + ret = EINVAL; + break; + } + *rtrim = '\0'; + strncpy(&option[optionpos], ltrim, linelen); + option[optionpos + linelen] = '\0'; + if (contline) + optionpos += linelen; + else { + if ((ret = config_opt_line(cfg, + parse_session, option)) != 0) { + fprintf(stderr, "wtperf: %s: %d: parse error\n", + filename, linenum); + break; + } + optionpos = 0; + } + } + if (ret == 0 && optionpos > 0) { + fprintf(stderr, "wtperf: %s: %d: last line continues\n", + filename, linenum); + ret = EINVAL; + } + + (void)fclose(fp); + return (ret); +} + +/* Parse a single line of config options. + * Continued lines have already been joined. + */ +int +config_opt_line(CONFIG *cfg, WT_SESSION *parse_session, const char *optstr) +{ + WT_CONFIG_ITEM k, v; + WT_CONFIG_SCAN *scan; + WT_CONNECTION *conn; + WT_EXTENSION_API *wt_api; + int ret, t_ret; + + conn = parse_session->connection; + wt_api = conn->get_extension_api(conn); + + if ((ret = wt_api->config_scan_begin(wt_api, parse_session, optstr, + strlen(optstr), &scan)) != 0) { + lprintf(cfg, ret, 0, "Error in config_scan_begin"); + return (ret); + } + + while (ret == 0) { + if ((ret = + wt_api->config_scan_next(wt_api, scan, &k, &v)) != 0) { + /* Any parse error has already been reported. */ + if (ret == WT_NOTFOUND) + ret = 0; + break; + } + ret = config_opt(cfg, &k, &v); + } + if ((t_ret = wt_api->config_scan_end(wt_api, scan)) != 0) { + lprintf(cfg, ret, 0, "Error in config_scan_end"); + if (ret == 0) + ret = t_ret; + } + + return (ret); +} + +/* Set a single string config option */ +int +config_opt_str(CONFIG *cfg, WT_SESSION *parse_session, + const char *name, const char *value) +{ + int ret; + char *optstr; + + /* name="value" */ + if ((optstr = malloc(strlen(name) + strlen(value) + 4)) == NULL) + return (enomem(cfg)); + sprintf(optstr, "%s=\"%s\"", name, value); + ret = config_opt_line(cfg, parse_session, optstr); + free(optstr); + return (ret); +} + +static void +pretty_print(const char *p, const char *indent) +{ + const char *t; + + for (;; p = t + 1) { + if (strlen(p) <= 70) + break; + for (t = p + 70; t > p && *t != ' '; --t) + ; + if (t == p) /* No spaces? */ + break; + printf("%s%.*s\n", + indent == NULL ? "" : indent, (int)(t - p), p); + } + if (*p != '\0') + printf("%s%s\n", indent == NULL ? "" : indent, p); +} + +static void +config_opt_usage(void) +{ + size_t i, nopt; + const char *defaultval, *typestr; + + pretty_print( + "The following are options settable using -o or -O, showing the " + "type and default value.\n", NULL); + pretty_print( + "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++) { + typestr = "?"; + defaultval = config_opts[i].defaultval; + switch (config_opts[i].type) { + case BOOL_TYPE: + typestr = "boolean"; + if (strcmp(defaultval, "0") == 0) + defaultval = "false"; + else + defaultval = "true"; + break; + case CONFIG_STRING_TYPE: + case STRING_TYPE: + typestr = "string"; + break; + case INT_TYPE: + typestr = "int"; + break; + case UINT32_TYPE: + typestr = "unsigned int"; + break; + } + printf("%s (%s, default %s)\n", + config_opts[i].name, typestr, defaultval); + pretty_print(config_opts[i].description, "\t"); + } +} + +void +print_config(CONFIG *cfg) +{ + printf("Workload configuration:\n"); + printf("\thome: %s\n", cfg->home); + printf("\ttable_name: %s\n", cfg->table_name); + printf("\tConnection configuration: %s\n", cfg->conn_config); + printf("\tTable configuration: %s\n", cfg->table_config); + printf("\t%s\n", cfg->create ? "Creating" : "Using existing"); + printf("\tWorkload period: %" PRIu32 "\n", cfg->run_time); + printf( + "\tCheckpoint interval: %" PRIu32 "\n", cfg->checkpoint_interval); + printf("\tReporting interval: %" PRIu32 "\n", cfg->report_interval); + printf("\tStatistics interval: %" PRIu32 "\n", cfg->stat_interval); + if (cfg->create) { + printf("\tInsert count: %" PRIu32 "\n", cfg->icount); + printf("\tNumber populate threads: %" PRIu32 "\n", + cfg->populate_threads); + } + printf("\tNumber read threads: %" PRIu32 "\n", cfg->read_threads); + printf("\tNumber insert threads: %" PRIu32 "\n", cfg->insert_threads); + if (cfg->insert_rmw) + printf("\tInsert operations are RMW.\n"); + printf("\tNumber update threads: %" PRIu32 "\n", cfg->update_threads); + printf("\tkey size: %" PRIu32 " data size: %" PRIu32 "\n", + cfg->key_sz, cfg->data_sz); + printf("\tVerbosity: %" PRIu32 "\n", cfg->verbose); +} + +void +usage(void) +{ + printf("wtperf [-LMSv] [-C config] " + "[-h home] [-O file] [-o option] [-T config]\n"); + printf("\t-L Use a large default configuration\n"); + printf("\t-M Use a medium default configuration\n"); + printf("\t-S Use a small default configuration\n"); + printf("\t-C <string> additional connection configuration\n"); + printf("\t (added to option conn_config)\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/misc.c b/bench/wtperf/misc.c new file mode 100644 index 00000000000..2a4b4e31489 --- /dev/null +++ b/bench/wtperf/misc.c @@ -0,0 +1,110 @@ +/*- + * Public Domain 2008-2013 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#include "wtperf.h" + +int +enomem(const CONFIG *cfg) +{ + const char *msg; + + msg = "Unable to allocate memory"; + if (cfg->logf == NULL) + fprintf(stderr, "%s\n", msg); + else + lprintf(cfg, ENOMEM, 0, "%s", msg); + return (ENOMEM); +} + +/* Setup the logging output mechanism. */ +int +setup_log_file(CONFIG *cfg) +{ + char *fname; + int ret; + + ret = 0; + + if (cfg->verbose < 1 && cfg->stat_interval == 0) + return (0); + + if ((fname = calloc(strlen(cfg->home) + + strlen(cfg->table_name) + strlen(".stat") + 2, 1)) == NULL) + return (enomem(cfg)); + + sprintf(fname, "%s/%s.stat", cfg->home, cfg->table_name); + if ((cfg->logf = fopen(fname, "w")) == NULL) { + fprintf(stderr, "Statistics failed to open log file.\n"); + ret = EINVAL; + } else { + /* Use line buffering for the log file. */ + (void)setvbuf(cfg->logf, NULL, _IOLBF, 0); + } + free(fname); + return (ret); +} + +/* + * Log printf - output a log message. + */ +void +lprintf(const CONFIG *cfg, int err, uint32_t level, const char *fmt, ...) +{ + va_list ap; + + if (err == 0 && level <= cfg->verbose) { + va_start(ap, fmt); + vfprintf(cfg->logf, fmt, ap); + va_end(ap); + fprintf(cfg->logf, "\n"); + + if (level < cfg->verbose) { + va_start(ap, fmt); + vprintf(fmt, ap); + va_end(ap); + printf("\n"); + } + } + if (err == 0) + return; + + /* We are dealing with an error. */ + va_start(ap, fmt); + vfprintf(stderr, fmt, ap); + va_end(ap); + fprintf(stderr, " Error: %s\n", wiredtiger_strerror(err)); + if (cfg->logf != NULL) { + va_start(ap, fmt); + vfprintf(cfg->logf, fmt, ap); + va_end(ap); + fprintf(cfg->logf, " Error: %s\n", wiredtiger_strerror(err)); + } + + /* Never attempt to continue if we got a panic from WiredTiger. */ + if (err == WT_PANIC) + exit(1); +} diff --git a/bench/wtperf/wtperf.c b/bench/wtperf/wtperf.c index c767590ac11..fb602d1635a 100644 --- a/bench/wtperf/wtperf.c +++ b/bench/wtperf/wtperf.c @@ -24,118 +24,18 @@ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR * OTHER DEALINGS IN THE SOFTWARE. */ -#include <sys/time.h> -#include <sys/stat.h> -#include <assert.h> -#include <ctype.h> -#include <dirent.h> -#include <errno.h> -#include <inttypes.h> -#include <limits.h> -#include <math.h> -#include <pthread.h> -#include <stddef.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <unistd.h> - -#include <wiredtiger.h> -#include <wiredtiger_ext.h> -#include <gcc.h> /* WiredTiger internal */ - -typedef struct { /* Per-thread structure */ - void *cfg; /* Enclosing handle */ - - pthread_t handle; /* Handle */ - uint64_t read_ops; /* Read ops */ - uint64_t update_ops; /* Update ops */ -} CONFIG_THREAD; - -typedef struct { - const char *home; /* WiredTiger home */ - char *uri; /* Object URI */ - - WT_CONNECTION *conn; /* Database connection */ - - FILE *logf; /* Logging handle */ - - CONFIG_THREAD *rthreads, *ithreads, *popthreads, *uthreads; - - enum { WT_PERF_INIT, WT_PERF_POPULATE, WT_PERF_WORKER } phase; - - struct timeval phase_start_time; - - /* Fields changeable on command line are listed in wtperf_opt.i */ -#define OPT_DECLARE_STRUCT -#include "wtperf_opt.i" -#undef OPT_DECLARE_STRUCT - -} CONFIG; - -typedef enum { - BOOL_TYPE, CONFIG_STRING_TYPE, INT_TYPE, STRING_TYPE, UINT32_TYPE -} CONFIG_OPT_TYPE; - -typedef struct { - const char *name; - const char *description; - const char *defaultval; - CONFIG_OPT_TYPE type; - size_t offset; -} CONFIG_OPT; - -/* All options changeable on command line using -o or -O are listed here. */ -CONFIG_OPT config_opts[] = { - -#define OPT_DEFINE_DESC -#include "wtperf_opt.i" -#undef OPT_DEFINE_DESC - -}; - -/* Worker thread types. */ -typedef enum { - WORKER_READ, WORKER_INSERT, WORKER_INSERT_RMW, WORKER_UPDATE } worker_type; -#define IS_INSERT_WORKER(w) \ - ((w) == WORKER_INSERT || (w) == WORKER_INSERT_RMW) - -/* Forward function definitions. */ -void *checkpoint_worker(void *); -int config_assign(CONFIG *, const CONFIG *); -void config_free(CONFIG *); -int config_opt(CONFIG *, WT_CONFIG_ITEM *, WT_CONFIG_ITEM *); -int config_opt_file(CONFIG *, WT_SESSION *, const char *); -int config_opt_int(CONFIG *, WT_SESSION *, const char *, const char *); -int config_opt_line(CONFIG *, WT_SESSION *, const char *); -int config_opt_str(CONFIG *, WT_SESSION *, const char *, const char *); -void config_opt_usage(void); -int execute_populate(CONFIG *); -int execute_workload(CONFIG *); -int find_table_count(CONFIG *); -void *insert_thread(void *); -void lprintf(const CONFIG *cfg, int err, uint32_t level, const char *fmt, ...) - WT_GCC_ATTRIBUTE((format (printf, 4, 5))); -void *populate_thread(void *); -void print_config(CONFIG *); -void *read_thread(void *); -int setup_log_file(CONFIG *); -int start_threads(CONFIG *, u_int, CONFIG_THREAD **, void *(*func)(void *)); -void *stat_worker(void *); -int stop_threads(CONFIG *, u_int, CONFIG_THREAD **); -void *update_thread(void *); -void usage(void); -void worker(CONFIG_THREAD *, worker_type); -uint64_t wtperf_rand(CONFIG *); -uint64_t wtperf_value_range(CONFIG *); +#include "wtperf.h" #define DEFAULT_LSM_CONFIG \ "key_format=S,value_format=S,type=lsm,exclusive=true," \ "leaf_page_max=4kb,internal_page_max=64kb,allocation_size=4kb," +#define IS_INSERT_WORKER(w) \ + ((w) == WORKER_INSERT || (w) == WORKER_INSERT_RMW) + /* Default values. */ -CONFIG default_cfg = { +static const CONFIG default_cfg = { "WT_TEST", /* home */ NULL, /* uri */ NULL, /* conn */ @@ -147,10 +47,9 @@ CONFIG default_cfg = { #define OPT_DEFINE_DEFAULT #include "wtperf_opt.i" #undef OPT_DEFINE_DEFAULT - }; -const char *small_config_str = +static const char * const small_config_str = "conn_config=\"cache_size=500MB\"," "table_config=\"lsm_chunk_size=5MB\"," "icount=500000," @@ -161,7 +60,7 @@ const char *small_config_str = "populate_threads=1," "read_threads=8,"; -const char *med_config_str = +static const char * const med_config_str = "conn_config=\"cache_size=1GB\"," "table_config=\"lsm_chunk_size=20MB\"," "icount=50000000," @@ -172,7 +71,7 @@ const char *med_config_str = "populate_threads=1," "read_threads=16,"; -const char *large_config_str = +static const char * const large_config_str = "conn_config=\"cache_size=2GB\"," "table_config=\"lsm_chunk_size=50MB\"," "icount=500000000," @@ -184,17 +83,17 @@ const char *large_config_str = "read_threads=16,"; -const char *debug_cconfig = "verbose=[lsm]"; -const char *debug_tconfig = ""; +static const char * const debug_cconfig = "verbose=[lsm]"; +static const char * const debug_tconfig = ""; -uint64_t g_nins_ops; /* insert count and key assignment */ -uint64_t g_npop_ops; /* population count and key assignment */ -uint64_t g_nread_ops; /* read operations */ -uint64_t g_nupdate_ops; /* update operations */ -uint32_t g_threads_quit; /* threads that exited early */ +static uint64_t g_nins_ops; /* insert count and key assignment */ +static uint64_t g_npop_ops; /* population count and key assignment */ +static uint64_t g_nread_ops; /* read operations */ +static uint64_t g_nupdate_ops; /* update operations */ +static uint32_t g_threads_quit; /* threads that exited early */ -int g_running; /* threads are running */ -int g_util_running; /* utility threads are running */ +static int g_running; /* threads are running */ +static int g_util_running; /* utility threads are running */ /* * Atomic update where needed. @@ -205,6 +104,22 @@ int g_util_running; /* utility threads are running */ #define ATOMIC_ADD(v, val) __sync_add_and_fetch(&(v), val) #endif +static void *checkpoint_worker(void *); +static int execute_populate(CONFIG *); +static int execute_workload(CONFIG *); +static int find_table_count(CONFIG *); +static void *insert_thread(void *); +static void *populate_thread(void *); +static void *read_thread(void *); +static int start_threads( + CONFIG *, u_int, CONFIG_THREAD **, void *(*func)(void *)); +static void *stat_worker(void *); +static int stop_threads(CONFIG *, u_int, CONFIG_THREAD **); +static void *update_thread(void *); +static void worker(CONFIG_THREAD *, worker_type); +static uint64_t wtperf_rand(CONFIG *); +static uint64_t wtperf_value_range(CONFIG *); + /* Retrieve an ID for the next populate operation. */ static inline uint64_t get_next_populate(void) @@ -249,20 +164,7 @@ sum_update_ops(CONFIG_THREAD *threads, u_int num) return (total); } -static int -enomem(const CONFIG *cfg) -{ - const char *msg; - - msg = "Unable to allocate memory"; - if (cfg->logf == NULL) - fprintf(stderr, "%s\n", msg); - else - lprintf(cfg, ENOMEM, 0, "%s", msg); - return (ENOMEM); -} - -void +static void worker(CONFIG_THREAD *thread, worker_type wtype) { CONFIG *cfg; @@ -398,14 +300,14 @@ err: if (ret != 0) free(key_buf); } -void * +static void * read_thread(void *arg) { worker((CONFIG_THREAD *)arg, WORKER_READ); return (NULL); } -void * +static void * insert_thread(void *arg) { CONFIG *cfg; @@ -416,14 +318,14 @@ insert_thread(void *arg) return (NULL); } -void * +static void * update_thread(void *arg) { worker((CONFIG_THREAD *)arg, WORKER_UPDATE); return (NULL); } -void * +static void * populate_thread(void *arg) { CONFIG *cfg; @@ -525,7 +427,7 @@ err: if (ret != 0) return (NULL); } -void * +static void * stat_worker(void *arg) { CONFIG *cfg; @@ -645,7 +547,7 @@ err: if (session != NULL) return (arg); } -void * +static void * checkpoint_worker(void *arg) { CONFIG *cfg; @@ -691,7 +593,7 @@ err: if (session != NULL) return (arg); } -int +static int execute_populate(CONFIG *cfg) { WT_CONNECTION *conn; @@ -789,7 +691,7 @@ execute_populate(CONFIG *cfg) return (0); } -int +static int execute_workload(CONFIG *cfg) { uint64_t last_inserts, last_reads, last_updates; @@ -891,7 +793,7 @@ err: g_running = 0; * Ensure that icount matches the number of records in the * existing table. */ -int +static int find_table_count(CONFIG *cfg) { WT_CONNECTION *conn; @@ -1204,384 +1106,7 @@ err: g_util_running = 0; return (ret); } -/* - * Following are utility functions. - */ - -/* Assign the src config to the dest. - * Any storage allocated in dest is freed as a result. - */ -int -config_assign(CONFIG *dest, const CONFIG *src) -{ - size_t i, len; - char *newstr, **pstr; - - config_free(dest); - memcpy(dest, src, sizeof(CONFIG)); - - 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) { - len = strlen(*pstr) + 1; - if ((newstr = malloc(len)) == NULL) - return (enomem(src)); - strncpy(newstr, *pstr, len); - *pstr = newstr; - } - } - return (0); -} - -/* Free any storage allocated in the config struct. - */ -void -config_free(CONFIG *cfg) -{ - size_t i; - char **pstr; - - 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 **) - ((unsigned char *)cfg + config_opts[i].offset); - if (*pstr != NULL) { - free(*pstr); - *pstr = NULL; - } - } - - free(cfg->uri); -} - -/* - * Check a single key=value returned by the config parser - * against our table of valid keys, along with the expected type. - * If everything is okay, set the value. - */ -int -config_opt(CONFIG *cfg, WT_CONFIG_ITEM *k, WT_CONFIG_ITEM *v) -{ - CONFIG_OPT *popt; - char *newstr, **strp; - size_t i, nopt; - uint64_t 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]; - break; - } - if (popt == 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); - return (EINVAL); - } - valueloc = ((unsigned char *)cfg + popt->offset); - switch (popt->type) { - case BOOL_TYPE: - if (v->type != WT_CONFIG_ITEM_BOOL) { - fprintf(stderr, "wtperf: Error: " - "bad bool value for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - *(int *)valueloc = (int)v->val; - break; - case INT_TYPE: - if (v->type != WT_CONFIG_ITEM_NUM) { - fprintf(stderr, "wtperf: Error: " - "bad int value for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - if (v->val > INT_MAX) { - fprintf(stderr, "wtperf: Error: " - "int value out of range for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - *(int *)valueloc = (int)v->val; - break; - case UINT32_TYPE: - if (v->type != WT_CONFIG_ITEM_NUM) { - fprintf(stderr, "wtperf: Error: " - "bad uint32 value for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - if (v->val < 0 || v->val > UINT_MAX) { - fprintf(stderr, "wtperf: Error: " - "uint32 value out of range for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - *(uint32_t *)valueloc = (uint32_t)v->val; - break; - case CONFIG_STRING_TYPE: - if (v->type != WT_CONFIG_ITEM_STRING) { - fprintf(stderr, "wtperf: Error: " - "bad string value for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - strp = (char **)valueloc; - newlen = v->len + 1; - if (*strp == NULL) { - if ((newstr = calloc(newlen, sizeof(char))) == NULL) - return (enomem(cfg)); - strncpy(newstr, v->str, v->len); - } else { - newlen += (strlen(*strp) + 1); - if ((newstr = calloc(newlen, sizeof(char))) == NULL) - return (enomem(cfg)); - snprintf(newstr, newlen, - "%s,%*s", *strp, (int)v->len, v->str); - /* Free the old value now we've copied it. */ - free(*strp); - } - *strp = newstr; - break; - case STRING_TYPE: - if (v->type != WT_CONFIG_ITEM_STRING) { - fprintf(stderr, "wtperf: Error: " - "bad string value for \'%.*s=%.*s\'\n", - (int)k->len, k->str, (int)v->len, v->str); - return (EINVAL); - } - strp = (char **)valueloc; - free(*strp); - if ((newstr = malloc(v->len + 1)) == NULL) - return (enomem(cfg)); - strncpy(newstr, v->str, v->len); - newstr[v->len] = '\0'; - *strp = newstr; - break; - } - return (0); -} - -/* Parse a configuration file. - * We recognize comments '#' and continuation via lines ending in '\'. - */ -int -config_opt_file(CONFIG *cfg, WT_SESSION *parse_session, const char *filename) -{ - FILE *fp; - size_t linelen, optionpos; - int contline, linenum, ret; - char line[256], option[1024]; - char *comment, *ltrim, *rtrim; - - if ((fp = fopen(filename, "r")) == NULL) { - fprintf(stderr, "wtperf: %s: %s\n", filename, strerror(errno)); - return (errno); - } - - ret = 0; - optionpos = 0; - linenum = 0; - while (fgets(line, sizeof(line), fp) != NULL) { - linenum++; - /* trim the line */ - for (ltrim = line; *ltrim && isspace(*ltrim); ltrim++) - ; - rtrim = <rim[strlen(ltrim)]; - if (rtrim > ltrim && rtrim[-1] == '\n') - rtrim--; - - contline = (rtrim > ltrim && rtrim[-1] == '\\'); - if (contline) - rtrim--; - - comment = strchr(ltrim, '#'); - if (comment != NULL && comment < rtrim) - rtrim = comment; - while (rtrim > ltrim && isspace(rtrim[-1])) - rtrim--; - - linelen = (size_t)(rtrim - ltrim); - if (linelen == 0) - continue; - - if (linelen + optionpos + 1 > sizeof(option)) { - fprintf(stderr, "wtperf: %s: %d: line overflow\n", - filename, linenum); - ret = EINVAL; - break; - } - *rtrim = '\0'; - strncpy(&option[optionpos], ltrim, linelen); - option[optionpos + linelen] = '\0'; - if (contline) - optionpos += linelen; - else { - if ((ret = config_opt_line(cfg, - parse_session, option)) != 0) { - fprintf(stderr, "wtperf: %s: %d: parse error\n", - filename, linenum); - break; - } - optionpos = 0; - } - } - if (ret == 0 && optionpos > 0) { - fprintf(stderr, "wtperf: %s: %d: last line continues\n", - filename, linenum); - ret = EINVAL; - } - - (void)fclose(fp); - return (ret); -} - -/* Parse a single line of config options. - * Continued lines have already been joined. - */ -int -config_opt_line(CONFIG *cfg, WT_SESSION *parse_session, const char *optstr) -{ - WT_CONFIG_ITEM k, v; - WT_CONFIG_SCAN *scan; - WT_CONNECTION *conn; - WT_EXTENSION_API *wt_api; - int ret, t_ret; - - conn = parse_session->connection; - wt_api = conn->get_extension_api(conn); - - if ((ret = wt_api->config_scan_begin(wt_api, parse_session, optstr, - strlen(optstr), &scan)) != 0) { - lprintf(cfg, ret, 0, "Error in config_scan_begin"); - return (ret); - } - - while (ret == 0) { - if ((ret = - wt_api->config_scan_next(wt_api, scan, &k, &v)) != 0) { - /* Any parse error has already been reported. */ - if (ret == WT_NOTFOUND) - ret = 0; - break; - } - ret = config_opt(cfg, &k, &v); - } - if ((t_ret = wt_api->config_scan_end(wt_api, scan)) != 0) { - lprintf(cfg, ret, 0, "Error in config_scan_end"); - if (ret == 0) - ret = t_ret; - } - - return (ret); -} - -/* Set a single string config option */ -int -config_opt_str(CONFIG *cfg, WT_SESSION *parse_session, - const char *name, const char *value) -{ - int ret; - char *optstr; - - /* name="value" */ - if ((optstr = malloc(strlen(name) + strlen(value) + 4)) == NULL) - return (enomem(cfg)); - sprintf(optstr, "%s=\"%s\"", name, value); - ret = config_opt_line(cfg, parse_session, optstr); - free(optstr); - return (ret); -} - -/* Set a single int config option */ -int -config_opt_int(CONFIG *cfg, WT_SESSION *parse_session, - const char *name, const char *value) -{ - int ret; - char *optstr; - - /* name=value */ - if ((optstr = malloc(strlen(name) + strlen(value) + 2)) == NULL) - return (enomem(cfg)); - sprintf(optstr, "%s=%s", name, value); - ret = config_opt_line(cfg, parse_session, optstr); - free(optstr); - return (ret); -} - -static void -pretty_print(const char *p, const char *indent) -{ - const char *t; - - for (;; p = t + 1) { - if (strlen(p) <= 70) - break; - for (t = p + 70; t > p && *t != ' '; --t) - ; - if (t == p) /* No spaces? */ - break; - printf("%s%.*s\n", - indent == NULL ? "" : indent, (int)(t - p), p); - } - if (*p != '\0') - printf("%s%s\n", indent == NULL ? "" : indent, p); -} - -void -config_opt_usage(void) -{ - size_t i, nopt; - const char *defaultval, *typestr; - - pretty_print( - "The following are options settable using -o or -O, showing the " - "type and default value.\n", NULL); - pretty_print( - "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++) { - typestr = "?"; - defaultval = config_opts[i].defaultval; - switch (config_opts[i].type) { - case BOOL_TYPE: - typestr = "boolean"; - if (strcmp(defaultval, "0") == 0) - defaultval = "false"; - else - defaultval = "true"; - break; - case CONFIG_STRING_TYPE: - case STRING_TYPE: - typestr = "string"; - break; - case INT_TYPE: - typestr = "int"; - break; - case UINT32_TYPE: - typestr = "unsigned int"; - break; - } - printf("%s (%s, default %s)\n", - config_opts[i].name, typestr, defaultval); - pretty_print(config_opts[i].description, "\t"); - } -} - -int +static int start_threads( CONFIG *cfg, u_int num, CONFIG_THREAD **threadsp, void *(*func)(void *)) { @@ -1604,7 +1129,7 @@ start_threads( return (0); } -int +static int stop_threads(CONFIG *cfg, u_int num, CONFIG_THREAD **threadsp) { CONFIG_THREAD *threads; @@ -1626,76 +1151,7 @@ stop_threads(CONFIG *cfg, u_int num, CONFIG_THREAD **threadsp) return (0); } -/* - * Log printf - output a log message. - */ -void -lprintf(const CONFIG *cfg, int err, uint32_t level, const char *fmt, ...) -{ - va_list ap; - - if (err == 0 && level <= cfg->verbose) { - va_start(ap, fmt); - vfprintf(cfg->logf, fmt, ap); - va_end(ap); - fprintf(cfg->logf, "\n"); - - if (level < cfg->verbose) { - va_start(ap, fmt); - vprintf(fmt, ap); - va_end(ap); - printf("\n"); - } - } - if (err == 0) - return; - - /* We are dealing with an error. */ - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); - fprintf(stderr, " Error: %s\n", wiredtiger_strerror(err)); - if (cfg->logf != NULL) { - va_start(ap, fmt); - vfprintf(cfg->logf, fmt, ap); - va_end(ap); - fprintf(cfg->logf, " Error: %s\n", wiredtiger_strerror(err)); - } - - /* Never attempt to continue if we got a panic from WiredTiger. */ - if (err == WT_PANIC) - exit(1); -} - -/* Setup the logging output mechanism. */ -int -setup_log_file(CONFIG *cfg) -{ - char *fname; - int ret; - - ret = 0; - - if (cfg->verbose < 1 && cfg->stat_interval == 0) - return (0); - - if ((fname = calloc(strlen(cfg->home) + - strlen(cfg->table_name) + strlen(".stat") + 2, 1)) == NULL) - return (enomem(cfg)); - - sprintf(fname, "%s/%s.stat", cfg->home, cfg->table_name); - if ((cfg->logf = fopen(fname, "w")) == NULL) { - fprintf(stderr, "Statistics failed to open log file.\n"); - ret = EINVAL; - } else { - /* Use line buffering for the log file. */ - (void)setvbuf(cfg->logf, NULL, _IOLBF, 0); - } - free(fname); - return (ret); -} - -uint64_t +static uint64_t wtperf_value_range(CONFIG *cfg) { if (cfg->random_range == 0) @@ -1706,7 +1162,7 @@ wtperf_value_range(CONFIG *cfg) extern uint32_t __wt_random(void); -uint64_t +static uint64_t wtperf_rand(CONFIG *cfg) { double S1, S2, U; @@ -1737,51 +1193,3 @@ wtperf_rand(CONFIG *cfg) rval = (rval % wtperf_value_range(cfg)) + 1; return (rval); } - -void -print_config(CONFIG *cfg) -{ - printf("Workload configuration:\n"); - printf("\thome: %s\n", cfg->home); - printf("\ttable_name: %s\n", cfg->table_name); - printf("\tConnection configuration: %s\n", cfg->conn_config); - printf("\tTable configuration: %s\n", cfg->table_config); - printf("\t%s\n", cfg->create ? "Creating" : "Using existing"); - printf("\tWorkload period: %" PRIu32 "\n", cfg->run_time); - printf( - "\tCheckpoint interval: %" PRIu32 "\n", cfg->checkpoint_interval); - printf("\tReporting interval: %" PRIu32 "\n", cfg->report_interval); - printf("\tStatistics interval: %" PRIu32 "\n", cfg->stat_interval); - if (cfg->create) { - printf("\tInsert count: %" PRIu32 "\n", cfg->icount); - printf("\tNumber populate threads: %" PRIu32 "\n", - cfg->populate_threads); - } - printf("\tNumber read threads: %" PRIu32 "\n", cfg->read_threads); - printf("\tNumber insert threads: %" PRIu32 "\n", cfg->insert_threads); - if (cfg->insert_rmw) - printf("\tInsert operations are RMW.\n"); - printf("\tNumber update threads: %" PRIu32 "\n", cfg->update_threads); - printf("\tkey size: %" PRIu32 " data size: %" PRIu32 "\n", - cfg->key_sz, cfg->data_sz); - printf("\tVerbosity: %" PRIu32 "\n", cfg->verbose); -} - -void -usage(void) -{ - printf("wtperf [-LMSv] [-C config] " - "[-h home] [-O file] [-o option] [-T config]\n"); - printf("\t-L Use a large default configuration\n"); - printf("\t-M Use a medium default configuration\n"); - printf("\t-S Use a small default configuration\n"); - printf("\t-C <string> additional connection configuration\n"); - printf("\t (added to option conn_config)\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/wtperf.h b/bench/wtperf/wtperf.h new file mode 100644 index 00000000000..4086b46bb7d --- /dev/null +++ b/bench/wtperf/wtperf.h @@ -0,0 +1,103 @@ +/*- + * Public Domain 2008-2013 WiredTiger, Inc. + * + * This is free and unencumbered software released into the public domain. + * + * Anyone is free to copy, modify, publish, use, compile, sell, or + * distribute this software, either in source code form or as a compiled + * binary, for any purpose, commercial or non-commercial, and by any + * means. + * + * In jurisdictions that recognize copyright laws, the author or authors + * of this software dedicate any and all copyright interest in the + * software to the public domain. We make this dedication for the benefit + * of the public at large and to the detriment of our heirs and + * successors. We intend this dedication to be an overt act of + * relinquishment in perpetuity of all present and future rights to this + * software under copyright law. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR + * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, + * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ +#include <sys/time.h> +#include <sys/stat.h> + +#include <assert.h> +#include <ctype.h> +#include <dirent.h> +#include <errno.h> +#include <inttypes.h> +#include <limits.h> +#include <math.h> +#include <pthread.h> +#include <stddef.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> + +#include <wiredtiger.h> +#include <wiredtiger_ext.h> +#include <gcc.h> /* WiredTiger internal */ + +typedef struct { /* Per-thread structure */ + void *cfg; /* Enclosing handle */ + + pthread_t handle; /* Handle */ + uint64_t read_ops; /* Read ops */ + uint64_t update_ops; /* Update ops */ +} CONFIG_THREAD; + +typedef struct { + const char *home; /* WiredTiger home */ + char *uri; /* Object URI */ + + WT_CONNECTION *conn; /* Database connection */ + + FILE *logf; /* Logging handle */ + + CONFIG_THREAD *rthreads, *ithreads, *popthreads, *uthreads; + + enum { WT_PERF_INIT, WT_PERF_POPULATE, WT_PERF_WORKER } phase; + + struct timeval phase_start_time; + + /* Fields changeable on command line are listed in wtperf_opt.i */ +#define OPT_DECLARE_STRUCT +#include "wtperf_opt.i" +#undef OPT_DECLARE_STRUCT + +} CONFIG; + +typedef enum { + BOOL_TYPE, CONFIG_STRING_TYPE, INT_TYPE, STRING_TYPE, UINT32_TYPE +} CONFIG_OPT_TYPE; + +typedef struct { + const char *name; + const char *description; + const char *defaultval; + CONFIG_OPT_TYPE type; + size_t offset; +} CONFIG_OPT; + +/* Worker thread types. */ +typedef enum { + WORKER_READ, WORKER_INSERT, WORKER_INSERT_RMW, WORKER_UPDATE } worker_type; + +int config_assign(CONFIG *, const CONFIG *); +void config_free(CONFIG *); +int config_opt_file(CONFIG *, WT_SESSION *, const char *); +int config_opt_line(CONFIG *, WT_SESSION *, const char *); +int config_opt_str(CONFIG *, WT_SESSION *, const char *, const char *); +int enomem(const CONFIG *); +void lprintf(const CONFIG *, int err, uint32_t, const char *, ...) + WT_GCC_ATTRIBUTE((format (printf, 4, 5))); +void print_config(CONFIG *); +int setup_log_file(CONFIG *); +void usage(void); |