summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/config/config_check.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/config/config_check.c')
-rw-r--r--src/third_party/wiredtiger/src/config/config_check.c263
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;