예제 #1
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);
}
예제 #2
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);
}
예제 #3
0
/*
 * __session_verify --
 *	WT_SESSION->verify method.
 */
static int
__session_verify(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, verify, config, cfg);
    ret = __wt_schema_worker(session, uri, cfg,
                             __wt_verify, WT_BTREE_EXCLUSIVE | WT_BTREE_VERIFY);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
예제 #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_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);
}
예제 #5
0
/*
 * __session_upgrade --
 *	WT_SESSION->upgrade method.
 */
static int
__session_upgrade(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, upgrade, config, cfg);
    ret = __wt_schema_worker(session, uri, cfg,
                             __wt_upgrade, WT_BTREE_EXCLUSIVE | WT_BTREE_UPGRADE);

err:
    API_END_NOTFOUND_MAP(session, ret);
}
예제 #6
0
/*
 * __session_rollback_transaction --
 *	WT_SESSION->rollback_transaction method.
 */
static int
__session_rollback_transaction(WT_SESSION *wt_session, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;
	SESSION_API_CALL(session, rollback_transaction, config, cfg);
	WT_CSTAT_INCR(session, txn_rollback);

	WT_TRET(__session_reset_cursors(session));

	WT_TRET(__wt_txn_rollback(session, cfg));

err:	API_END(session);
	return (ret);
}
예제 #7
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);
}
예제 #8
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);
}
예제 #9
0
/*
 * __session_begin_transaction --
 *	WT_SESSION->begin_transaction method.
 */
static int
__session_begin_transaction(WT_SESSION *wt_session, const char *config)
{
	WT_DECL_RET;
	WT_SESSION_IMPL *session;

	session = (WT_SESSION_IMPL *)wt_session;
	SESSION_API_CALL(session, begin_transaction, config, cfg);
	WT_CSTAT_INCR(session, txn_begin);

	if (!F_ISSET(S2C(session), WT_CONN_TRANSACTIONAL))
		WT_ERR_MSG(session, EINVAL,
		    "Database not configured for transactions");
	if (F_ISSET(&session->txn, TXN_RUNNING))
		WT_ERR_MSG(session, EINVAL, "Transaction already running");

	WT_ERR(__session_reset_cursors(session));

	ret = __wt_txn_begin(session, cfg);

err:	API_END(session);
	return (ret);
}
예제 #10
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);
}
예제 #11
0
/*
 * __wt_session_compact --
 *	WT_SESSION.compact method.
 */
int
__wt_session_compact(
    WT_SESSION *wt_session, const char *uri, const char *config)
{
	WT_COMPACT_STATE compact;
	WT_CONFIG_ITEM cval;
	WT_DATA_SOURCE *dsrc;
	WT_DECL_RET;
	WT_SESSION_IMPL *session;
	u_int i;
	bool ignore_cache_size_set;

	ignore_cache_size_set = false;

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

	/*
	 * The compaction thread should not block when the cache is full: it is
	 * holding locks blocking checkpoints and once the cache is full, it can
	 * spend a long time doing eviction.
	 */
	if (!F_ISSET(session, WT_SESSION_IGNORE_CACHE_SIZE)) {
		ignore_cache_size_set = true;
		F_SET(session, WT_SESSION_IGNORE_CACHE_SIZE);
	}

	/* In-memory ignores compaction operations. */
	if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY))
		goto err;

	/*
	 * Non-LSM object compaction requires checkpoints, which are impossible
	 * in transactional contexts. Disallow in all contexts (there's no
	 * reason for LSM to allow this, possible or not), and check now so the
	 * error message isn't confusing.
	 */
	WT_ERR(__wt_txn_context_check(session, false));

	/* Disallow objects in the WiredTiger name space. */
	WT_ERR(__wt_str_name_check(session, uri));

	if (!WT_PREFIX_MATCH(uri, "colgroup:") &&
	    !WT_PREFIX_MATCH(uri, "file:") &&
	    !WT_PREFIX_MATCH(uri, "index:") &&
	    !WT_PREFIX_MATCH(uri, "lsm:") &&
	    !WT_PREFIX_MATCH(uri, "table:")) {
		if ((dsrc = __wt_schema_get_source(session, uri)) != NULL)
			ret = dsrc->compact == NULL ?
			    __wt_object_unsupported(session, uri) :
			    dsrc->compact(
			    dsrc, wt_session, uri, (WT_CONFIG_ARG *)cfg);
		else
			ret = __wt_bad_object_type(session, uri);
		goto err;
	}

	/* Setup the session handle's compaction state structure. */
	memset(&compact, 0, sizeof(WT_COMPACT_STATE));
	session->compact = &compact;

	/* Compaction can be time-limited. */
	WT_ERR(__wt_config_gets(session, cfg, "timeout", &cval));
	session->compact->max_time = (uint64_t)cval.val;
	__wt_epoch(session, &session->compact->begin);

	/* Find the types of data sources being compacted. */
	WT_WITH_SCHEMA_LOCK(session,
	    ret = __wt_schema_worker(session, uri,
	    __compact_handle_append, __compact_uri_analyze, cfg, 0));
	WT_ERR(ret);

	if (session->compact->lsm_count != 0)
		WT_ERR(__wt_schema_worker(
		    session, uri, NULL, __wt_lsm_compact, cfg, 0));
	if (session->compact->file_count != 0)
		WT_ERR(__compact_worker(session));

err:	session->compact = NULL;

	for (i = 0; i < session->op_handle_next; ++i) {
		WT_WITH_DHANDLE(session, session->op_handle[i],
		    WT_TRET(__compact_end(session)));
		WT_WITH_DHANDLE(session, session->op_handle[i],
		    WT_TRET(__wt_session_release_dhandle(session)));
	}

	__wt_free(session, session->op_handle);
	session->op_handle_allocated = session->op_handle_next = 0;

	/*
	 * Release common session resources (for example, checkpoint may acquire
	 * significant reconciliation structures/memory).
	 */
	WT_TRET(__wt_session_release_resources(session));

	if (ignore_cache_size_set)
		F_CLR(session, WT_SESSION_IGNORE_CACHE_SIZE);

	if (ret != 0)
		WT_STAT_CONN_INCR(session, session_table_compact_fail);
	else
		WT_STAT_CONN_INCR(session, session_table_compact_success);
	API_END_RET_NOTFOUND_MAP(session, ret);
}
예제 #12
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);
}
예제 #13
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);
}
예제 #14
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);
}