Beispiel #1
0
/*
 * __wt_schema_truncate --
 *	WT_SESSION::truncate without a range.
 */
int
__wt_schema_truncate(
    WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
{
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	const char *tablename;

	tablename = uri;

	if (WT_PREFIX_MATCH(uri, "file:")) {
		ret = __truncate_file(session, uri);
	} else if (WT_PREFIX_MATCH(uri, "lsm:"))
		ret = __wt_lsm_tree_truncate(session, uri, cfg);
	else if (WT_PREFIX_SKIP(tablename, "table:"))
		ret = __truncate_table(session, tablename, cfg);
	else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL)
		ret = dsrc->truncate == NULL ?
		    __truncate_dsrc(session, uri) :
		    dsrc->truncate(
		    dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg);
	else
		ret = __wt_bad_object_type(session, uri);

	/* If we didn't find a metadata entry, map that error to ENOENT. */
	return (ret == WT_NOTFOUND ? ENOENT : ret);
}
Beispiel #2
0
/*
 * __session_open_cursor --
 *	WT_SESSION->open_cursor method.
 */
static int
__session_open_cursor(WT_SESSION *wt_session,
    const char *uri, WT_CURSOR *to_dup, const char *config, WT_CURSOR **cursorp)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;
	SESSION_API_CALL(session, open_cursor, config, cfg);

	if ((to_dup == NULL && uri == NULL) || (to_dup != NULL && uri != NULL))
		WT_ERR_MSG(session, EINVAL,
		    "should be passed either a URI or a cursor to duplicate, "
		    "but not both");

	if (to_dup != NULL) {
		uri = to_dup->uri;
		if (WT_PREFIX_MATCH(uri, "colgroup:") ||
		    WT_PREFIX_MATCH(uri, "index:") ||
		    WT_PREFIX_MATCH(uri, "file:") ||
		    WT_PREFIX_MATCH(uri, "lsm:") ||
		    WT_PREFIX_MATCH(uri, "table:"))
			ret = __wt_cursor_dup(session, to_dup, cfg, cursorp);
		else
			ret = __wt_bad_object_type(session, uri);
	} else
		ret = __wt_open_cursor(session, uri, NULL, cfg, cursorp);

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #3
0
/*
 * __curfile_equals --
 *	WT_CURSOR->equals method for the btree cursor type.
 */
static int
__curfile_equals(WT_CURSOR *a, WT_CURSOR *b, int *equalp)
{
	WT_CURSOR_BTREE *cbt;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	cbt = (WT_CURSOR_BTREE *)a;
	CURSOR_API_CALL(a, session, equals, cbt->btree);

	/*
	 * Check both cursors are a "file:" type then call the underlying
	 * function, it can handle cursors pointing to different objects.
	 */
	if (!WT_PREFIX_MATCH(a->internal_uri, "file:") ||
	    !WT_PREFIX_MATCH(b->internal_uri, "file:"))
		WT_ERR_MSG(session, EINVAL,
		    "Cursors must reference the same object");

	WT_CURSOR_CHECKKEY(a);
	WT_CURSOR_CHECKKEY(b);

	ret = __wt_btcur_equals(
	    (WT_CURSOR_BTREE *)a, (WT_CURSOR_BTREE *)b, equalp);

err:	API_END_RET(session, ret);
}
Beispiel #4
0
/*
 * __wt_schema_range_truncate --
 *	WT_SESSION::truncate with a range.
 */
int
__wt_schema_range_truncate(
    WT_SESSION_IMPL *session, WT_CURSOR *start, WT_CURSOR *stop)
{
	WT_CURSOR *cursor;
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	const char *uri;

	cursor = (start != NULL) ? start : stop;
	uri = cursor->internal_uri;

	if (WT_PREFIX_MATCH(uri, "file:"))
		WT_WITH_BTREE(session, ((WT_CURSOR_BTREE *)cursor)->btree,
		    ret = __wt_btcur_range_truncate(
			(WT_CURSOR_BTREE *)start, (WT_CURSOR_BTREE *)stop));
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __wt_table_range_truncate(
		    (WT_CURSOR_TABLE *)start, (WT_CURSOR_TABLE *)stop);
	else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL &&
	    dsrc->range_truncate != NULL)
		ret = dsrc->range_truncate(dsrc, &session->iface, start, stop);
	else
		ret = __wt_range_truncate(start, stop);

	return (ret);
}
Beispiel #5
0
/*
 * __wt_backup_list_uri_append --
 *	Append a new file name to the list, allocate space as necessary.
 *	Called via the schema_worker function.
 */
int
__wt_backup_list_uri_append(
    WT_SESSION_IMPL *session, const char *name, int *skip)
{
	WT_CURSOR_BACKUP *cb;
	char *value;

	cb = session->bkp_cursor;
	WT_UNUSED(skip);

	if (WT_PREFIX_MATCH(name, "log:")) {
		WT_RET(__backup_log_append(session, cb, 0));
		return (0);
	}

	/* Add the metadata entry to the backup file. */
	WT_RET(__wt_metadata_search(session, name, &value));
	WT_RET_TEST(
	    (fprintf(cb->bfp, "%s\n%s\n", name, value) < 0), __wt_errno());
	__wt_free(session, value);

	/* Add file type objects to the list of files to be copied. */
	if (WT_PREFIX_MATCH(name, "file:"))
		WT_RET(__backup_list_append(session, cb, name));

	return (0);
}
Beispiel #6
0
/*通过table的schema信息来统计lsm tree和btree的数量*/
int __wt_compact_uri_analyze(WT_SESSION_IMPL* session, const char* uri, int* skip)
{
	if(WT_PREFIX_MATCH(uri, "lsm:")){
		session->compact->lsm_count++;
		*skip = 1;
	}
	else if(WT_PREFIX_MATCH(uri, "file:"))
		session->compact->file_count++;
	return 0;
}
Beispiel #7
0
/*
 * __wt_schema_drop --
 *	Process a WT_SESSION::drop operation for all supported types.
 */
int
__wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
{
    WT_CONFIG_ITEM cval;
    WT_DATA_SOURCE *dsrc;
    WT_DECL_RET;
    bool force;

    WT_RET(__wt_config_gets_def(session, cfg, "force", 0, &cval));
    force = cval.val != 0;

    WT_RET(__wt_meta_track_on(session));

    /* Paranoia: clear any handle from our caller. */
    session->dhandle = NULL;

    if (WT_PREFIX_MATCH(uri, "colgroup:"))
        ret = __drop_colgroup(session, uri, force, cfg);
    else if (WT_PREFIX_MATCH(uri, "file:"))
        ret = __drop_file(session, uri, force, cfg);
    else if (WT_PREFIX_MATCH(uri, "index:"))
        ret = __drop_index(session, uri, force, cfg);
    else if (WT_PREFIX_MATCH(uri, "lsm:"))
        ret = __wt_lsm_tree_drop(session, uri, cfg);
    else if (WT_PREFIX_MATCH(uri, "table:"))
        ret = __drop_table(session, uri, cfg);
    else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL)
        ret = dsrc->drop == NULL ?
              __wt_object_unsupported(session, uri) :
              dsrc->drop(
                  dsrc, &session->iface, uri, (WT_CONFIG_ARG *)cfg);
    else
        ret = __wt_bad_object_type(session, uri);

    /*
     * Map WT_NOTFOUND to ENOENT, based on the assumption WT_NOTFOUND means
     * there was no metadata entry.  Map ENOENT to zero if force is set.
     */
    if (ret == WT_NOTFOUND || ret == ENOENT)
        ret = force ? 0 : ENOENT;

    /* Bump the schema generation so that stale data is ignored. */
    ++S2C(session)->schema_gen;

    WT_TRET(__wt_meta_track_off(session, true, ret != 0));

    return (ret);
}
Beispiel #8
0
/*
 * __compact_uri_analyze --
 *	Extract information relevant to deciding what work compact needs to
 *	do from a URI that is part of a table schema.
 *	Called via the schema_worker function.
 */
static int
__compact_uri_analyze(WT_SESSION_IMPL *session, const char *uri, bool *skipp)
{
	/*
	 * Add references to schema URI objects to the list of objects to be
	 * compacted.  Skip over LSM trees or we will get false positives on
	 * the "file:" URIs for the chunks.
	 */
	if (WT_PREFIX_MATCH(uri, "lsm:")) {
		session->compact->lsm_count++;
		*skipp = true;
	} else if (WT_PREFIX_MATCH(uri, "file:"))
		session->compact->file_count++;

	return (0);
}
Beispiel #9
0
/*
 * __backup_list_append --
 *	Append a new file name to the list, allocate space as necessary.
 */
static int
__backup_list_append(
    WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri)
{
	char **p;
	const char *name;

	/* Leave a NULL at the end to mark the end of the list. */
	WT_RET(__wt_realloc_def(session, &cb->list_allocated,
	    cb->list_next + 2, &cb->list));
	p = &cb->list[cb->list_next];
	p[0] = p[1] = NULL;

	name = uri;

	/*
	 * If it's a file in the database we need to remove the prefix.
	 */
	if (WT_PREFIX_MATCH(uri, "file:"))
		name += strlen("file:");

	/*
	 * !!!
	 * Assumes metadata file entries map one-to-one to physical files.
	 * To support a block manager where that's not the case, we'd need
	 * to call into the block manager and get a list of physical files
	 * that map to this logical "file".  I'm not going to worry about
	 * that for now, that block manager might not even support physical
	 * copying of files by applications.
	 */
	WT_RET(__wt_strdup(session, name, p));

	++cb->list_next;
	return (0);
}
Beispiel #10
0
/*
 * __recovery_file_scan --
 *	Scan the files referenced from the metadata and gather information
 *	about them for recovery.
 */
static int
__recovery_file_scan(WT_RECOVERY *r)
{
	WT_CURSOR *c;
	WT_DECL_RET;
	int cmp;
	const char *uri, *config;

	/* Scan through all files in the metadata. */
	c = r->files[0].c;
	c->set_key(c, "file:");
	if ((ret = c->search_near(c, &cmp)) != 0) {
		/* Is the metadata empty? */
		WT_RET_NOTFOUND_OK(ret);
		return (0);
	}
	if (cmp < 0)
		WT_RET_NOTFOUND_OK(c->next(c));
	for (; ret == 0; ret = c->next(c)) {
		WT_RET(c->get_key(c, &uri));
		if (!WT_PREFIX_MATCH(uri, "file:"))
			break;
		WT_RET(c->get_value(c, &config));
		WT_RET(__recovery_setup_file(r, uri, config));
	}
	WT_RET_NOTFOUND_OK(ret);
	return (0);
}
Beispiel #11
0
int
__wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
{
	WT_CONFIG_ITEM cval;
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	int force;

	WT_RET(__wt_config_gets_defno(session, cfg, "force", &cval));
	force = (cval.val != 0);

	/* Disallow drops from the WiredTiger name space. */
	WT_RET(__wt_schema_name_check(session, uri));

	WT_RET(__wt_meta_track_on(session));

	/* Be careful to ignore any btree handle in our caller. */
	WT_CLEAR_BTREE_IN_SESSION(session);

	if (WT_PREFIX_MATCH(uri, "colgroup:"))
		ret = __drop_colgroup(session, uri, cfg);
	else if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __drop_file(session, uri, force, cfg);
	else if (WT_PREFIX_MATCH(uri, "index:"))
		ret = __drop_index(session, uri, cfg);
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __drop_table(session, uri, force, cfg);
	else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0)
		ret = dsrc->drop(dsrc, &session->iface, uri, cfg);

	/*
	 * Map WT_NOTFOUND to ENOENT (or to 0 if "force" is set), based on the
	 * assumption WT_NOTFOUND means there was no metadata entry.  The
	 * underlying drop functions should handle this case (we passed them
	 * the "force" value), but better safe than sorry.
	 */
	if (ret == WT_NOTFOUND)
		ret = force ? 0 : ENOENT;

	/* Bump the schema generation so that stale data is ignored. */
	++S2C(session)->schema_gen;

	WT_TRET(__wt_meta_track_off(session, ret != 0));

	return (ret);
}
Beispiel #12
0
/*
 * __wt_schema_rename --
 *	WT_SESSION::rename.
 */
int
__wt_schema_rename(WT_SESSION_IMPL *session,
    const char *uri, const char *newuri, const char *cfg[])
{
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	const char *p, *t;

	/* Disallow renames to/from the WiredTiger name space. */
	WT_RET(__wt_schema_name_check(session, uri));
	WT_RET(__wt_schema_name_check(session, newuri));

	/* The target type must match the source type. */
	for (p = uri, t = newuri; *p == *t && *p != ':'; ++p, ++t)
		;
	if (*p != ':' || *t != ':')
		WT_RET_MSG(session, EINVAL,
		    "rename target type must match URI: %s to %s", uri, newuri);

	/*
	 * We track rename operations, if we fail in the middle, we want to
	 * back it all out.
	 */
	WT_RET(__wt_meta_track_on(session));

	if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __rename_file(session, uri, newuri);
	else if (WT_PREFIX_MATCH(uri, "lsm:"))
		ret = __wt_lsm_tree_rename(session, uri, newuri, cfg);
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __rename_table(session, uri, newuri, cfg);
	else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0)
		ret = dsrc->rename == NULL ?
		    __wt_object_unsupported(session, uri) :
		    dsrc->rename(dsrc, &session->iface,
			uri, newuri, (WT_CONFIG_ARG *)cfg);

	/* Bump the schema generation so that stale data is ignored. */
	++S2C(session)->schema_gen;

	WT_TRET(__wt_meta_track_off(session, ret != 0));

	/* If we didn't find a metadata entry, map that error to ENOENT. */
	return (ret == WT_NOTFOUND ? ENOENT : ret);
}
Beispiel #13
0
/*
 * __wt_open_cursor --
 *	Internal version of WT_SESSION::open_cursor.
 */
int
__wt_open_cursor(WT_SESSION_IMPL *session,
    const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp)
{
	WT_COLGROUP *colgroup;
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;

	if (WT_PREFIX_MATCH(uri, "backup:"))
		ret = __wt_curbackup_open(session, uri, cfg, cursorp);
	else if (WT_PREFIX_MATCH(uri, "colgroup:")) {
		/*
		 * Column groups are a special case: open a cursor on the
		 * underlying data source.
		 */
		WT_RET(__wt_schema_get_colgroup(session, uri, NULL, &colgroup));
		ret = __wt_open_cursor(
		    session, colgroup->source, owner, cfg, cursorp);
	} else if (WT_PREFIX_MATCH(uri, "config:"))
		ret = __wt_curconfig_open(session, uri, cfg, cursorp);
	else if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __wt_curfile_open(session, uri, owner, cfg, cursorp);
	else if (WT_PREFIX_MATCH(uri, "index:"))
		ret = __wt_curindex_open(session, uri, cfg, cursorp);
	else if (WT_PREFIX_MATCH(uri, "statistics:"))
		ret = __wt_curstat_open(session, uri, cfg, cursorp);
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __wt_curtable_open(session, uri, cfg, cursorp);
	else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0)
		ret = dsrc->open_cursor(dsrc, &session->iface,
		    uri, owner, cfg, cursorp);

	return (ret);
}
Beispiel #14
0
/*
 * __backup_uri --
 *	Backup a list of objects.
 */
static int
__backup_uri(WT_SESSION_IMPL *session,
             WT_CURSOR_BACKUP *cb, const char *cfg[], int *foundp, int *log_only)
{
    WT_CONFIG targetconf;
    WT_CONFIG_ITEM cval, k, v;
    WT_DECL_ITEM(tmp);
    WT_DECL_RET;
    int target_list;
    const char *uri;

    *foundp = 0;
    *log_only = 0;

    /*
     * If we find a non-empty target configuration string, we have a job,
     * otherwise it's not our problem.
     */
    WT_RET(__wt_config_gets(session, cfg, "target", &cval));
    WT_RET(__wt_config_subinit(session, &targetconf, &cval));
    for (cb->list_next = 0, target_list = 0;
            (ret = __wt_config_next(&targetconf, &k, &v)) == 0; ++target_list) {
        /* If it is our first time through, allocate. */
        if (target_list == 0) {
            *foundp = 1;
            WT_ERR(__wt_scr_alloc(session, 512, &tmp));
        }

        WT_ERR(__wt_buf_fmt(session, tmp, "%.*s", (int)k.len, k.str));
        uri = tmp->data;
        if (v.len != 0)
            WT_ERR_MSG(session, EINVAL,
                       "%s: invalid backup target: URIs may need quoting",
                       uri);

        /*
         * Handle log targets.  We do not need to go through the
         * schema worker, just call the function to append them.
         * Set log_only only if it is our only URI target.
         */
        if (WT_PREFIX_MATCH(uri, "log:")) {
            if (target_list == 0)
                *log_only = 1;
            else
                *log_only = 0;
            WT_ERR(__wt_backup_list_uri_append(
                       session, uri, NULL));
        } else
            WT_ERR(__wt_schema_worker(session,
                                      uri, NULL, __wt_backup_list_uri_append, cfg, 0));
    }
    WT_ERR_NOTFOUND_OK(ret);

err:
    __wt_scr_free(session, &tmp);
    return (ret);
}
Beispiel #15
0
/*
 * __wt_curfile_open --
 *	WT_SESSION->open_cursor method for the btree cursor type.
 */
int
__wt_curfile_open(WT_SESSION_IMPL *session, const char *uri,
                  WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp)
{
    WT_CONFIG_ITEM cval;
    WT_DECL_RET;
    uint32_t flags;
    bool bitmap, bulk;

    bitmap = bulk = false;
    flags = 0;

    WT_RET(__wt_config_gets_def(session, cfg, "bulk", 0, &cval));
    if (cval.type == WT_CONFIG_ITEM_BOOL ||
            (cval.type == WT_CONFIG_ITEM_NUM &&
             (cval.val == 0 || cval.val == 1))) {
        bitmap = false;
        bulk = cval.val != 0;
    } else if (WT_STRING_MATCH("bitmap", cval.str, cval.len))
        bitmap = bulk = true;
    else
        WT_RET_MSG(session, EINVAL,
                   "Value for 'bulk' must be a boolean or 'bitmap'");

    /* Bulk handles require exclusive access. */
    if (bulk)
        LF_SET(WT_BTREE_BULK | WT_DHANDLE_EXCLUSIVE);

    /* Get the handle and lock it while the cursor is using it. */
    if (WT_PREFIX_MATCH(uri, "file:")) {
        /*
         * If we are opening a bulk cursor, get the handle while
         * holding the checkpoint lock.  This prevents a bulk cursor
         * open failing with EBUSY due to a database-wide checkpoint.
         */
        if (bulk)
            __wt_spin_lock(
                session, &S2C(session)->checkpoint_lock);
        ret = __wt_session_get_btree_ckpt(session, uri, cfg, flags);
        if (bulk)
            __wt_spin_unlock(
                session, &S2C(session)->checkpoint_lock);
        WT_RET(ret);
    } else
        WT_RET(__wt_bad_object_type(session, uri));

    WT_ERR(__wt_curfile_create(session, owner, cfg, bulk, bitmap, cursorp));

    /* Increment the data-source's in-use counter. */
    __wt_cursor_dhandle_incr_use(session);
    return (0);

err:	/* If the cursor could not be opened, release the handle. */
    WT_TRET(__wt_session_release_btree(session));
    return (ret);
}
Beispiel #16
0
/*
 * __meta_btree_apply --
 *	Apply a function to all files listed in the metadata, apart from the
 *	metadata file.
 */
static inline int
__meta_btree_apply(WT_SESSION_IMPL *session, WT_CURSOR *cursor,
    int (*file_func)(WT_SESSION_IMPL *, const char *[]),
    int (*name_func)(WT_SESSION_IMPL *, const char *, bool *),
    const char *cfg[])
{
	WT_DECL_RET;
	int t_ret;
	const char *uri;
	bool skip;

	/*
	 * Accumulate errors but continue through to the end of the metadata.
	 */
	while ((t_ret = cursor->next(cursor)) == 0) {
		if ((t_ret = cursor->get_key(cursor, &uri)) != 0 ||
		    strcmp(uri, WT_METAFILE_URI) == 0) {
			WT_TRET(t_ret);
			continue;
		}

		skip = false;
		if (name_func != NULL &&
		    (t_ret = name_func(session, uri, &skip)) != 0) {
			WT_TRET(t_ret);
			continue;
		}

		if (file_func == NULL || skip || !WT_PREFIX_MATCH(uri, "file:"))
			continue;

		/*
		 * We need to pull the handle into the session handle cache
		 * and make sure it's referenced to stop other internal code
		 * dropping the handle (e.g in LSM when cleaning up obsolete
		 * chunks).  Holding the schema lock isn't enough.
		 *
		 * Handles that are busy are skipped without the whole
		 * operation failing.  This deals among other cases with
		 * checkpoint encountering handles that are locked (e.g., for
		 * bulk loads or verify operations).
		 */
		if ((t_ret = __wt_session_get_dhandle(
		    session, uri, NULL, NULL, 0)) != 0) {
			WT_TRET_BUSY_OK(t_ret);
			continue;
		}

		WT_SAVE_DHANDLE(session, WT_TRET(file_func(session, cfg)));
		WT_TRET(__wt_session_release_dhandle(session));
	}
	WT_TRET_NOTFOUND_OK(t_ret);

	return (ret);
}
Beispiel #17
0
/*
 * util_name --
 *	Build a name.
 */
char *
util_name(const char *s, const char *type, u_int flags)
{
	size_t len;
	int copy;
	char *name;

	copy = 0;
	if (WT_PREFIX_MATCH(s, "backup:")) {
		goto type_err;
	} else if (WT_PREFIX_MATCH(s, "colgroup:")) {
		if (!(flags & UTIL_COLGROUP_OK))
			goto type_err;
		copy = 1;
	} else if (WT_PREFIX_MATCH(s, "config:")) {
		goto type_err;
	} else if (WT_PREFIX_MATCH(s, "file:")) {
		if (!(flags & UTIL_FILE_OK))
			goto type_err;
		copy = 1;
	} else if (WT_PREFIX_MATCH(s, "index:")) {
		if (!(flags & UTIL_INDEX_OK))
			goto type_err;
		copy = 1;
	} else if (WT_PREFIX_MATCH(s, "lsm:")) {
		if (!(flags & UTIL_LSM_OK))
			goto type_err;
		copy = 1;
	} else if (WT_PREFIX_MATCH(s, "statistics:")) {
		goto type_err;
	} else if (WT_PREFIX_MATCH(s, "table:")) {
		if (!(flags & UTIL_TABLE_OK)) {
type_err:		fprintf(stderr,
			    "%s: %s: unsupported object type: %s\n",
			    progname, command, s);
			return (NULL);
		}
		copy = 1;
	}

	len = strlen(type) + strlen(s) + 2;
	if ((name = calloc(len, 1)) == NULL) {
		(void)util_err(errno, NULL);
		return (NULL);
	}

	if (copy)
		strcpy(name, s);
	else
		snprintf(name, len, "%s:%s", type, s);
	return (name);
}
Beispiel #18
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);
}
Beispiel #19
0
/*
 * __backup_list_append --
 *	Append a new file name to the list, allocate space as necessary.
 */
static int
__backup_list_append(
    WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb, const char *uri)
{
	WT_CURSOR_BACKUP_ENTRY *p;
	WT_DATA_HANDLE *old_dhandle;
	WT_DECL_RET;
	const char *name;
	int need_handle;

	/* Leave a NULL at the end to mark the end of the list. */
	WT_RET(__wt_realloc_def(session, &cb->list_allocated,
	    cb->list_next + 2, &cb->list));
	p = &cb->list[cb->list_next];
	p[0].name = p[1].name = NULL;
	p[0].handle = p[1].handle = NULL;

	need_handle = 0;
	name = uri;
	if (WT_PREFIX_MATCH(uri, "file:")) {
		need_handle = 1;
		name += strlen("file:");
	}

	/*
	 * !!!
	 * Assumes metadata file entries map one-to-one to physical files.
	 * To support a block manager where that's not the case, we'd need
	 * to call into the block manager and get a list of physical files
	 * that map to this logical "file".  I'm not going to worry about
	 * that for now, that block manager might not even support physical
	 * copying of files by applications.
	 */
	WT_RET(__wt_strdup(session, name, &p->name));

	/*
	 * If it's a file in the database, get a handle for the underlying
	 * object (this handle blocks schema level operations, for example
	 * WT_SESSION.drop or an LSM file discard after level merging).
	 */
	if (need_handle) {
		old_dhandle = session->dhandle;
		if ((ret =
		    __wt_session_get_btree(session, uri, NULL, NULL, 0)) == 0)
			p->handle = session->dhandle;
		session->dhandle = old_dhandle;
		WT_RET(ret);
	}

	++cb->list_next;
	return (0);
}
Beispiel #20
0
/*
 * __huffman_confchk_file --
 *	Check for a Huffman configuration file and return the file name.
 */
static int
__huffman_confchk_file(
    WT_SESSION_IMPL *session, WT_CONFIG_ITEM *v, int *is_utf8p, FILE **fpp)
{
	FILE *fp;
	WT_DECL_RET;
	size_t len;
	char *fname;

	/* Look for a prefix and file name. */
	len = 0;
	if (is_utf8p != NULL)
		*is_utf8p = 0;
	if (WT_PREFIX_MATCH(v->str, "utf8")) {
		if (is_utf8p != NULL)
			*is_utf8p = 1;
		len = strlen("utf8");
	} else if (WT_PREFIX_MATCH(v->str, "utf16"))
		len = strlen("utf16");
	if (len == 0 || len >= v->len)
		WT_RET_MSG(session, EINVAL,
		    "illegal Huffman configuration: %.*s", (int)v->len, v->str);

	/* Check the file exists. */
	WT_RET(__wt_strndup(session, v->str + len, v->len - len, &fname));
	WT_ERR(__wt_fopen(session,
	    fname, WT_FHANDLE_READ, WT_FOPEN_FIXED, &fp));

	/* Optionally return the file handle. */
	if (fpp == NULL)
		(void)__wt_fclose(&fp, WT_FHANDLE_READ);
	else
		*fpp = fp;

err:	__wt_free(session, fname);

	return (ret);
}
Beispiel #21
0
/*
 * __wt_meta_btree_apply --
 *	Apply a function to all files listed in the metadata, apart from the
 *	metadata file.
 */
int
__wt_meta_btree_apply(WT_SESSION_IMPL *session,
    int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[])
{
	WT_CURSOR *cursor;
	WT_DATA_HANDLE *saved_dhandle;
	WT_DECL_RET;
	const char *uri;
	int cmp, tret;

	saved_dhandle = session->dhandle;
	WT_RET(__wt_metadata_cursor(session, NULL, &cursor));
	cursor->set_key(cursor, "file:");
	if ((tret = cursor->search_near(cursor, &cmp)) == 0 && cmp < 0)
		tret = cursor->next(cursor);
	for (; tret == 0; tret = cursor->next(cursor)) {
		WT_ERR(cursor->get_key(cursor, &uri));
		if (!WT_PREFIX_MATCH(uri, "file:"))
			break;
		else if (strcmp(uri, WT_METAFILE_URI) == 0)
			continue;

		/*
		 * We need to pull the handle into the session handle cache
		 * and make sure it's referenced to stop other internal code
		 * dropping the handle (e.g in LSM when cleaning up obsolete
		 * chunks).  Holding the metadata lock isn't enough.
		 */
		ret = __wt_session_get_btree(session, uri, NULL, NULL, 0);
		if (ret == 0) {
			WT_SAVE_DHANDLE(session,
			    ret = func(session, cfg));
			if (WT_META_TRACKING(session))
				WT_TRET(
				    __wt_meta_track_handle_lock(session, 0));
			else
				WT_TRET(__wt_session_release_btree(session));
		} else if (ret == EBUSY)
			ret = __wt_conn_btree_apply_single(
			    session, uri, NULL, func, cfg);
		WT_ERR(ret);
	}

	if (tret != WT_NOTFOUND)
		WT_TRET(tret);
err:	WT_TRET(cursor->close(cursor));
	session->dhandle = saved_dhandle;
	return (ret);
}
Beispiel #22
0
int
__wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
{
	WT_CONFIG_ITEM cval;
	int force, ret;

	cval.val = 0;
	ret = __wt_config_gets(session, cfg, "force", &cval);
	if (ret != 0 && ret != WT_NOTFOUND)
		WT_RET(ret);
	force = cval.val == 0 ? 0 : 1;

	/* Disallow drops from the WiredTiger name space. */
	WT_RET(__wt_schema_name_check(session, uri));

	if (WT_PREFIX_MATCH(uri, "colgroup:"))
		ret = __drop_colgroup(session, uri, force, cfg);
	else if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __drop_file(session, uri, force);
	else if (WT_PREFIX_MATCH(uri, "index:"))
		ret = __drop_index(session, uri, force, cfg);
	else if (WT_PREFIX_MATCH(uri, "table:"))
		ret = __drop_table(session, uri, force);
	else
		return (__wt_unknown_object_type(session, uri));

	/*
	 * Map WT_NOTFOUND to ENOENT (or to 0 if "force" is set), based on the
	 * assumption WT_NOTFOUND means there was no schema file entry.  The
	 * underlying drop functions should handle this case (we passed them
	 * the "force" value), but better safe than sorry.
	 */
	if (ret == WT_NOTFOUND)
		ret = force ? 0 : ENOENT;
	return (ret);
}
Beispiel #23
0
/*
 * config_reorder --
 *	For table dumps, reorder the list so tables are first.
 *	For other dumps, make any needed checks.
 */
int
config_reorder(char **list)
{
	char **entry, *p;

	/*
	 * Search for a table name -- if we find one, then it's table dump,
	 * otherwise, it's a single file dump.
	 */
	for (entry = list; *entry != NULL; ++entry)
		if (WT_PREFIX_MATCH(*entry, "table:"))
			break;
	if (*entry == NULL) {
		/*
		 * Single file dumps can only have two lines, the file name and
		 * the configuration information.
		 */
		if ((list[0] == NULL || list[1] == NULL || list[2] != NULL) ||
		    (WT_PREFIX_MATCH(list[0], "file:") &&
		    WT_PREFIX_MATCH(list[0], "lsm:")))
			return (format());

		entry = list;
	}

	/*
	 * Make sure the table key/value pair comes first, then we can just
	 * run through the array in order.  (We already checked that we had
	 * a multiple of 2 entries, so this is safe.)
	 */
	if (entry != list) {
		p = list[0]; list[0] = entry[0]; entry[0] = p;
		p = list[1]; list[1] = entry[1]; entry[1] = p;
	}
	return (0);
}
Beispiel #24
0
/*
 * util_uri --
 *	Build a name.
 */
char *
util_uri(WT_SESSION *session, const char *s, const char *type)
{
	WT_DECL_RET;
	size_t len;
	char *name;

	if (WT_PREFIX_MATCH(s, "backup:") ||
	    WT_PREFIX_MATCH(s, "config:") ||
	    WT_PREFIX_MATCH(s, "statistics:")) {
		fprintf(stderr,
		    "%s: %s: unsupported object type: %s\n",
		    progname, command, s);
		return (NULL);
	}

	len = strlen(type) + strlen(s) + 2;
	if ((name = calloc(len, 1)) == NULL) {
		(void)util_err(session, errno, NULL);
		return (NULL);
	}

	/*
	 * If the string has a URI prefix, use it verbatim, otherwise prepend
	 * the default type for the operation.
	 */
	if (strchr(s, ':') != NULL)
		WT_ERR(__wt_snprintf(name, len, "%s", s));
	else
		WT_ERR(__wt_snprintf(name, len, "%s:%s", type, s));
	return (name);

err:	free(name);
	(void)util_err(session, ret, NULL);
	return (NULL);
}
Beispiel #25
0
/*
 * __wt_lsm_compact --
 *	Compact an LSM tree called via __wt_schema_worker.
 */
int
__wt_lsm_compact(WT_SESSION_IMPL *session, const char *name, int *skip)
{
	WT_DECL_RET;
	WT_LSM_TREE *lsm_tree;
	uint64_t last_merge_progressing;
	time_t begin, end;

	/*
	 * This function is applied to all matching sources: ignore anything
	 * that is not an LSM tree.
	 */
	if (!WT_PREFIX_MATCH(name, "lsm:"))
		return (0);

	/* Tell __wt_schema_worker not to look inside the LSM tree. */
	*skip = 1;

	WT_RET(__wt_lsm_tree_get(session, name, 0, &lsm_tree));

	if (!F_ISSET(S2C(session), WT_CONN_LSM_MERGE) ||
	    lsm_tree->merge_threads == 0)
		WT_RET_MSG(session, EINVAL,
		    "LSM compaction requires active merge threads");

	WT_RET(__wt_seconds(session, &begin));

	F_SET(lsm_tree, WT_LSM_TREE_COMPACTING);

	/* Wake up the merge threads. */
	WT_RET(__wt_cond_signal(session, lsm_tree->work_cond));

	/* Now wait for merge activity to stop. */
	do {
		last_merge_progressing = lsm_tree->merge_progressing;
		__wt_sleep(1, 0);
		WT_RET(__wt_seconds(session, &end));
		if (session->compact->max_time > 0 &&
		    session->compact->max_time < (uint64_t)(end - begin))
			WT_ERR(ETIMEDOUT);
	} while (lsm_tree->merge_progressing != last_merge_progressing &&
	    lsm_tree->nchunks > 1);

err:	F_CLR(lsm_tree, WT_LSM_TREE_COMPACTING);

	return (ret);
}
Beispiel #26
0
/*
 * __backup_list_uri_append --
 *	Append a new file name to the list, allocate space as necessary.
 *	Called via the schema_worker function.
 */
static int
__backup_list_uri_append(
    WT_SESSION_IMPL *session, const char *name, bool *skip)
{
	WT_CURSOR_BACKUP *cb;
	char *value;

	cb = session->bkp_cursor;
	WT_UNUSED(skip);

	/*
	 * While reading the metadata file, check there are no data sources
	 * that 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 (WT_PREFIX_MATCH(name, "log:")) {
		WT_RET(__backup_log_append(session, cb, false));
		return (0);
	}

	if (!WT_PREFIX_MATCH(name, "file:") &&
	    !WT_PREFIX_MATCH(name, "colgroup:") &&
	    !WT_PREFIX_MATCH(name, "index:") &&
	    !WT_PREFIX_MATCH(name, "lsm:") &&
	    !WT_PREFIX_MATCH(name, "table:"))
		WT_RET_MSG(session, ENOTSUP,
		    "hot backup is not supported for objects of type %s",
		    name);

	/* Ignore the lookaside table. */
	if (strcmp(name, WT_LAS_URI) == 0)
		return (0);

	/* Add the metadata entry to the backup file. */
	WT_RET(__wt_metadata_search(session, name, &value));
	WT_RET(__wt_fprintf(cb->bfp, "%s\n%s\n", name, value));
	__wt_free(session, value);

	/* Add file type objects to the list of files to be copied. */
	if (WT_PREFIX_MATCH(name, "file:"))
		WT_RET(__backup_list_append(session, cb, name));

	return (0);
}
Beispiel #27
0
/*
 * __wt_schema_truncate --
 *	WT_SESSION::truncate.
 */
int
__wt_schema_truncate(
    WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
{
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	const char *tablename;

	WT_UNUSED(cfg);
	tablename = uri;

	if (WT_PREFIX_MATCH(uri, "file:"))
		ret = __truncate_file(session, uri);
	else if (WT_PREFIX_SKIP(tablename, "table:"))
		ret = __truncate_table(session, tablename);
	else if ((ret = __wt_schema_get_source(session, uri, &dsrc)) == 0)
		ret = dsrc->truncate(dsrc, &session->iface, uri, cfg);

	/* If we didn't find a metadata entry, map that error to ENOENT. */
	return (ret == WT_NOTFOUND ? ENOENT : ret);
}
Beispiel #28
0
/*
 * __wt_curfile_open --
 *	WT_SESSION->open_cursor method for the btree cursor type.
 */
int
__wt_curfile_open(WT_SESSION_IMPL *session, const char *uri,
    WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp)
{
	WT_CONFIG_ITEM cval;
	WT_DECL_RET;
	int bitmap, bulk;
	uint32_t flags;

	flags = 0;

	WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval));
	if (cval.type == ITEM_NUM && (cval.val == 0 || cval.val == 1)) {
		bitmap = 0;
		bulk = (cval.val != 0);
	} else if (WT_STRING_MATCH("bitmap", cval.str, cval.len))
		bitmap = bulk = 1;
	else
		WT_RET_MSG(session, EINVAL,
		    "Value for 'bulk' must be a boolean or 'bitmap'");

	/* Bulk handles require exclusive access. */
	if (bulk)
		LF_SET(WT_BTREE_BULK | WT_BTREE_EXCLUSIVE);

	/* TODO: handle projections. */

	/* Get the handle and lock it while the cursor is using it. */
	if (WT_PREFIX_MATCH(uri, "file:"))
		WT_RET(__wt_session_get_btree_ckpt(session, uri, cfg, flags));
	else
		WT_RET(__wt_bad_object_type(session, uri));

	WT_ERR(__wt_curfile_create(session, owner, cfg, bulk, bitmap, cursorp));
	return (0);

err:	/* If the cursor could not be opened, release the handle. */
	WT_TRET(__wt_session_release_btree(session));
	return (ret);
}
Beispiel #29
0
/*
 * __meta_btree_apply --
 *	Apply a function to all files listed in the metadata, apart from the
 *	metadata file.
 */
static inline int
__meta_btree_apply(WT_SESSION_IMPL *session, WT_CURSOR *cursor,
    int (*file_func)(WT_SESSION_IMPL *, const char *[]),
    int (*name_func)(WT_SESSION_IMPL *, const char *, bool *),
    const char *cfg[])
{
	WT_DECL_RET;
	const char *uri;
	bool skip;

	while ((ret = cursor->next(cursor)) == 0) {
		WT_RET(cursor->get_key(cursor, &uri));
		if (strcmp(uri, WT_METAFILE_URI) == 0)
			continue;

		skip = false;
		if (name_func != NULL)
			WT_RET(name_func(session, uri, &skip));

		if (file_func == NULL || skip || !WT_PREFIX_MATCH(uri, "file:"))
			continue;

		/*
		 * We need to pull the handle into the session handle cache
		 * and make sure it's referenced to stop other internal code
		 * dropping the handle (e.g in LSM when cleaning up obsolete
		 * chunks).  Holding the metadata lock isn't enough.
		 */
		if ((ret = __wt_session_get_btree(
		    session, uri, NULL, NULL, 0)) != 0)
			return (ret == EBUSY ? 0 : ret);
		WT_SAVE_DHANDLE(session, ret = file_func(session, cfg));
		WT_TRET(__wt_session_release_btree(session));
		WT_RET(ret);
	}
	WT_RET_NOTFOUND_OK(ret);

	return (0);
}
Beispiel #30
0
/*
 * __wt_curfile_open --
 *	WT_SESSION->open_cursor method for the btree cursor type.
 */
int
__wt_curfile_open(WT_SESSION_IMPL *session, const char *uri,
    WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp)
{
	WT_CONFIG_ITEM cval;
	WT_DECL_RET;
	uint32_t flags;

	/*
	 * Bulk and no cache handles are exclusive and may not be used by more
	 * than a single thread.
	 * Additionally set the discard flag on no cache handles so they are
	 * destroyed on close.
	 */
	flags = 0;
	WT_RET(__wt_config_gets_defno(session, cfg, "bulk", &cval));
	if (cval.val != 0)
		LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_BULK);
	WT_RET(__wt_config_gets_defno(session, cfg, "no_cache", &cval));
	if (cval.val != 0)
		LF_SET(WT_BTREE_EXCLUSIVE | WT_BTREE_NO_CACHE);

	/* TODO: handle projections. */

	/* Get the handle and lock it while the cursor is using it. */
	if (WT_PREFIX_MATCH(uri, "file:"))
		WT_RET(__wt_session_get_btree_ckpt(session, uri, cfg, flags));
	else
		WT_RET(__wt_bad_object_type(session, uri));

	WT_ERR(__wt_curfile_create(session, owner, cfg, cursorp));
	return (0);

err:	/* If the cursor could not be opened, release the handle. */
	(void)__wt_session_release_btree(session);
	return (ret);
}