/* * __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); }
/* * __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); }