コード例 #1
0
ファイル: config_check.c プロジェクト: umerazad/wiredtiger
/*
 * __wt_configure_method --
 *	WT_CONNECTION.configure_method.
 */
int
__wt_configure_method(WT_SESSION_IMPL *session,
                      const char *method, const char *uri,
                      const char *config, const char *type, const char *check)
{
    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's 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_def(session, 1, &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;

    /*
     * Build a new checks entry name field.  There may be a default value
     * in the config argument we're passed, we don't want that as part of
     * the checks entry name field.
     */
    WT_ERR(__wt_strdup(session, config, &newcheck_name));
    if ((p = strchr(newcheck_name, '=')) != NULL)
        *p = '\0';

    /*
     * Build a new checks array.  The new configuration name may replace
     * an existing check with new information, in that case skip the old
     * version.
     */
    for (cnt = 0, cp = (*epp)->checks; cp->name != NULL; ++cp)
        ++cnt;
    WT_ERR(__wt_calloc_def(session, cnt + 2, &checks));
    for (cnt = 0, 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, add them to the list now.
     */
    WT_ERR(__wt_conn_foc_add(session,
                             entry, entry->base,
                             checks, newcheck->name, newcheck->type, newcheck->checks, NULL));

    *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);
        }
        __wt_free(session, newcheck_name);
    }

    __wt_spin_unlock(session, &conn->api_lock);
    return (ret);
}
コード例 #2
0
ファイル: config_api.c プロジェクト: ksuarz/mongo
/*
 * __wt_configure_method --
 *	WT_CONNECTION.configure_method.
 */
int
__wt_configure_method(WT_SESSION_IMPL *session,
    const char *method, const char *uri,
    const char *config, const char *type, const char *check)
{
	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\"");

	/*
	 * Translate the method name to our configuration names, then find a
	 * match.
	 */
	for (epp = conn->config_entries;
	    *epp != NULL && (*epp)->method != NULL; ++epp)
		if (strcmp((*epp)->method, method) == 0)
			break;
	if (*epp == NULL || (*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;

	/*
	 * 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.
	 */
	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));
	WT_ERR(__wt_strdup(session, check, &newcheck->checks));
	entry->checks = checks;
	entry->checks_entries = 0;

	/*
	 * Confirm the configuration string passes the new set of
	 * checks.
	 */
	WT_ERR(__wt_config_check(session, entry, 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.
	 */
	__wt_conn_foc_add(session, entry->base);
	__wt_conn_foc_add(session, entry);
	__wt_conn_foc_add(session, checks);
	__wt_conn_foc_add(session, newcheck->type);
	__wt_conn_foc_add(session, newcheck->checks);
	__wt_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);
		}
		__wt_free(session, newcheck_name);
	}

	__wt_spin_unlock(session, &conn->api_lock);
	return (ret);
}