Exemplo n.º 1
0
/*
 * __backup_all --
 *	Backup all objects in the database.
 */
static int
__backup_all(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
{
	WT_CONFIG_ITEM cval;
	WT_CURSOR *cursor;
	WT_DECL_RET;
	const char *key, *value;

	cursor = NULL;

	/*
	 * Open a cursor on the metadata file and copy all of the entries to
	 * the hot backup file.
	 */
	WT_ERR(__wt_metadata_cursor(session, NULL, &cursor));
	while ((ret = cursor->next(cursor)) == 0) {
		WT_ERR(cursor->get_key(cursor, &key));
		WT_ERR(cursor->get_value(cursor, &value));
		WT_ERR_TEST((fprintf(
		    cb->bfp, "%s\n%s\n", key, value) < 0), __wt_errno());

		/*
		 * While reading the metadata file, check there are no "sources"
		 * or "types" which can't support hot backup.  This checks for
		 * a data source that's non-standard, which can't be backed up,
		 * but is also sanity checking: if there's an entry backed by
		 * anything other than a file or lsm entry, we're confused.
		 */
		if ((ret = __wt_config_getones(
		    session, value, "type", &cval)) == 0 &&
		    !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "file") &&
		    !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "lsm"))
			WT_ERR_MSG(session, ENOTSUP,
			    "hot backup is not supported for objects of "
			    "type %.*s", (int)cval.len, cval.str);
		WT_ERR_NOTFOUND_OK(ret);
		if ((ret =__wt_config_getones(
		    session, value, "source", &cval)) == 0 &&
		    !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "file:") &&
		    !WT_PREFIX_MATCH_LEN(cval.str, cval.len, "lsm:"))
			WT_ERR_MSG(session, ENOTSUP,
			    "hot backup is not supported for objects of "
			    "source %.*s", (int)cval.len, cval.str);
		WT_ERR_NOTFOUND_OK(ret);
	}
	WT_ERR_NOTFOUND_OK(ret);

	/* Build a list of the file objects that need to be copied. */
	WT_WITH_DHANDLE_LOCK(session,
	    ret = __wt_meta_btree_apply(
	    session, __backup_list_all_append, NULL));

err:	if (cursor != NULL)
		WT_TRET(cursor->close(cursor));
	return (ret);
}
Exemplo n.º 2
0
/*
 * __snap_get_last --
 *	Return the cookie associated with the file's last snapshot.
 */
static int
__snap_get_last(
    WT_SESSION_IMPL *session, const char *config, WT_ITEM *addr)
{
	WT_CONFIG snapconf;
	WT_CONFIG_ITEM a, k, v;
	int64_t found;

	WT_RET(__wt_config_getones(session, config, "snapshot", &v));
	WT_RET(__wt_config_subinit(session, &snapconf, &v));
	for (found = 0; __wt_config_next(&snapconf, &k, &v) == 0;) {
		if (found) {
			WT_RET(__wt_config_subgets(session, &v, "order", &a));
			if (a.val < found)
				continue;
		}

		WT_RET(__wt_config_subgets(session, &v, "addr", &a));
		if (a.len == 0)
			WT_RET(EINVAL);

		/* Our caller wants the raw cookie, not the hex. */
		WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr));
		WT_RET(__wt_config_subgets(session, &v, "order", &a));
		found = a.val;
	}

	return (found ? 0 : WT_NOTFOUND);
}
Exemplo n.º 3
0
/*
 * __wt_schema_index_source --
 *	Get the URI of the data source for an index.
 */
int
__wt_schema_index_source(WT_SESSION_IMPL *session,
    WT_TABLE *table, const char *idxname, const char *config, WT_ITEM *buf)
{
	WT_CONFIG_ITEM cval;
	WT_DECL_RET;
	size_t len;
	const char *prefix, *suffix, *tablename;

	tablename = table->name + strlen("table:");
	if ((ret = __wt_config_getones(session, config, "type", &cval)) == 0 &&
	    !WT_STRING_MATCH("file", cval.str, cval.len)) {
		prefix = cval.str;
		len = cval.len;
		suffix = "_idx";
	} else {
		prefix = "file";
		len = strlen(prefix);
		suffix = ".wti";
	}
	WT_RET_NOTFOUND_OK(ret);

	WT_RET(__wt_buf_fmt(session, buf, "%.*s:%s_%s%s",
	    (int)len, prefix, tablename, idxname, suffix));

	return (0);
}
Exemplo n.º 4
0
/*
 * __ckpt_last_addr --
 *	Return the cookie associated with the file's last checkpoint.
 */
static int
__ckpt_last_addr(
    WT_SESSION_IMPL *session, const char *config, WT_ITEM *addr)
{
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM a, k, v;
	int64_t found;

	WT_RET(__wt_config_getones(session, config, "checkpoint", &v));
	WT_RET(__wt_config_subinit(session, &ckptconf, &v));
	for (found = 0; __wt_config_next(&ckptconf, &k, &v) == 0;) {
		/* Ignore checkpoints before the ones we've already seen. */
		WT_RET(__wt_config_subgets(session, &v, "order", &a));
		if (found && a.val < found)
			continue;
		found = a.val;

		/*
		 * Copy out the address; our caller wants the raw cookie, not
		 * the hex.
		 */
		WT_RET(__wt_config_subgets(session, &v, "addr", &a));
		if (a.len != 0)
			WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr));
	}

	return (found ? 0 : WT_NOTFOUND);
}
Exemplo n.º 5
0
/*
 * __wt_meta_ckptlist_get --
 *	Load all available checkpoint information for a file.
 */
int
__wt_meta_ckptlist_get(
    WT_SESSION_IMPL *session, const char *fname, WT_CKPT **ckptbasep)
{
	WT_CKPT *ckpt, *ckptbase;
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM k, v;
	WT_DECL_ITEM(buf);
	WT_DECL_RET;
	size_t allocated, slot;
	char *config;

	*ckptbasep = NULL;

	ckptbase = NULL;
	allocated = slot = 0;
	config = NULL;

	/* Retrieve the metadata information for the file. */
	WT_RET(__wt_metadata_search(session, fname, &config));

	/* Load any existing checkpoints into the array. */
	WT_ERR(__wt_scr_alloc(session, 0, &buf));
	if (__wt_config_getones(session, config, "checkpoint", &v) == 0) {
		__wt_config_subinit(session, &ckptconf, &v);
		for (; __wt_config_next(&ckptconf, &k, &v) == 0; ++slot) {
			WT_ERR(__wt_realloc_def(
			    session, &allocated, slot + 1, &ckptbase));
			ckpt = &ckptbase[slot];

			WT_ERR(__ckpt_load(session, &k, &v, ckpt));
		}
	}

	/*
	 * Allocate an extra slot for a new value, plus a slot to mark the end.
	 *
	 * This isn't very clean, but there's necessary cooperation between the
	 * schema layer (that maintains the list of checkpoints), the btree
	 * layer (that knows when the root page is written, creating a new
	 * checkpoint), and the block manager (which actually creates the
	 * checkpoint).  All of that cooperation is handled in the WT_CKPT
	 * structure referenced from the WT_BTREE structure.
	 */
	WT_ERR(__wt_realloc_def(session, &allocated, slot + 2, &ckptbase));

	/* Sort in creation-order. */
	qsort(ckptbase, slot, sizeof(WT_CKPT), __ckpt_compare_order);

	/* Return the array to our caller. */
	*ckptbasep = ckptbase;

	if (0) {
err:		__wt_meta_ckptlist_free(session, &ckptbase);
	}
	__wt_free(session, config);
	__wt_scr_free(session, &buf);

	return (ret);
}
Exemplo n.º 6
0
/*
 * __ckpt_version_chk --
 *	Check the version major/minor numbers.
 */
static int
__ckpt_version_chk(
    WT_SESSION_IMPL *session, const char *fname, const char *config)
{
	WT_CONFIG_ITEM a, v;
	int majorv, minorv;

	WT_RET(__wt_config_getones(session, config, "version", &v));
	WT_RET(__wt_config_subgets(session, &v, "major", &a));
	majorv = (int)a.val;
	WT_RET(__wt_config_subgets(session, &v, "minor", &a));
	minorv = (int)a.val;

	if (majorv < WT_BTREE_MAJOR_VERSION_MIN ||
	    majorv > WT_BTREE_MAJOR_VERSION_MAX ||
	    (majorv == WT_BTREE_MAJOR_VERSION_MIN &&
	    minorv < WT_BTREE_MINOR_VERSION_MIN) ||
	    (majorv == WT_BTREE_MAJOR_VERSION_MAX &&
	    minorv > WT_BTREE_MINOR_VERSION_MAX))
		WT_RET_MSG(session, EACCES,
		    "%s is an unsupported WiredTiger source file version %d.%d"
		    "; this WiredTiger build only supports versions from %d.%d "
		    "to %d.%d",
		    fname,
		    majorv, minorv,
		    WT_BTREE_MAJOR_VERSION_MIN,
		    WT_BTREE_MINOR_VERSION_MIN,
		    WT_BTREE_MAJOR_VERSION_MAX,
		    WT_BTREE_MINOR_VERSION_MAX);
	return (0);
}
Exemplo n.º 7
0
/*
 * __create_data_source --
 *	Create a custom data source.
 */
static int
__create_data_source(WT_SESSION_IMPL *session,
    const char *uri, const char *config, WT_DATA_SOURCE *dsrc)
{
	WT_CONFIG_ITEM cval;
	const char *cfg[] = {
	    WT_CONFIG_BASE(session, session_create), config, NULL };

	/*
	 * Check to be sure the key/value formats are legal: the underlying
	 * data source doesn't have access to the functions that check.
	 */
	WT_RET(__wt_config_gets(session, cfg, "key_format", &cval));
	WT_RET(__wt_struct_check(session, cval.str, cval.len, NULL, NULL));
	WT_RET(__wt_config_gets(session, cfg, "value_format", &cval));
	WT_RET(__wt_struct_check(session, cval.str, cval.len, NULL, NULL));

	/*
	 * User-specified collators aren't supported for data-source objects.
	 */
	if (__wt_config_getones(
	    session, config, "collator", &cval) != WT_NOTFOUND)
		WT_RET_MSG(session, EINVAL,
		    "WT_DATA_SOURCE objects do not support WT_COLLATOR "
		    "ordering");

	return (dsrc->create(dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg));
}
Exemplo n.º 8
0
/*
 * __wt_config_gets_defno --
 *	Given a NULL-terminated list of configuration strings, and if the
 * application supplied any configuration strings, find the final value for
 * a given string key
 */
int
__wt_config_gets_defno(WT_SESSION_IMPL *session,
    const char **cfg, const char *key, WT_CONFIG_ITEM *value)
{
	static const WT_CONFIG_ITEM false_value = {
		"", 0, 0, ITEM_NUM
	};

	/*
	 * This is a performance hack: it's expensive to repeatedly parse
	 * configuration strings, so don't do it unless it's necessary in
	 * performance paths like cursor creation.  Assume the second
	 * configuration string is the application's configuration string, and
	 * if it's not set (which is true most of the time), then assume the
	 * default answer is "false", and return that.  This makes it much
	 * faster to open cursors when checking for obscure open configuration
	 * strings like "next_random".
	 */
	*value = false_value;
	if (cfg == NULL || cfg[1] == NULL)
		return (0);
	else if (cfg[2] == NULL)
		WT_RET_NOTFOUND_OK(
		    __wt_config_getones(session, cfg[1], key, value));
	return (__wt_config_gets(session, cfg, key, value));
}
Exemplo n.º 9
0
/*
 * __recovery_setup_file --
 *	Set up the recovery slot for a file.
 */
static int
__recovery_setup_file(WT_RECOVERY *r, const char *uri, const char *config)
{
	WT_CONFIG_ITEM cval;
	WT_LSN lsn;
	uint32_t fileid, lsnfile, lsnoffset;

	WT_RET(__wt_config_getones(r->session, config, "id", &cval));
	fileid = (uint32_t)cval.val;

	/* Track the largest file ID we have seen. */
	if (fileid > r->max_fileid)
		r->max_fileid = fileid;

	if (r->nfiles <= fileid) {
		WT_RET(__wt_realloc_def(
		    r->session, &r->file_alloc, fileid + 1, &r->files));
		r->nfiles = fileid + 1;
	}

	WT_RET(__wt_strdup(r->session, uri, &r->files[fileid].uri));
	WT_RET(
	    __wt_config_getones(r->session, config, "checkpoint_lsn", &cval));
	/* If there is checkpoint logged for the file, apply everything. */
	if (cval.type != WT_CONFIG_ITEM_STRUCT)
		WT_INIT_LSN(&lsn);
	/* NOLINTNEXTLINE(cert-err34-c) */
	else if (sscanf(cval.str,
	    "(%" SCNu32 ",%" SCNu32 ")", &lsnfile, &lsnoffset) == 2)
		WT_SET_LSN(&lsn, lsnfile, lsnoffset);
	else
		WT_RET_MSG(r->session, EINVAL,
		    "Failed to parse checkpoint LSN '%.*s'",
		    (int)cval.len, cval.str);
	r->files[fileid].ckpt_lsn = lsn;

	__wt_verbose(r->session, WT_VERB_RECOVERY,
	    "Recovering %s with id %" PRIu32 " @ (%" PRIu32 ", %" PRIu32 ")",
	    uri, fileid, lsn.l.file, lsn.l.offset);

	if ((!WT_IS_MAX_LSN(&lsn) && !WT_IS_INIT_LSN(&lsn)) &&
	    (WT_IS_MAX_LSN(&r->max_ckpt_lsn) ||
	    __wt_log_cmp(&lsn, &r->max_ckpt_lsn) > 0))
		r->max_ckpt_lsn = lsn;

	return (0);
}
Exemplo n.º 10
0
/*
 * __wt_config_getones_none --
 *	Get the value for a given string key from a single config string.
 * Treat "none" as empty.
 */
int
__wt_config_getones_none(WT_SESSION_IMPL *session,
    const char *config, const char *key, WT_CONFIG_ITEM *value)
{
	WT_RET(__wt_config_getones(session, config, key, value));
	if (WT_STRING_MATCH("none", value->str, value->len))
		value->len = 0;
	return (0);
}
Exemplo n.º 11
0
/*
 * __recovery_set_checkpoint_timestamp --
 *	Set the checkpoint timestamp as retrieved from the metadata file.
 */
static int
__recovery_set_checkpoint_timestamp(WT_RECOVERY *r)
{
	WT_CONFIG_ITEM cval;
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	wt_timestamp_t ckpt_timestamp;
	char ts_string[WT_TS_INT_STRING_SIZE], *sys_config;

	sys_config = NULL;

	session = r->session;
	conn = S2C(session);
	/*
	 * Read the system checkpoint information from the metadata file and
	 * save the stable timestamp of the last checkpoint for later query.
	 * This gets saved in the connection.
	 */
	ckpt_timestamp = 0;

	/* Search in the metadata for the system information. */
	WT_ERR_NOTFOUND_OK(
	    __wt_metadata_search(session, WT_SYSTEM_CKPT_URI, &sys_config));
	if (sys_config != NULL) {
		WT_CLEAR(cval);
		WT_ERR_NOTFOUND_OK(__wt_config_getones(
		    session, sys_config, "checkpoint_timestamp", &cval));
		if (cval.len != 0) {
			__wt_verbose(session, WT_VERB_RECOVERY,
			    "Recovery timestamp %.*s",
			    (int)cval.len, cval.str);
			WT_ERR(__wt_txn_parse_timestamp_raw(session,
			    "recovery", &ckpt_timestamp, &cval));
		}
	}

	/*
	 * Set the recovery checkpoint timestamp and the metadata checkpoint
	 * timestamp so that the checkpoint after recovery writes the correct
	 * value into the metadata.
	 */
	conn->txn_global.meta_ckpt_timestamp =
	    conn->txn_global.recovery_timestamp = ckpt_timestamp;

	if (WT_VERBOSE_ISSET(session,
	    WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS)) {
		__wt_timestamp_to_string(
		    conn->txn_global.recovery_timestamp, ts_string);
		__wt_verbose(session,
		    WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS,
		    "Set global recovery timestamp: %s", ts_string);
	}
err:	__wt_free(session, sys_config);
	return (ret);
}
Exemplo n.º 12
0
/*
 * __recovery_setup_file --
 *	Set up the recovery slot for a file.
 */
static int
__recovery_setup_file(WT_RECOVERY *r, const char *uri, const char *config)
{
	WT_CONFIG_ITEM cval;
	WT_LSN lsn;
	uint32_t fileid;

	WT_RET(__wt_config_getones(r->session, config, "id", &cval));
	fileid = (uint32_t)cval.val;

	/* Track the largest file ID we have seen. */
	if (fileid > r->max_fileid)
		r->max_fileid = fileid;

	if (r->nfiles <= fileid) {
		WT_RET(__wt_realloc_def(
		    r->session, &r->file_alloc, fileid + 1, &r->files));
		r->nfiles = fileid + 1;
	}

	WT_RET(__wt_strdup(r->session, uri, &r->files[fileid].uri));
	WT_RET(
	    __wt_config_getones(r->session, config, "checkpoint_lsn", &cval));
	/* If there is checkpoint logged for the file, apply everything. */
	if (cval.type != WT_CONFIG_ITEM_STRUCT)
		WT_INIT_LSN(&lsn);
	else if (sscanf(cval.str, "(%" PRIu32 ",%" PRIdMAX ")",
	    &lsn.file, (intmax_t*)&lsn.offset) != 2)
		WT_RET_MSG(r->session, EINVAL,
		    "Failed to parse checkpoint LSN '%.*s'",
		    (int)cval.len, cval.str);
	r->files[fileid].ckpt_lsn = lsn;

	WT_RET(__wt_verbose(r->session, WT_VERB_RECOVERY,
	    "Recovering %s with id %u @ (%" PRIu32 ", %" PRIu64 ")",
	    uri, fileid, lsn.file, lsn.offset));

	return (0);

}
Exemplo n.º 13
0
/*
 * __wt_ext_config_get_string --
 *	Given a configuration string, find the value for a given string key
 *	(external API version).
 */
int
__wt_ext_config_get_string(WT_EXTENSION_API *wt_api,
    WT_SESSION *wt_session, const char *config, const char *key,
    WT_CONFIG_ITEM *cval)
{
	WT_CONNECTION_IMPL *conn;
	WT_SESSION_IMPL *session;

	conn = (WT_CONNECTION_IMPL *)wt_api->conn;
	if ((session = (WT_SESSION_IMPL *)wt_session) == NULL)
		session = conn->default_session;

	return (__wt_config_getones(session, config, key, cval));
}
Exemplo n.º 14
0
/*
 * __snap_get_name --
 *	Return the cookie associated with a file's named snapshot.
 */
static int
__snap_get_name(WT_SESSION_IMPL *session,
    const char *name, const char *config, WT_ITEM *addr)
{
	WT_CONFIG snapconf;
	WT_CONFIG_ITEM a, k, v;

	WT_RET(__wt_config_getones(session, config, "snapshot", &v));
	WT_RET(__wt_config_subinit(session, &snapconf, &v));
	while (__wt_config_next(&snapconf, &k, &v) == 0)
		if (strlen(name) == k.len && strncmp(name, k.str, k.len) == 0) {
			WT_RET(__wt_config_subgets(session, &v, "addr", &a));
			WT_RET(__wt_nhex_to_raw(session, a.str, a.len, addr));
			return (0);
		}
	return (WT_NOTFOUND);
}
Exemplo n.º 15
0
/*
 * __wt_config_gets_def --
 *	Performance hack: skip parsing config strings by hard-coding defaults.
 *
 *	It's expensive to repeatedly parse configuration strings, so don't do
 *	it unless it's necessary in performance paths like cursor creation.
 *	Assume the second configuration string is the application's
 *	configuration string, and if it's not set (which is true most of the
 *	time), then use the supplied default value.  This makes it faster to
 *	open cursors when checking for obscure open configuration strings like
 *	"next_random".
 */
int
__wt_config_gets_def(WT_SESSION_IMPL *session,
    const char **cfg, const char *key, int def, WT_CONFIG_ITEM *value)
{
	static const WT_CONFIG_ITEM false_value = {
		"", 0, 0, WT_CONFIG_ITEM_NUM
	};

	*value = false_value;
	value->val = def;
	if (cfg == NULL || cfg[0] == NULL || cfg[1] == NULL)
		return (0);
	else if (cfg[2] == NULL)
		WT_RET_NOTFOUND_OK(
		    __wt_config_getones(session, cfg[1], key, value));
	return (__wt_config_gets(session, cfg, key, value));
}
Exemplo n.º 16
0
/*
 * __wt_config_upgrade --
 *	Upgrade a configuration string by appended the replacement version.
 */
int
__wt_config_upgrade(WT_SESSION_IMPL *session, WT_ITEM *buf)
{
	WT_CONFIG_ITEM v;
	const char *config;

	config = buf->data;

	/*
	 * wiredtiger_open:
	 *	lsm_merge=boolean -> lsm_manager=(merge=boolean)
	 */
	if (__wt_config_getones(
	    session, config, "lsm_merge", &v) != WT_NOTFOUND)
		WT_RET(__wt_buf_catfmt(session, buf,
		    ",lsm_manager=(merge=%s)", v.val ? "true" : "false"));

	return (0);
}
Exemplo n.º 17
0
static int
__create_data_source(WT_SESSION_IMPL *session,
    const char *uri, const char *config, WT_DATA_SOURCE *dsrc)
{
	WT_CONFIG_ITEM cval;
	const char *cfg[] = {
	    WT_CONFIG_BASE(session, session_create), config, NULL };

	/*
	 * User-specified collators aren't supported for data-source objects.
	 */
	if (__wt_config_getones(
	    session, config, "collator", &cval) != WT_NOTFOUND)
		WT_RET_MSG(session, EINVAL,
		    "WT_DATA_SOURCE objects do not support WT_COLLATOR "
		    "ordering");

	return (dsrc->create(dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg));
}
Exemplo n.º 18
0
/*
 * __ckpt_named --
 *	Return the information associated with a file's named checkpoint.
 */
static int
__ckpt_named(WT_SESSION_IMPL *session,
    const char *checkpoint, const char *config, WT_CKPT *ckpt)
{
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM k, v;

	WT_RET(__wt_config_getones(session, config, "checkpoint", &v));
	WT_RET(__wt_config_subinit(session, &ckptconf, &v));

	/*
	 * Take the first match: there should never be more than a single
	 * checkpoint of any name.
	 */
	while (__wt_config_next(&ckptconf, &k, &v) == 0)
		if (WT_STRING_MATCH(checkpoint, k.str, k.len))
			return (__ckpt_load(session, &k, &v, ckpt));

	return (WT_NOTFOUND);
}
Exemplo n.º 19
0
/*
 * __wt_schema_create --
 *	Process a WT_SESSION::create operation for all supported types.
 */
int
__wt_schema_create(
    WT_SESSION_IMPL *session, const char *uri, const char *config)
{
	WT_CONFIG_ITEM cval;
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	int exclusive;

	exclusive = (
	    __wt_config_getones(session, config, "exclusive", &cval) == 0 &&
	    cval.val != 0);

	/*
	 * We track create operations: if we fail in the middle of creating a
	 * complex object, we want to back it all out.
	 */
	WT_RET(__wt_meta_track_on(session));

	if (WT_PREFIX_MATCH(uri, "colgroup:"))
		ret = __create_colgroup(session, uri, exclusive, config);
	else if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __create_file(session, uri, exclusive, config);
	else if (WT_PREFIX_MATCH(uri, "lsm:"))
		ret = __wt_lsm_tree_create(session, uri, exclusive, config);
	else if (WT_PREFIX_MATCH(uri, "index:"))
		ret = __create_index(session, uri, exclusive, config);
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __create_table(session, uri, exclusive, config);
	else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL)
		ret = dsrc->create == NULL ?
		    __wt_object_unsupported(session, uri) :
		    __create_data_source(session, uri, config, dsrc);
	else
		ret = __wt_bad_object_type(session, uri);

	session->dhandle = NULL;
	WT_TRET(__wt_meta_track_off(session, 1, ret != 0));

	return (ret);
}
Exemplo n.º 20
0
/*
 * __ckpt_last_name --
 *	Return the name associated with the file's last unnamed checkpoint.
 */
static int
__ckpt_last_name(
    WT_SESSION_IMPL *session, const char *config, const char **namep)
{
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM a, k, v;
	WT_DECL_RET;
	int64_t found;

	*namep = NULL;

	WT_ERR(__wt_config_getones(session, config, "checkpoint", &v));
	WT_ERR(__wt_config_subinit(session, &ckptconf, &v));
	for (found = 0; __wt_config_next(&ckptconf, &k, &v) == 0;) {
		/*
		 * We only care about unnamed checkpoints; applications may not
		 * use any matching prefix as a checkpoint name, the comparison
		 * is pretty simple.
		 */
		if (k.len < strlen(WT_CHECKPOINT) ||
		    strncmp(k.str, WT_CHECKPOINT, strlen(WT_CHECKPOINT)) != 0)
			continue;

		/* Ignore checkpoints before the ones we've already seen. */
		WT_ERR(__wt_config_subgets(session, &v, "order", &a));
		if (found && a.val < found)
			continue;

		if (*namep != NULL)
			__wt_free(session, *namep);
		WT_ERR(__wt_strndup(session, k.str, k.len, namep));
		found = a.val;
	}
	if (!found)
		ret = WT_NOTFOUND;

	if (0) {
err:		__wt_free(session, namep);
	}
	return (ret);
}
Exemplo n.º 21
0
/*
 * __wt_txn_reconfigure --
 *	WT_SESSION::reconfigure for transactions.
 */
int
__wt_txn_reconfigure(WT_SESSION_IMPL *session, const char *config)
{
	WT_CONFIG_ITEM cval;
	WT_DECL_RET;
	WT_TXN *txn;

	txn = &session->txn;

	ret = __wt_config_getones(session, config, "isolation", &cval);
	if (ret == 0 && cval.len != 0) {
		session->isolation = txn->isolation =
		    WT_STRING_MATCH("snapshot", cval.str, cval.len) ?
		    WT_ISO_SNAPSHOT :
		    WT_STRING_MATCH("read-uncommitted", cval.str, cval.len) ?
		    WT_ISO_READ_UNCOMMITTED : WT_ISO_READ_COMMITTED;
	}
	WT_RET_NOTFOUND_OK(ret);

	return (0);
}
Exemplo n.º 22
0
/*
 * __ckpt_last --
 *	Return the information associated with the file's last checkpoint.
 */
static int
__ckpt_last(WT_SESSION_IMPL *session, const char *config, WT_CKPT *ckpt)
{
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM a, k, v;
	int64_t found;

	WT_RET(__wt_config_getones(session, config, "checkpoint", &v));
	WT_RET(__wt_config_subinit(session, &ckptconf, &v));
	for (found = 0; __wt_config_next(&ckptconf, &k, &v) == 0;) {
		/* Ignore checkpoints before the ones we've already seen. */
		WT_RET(__wt_config_subgets(session, &v, "order", &a));
		if (found) {
			if (a.val < found)
				continue;
			__wt_meta_checkpoint_free(session, ckpt);
		}
		found = a.val;
		WT_RET(__ckpt_load(session, &k, &v, ckpt));
	}

	return (found ? 0 : WT_NOTFOUND);
}
Exemplo n.º 23
0
/*
 * __wt_config_gets_def --
 *	Performance hack: skip parsing config strings by hard-coding defaults.
 *
 *	It's expensive to repeatedly parse configuration strings, so don't do
 *	it unless it's necessary in performance paths like cursor creation.
 *	Assume the second configuration string is the application's
 *	configuration string, and if it's not set (which is true most of the
 *	time), then use the supplied default value.  This makes it faster to
 *	open cursors when checking for obscure open configuration strings like
 *	"next_random".
 */
int
__wt_config_gets_def(WT_SESSION_IMPL *session,
    const char **cfg, const char *key, int def, WT_CONFIG_ITEM *value)
{
	WT_CONFIG_ITEM_STATIC_INIT(false_value);
	const char **end;

	*value = false_value;
	value->val = def;

	if (cfg == NULL)
		return (0);

	/*
	 * Checking the "length" of the pointer array is a little odd, but it's
	 * deliberate. The reason is because we pass variable length arrays of
	 * pointers as the configuration argument, some of which have only one
	 * element and the NULL termination. Static analyzers (like Coverity)
	 * complain if we read from an offset past the end of the array, even
	 * if we check there's no NULL slots before the offset.
	 */
	for (end = cfg; *end != NULL; ++end)
		;
	switch ((int)(end - cfg)) {
	case 0:				/* cfg[0] == NULL */
	case 1:				/* cfg[1] == NULL */
		return (0);
	case 2:				/* cfg[2] == NULL */
		WT_RET_NOTFOUND_OK(
		    __wt_config_getones(session, cfg[1], key, value));
		return (0);
	default:
		return (__wt_config_gets(session, cfg, key, value));
	}
	/* NOTREACHED */
}
Exemplo n.º 24
0
/*
 * __ckpt_named_addr --
 *	Return the cookie associated with a file's named checkpoint.
 */
static int
__ckpt_named_addr(WT_SESSION_IMPL *session,
    const char *checkpoint, const char *config, WT_ITEM *addr)
{
	WT_CONFIG ckptconf;
	WT_CONFIG_ITEM a, k, v;

	WT_RET(__wt_config_getones(session, config, "checkpoint", &v));
	WT_RET(__wt_config_subinit(session, &ckptconf, &v));

	/*
	 * Take the first match: there should never be more than a single
	 * checkpoint of any name.
	 */
	while (__wt_config_next(&ckptconf, &k, &v) == 0)
		if (WT_STRING_MATCH(checkpoint, k.str, k.len)) {
			WT_RET(__wt_config_subgets(session, &v, "addr", &a));
			if (a.len != 0)
				WT_RET(__wt_nhex_to_raw(
				    session, a.str, a.len, addr));
			return (0);
		}
	return (WT_NOTFOUND);
}
Exemplo n.º 25
0
/*
 * __schema_open_table --
 *	Open a named table (internal version).
 */
static int
__schema_open_table(WT_SESSION_IMPL *session,
    const char *name, size_t namelen, bool ok_incomplete, WT_TABLE **tablep)
{
	WT_CONFIG cparser;
	WT_CONFIG_ITEM ckey, cval;
	WT_CURSOR *cursor;
	WT_DECL_ITEM(buf);
	WT_DECL_RET;
	WT_TABLE *table;
	const char *tconfig;
	char *tablename;

	cursor = NULL;
	table = NULL;
	tablename = NULL;

	WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE));

	WT_ERR(__wt_scr_alloc(session, 0, &buf));
	WT_ERR(__wt_buf_fmt(session, buf, "table:%.*s", (int)namelen, name));
	WT_ERR(__wt_strndup(session, buf->data, buf->size, &tablename));

	WT_ERR(__wt_metadata_cursor(session, &cursor));
	cursor->set_key(cursor, tablename);
	WT_ERR(cursor->search(cursor));
	WT_ERR(cursor->get_value(cursor, &tconfig));

	WT_ERR(__wt_calloc_one(session, &table));
	table->name = tablename;
	tablename = NULL;
	table->name_hash = __wt_hash_city64(name, namelen);

	WT_ERR(__wt_config_getones(session, tconfig, "columns", &cval));

	WT_ERR(__wt_config_getones(session, tconfig, "key_format", &cval));
	WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->key_format));
	WT_ERR(__wt_config_getones(session, tconfig, "value_format", &cval));
	WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->value_format));
	WT_ERR(__wt_strdup(session, tconfig, &table->config));

	/* Point to some items in the copy to save re-parsing. */
	WT_ERR(__wt_config_getones(session, table->config,
	    "columns", &table->colconf));

	/*
	 * Count the number of columns: tables are "simple" if the columns
	 * are not named.
	 */
	WT_ERR(__wt_config_subinit(session, &cparser, &table->colconf));
	table->is_simple = true;
	while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0)
		table->is_simple = false;
	if (ret != WT_NOTFOUND)
		goto err;

	/* Check that the columns match the key and value formats. */
	if (!table->is_simple)
		WT_ERR(__wt_schema_colcheck(session,
		    table->key_format, table->value_format, &table->colconf,
		    &table->nkey_columns, NULL));

	WT_ERR(__wt_config_getones(session, table->config,
	    "colgroups", &table->cgconf));

	/* Count the number of column groups. */
	WT_ERR(__wt_config_subinit(session, &cparser, &table->cgconf));
	table->ncolgroups = 0;
	while ((ret = __wt_config_next(&cparser, &ckey, &cval)) == 0)
		++table->ncolgroups;
	if (ret != WT_NOTFOUND)
		goto err;

	if (table->ncolgroups > 0 && table->is_simple)
		WT_ERR_MSG(session, EINVAL,
		    "%s requires a table with named columns", tablename);

	WT_ERR(__wt_calloc_def(session, WT_COLGROUPS(table), &table->cgroups));
	WT_ERR(__wt_schema_open_colgroups(session, table));

	if (!ok_incomplete && !table->cg_complete)
		WT_ERR_MSG(session, EINVAL, "'%s' cannot be used "
		    "until all column groups are created",
		    table->name);

	/* Copy the schema generation into the new table. */
	table->schema_gen = S2C(session)->schema_gen;

	*tablep = table;

	if (0) {
err:		WT_TRET(__wt_schema_destroy_table(session, &table));
	}
	WT_TRET(__wt_metadata_cursor_release(session, &cursor));

	__wt_free(session, tablename);
	__wt_scr_free(session, &buf);
	return (ret);
}
Exemplo n.º 26
0
/*
 * __wt_schema_open_colgroups --
 *	Open the column groups for a table.
 */
int
__wt_schema_open_colgroups(WT_SESSION_IMPL *session, WT_TABLE *table)
{
	WT_COLGROUP *colgroup;
	WT_CONFIG cparser;
	WT_CONFIG_ITEM ckey, cval;
	WT_DECL_RET;
	WT_DECL_ITEM(buf);
	char *cgconfig;
	u_int i;

	WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE));

	if (table->cg_complete)
		return (0);

	colgroup = NULL;
	cgconfig = NULL;

	WT_RET(__wt_scr_alloc(session, 0, &buf));

	WT_ERR(__wt_config_subinit(session, &cparser, &table->cgconf));

	/* Open each column group. */
	for (i = 0; i < WT_COLGROUPS(table); i++) {
		if (table->ncolgroups > 0)
			WT_ERR(__wt_config_next(&cparser, &ckey, &cval));
		else
			WT_CLEAR(ckey);

		/*
		 * Always open from scratch: we may have failed part of the way
		 * through opening a table, or column groups may have changed.
		 */
		__wt_schema_destroy_colgroup(session, &table->cgroups[i]);

		WT_ERR(__wt_buf_init(session, buf, 0));
		WT_ERR(__wt_schema_colgroup_name(session, table,
		    ckey.str, ckey.len, buf));
		if ((ret = __wt_metadata_search(
		    session, buf->data, &cgconfig)) != 0) {
			/* It is okay if the table is incomplete. */
			if (ret == WT_NOTFOUND)
				ret = 0;
			goto err;
		}

		WT_ERR(__wt_calloc_one(session, &colgroup));
		WT_ERR(__wt_strndup(
		    session, buf->data, buf->size, &colgroup->name));
		colgroup->config = cgconfig;
		cgconfig = NULL;
		WT_ERR(__wt_config_getones(session,
		    colgroup->config, "columns", &colgroup->colconf));
		WT_ERR(__wt_config_getones(
		    session, colgroup->config, "source", &cval));
		WT_ERR(__wt_strndup(
		    session, cval.str, cval.len, &colgroup->source));
		table->cgroups[i] = colgroup;
		colgroup = NULL;
	}

	if (!table->is_simple) {
		WT_ERR(__wt_table_check(session, table));

		WT_ERR(__wt_buf_init(session, buf, 0));
		WT_ERR(__wt_struct_plan(session,
		    table, table->colconf.str, table->colconf.len, true, buf));
		WT_ERR(__wt_strndup(
		    session, buf->data, buf->size, &table->plan));
	}

	table->cg_complete = true;

err:	__wt_scr_free(session, &buf);
	__wt_schema_destroy_colgroup(session, &colgroup);
	if (cgconfig != NULL)
		__wt_free(session, cgconfig);
	return (ret);
}
Exemplo n.º 27
0
/*
 * __open_index --
 *	Open an index.
 */
static int
__open_index(WT_SESSION_IMPL *session, WT_TABLE *table, WT_INDEX *idx)
{
	WT_CONFIG colconf;
	WT_CONFIG_ITEM ckey, cval, metadata;
	WT_DECL_ITEM(buf);
	WT_DECL_ITEM(plan);
	WT_DECL_RET;
	u_int npublic_cols, i;

	WT_ERR(__wt_scr_alloc(session, 0, &buf));

	/* Get the data source from the index config. */
	WT_ERR(__wt_config_getones(session, idx->config, "source", &cval));
	WT_ERR(__wt_strndup(session, cval.str, cval.len, &idx->source));

	WT_ERR(__wt_config_getones(session, idx->config, "immutable", &cval));
	if (cval.val)
		F_SET(idx, WT_INDEX_IMMUTABLE);

	/*
	 * Compatibility: we didn't always maintain collator information in
	 * index metadata, cope when it isn't found.
	 */
	WT_CLEAR(cval);
	WT_ERR_NOTFOUND_OK(__wt_config_getones(
	    session, idx->config, "collator", &cval));
	if (cval.len != 0) {
		WT_CLEAR(metadata);
		WT_ERR_NOTFOUND_OK(__wt_config_getones(
		    session, idx->config, "app_metadata", &metadata));
		WT_ERR(__wt_collator_config(
		    session, idx->name, &cval, &metadata,
		    &idx->collator, &idx->collator_owned));
	}

	WT_ERR(__wt_extractor_config(
	    session, idx->name, idx->config, &idx->extractor,
	    &idx->extractor_owned));

	WT_ERR(__wt_config_getones(session, idx->config, "key_format", &cval));
	WT_ERR(__wt_strndup(session, cval.str, cval.len, &idx->key_format));

	/*
	 * The key format for an index is somewhat subtle: the application
	 * specifies a set of columns that it will use for the key, but the
	 * engine usually adds some hidden columns in order to derive the
	 * primary key.  These hidden columns are part of the file's key.
	 *
	 * The file's key_format is stored persistently, we need to calculate
	 * the index cursor key format (which will usually omit some of those
	 * keys).
	 */
	WT_ERR(__wt_buf_init(session, buf, 0));
	WT_ERR(__wt_config_getones(
	    session, idx->config, "columns", &idx->colconf));

	/* Start with the declared index columns. */
	WT_ERR(__wt_config_subinit(session, &colconf, &idx->colconf));
	for (npublic_cols = 0;
	    (ret = __wt_config_next(&colconf, &ckey, &cval)) == 0;
	    ++npublic_cols)
		WT_ERR(__wt_buf_catfmt(
		    session, buf, "%.*s,", (int)ckey.len, ckey.str));
	if (ret != WT_NOTFOUND)
		goto err;

	/*
	 * If we didn't find any columns, the index must have an extractor.
	 * We don't rely on this unconditionally because it was only added to
	 * the metadata after version 2.3.1.
	 */
	if (npublic_cols == 0) {
		WT_ERR(__wt_config_getones(
		    session, idx->config, "index_key_columns", &cval));
		npublic_cols = (u_int)cval.val;
		WT_ASSERT(session, npublic_cols != 0);
		for (i = 0; i < npublic_cols; i++)
			WT_ERR(__wt_buf_catfmt(session, buf, "\"bad col\","));
	}

	/*
	 * Now add any primary key columns from the table that are not
	 * already part of the index key.
	 */
	WT_ERR(__wt_config_subinit(session, &colconf, &table->colconf));
	for (i = 0; i < table->nkey_columns &&
	    (ret = __wt_config_next(&colconf, &ckey, &cval)) == 0;
	    i++) {
		/*
		 * If the primary key column is already in the secondary key,
		 * don't add it again.
		 */
		if (__wt_config_subgetraw(
		    session, &idx->colconf, &ckey, &cval) == 0)
			continue;
		WT_ERR(__wt_buf_catfmt(
		    session, buf, "%.*s,", (int)ckey.len, ckey.str));
	}
	WT_ERR_NOTFOUND_OK(ret);

	/*
	 * If the table doesn't yet have its column groups, don't try to
	 * calculate a plan: we are just checking that the index creation is
	 * sane.
	 */
	if (!table->cg_complete)
		goto err;

	WT_ERR(__wt_scr_alloc(session, 0, &plan));
	WT_ERR(__wt_struct_plan(
	    session, table, buf->data, buf->size, false, plan));
	WT_ERR(__wt_strndup(session, plan->data, plan->size, &idx->key_plan));

	/* Set up the cursor key format (the visible columns). */
	WT_ERR(__wt_buf_init(session, buf, 0));
	WT_ERR(__wt_struct_truncate(session,
	    idx->key_format, npublic_cols, buf));
	WT_ERR(__wt_strndup(
	    session, buf->data, buf->size, &idx->idxkey_format));

	/*
	 * Add a trailing padding byte to the format.  This ensures that there
	 * will be no special optimization of the last column, so the primary
	 * key columns can be simply appended.
	 */
	WT_ERR(__wt_buf_catfmt(session, buf, "x"));
	WT_ERR(__wt_strndup(session, buf->data, buf->size, &idx->exkey_format));

	/* By default, index cursor values are the table value columns. */
	/* TODO Optimize to use index columns in preference to table lookups. */
	WT_ERR(__wt_buf_init(session, plan, 0));
	WT_ERR(__wt_struct_plan(session,
	    table, table->colconf.str, table->colconf.len, true, plan));
	WT_ERR(__wt_strndup(session, plan->data, plan->size, &idx->value_plan));

err:	__wt_scr_free(session, &buf);
	__wt_scr_free(session, &plan);
	return (ret);
}
Exemplo n.º 28
0
/*
 * __rename_tree --
 *	Rename an index or colgroup reference.
 */
static int
__rename_tree(WT_SESSION_IMPL *session,
    WT_TABLE *table, const char *newuri, const char *name, const char *cfg[])
{
	WT_CONFIG_ITEM cval;
	WT_DECL_ITEM(nn);
	WT_DECL_ITEM(ns);
	WT_DECL_ITEM(nv);
	WT_DECL_ITEM(os);
	WT_DECL_RET;
	bool is_colgroup;
	const char *newname, *olduri, *suffix;
	char *value;

	olduri = table->name;
	value = NULL;

	newname = newuri;
	(void)WT_PREFIX_SKIP(newname, "table:");

	/*
	 * Create the new data source URI and update the schema value.
	 *
	 * 'name' has the format (colgroup|index):<tablename>[:<suffix>];
	 * we need the suffix.
	 */
	is_colgroup = WT_PREFIX_MATCH(name, "colgroup:");
	if (!is_colgroup && !WT_PREFIX_MATCH(name, "index:"))
		WT_ERR_MSG(session, EINVAL,
		    "expected a 'colgroup:' or 'index:' source: '%s'", name);

	suffix = strchr(name, ':');
	/* An existing table should have a well formed name. */
	WT_ASSERT(session, suffix != NULL);
	suffix = strchr(suffix + 1, ':');

	WT_ERR(__wt_scr_alloc(session, 0, &nn));
	WT_ERR(__wt_buf_fmt(session, nn, "%s%s%s",
	    is_colgroup ? "colgroup:" : "index:",
	    newname,
	    (suffix == NULL) ? "" : suffix));

	/* Skip the colon, if any. */
	if (suffix != NULL)
		++suffix;

	/* Read the old schema value. */
	WT_ERR(__wt_metadata_search(session, name, &value));

	/*
	 * Calculate the new data source URI.  Use the existing table structure
	 * and substitute the new name temporarily.
	 */
	WT_ERR(__wt_scr_alloc(session, 0, &ns));
	table->name = newuri;
	if (is_colgroup)
		WT_ERR(__wt_schema_colgroup_source(
		    session, table, suffix, value, ns));
	else
		WT_ERR(__wt_schema_index_source(
		    session, table, suffix, value, ns));

	if ((ret = __wt_config_getones(session, value, "source", &cval)) != 0)
		WT_ERR_MSG(session, EINVAL,
		    "index or column group has no data source: %s", value);

	/* Take a copy of the old data source. */
	WT_ERR(__wt_scr_alloc(session, 0, &os));
	WT_ERR(__wt_buf_fmt(session, os, "%.*s", (int)cval.len, cval.str));

	/* Overwrite it with the new data source. */
	WT_ERR(__wt_scr_alloc(session, 0, &nv));
	WT_ERR(__wt_buf_fmt(session, nv, "%.*s%s%s",
	    (int)WT_PTRDIFF(cval.str, value), value,
	    (const char *)ns->data, cval.str + cval.len));

	/*
	 * Do the rename before updating the metadata to avoid leaving the
	 * metadata inconsistent if the rename fails.
	 */
	WT_ERR(__wt_schema_rename(session, os->data, ns->data, cfg));

	/*
	 * Remove the old metadata entry.
	 * Insert the new metadata entry.
	 */
	WT_ERR(__wt_metadata_remove(session, name));
	WT_ERR(__wt_metadata_insert(session, nn->data, nv->data));

err:	__wt_scr_free(session, &nn);
	__wt_scr_free(session, &ns);
	__wt_scr_free(session, &nv);
	__wt_scr_free(session, &os);
	__wt_free(session, value);
	table->name = olduri;
	return (ret);
}
Exemplo n.º 29
0
/*
 * dump_table_config_complex --
 *	Dump the column groups or indices for a table.
 */
static int
dump_table_config_complex(WT_SESSION *session, WT_CURSOR *cursor,
    WT_CURSOR *srch, const char *name, const char *entry, bool json)
{
	WT_CONFIG_ITEM cval;
	WT_DECL_RET;
	bool multiple;
	const char *groupname, *key, *sep;
	size_t len;
	int exact;
	const char *v;
	char *p, *cfg[3] = {NULL, NULL, NULL};

	multiple = false;
	sep = "";

	if (json) {
		if (strcmp(entry, "colgroup:") == 0) {
			groupname = "colgroups";
			sep = ",";
		} else {
			groupname = "indices";
		}
		if (printf("            \"%s\" : [", groupname) < 0)
			return (util_err(session, EIO, NULL));
	}
	/*
	 * Search the file looking for column group and index key/value pairs:
	 * for each one, look up the related source information and append it
	 * to the base record, where the column group and index configuration
	 * overrides the source configuration.
	 */
	cursor->set_key(cursor, entry);
	if ((ret = cursor->search_near(cursor, &exact)) != 0) {
		if (ret == WT_NOTFOUND)
			return (0);
		return (util_cerr(cursor, "search_near", ret));
	}
	if (exact >= 0)
		goto match;
	while ((ret = cursor->next(cursor)) == 0) {
match:		if ((ret = cursor->get_key(cursor, &key)) != 0)
			return (util_cerr(cursor, "get_key", ret));

		/* Check if we've finished the list of entries. */
		if (!WT_PREFIX_MATCH(key, entry))
			break;

		/*
		 * Check for a table name match. This test will match "simple"
		 * table column-groups as well as the more complex ones, but
		 * the previous version of the test was wrong and we're only
		 * in this function in the case of complex tables.
		 */
		if (!WT_PREFIX_MATCH(key + strlen(entry), name))
			continue;

		/* Get the value. */
		if ((ret = cursor->get_value(cursor, &v)) != 0)
			return (util_cerr(cursor, "get_value", ret));
		if ((cfg[1] = strdup(v)) == NULL)
			return (util_err(session, errno, NULL));

		/* Crack it and get the underlying source. */
		if ((ret = __wt_config_getones(
		    (WT_SESSION_IMPL *)session, cfg[1], "source", &cval)) != 0)
			return (
			    util_err(session, ret, "%s: source entry", key));

		/* Nul-terminate the source entry. */
		len = cval.len + 10;
		if ((p = malloc(len)) == NULL)
			return (util_err(session, errno, NULL));
		(void)snprintf(p, len, "%.*s", (int)cval.len, cval.str);
		srch->set_key(srch, p);
		if ((ret = srch->search(srch)) != 0)
			ret = util_err(session, ret, "%s: %s", key, p);
		free(p);
		if (ret != 0)
			return (1);

		/* Get the source's value. */
		if ((ret = srch->get_value(srch, &v)) != 0)
			return (util_cerr(cursor, "get_value", ret));
		if ((cfg[0] = strdup(v)) == NULL)
			return (util_err(session, errno, NULL));

		if (json && printf("%s\n", multiple ? "," : "") < 0)
			return (util_err(session, EIO, NULL));
		/*
		 * The dumped configuration string is the original key plus the
		 * source's configuration, where the values of the original key
		 * override any source configurations of the same name.
		 */
		if (print_config(session, key, cfg, json, false) != 0)
			return (util_err(session, EIO, NULL));
		multiple = true;
	}
	if (json && printf("\n            ]%s\n", sep) < 0)
		return (util_err(session, EIO, NULL));
	free(cfg[0]);
	free(cfg[1]);

	if (ret == 0 || ret == WT_NOTFOUND)
		return (0);
	return (util_cerr(cursor, "next", ret));
}
Exemplo n.º 30
0
/*
 * dump_table_config --
 *	Dump the config for a table.
 */
static int
dump_table_config(
    WT_SESSION *session, WT_CURSOR *cursor, const char *uri, bool json)
{
	WT_CONFIG_ITEM cval;
	WT_CURSOR *srch;
	WT_DECL_RET;
	size_t len;
	int tret;
	bool complex_table;
	const char *name, *v;
	char *p, **cfg, *_cfg[4] = {NULL, NULL, NULL, NULL};

	p = NULL;
	cfg = &_cfg[3];

	/* Get the table name. */
	if ((name = strchr(uri, ':')) == NULL) {
		fprintf(stderr, "%s: %s: corrupted uri\n", progname, uri);
		return (1);
	}
	++name;

	/*
	 * Dump out the config information: first, dump the uri entry itself,
	 * it overrides all subsequent configurations.
	 */
	cursor->set_key(cursor, uri);
	if ((ret = cursor->search(cursor)) != 0)
		WT_ERR(util_cerr(cursor, "search", ret));
	if ((ret = cursor->get_value(cursor, &v)) != 0)
		WT_ERR(util_cerr(cursor, "get_value", ret));
	if ((*--cfg = strdup(v)) == NULL)
		WT_ERR(util_err(session, errno, NULL));

	/*
	 * Workaround for WiredTiger "simple" table handling. Simple tables
	 * have column-group entries, but they aren't listed in the metadata's
	 * table entry, and the name is different from other column-groups.
	 * Figure out if it's a simple table and in that case, retrieve the
	 * column-group's configuration value and the column-group's "source"
	 * entry, where the column-group entry overrides the source's.
	 */
	complex_table = false;
	if (WT_PREFIX_MATCH(uri, "table:")) {
		len = strlen("colgroup:") + strlen(name) + 1;
		if ((p = malloc(len)) == NULL)
			WT_ERR(util_err(session, errno, NULL));
		(void)snprintf(p, len, "colgroup:%s", name);
		cursor->set_key(cursor, p);
		if ((ret = cursor->search(cursor)) == 0) {
			if ((ret = cursor->get_value(cursor, &v)) != 0)
				WT_ERR(util_cerr(cursor, "get_value", ret));
			if ((*--cfg = strdup(v)) == NULL)
				WT_ERR(util_err(session, errno, NULL));
			if ((ret =__wt_config_getones(
			    (WT_SESSION_IMPL *)session,
			    *cfg, "source", &cval)) != 0)
				WT_ERR(util_err(
				    session, ret, "%s: source entry", p));
			free(p);
			len = cval.len + 10;
			if ((p = malloc(len)) == NULL)
				WT_ERR(util_err(session, errno, NULL));
			(void)snprintf(p, len, "%.*s", (int)cval.len, cval.str);
			cursor->set_key(cursor, p);
			if ((ret = cursor->search(cursor)) != 0)
				WT_ERR(util_cerr(cursor, "search", ret));
			if ((ret = cursor->get_value(cursor, &v)) != 0)
				WT_ERR(util_cerr(cursor, "get_value", ret));
			if ((*--cfg = strdup(v)) == NULL)
				WT_ERR(util_err(session, errno, NULL));
		} else
			complex_table = true;
	}

	WT_ERR(print_config(session, uri, cfg, json, true));

	if (complex_table) {
		/*
		 * The underlying table configuration function needs a second
		 * cursor: open one before calling it, it makes error handling
		 * hugely simpler.
		 */
		if ((ret = session->open_cursor(
		    session, "metadata:", NULL, NULL, &srch)) != 0)
			WT_ERR(util_cerr(cursor, "open_cursor", ret));

		if ((ret = dump_table_config_complex(
		    session, cursor, srch, name, "colgroup:", json)) == 0)
			ret = dump_table_config_complex(
			    session, cursor, srch, name, "index:", json);

		if ((tret = srch->close(srch)) != 0) {
			tret = util_cerr(cursor, "close", tret);
			if (ret == 0)
				ret = tret;
		}
	} else if (json && printf(
		    "            \"colgroups\" : [],\n"
		    "            \"indices\" : []\n") < 0)
		WT_ERR(util_cerr(cursor, NULL, EIO));

err:	free(p);
	free(_cfg[0]);
	free(_cfg[1]);
	free(_cfg[2]);
	return (ret);
}