Exemplo n.º 1
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);
}
Exemplo n.º 2
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);
}