diff options
Diffstat (limited to 'src/third_party/wiredtiger/src/config/config_check.c')
-rw-r--r-- | src/third_party/wiredtiger/src/config/config_check.c | 263 |
1 files changed, 48 insertions, 215 deletions
diff --git a/src/third_party/wiredtiger/src/config/config_check.c b/src/third_party/wiredtiger/src/config/config_check.c index 391209104c7..b09a1a10a85 100644 --- a/src/third_party/wiredtiger/src/config/config_check.c +++ b/src/third_party/wiredtiger/src/config/config_check.c @@ -9,228 +9,65 @@ #include "wt_internal.h" static int config_check( - WT_SESSION_IMPL *, const WT_CONFIG_CHECK *, const char *, size_t); + WT_SESSION_IMPL *, const WT_CONFIG_CHECK *, u_int, const char *, size_t); /* - * __conn_foc_add -- - * Add a new entry into the connection's free-on-close list. - */ -static int -__conn_foc_add(WT_SESSION_IMPL *session, const void *p) -{ - WT_CONNECTION_IMPL *conn; - - conn = S2C(session); - - /* - * Our caller is expected to be holding any locks we need. - */ - WT_RET(__wt_realloc_def( - session, &conn->foc_size, conn->foc_cnt + 1, &conn->foc)); - - conn->foc[conn->foc_cnt++] = (void *)p; - return (0); -} - -/* - * __wt_conn_foc_discard -- - * Discard any memory the connection accumulated. + * __wt_config_check -- + * Check the keys in an application-supplied config string match what is + * specified in an array of check strings. */ -void -__wt_conn_foc_discard(WT_SESSION_IMPL *session) +int +__wt_config_check(WT_SESSION_IMPL *session, + const WT_CONFIG_ENTRY *entry, const char *config, size_t config_len) { - WT_CONNECTION_IMPL *conn; - size_t i; - - conn = S2C(session); - /* - * If we have a list of chunks to free, run through the list, then - * free the list itself. + * Callers don't check, it's a fast call without a configuration or + * check array. */ - for (i = 0; i < conn->foc_cnt; ++i) - __wt_free(session, conn->foc[i]); - __wt_free(session, conn->foc); + return (config == NULL || entry->checks == NULL ? 0 : + config_check(session, + entry->checks, entry->checks_entries, config, config_len)); } /* - * __wt_configure_method -- - * WT_CONNECTION.configure_method. + * config_check_search -- + * Search a set of checks for a matching name. */ -int -__wt_configure_method(WT_SESSION_IMPL *session, - const char *method, const char *uri, - const char *config, const char *type, const char *check) +static inline int +config_check_search(WT_SESSION_IMPL *session, + const WT_CONFIG_CHECK *checks, u_int entries, + const char *str, size_t len, int *ip) { - const WT_CONFIG_CHECK *cp; - WT_CONFIG_CHECK *checks, *newcheck; - const WT_CONFIG_ENTRY **epp; - WT_CONFIG_ENTRY *entry; - WT_CONNECTION_IMPL *conn; - WT_DECL_RET; - size_t cnt; - char *newcheck_name, *p; - - /* - * !!! - * We ignore the specified uri, that is, all new configuration options - * will be valid for all data sources. That shouldn't be too bad - * as the worst that can happen is an application might specify some - * configuration option and not get an error -- the option should be - * ignored by the underlying implementation since it's unexpected, so - * there shouldn't be any real problems. Eventually I expect we will - * get the whole data-source thing sorted, at which time there may be - * configuration arrays for each data source, and that's when the uri - * will matter. - */ - WT_UNUSED(uri); - - conn = S2C(session); - checks = newcheck = NULL; - entry = NULL; - newcheck_name = NULL; - - /* Argument checking; we only support a limited number of types. */ - if (config == NULL) - WT_RET_MSG(session, EINVAL, "no configuration specified"); - if (type == NULL) - WT_RET_MSG(session, EINVAL, "no configuration type specified"); - if (strcmp(type, "boolean") != 0 && strcmp(type, "int") != 0 && - strcmp(type, "list") != 0 && strcmp(type, "string") != 0) - WT_RET_MSG(session, EINVAL, - "type must be one of \"boolean\", \"int\", \"list\" or " - "\"string\""); - - /* Find a match for the method name. */ - for (epp = conn->config_entries; (*epp)->method != NULL; ++epp) - if (strcmp((*epp)->method, method) == 0) - break; - if ((*epp)->method == NULL) - WT_RET_MSG(session, - WT_NOTFOUND, "no method matching %s found", method); - - /* - * Technically possible for threads to race, lock the connection while - * adding the new configuration information. We're holding the lock - * for an extended period of time, but configuration changes should be - * rare and only happen during startup. - */ - __wt_spin_lock(session, &conn->api_lock); - - /* - * Allocate new configuration entry and fill it in. - * - * The new base value is the previous base value, a separator and the - * new configuration string. - */ - WT_ERR(__wt_calloc_one(session, &entry)); - entry->method = (*epp)->method; - WT_ERR(__wt_calloc_def(session, - strlen((*epp)->base) + strlen(",") + strlen(config) + 1, &p)); - (void)strcpy(p, (*epp)->base); - (void)strcat(p, ","); - (void)strcat(p, config); - entry->base = p; + u_int base, indx, limit; + int cmp; /* - * There may be a default value in the config argument passed in (for - * example, (kvs_parallelism=64"). The default value isn't part of the - * name, build a new one. + * For standard sets of configuration information, we know how many + * entries and that they're sorted, do a binary search. Else, do it + * the slow way. */ - WT_ERR(__wt_strdup(session, config, &newcheck_name)); - if ((p = strchr(newcheck_name, '=')) != NULL) - *p = '\0'; - - /* - * The new configuration name may replace an existing check with new - * information, in that case skip the old version. - */ - cnt = 0; - if ((*epp)->checks != NULL) - for (cp = (*epp)->checks; cp->name != NULL; ++cp) - ++cnt; - WT_ERR(__wt_calloc_def(session, cnt + 2, &checks)); - cnt = 0; - if ((*epp)->checks != NULL) - for (cp = (*epp)->checks; cp->name != NULL; ++cp) - if (strcmp(newcheck_name, cp->name) != 0) - checks[cnt++] = *cp; - newcheck = &checks[cnt]; - newcheck->name = newcheck_name; - WT_ERR(__wt_strdup(session, type, &newcheck->type)); - if (check != NULL) - WT_ERR(__wt_strdup(session, check, &newcheck->checks)); - entry->checks = checks; - - /* - * Confirm the configuration string passes the new set of - * checks. - */ - WT_ERR(config_check(session, entry->checks, config, 0)); - - /* - * The next time this configuration is updated, we don't want to figure - * out which of these pieces of memory were allocated and will need to - * be free'd on close (this isn't a heavily used API and it's too much - * work); add them all to the free-on-close list now. We don't check - * for errors deliberately, we'd have to figure out which elements have - * already been added to the free-on-close array and which have not in - * order to avoid freeing chunks of memory twice. Again, this isn't a - * commonly used API and it shouldn't ever happen, just leak it. - */ - (void)__conn_foc_add(session, entry->base); - (void)__conn_foc_add(session, entry); - (void)__conn_foc_add(session, checks); - (void)__conn_foc_add(session, newcheck->type); - (void)__conn_foc_add(session, newcheck->checks); - (void)__conn_foc_add(session, newcheck_name); - - /* - * Instead of using locks to protect configuration information, assume - * we can atomically update a pointer to a chunk of memory, and because - * a pointer is never partially written, readers will correctly see the - * original or new versions of the memory. Readers might be using the - * old version as it's being updated, though, which means we cannot free - * the old chunk of memory until all possible readers have finished. - * Currently, that's on connection close: in other words, we can use - * this because it's small amounts of memory, and we really, really do - * not want to acquire locks every time we access configuration strings, - * since that's done on every API call. - */ - WT_PUBLISH(*epp, entry); - - if (0) { -err: if (entry != NULL) { - __wt_free(session, entry->base); - __wt_free(session, entry); - } - __wt_free(session, checks); - if (newcheck != NULL) { - __wt_free(session, newcheck->type); - __wt_free(session, newcheck->checks); + if (entries == 0) { + for (indx = 0; checks[indx].name != NULL; indx++) + if (WT_STRING_MATCH(checks[indx].name, str, len)) { + *ip = (int)indx; + return (0); + } + } else + for (base = 0, limit = entries; limit != 0; limit >>= 1) { + indx = base + (limit >> 1); + cmp = strncmp(checks[indx].name, str, len); + if (cmp == 0 && checks[indx].name[len] == '\0') { + *ip = (int)indx; + return (0); + } + if (cmp < 0) { + base = indx + 1; + --limit; + } } - __wt_free(session, newcheck_name); - } - - __wt_spin_unlock(session, &conn->api_lock); - return (ret); -} -/* - * __wt_config_check -- - * Check the keys in an application-supplied config string match what is - * specified in an array of check strings. - */ -int -__wt_config_check(WT_SESSION_IMPL *session, - const WT_CONFIG_ENTRY *entry, const char *config, size_t config_len) -{ - /* - * Callers don't check, it's a fast call without a configuration or - * check array. - */ - return (config == NULL || entry->checks == NULL ? - 0 : config_check(session, entry->checks, config, config_len)); + WT_RET_MSG(session, EINVAL, + "unknown configuration key: '%.*s'", (int)len, str); } /* @@ -240,7 +77,8 @@ __wt_config_check(WT_SESSION_IMPL *session, */ static int config_check(WT_SESSION_IMPL *session, - const WT_CONFIG_CHECK *checks, const char *config, size_t config_len) + const WT_CONFIG_CHECK *checks, u_int checks_entries, + const char *config, size_t config_len) { WT_CONFIG parser, cparser, sparser; WT_CONFIG_ITEM k, v, ck, cv, dummy; @@ -263,13 +101,8 @@ config_check(WT_SESSION_IMPL *session, (int)k.len, k.str); /* Search for a matching entry. */ - for (i = 0; checks[i].name != NULL; i++) - if (WT_STRING_MATCH(checks[i].name, k.str, k.len)) - break; - if (checks[i].name == NULL) - WT_RET_MSG(session, EINVAL, - "unknown configuration key: '%.*s'", - (int)k.len, k.str); + WT_RET(config_check_search( + session, checks, checks_entries, k.str, k.len, &i)); if (strcmp(checks[i].type, "boolean") == 0) { badtype = (v.type != WT_CONFIG_ITEM_BOOL && @@ -278,7 +111,7 @@ config_check(WT_SESSION_IMPL *session, } else if (strcmp(checks[i].type, "category") == 0) { /* Deal with categories of the form: XXX=(XXX=blah). */ ret = config_check(session, - checks[i].subconfigs, + checks[i].subconfigs, checks[i].subconfigs_entries, k.str + strlen(checks[i].name) + 1, v.len); if (ret != EINVAL) badtype = 0; |