diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/format/config.c')
-rw-r--r-- | src/third_party/wiredtiger/test/format/config.c | 604 |
1 files changed, 604 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/test/format/config.c b/src/third_party/wiredtiger/test/format/config.c new file mode 100644 index 00000000000..84afedb0a63 --- /dev/null +++ b/src/third_party/wiredtiger/test/format/config.c @@ -0,0 +1,604 @@ +/*- + * Public Domain 2014-2015 MongoDB, Inc. + * Public Domain 2008-2014 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 "format.h" +#include "config.h" + +static void config_checksum(void); +static void config_compression(void); +static const char *config_file_type(u_int); +static CONFIG *config_find(const char *, size_t); +static int config_is_perm(const char *); +static void config_isolation(void); +static void config_map_checksum(const char *, u_int *); +static void config_map_compression(const char *, u_int *); +static void config_map_file_type(const char *, u_int *); +static void config_map_isolation(const char *, u_int *); + +/* + * config_setup -- + * Initialize configuration for a run. + */ +void +config_setup(void) +{ + CONFIG *cp; + + /* Clear any temporary values. */ + config_clear(); + + /* + * Choose a data source type and a file type: they're interrelated (LSM + * trees are only compatible with row-store) and other items depend on + * them. + */ + if (!config_is_perm("data_source")) + switch (mmrand(NULL, 1, 3)) { + case 1: + config_single("data_source=file", 0); + break; + case 2: + config_single("data_source=lsm", 0); + break; + case 3: + config_single("data_source=table", 0); + break; + } + + if (!config_is_perm("file_type")) + switch (DATASOURCE("lsm") ? 5 : mmrand(NULL, 1, 10)) { + case 1: + config_single("file_type=fix", 0); + break; + case 2: case 3: case 4: + config_single("file_type=var", 0); + break; + case 5: case 6: case 7: case 8: case 9: case 10: + config_single("file_type=row", 0); + break; + } + config_map_file_type(g.c_file_type, &g.type); + + /* + * If data_source and file_type were both "permanent", we may still + * have a mismatch. + */ + if (DATASOURCE("lsm") && g.type != ROW) { + fprintf(stderr, + "%s: lsm data_source is only compatible with row file_type\n", + g.progname); + exit(EXIT_FAILURE); + } + + /* + * Build the top-level object name: we're overloading data_source in + * our configuration, LSM or KVS devices are "tables", but files are + * tested as well. + */ + if ((g.uri = malloc(256)) == NULL) + die(errno, "malloc"); + strcpy(g.uri, DATASOURCE("file") ? "file:" : "table:"); + if (DATASOURCE("helium")) + strcat(g.uri, "dev1/"); + strcat(g.uri, WT_NAME); + + /* Fill in random values for the rest of the run. */ + for (cp = c; cp->name != NULL; ++cp) { + if (F_ISSET(cp, C_IGNORE | C_PERM | C_TEMP)) + continue; + + /* + * Boolean flags are 0 or 1, but only set N in 100 where the + * variable's min value is N. Set the flag if we rolled >= + * the min, 0 otherwise. + */ + if (F_ISSET(cp, C_BOOL)) + *cp->v = mmrand(NULL, 1, 100) <= cp->min ? 1 : 0; + else + *cp->v = CONF_RAND(cp); + } + + /* Required shared libraries. */ + if (DATASOURCE("helium") && access(HELIUM_PATH, R_OK) != 0) + die(errno, "Levyx/helium shared library: %s", HELIUM_PATH); + if (DATASOURCE("kvsbdb") && access(KVS_BDB_PATH, R_OK) != 0) + die(errno, "kvsbdb shared library: %s", KVS_BDB_PATH); + + /* Some data-sources don't support user-specified collations. */ + if (DATASOURCE("helium") || DATASOURCE("kvsbdb")) + g.c_reverse = 0; + + config_checksum(); + config_compression(); + config_isolation(); + + /* + * Periodically, run single-threaded so we can compare the results to + * a Berkeley DB copy, as long as the thread-count isn't nailed down. + * Don't do it on the first run, all our smoke tests would hit it. + */ + if (!g.replay && g.run_cnt % 20 == 19 && !config_is_perm("threads")) + g.c_threads = 1; + + /* + * Periodically, set the delete percentage to 0 so salvage gets run, + * as long as the delete percentage isn't nailed down. + * Don't do it on the first run, all our smoke tests would hit it. + */ + if (!g.replay && g.run_cnt % 10 == 9 && !config_is_perm("delete_pct")) + g.c_delete_pct = 0; + + /* + * If this is an LSM run, set the cache size and crank up the insert + * percentage. + */ + if (DATASOURCE("lsm")) { + if (!config_is_perm("cache")) + g.c_cache = 30 * g.c_chunk_size; + + if (!config_is_perm("insert_pct")) + g.c_insert_pct = mmrand(NULL, 50, 85); + } + + /* Make the default maximum-run length 20 minutes. */ + if (!config_is_perm("timer")) + g.c_timer = 20; + + /* + * Key/value minimum/maximum are related, correct unless specified by + * the configuration. + */ + if (!config_is_perm("key_min") && g.c_key_min > g.c_key_max) + g.c_key_min = g.c_key_max; + if (!config_is_perm("key_max") && g.c_key_max < g.c_key_min) + g.c_key_max = g.c_key_min; + if (g.c_key_min > g.c_key_max) + die(EINVAL, "key_min may not be larger than key_max"); + + if (!config_is_perm("value_min") && g.c_value_min > g.c_value_max) + g.c_value_min = g.c_value_max; + if (!config_is_perm("value_max") && g.c_value_max < g.c_value_min) + g.c_value_max = g.c_value_min; + if (g.c_value_min > g.c_value_max) + die(EINVAL, "value_min may not be larger than value_max"); + + /* Reset the key count. */ + g.key_cnt = 0; +} + +/* + * config_checksum -- + * Checksum configuration. + */ +static void +config_checksum(void) +{ + /* Choose a checksum mode if nothing was specified. */ + if (!config_is_perm("checksum")) + switch (mmrand(NULL, 1, 10)) { + case 1: /* 10% */ + config_single("checksum=on", 0); + break; + case 2: /* 10% */ + config_single("checksum=off", 0); + break; + default: /* 80% */ + config_single("checksum=uncompressed", 0); + break; + } +} + +/* + * config_compression -- + * Compression configuration. + */ +static void +config_compression(void) +{ + const char *cstr; + + /* + * Compression: choose something if compression wasn't specified, + * otherwise confirm the appropriate shared library is available. + * We used to verify that the libraries existed but that's no longer + * robust, since it's possible to build compression libraries into + * the WiredTiger library. + */ + if (!config_is_perm("compression")) { + cstr = "compression=none"; + switch (mmrand(NULL, 1, 20)) { + case 1: case 2: case 3: case 4: /* 20% no compression */ + break; + case 5: case 6: /* 10% bzip */ + cstr = "compression=bzip"; + break; + case 7: /* 5% bzip-raw */ + cstr = "compression=bzip-raw"; + break; + case 8: case 9: case 10: case 11: /* 20% lz4 */ + cstr = "compression=lz4"; + break; + case 12: case 13: case 14: case 15: /* 20% snappy */ + cstr = "compression=snappy"; + break; + case 16: case 17: case 18: case 19: /* 20% zlib */ + cstr = "compression=zlib"; + break; + case 20: /* 5% zlib-no-raw */ + cstr = "compression=zlib-noraw"; + break; + } + + config_single(cstr, 0); + } +} + +/* + * config_isolation -- + * Isolation configuration. + */ +static void +config_isolation(void) +{ + const char *cstr; + + /* + * Isolation: choose something if isolation wasn't specified. + */ + if (!config_is_perm("isolation")) { + /* Avoid "maybe uninitialized" warnings. */ + switch (mmrand(NULL, 1, 4)) { + case 1: + cstr = "isolation=random"; + break; + case 2: + cstr = "isolation=read-uncommitted"; + break; + case 3: + cstr = "isolation=read-committed"; + break; + case 4: + default: + cstr = "isolation=snapshot"; + break; + } + config_single(cstr, 0); + } +} + +/* + * config_error -- + * Display configuration information on error. + */ +void +config_error(void) +{ + CONFIG *cp; + + /* Display configuration names. */ + fprintf(stderr, "\n"); + fprintf(stderr, "Configuration names:\n"); + for (cp = c; cp->name != NULL; ++cp) + if (strlen(cp->name) > 17) + fprintf(stderr, + "%s\n%17s: %s\n", cp->name, " ", cp->desc); + else + fprintf(stderr, "%17s: %s\n", cp->name, cp->desc); +} + +/* + * config_print -- + * Print configuration information. + */ +void +config_print(int error_display) +{ + CONFIG *cp; + FILE *fp; + + if (error_display) + fp = stdout; + else + if ((fp = fopen(g.home_config, "w")) == NULL) + die(errno, "fopen: %s", g.home_config); + + fprintf(fp, "############################################\n"); + fprintf(fp, "# RUN PARAMETERS\n"); + fprintf(fp, "############################################\n"); + + /* Display configuration values. */ + for (cp = c; cp->name != NULL; ++cp) + if (F_ISSET(cp, C_STRING)) + fprintf(fp, "%s=%s\n", cp->name, + *cp->vstr == NULL ? "" : *cp->vstr); + else + fprintf(fp, "%s=%" PRIu32 "\n", cp->name, *cp->v); + + fprintf(fp, "############################################\n"); + if (fp != stdout) + (void)fclose(fp); +} + +/* + * config_file -- + * Read configuration values from a file. + */ +void +config_file(const char *name) +{ + FILE *fp; + char *p, buf[256]; + + if ((fp = fopen(name, "r")) == NULL) + die(errno, "fopen: %s", name); + while (fgets(buf, sizeof(buf), fp) != NULL) { + for (p = buf; *p != '\0' && *p != '\n'; ++p) + ; + *p = '\0'; + if (buf[0] == '\0' || buf[0] == '#') + continue; + config_single(buf, 1); + } + (void)fclose(fp); +} + +/* + * config_clear -- + * Clear per-run values. + */ +void +config_clear(void) +{ + CONFIG *cp; + + /* Clear configuration data. */ + for (cp = c; cp->name != NULL; ++cp) { + F_CLR(cp, C_TEMP); + if (!F_ISSET(cp, C_PERM) && + F_ISSET(cp, C_STRING) && cp->vstr != NULL) { + free(*cp->vstr); + *cp->vstr = NULL; + } + } + free(g.uri); + g.uri = NULL; +} + +/* + * config_single -- + * Set a single configuration structure value. + */ +void +config_single(const char *s, int perm) +{ + CONFIG *cp; + uint64_t v; + char *p; + const char *ep; + + if ((ep = strchr(s, '=')) == NULL) { + fprintf(stderr, + "%s: %s: illegal configuration value\n", g.progname, s); + exit(EXIT_FAILURE); + } + + cp = config_find(s, (size_t)(ep - s)); + F_SET(cp, perm ? C_PERM : C_TEMP); + ++ep; + + if (F_ISSET(cp, C_STRING)) { + if (strncmp(s, "data_source", strlen("data_source")) == 0 && + strncmp("file", ep, strlen("file")) != 0 && + strncmp("helium", ep, strlen("helium")) != 0 && + strncmp("kvsbdb", ep, strlen("kvsbdb")) != 0 && + strncmp("lsm", ep, strlen("lsm")) != 0 && + strncmp("table", ep, strlen("table")) != 0) { + fprintf(stderr, + "Invalid data source option: %s\n", ep); + exit(EXIT_FAILURE); + } + + if (strncmp(s, "checksum", strlen("checksum")) == 0) { + config_map_checksum(ep, &g.c_checksum_flag); + *cp->vstr = strdup(ep); + } else if (strncmp( + s, "compression", strlen("compression")) == 0) { + config_map_compression(ep, &g.c_compression_flag); + *cp->vstr = strdup(ep); + } else if (strncmp(s, "isolation", strlen("isolation")) == 0) { + config_map_isolation(ep, &g.c_isolation_flag); + *cp->vstr = strdup(ep); + } else if (strncmp(s, "file_type", strlen("file_type")) == 0) { + config_map_file_type(ep, &g.type); + *cp->vstr = strdup(config_file_type(g.type)); + } else { + if (*cp->vstr != NULL) + free(*cp->vstr); + *cp->vstr = strdup(ep); + } + if (*cp->vstr == NULL) + die(errno, "malloc"); + + return; + } + + v = strtoul(ep, &p, 10); + if (*p != '\0') { + fprintf(stderr, "%s: %s: illegal numeric value\n", + g.progname, s); + exit(EXIT_FAILURE); + } + if (F_ISSET(cp, C_BOOL)) { + if (v != 0 && v != 1) { + fprintf(stderr, "%s: %s: value of boolean not 0 or 1\n", + g.progname, s); + exit(EXIT_FAILURE); + } + } else if ((uint32_t)v < cp->min || (uint32_t)v > cp->maxset) { + fprintf(stderr, "%s: %s: value of %" PRIu32 + " outside min/max values of %" PRIu32 "-%" PRIu32 "\n", + g.progname, s, *cp->v, cp->min, cp->maxset); + exit(EXIT_FAILURE); + } + *cp->v = (uint32_t)v; +} + +/* + * config_map_file_type -- + * Map a file type configuration to a flag. + */ +static void +config_map_file_type(const char *s, u_int *vp) +{ + if (strcmp(s, "fix") == 0 || + strcmp(s, "fixed-length column-store") == 0) + *vp = FIX; + else if (strcmp(s, "var") == 0 || + strcmp(s, "variable-length column-store") == 0) + *vp = VAR; + else if (strcmp(s, "row") == 0 || + strcmp(s, "row-store") == 0) + *vp = ROW; + else + die(EINVAL, "illegal file type configuration: %s", s); +} + +/* + * config_map_checksum -- + * Map a checksum configuration to a flag. + */ +static void +config_map_checksum(const char *s, u_int *vp) +{ + if (strcmp(s, "on") == 0) + *vp = CHECKSUM_ON; + else if (strcmp(s, "off") == 0) + *vp = CHECKSUM_ON; + else if (strcmp(s, "uncompressed") == 0) + *vp = CHECKSUM_UNCOMPRESSED; + else + die(EINVAL, "illegal checksum configuration: %s", s); +} + +/* + * config_map_compression -- + * Map a compression configuration to a flag. + */ +static void +config_map_compression(const char *s, u_int *vp) +{ + if (strcmp(s, "none") == 0) + *vp = COMPRESS_NONE; + else if (strcmp(s, "bzip") == 0) + *vp = COMPRESS_BZIP; + else if (strcmp(s, "bzip-raw") == 0) + *vp = COMPRESS_BZIP_RAW; + else if (strcmp(s, "lz4") == 0) + *vp = COMPRESS_LZ4; + else if (strcmp(s, "lzo") == 0) + *vp = COMPRESS_LZO; + else if (strcmp(s, "snappy") == 0) + *vp = COMPRESS_SNAPPY; + else if (strcmp(s, "zlib") == 0) + *vp = COMPRESS_ZLIB; + else if (strcmp(s, "zlib-noraw") == 0) + *vp = COMPRESS_ZLIB_NO_RAW; + else + die(EINVAL, "illegal compression configuration: %s", s); +} + +/* + * config_map_isolation -- + * Map an isolation configuration to a flag. + */ +static void +config_map_isolation(const char *s, u_int *vp) +{ + if (strcmp(s, "random") == 0) + *vp = ISOLATION_RANDOM; + else if (strcmp(s, "read-uncommitted") == 0) + *vp = ISOLATION_READ_UNCOMMITTED; + else if (strcmp(s, "read-committed") == 0) + *vp = ISOLATION_READ_COMMITTED; + else if (strcmp(s, "snapshot") == 0) + *vp = ISOLATION_SNAPSHOT; + else + die(EINVAL, "illegal isolation configuration: %s", s); +} + +/* + * config_find + * Find a specific configuration entry. + */ +static CONFIG * +config_find(const char *s, size_t len) +{ + CONFIG *cp; + + for (cp = c; cp->name != NULL; ++cp) + if (strncmp(s, cp->name, len) == 0 && cp->name[len] == '\0') + return (cp); + + fprintf(stderr, + "%s: %s: unknown configuration keyword\n", g.progname, s); + config_error(); + exit(EXIT_FAILURE); +} + +/* + * config_is_perm + * Return if a specific configuration entry was permanently set. + */ +static int +config_is_perm(const char *s) +{ + CONFIG *cp; + + cp = config_find(s, strlen(s)); + return (F_ISSET(cp, C_PERM) ? 1 : 0); +} + +/* + * config_file_type -- + * Return the file type as a string. + */ +static const char * +config_file_type(u_int type) +{ + switch (type) { + case FIX: + return ("fixed-length column-store"); + case VAR: + return ("variable-length column-store"); + case ROW: + return ("row-store"); + default: + break; + } + return ("error: unknown file type"); +} |