Beispiel #1
0
/*
 * __session_drop --
 *	WT_SESSION->drop method.
 */
static int
__session_drop(WT_SESSION *wt_session, const char *name, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;
    SESSION_API_CALL(session, drop, config, cfg);
    ret = __wt_schema_drop(session, name, cfg);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #2
0
/*
 * __session_dumpfile --
 *	WT_SESSION->dumpfile method.
 */
static int
__session_dumpfile(WT_SESSION *wt_session, const char *uri, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;
    SESSION_API_CALL(session, dumpfile, config, cfg);
    ret = __wt_schema_worker(session, uri, cfg,
                             __wt_dumpfile, WT_BTREE_EXCLUSIVE | WT_BTREE_VERIFY);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #3
0
/*
 * __session_sync --
 *	WT_SESSION->sync method.
 */
static int
__session_sync(WT_SESSION *wt_session, const char *uri, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;

    SESSION_API_CALL(session, sync, config, cfg);
    ret = __wt_schema_worker(session, uri, cfg, __wt_btree_sync, 0);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #4
0
/*
 * __session_rename --
 *	WT_SESSION->rename method.
 */
static int
__session_rename(WT_SESSION *wt_session,
                 const char *uri, const char *newname, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;
    SESSION_API_CALL(session, rename, config, cfg);
    ret = __wt_schema_rename(session, uri, newname, cfg);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #5
0
/*
 * __session_create --
 *	WT_SESSION->create method.
 */
static int
__session_create(WT_SESSION *wt_session, const char *name, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;
    SESSION_API_CALL(session, create, config, cfg);
    WT_UNUSED(cfg);
    WT_ERR(__wt_schema_create(session, name, config));

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #6
0
/*
 * __session_compact_worker --
 *	Worker function to do the actual compaction call.
 */
static int
__session_compact_worker(
    WT_SESSION *wt_session, const char *uri, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

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

	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_worker(session, uri, __wt_compact, cfg, 0));

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #7
0
/*
 * __conn_configure_method --
 *	WT_CONNECTION.configure_method method.
 */
static int
__conn_configure_method(WT_CONNECTION *wt_conn, const char *method,
    const char *uri, const char *config, const char *type, const char *check)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	conn = (WT_CONNECTION_IMPL *)wt_conn;
	CONNECTION_API_CALL_NOCONF(conn, session, configure_method);

	ret = __wt_configure_method(session, method, uri, config, type, check);

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #8
0
/*
 * __session_verify --
 *	WT_SESSION->verify method.
 */
static int
__session_verify(WT_SESSION *wt_session, const char *uri, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;

	SESSION_API_CALL(session, verify, config, cfg);
	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_worker(session, uri,
		__wt_verify, cfg, WT_BTREE_EXCLUSIVE | WT_BTREE_VERIFY));

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #9
0
/*
 * __session_drop --
 *	WT_SESSION->drop method.
 */
static int
__session_drop(WT_SESSION *wt_session, const char *uri, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

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

	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_drop(session, uri, cfg));

err:	/* Note: drop operations cannot be unrolled (yet?). */
	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #10
0
/*
 * __session_rename --
 *	WT_SESSION->rename method.
 */
static int
__session_rename(WT_SESSION *wt_session,
    const char *uri, const char *newname, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

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

	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_rename(session, uri, newname, cfg));

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #11
0
/*
 * __conn_load_extension --
 *	WT_CONNECTION->load_extension method.
 */
static int
__conn_load_extension(
    WT_CONNECTION *wt_conn, const char *path, const char *config)
{
	WT_CONFIG_ITEM cval;
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_DLH *dlh;
	WT_SESSION_IMPL *session;
	int (*entry)(WT_SESSION *, WT_EXTENSION_API *, const char *);
	const char *entry_name;

	dlh = NULL;

	conn = (WT_CONNECTION_IMPL *)wt_conn;
	CONNECTION_API_CALL(conn, session, load_extension, config, cfg);

	entry_name = NULL;
	WT_ERR(__wt_config_gets(session, cfg, "entry", &cval));
	WT_ERR(__wt_strndup(session, cval.str, cval.len, &entry_name));

	/*
	 * This assumes the underlying shared libraries are reference counted,
	 * that is, that re-opening a shared library simply increments a ref
	 * count, and closing it simply decrements the ref count, and the last
	 * close discards the reference entirely -- in other words, we do not
	 * check to see if we've already opened this shared library.
	 */
	WT_ERR(__wt_dlopen(session, path, &dlh));
	WT_ERR(__wt_dlsym(session, dlh, entry_name, &entry));

	/* Call the entry function. */
	WT_ERR(entry(&session->iface, &__api, config));

	/* Link onto the environment's list of open libraries. */
	__wt_spin_lock(session, &conn->api_lock);
	TAILQ_INSERT_TAIL(&conn->dlhqh, dlh, q);
	__wt_spin_unlock(session, &conn->api_lock);

	if (0) {
err:		if (dlh != NULL)
			WT_TRET(__wt_dlclose(session, dlh));
	}
	__wt_free(session, entry_name);

	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #12
0
/*
 * __session_create --
 *	WT_SESSION->create method.
 */
static int
__session_create(WT_SESSION *wt_session, const char *uri, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

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

	/* Disallow objects in the WiredTiger name space. */
	WT_ERR(__wt_schema_name_check(session, uri));
	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_create(session, uri, config));

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #13
0
/*
 * __conn_add_extractor --
 *	WT_CONNECTION->add_extractor method.
 */
static int
__conn_add_extractor(WT_CONNECTION *wt_conn,
    const char *name, WT_EXTRACTOR *extractor, const char *config)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	WT_UNUSED(name);
	WT_UNUSED(extractor);
	ret = ENOTSUP;

	conn = (WT_CONNECTION_IMPL *)wt_conn;
	CONNECTION_API_CALL(conn, session, add_extractor, config, cfg);
	WT_UNUSED(cfg);

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #14
0
/*
 * __session_checkpoint --
 *	WT_SESSION->checkpoint method.
 */
static int
__session_checkpoint(WT_SESSION *wt_session, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	WT_TXN *txn;

	session = (WT_SESSION_IMPL *)wt_session;
	txn = &session->txn;

	WT_CSTAT_INCR(session, checkpoint);
	SESSION_API_CALL(session, checkpoint, config, cfg);

	/*
	 * Checkpoints require a snapshot to write a transactionally consistent
	 * snapshot of the data.
	 *
	 * We can't use an application's transaction: if it has uncommitted
	 * changes, they will be written in the checkpoint and may appear after
	 * a crash.
	 *
	 * Use a real snapshot transaction: we don't want any chance of the
	 * snapshot being updated during the checkpoint.  Eviction is prevented
	 * from evicting anything newer than this because we track the oldest
	 * transaction ID in the system that is not visible to all readers.
	 */
	if (F_ISSET(txn, TXN_RUNNING))
		WT_ERR_MSG(session, EINVAL,
		    "Checkpoint not permitted in a transaction");

	/*
	 * Reset open cursors.
	 *
	 * We do this here explicitly even though it will happen implicitly in
	 * the call to begin_transaction for the checkpoint, in case some
	 * implementation of WT_CURSOR::reset needs the schema lock.
	 */
	WT_ERR(__session_reset_cursors(session));

	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_txn_checkpoint(session, cfg));

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #15
0
/*
 * __conn_open_session --
 *	WT_CONNECTION->open_session method.
 */
static int
__conn_open_session(WT_CONNECTION *wt_conn,
    WT_EVENT_HANDLER *event_handler, const char *config,
    WT_SESSION **wt_sessionp)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_SESSION_IMPL *session, *session_ret;

	conn = (WT_CONNECTION_IMPL *)wt_conn;
	session_ret = NULL;

	CONNECTION_API_CALL(conn, session, open_session, config, cfg);
	WT_UNUSED(cfg);

	WT_ERR(__wt_open_session(conn, 0, event_handler, config, &session_ret));

	*wt_sessionp = &session_ret->iface;

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #16
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_SESSION_IMPL *session;
    int ret;

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

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

    if (to_dup != NULL)
        ret = __wt_cursor_dup(session, to_dup, config, cursorp);
    else if (WT_PREFIX_MATCH(uri, "colgroup:"))
        ret = __wt_curfile_open(session, uri, 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, 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 {
        __wt_err(session, EINVAL, "Unknown cursor type '%s'", uri);
        ret = EINVAL;
    }

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #17
0
/*
 * __conn_close --
 *	WT_CONNECTION->close method.
 */
static int
__conn_close(WT_CONNECTION *wt_conn, const char *config)
{
	WT_CONNECTION_IMPL *conn;
	WT_DECL_RET;
	WT_NAMED_COLLATOR *ncoll;
	WT_NAMED_COMPRESSOR *ncomp;
	WT_NAMED_DATA_SOURCE *ndsrc;
	WT_SESSION *wt_session;
	WT_SESSION_IMPL *s, *session;
	uint32_t i;

	conn = (WT_CONNECTION_IMPL *)wt_conn;

	CONNECTION_API_CALL(conn, session, close, config, cfg);
	WT_UNUSED(cfg);

	/*
	 * Close open, external sessions.
	 * Additionally, the session's hazard pointer memory isn't discarded
	 * during normal session close because access to it isn't serialized.
	 * Discard it now.  Note the loop for the hazard pointer memory, it's
	 * the entire session array, not only the active session count, as the
	 * active session count may be less than the maximum session count.
	 */
	for (s = conn->sessions, i = 0; i < conn->session_cnt; ++s, ++i)
		if (s->active && !F_ISSET(s, WT_SESSION_INTERNAL)) {
			wt_session = &s->iface;
			WT_TRET(wt_session->close(wt_session, config));
		}
	for (s = conn->sessions, i = 0; i < conn->session_size; ++s, ++i)
		if (!F_ISSET(s, WT_SESSION_INTERNAL))
			__wt_free(session, s->hazard);

	/*
	 * Shut down server threads other than the eviction server, which is
	 * needed later to close btree handles.  Some of these threads access
	 * btree handles, so take care in ordering shutdown to make sure they
	 * exit before files are closed.
	 */
	F_CLR(conn, WT_CONN_SERVER_RUN);
	WT_TRET(__wt_checkpoint_destroy(conn));
	WT_TRET(__wt_statlog_destroy(conn));

	/* Clean up open LSM handles. */
	WT_ERR(__wt_lsm_cleanup(&conn->iface));

	/* Close open btree handles. */
	WT_TRET(__wt_conn_btree_discard(conn));

	/* Free memory for collators */
	while ((ncoll = TAILQ_FIRST(&conn->collqh)) != NULL)
		__conn_remove_collator(conn, ncoll);

	/* Free memory for compressors */
	while ((ncomp = TAILQ_FIRST(&conn->compqh)) != NULL)
		__conn_remove_compressor(conn, ncomp);

	/* Free memory for data sources */
	while ((ndsrc = TAILQ_FIRST(&conn->dsrcqh)) != NULL)
		__conn_remove_data_source(conn, ndsrc);

	WT_TRET(__wt_connection_close(conn));

	/* We no longer have a session, don't try to update it. */
	session = NULL;

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #18
0
/*
 * __session_close --
 *	WT_SESSION->close method.
 */
static int
__session_close(WT_SESSION *wt_session, const char *config)
{
	WT_CONNECTION_IMPL *conn;
	WT_CURSOR *cursor;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	int tret;

	conn = (WT_CONNECTION_IMPL *)wt_session->connection;
	session = (WT_SESSION_IMPL *)wt_session;

	SESSION_API_CALL(session, close, config, cfg);
	WT_UNUSED(cfg);

	/* Rollback any active transaction. */
	if (F_ISSET(&session->txn, TXN_RUNNING))
		WT_TRET(__session_rollback_transaction(wt_session, NULL));

	/* Close all open cursors. */
	while ((cursor = TAILQ_FIRST(&session->cursors)) != NULL)
		WT_TRET(cursor->close(cursor));

	WT_ASSERT(session, session->ncursors == 0);

	/*
	 * Acquire the schema lock: we may be closing btree handles.
	 *
	 * Note that in some special cases, the schema may already be locked
	 * (e.g., if this session is an LSM tree worker and the tree is being
	 * dropped).
	 */
	WT_WITH_SCHEMA_LOCK_OPT(session, tret = __session_close_cache(session));
	WT_TRET(tret);

	/* Discard metadata tracking. */
	__wt_meta_track_discard(session);

	/* Discard scratch buffers. */
	__wt_scr_discard(session);

	/* Free transaction information. */
	__wt_txn_destroy(session);

	/* Confirm we're not holding any hazard references. */
	__wt_hazard_close(session);

	/* Free the reconciliation information. */
	__wt_rec_destroy(session, &session->reconcile);

	/* Free the eviction exclusive-lock information. */
	__wt_free(session, session->excl);

	/* Destroy the thread's mutex. */
	if (session->cond != NULL)
		(void)__wt_cond_destroy(session, session->cond);

	/* The API lock protects opening and closing of sessions. */
	__wt_spin_lock(session, &conn->api_lock);

	/*
	 * Sessions are re-used, clear the structure: this code sets the active
	 * field to 0, which will exclude the hazard array from review by the
	 * eviction thread.   Note: there's no serialization support around the
	 * review of the hazard array, which means threads checking for hazard
	 * references first check the active field (which may be 0) and then use
	 * the hazard pointer (which cannot be NULL).  For this reason, clear
	 * the session structure carefully.
	 *
	 * We don't need to publish here, because regardless of the active field
	 * being non-zero, the hazard reference is always valid.
	 */
	WT_SESSION_CLEAR(session);
	session = conn->default_session;

	/*
	 * Decrement the count of active sessions if that's possible: a session
	 * being closed may or may not be at the end of the array, step toward
	 * the beginning of the array until we reach an active session.
	 */
	while (conn->sessions[conn->session_cnt - 1].active == 0)
		if (--conn->session_cnt == 0)
			break;

	__wt_spin_unlock(session, &conn->api_lock);

err:	API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #19
0
/*
 * __session_close --
 *	WT_SESSION->close method.
 */
static int
__session_close(WT_SESSION *wt_session, const char *config)
{
    WT_BTREE_SESSION *btree_session;
    WT_CONNECTION_IMPL *conn;
    WT_CURSOR *cursor;
    WT_SESSION_IMPL *session, **tp;
    int ret;

    conn = (WT_CONNECTION_IMPL *)wt_session->connection;
    session = (WT_SESSION_IMPL *)wt_session;

    SESSION_API_CALL(session, close, config, cfg);
    WT_UNUSED(cfg);

    while ((cursor = TAILQ_FIRST(&session->cursors)) != NULL)
        WT_TRET(cursor->close(cursor));

    while ((btree_session = TAILQ_FIRST(&session->btrees)) != NULL)
        WT_TRET(__wt_session_remove_btree(session, btree_session, 0));

    WT_TRET(__wt_schema_close_tables(session));

    __wt_spin_lock(session, &conn->spinlock);

    /* Discard scratch buffers. */
    __wt_scr_discard(session);

    /* Confirm we're not holding any hazard references. */
    __wt_hazard_empty(session);

    /* Free the reconciliation information. */
    __wt_rec_destroy(session);

    /* Free the eviction exclusive-lock information. */
    __wt_free(session, session->excl);

    /* Destroy the thread's mutex. */
    if (session->cond != NULL)
        (void)__wt_cond_destroy(session, session->cond);

    /*
     * Replace the session reference we're closing with the last entry in
     * the table, then clear the last entry.  As far as the walk of the
     * server threads is concerned, it's OK if the session appears twice,
     * or if it doesn't appear at all, so these lines can race all they
     * want.
     */
    for (tp = conn->sessions; *tp != session; ++tp)
        ;
    --conn->session_cnt;
    *tp = conn->sessions[conn->session_cnt];
    conn->sessions[conn->session_cnt] = NULL;

    /*
     * Publish, making the session array entry available for re-use.  There
     * must be a barrier here to ensure the cleanup above completes before
     * the entry is re-used.
     */
    WT_PUBLISH(session->iface.connection, NULL);

    session = &conn->default_session;
    __wt_spin_unlock(session, &conn->spinlock);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
Beispiel #20
0
/*
 * __session_truncate --
 *	WT_SESSION->truncate method.
 */
static int
__session_truncate(WT_SESSION *wt_session,
                   const char *uri, WT_CURSOR *start, WT_CURSOR *stop, const char *config)
{
    WT_SESSION_IMPL *session;
    int ret;

    session = (WT_SESSION_IMPL *)wt_session;

    SESSION_API_CALL(session, truncate, config, cfg);
    /*
     * If the URI is specified, we don't need a start/stop, if start/stop
     * is specified, we don't need a URI.
     *
     * If no URI is specified, and both cursors are specified, start/stop
     * must reference the same object.
     *
     * Any specified cursor must have been initialized.
     */
    if ((uri == NULL && start == NULL && stop == NULL) ||
            (uri != NULL && (start != NULL || stop != NULL)))
        WT_ERR_MSG(session, EINVAL,
                   "the truncate method should be passed either a URI or "
                   "start/stop cursors, but not both");
    if (start != NULL && stop != NULL && strcmp(start->uri, stop->uri) != 0)
        WT_ERR_MSG(session, EINVAL,
                   "truncate method cursors must reference the same object");
    if ((start != NULL && !F_ISSET(start, WT_CURSTD_KEY_SET)) ||
            (stop != NULL && !F_ISSET(stop, WT_CURSTD_KEY_SET)))
        WT_ERR_MSG(session, EINVAL,
                   "the truncate method cursors must have their keys set");

    if (uri == NULL) {
        /*
         * From a starting/stopping cursor to the begin/end of the
         * object is easy, walk the object.
         */
        if (start == NULL)
            for (;;) {
                WT_ERR(stop->remove(stop));
                if ((ret = stop->prev(stop)) != 0) {
                    if (ret == WT_NOTFOUND)
                        ret = 0;
                    break;
                }
            }
        else
            for (;;) {
                WT_ERR(start->remove(start));
                if (stop != NULL &&
                        start->equals(start, stop))
                    break;
                if ((ret = start->next(start)) != 0) {
                    if (ret == WT_NOTFOUND)
                        ret = 0;
                    break;
                }
            }
    } else
        ret = __wt_schema_truncate(session, uri, cfg);

err:
    API_END_NOTFOUND_MAP(session, ret);
}