/* * __wt_rwlock_destroy -- * Destroy a read/write lock. */ void __wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK *l) { l->u.v = 0; __wt_cond_destroy(session, &l->cond_readers); __wt_cond_destroy(session, &l->cond_writers); }
/* * __wt_sweep_destroy -- * Destroy the handle-sweep thread. */ int __wt_sweep_destroy(WT_CONNECTION_IMPL *conn) { WT_DECL_RET; WT_SESSION *wt_session; WT_SESSION_IMPL *session; session = conn->default_session; F_CLR(conn, WT_CONN_SERVER_SWEEP); if (conn->sweep_tid_set) { WT_TRET(__wt_cond_signal(session, conn->sweep_cond)); WT_TRET(__wt_thread_join(session, conn->sweep_tid)); conn->sweep_tid_set = 0; } WT_TRET(__wt_cond_destroy(session, &conn->sweep_cond)); if (conn->sweep_session != NULL) { wt_session = &conn->sweep_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); conn->sweep_session = NULL; } return (ret); }
/* * __wt_checkpoint_server_destroy -- * Destroy the checkpoint server thread. */ int __wt_checkpoint_server_destroy(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_SESSION *wt_session; conn = S2C(session); F_CLR(conn, WT_CONN_SERVER_CHECKPOINT); if (conn->ckpt_tid_set) { __wt_cond_signal(session, conn->ckpt_cond); WT_TRET(__wt_thread_join(session, conn->ckpt_tid)); conn->ckpt_tid_set = false; } WT_TRET(__wt_cond_destroy(session, &conn->ckpt_cond)); /* Close the server thread's session. */ if (conn->ckpt_session != NULL) { wt_session = &conn->ckpt_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); } /* * Ensure checkpoint settings are cleared - so that reconfigure doesn't * get confused. */ conn->ckpt_session = NULL; conn->ckpt_tid_set = false; conn->ckpt_cond = NULL; conn->ckpt_usecs = 0; return (ret); }
/* * __wt_thread_group_destroy -- * Shut down a thread group. Our caller must hold the lock. */ int __wt_thread_group_destroy(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group) { WT_DECL_RET; __wt_verbose(session, WT_VERB_THREAD_GROUP, "Destroying thread group: %p", (void *)group); WT_ASSERT(session, __wt_rwlock_islocked(session, group->lock)); /* Shut down all threads and free associated resources. */ WT_TRET(__thread_group_shrink(session, group, 0)); __wt_free(session, group->threads); WT_TRET(__wt_cond_destroy(session, &group->wait_cond)); __wt_rwlock_destroy(session, &group->lock); /* * Clear out any settings from the group, some structures are reused * for different thread groups - in particular the eviction thread * group for recovery and then normal runtime. */ memset(group, 0, sizeof(*group)); return (ret); }
/* * __wt_checkpoint_destroy -- * Destroy the checkpoint server thread. */ int __wt_checkpoint_destroy(WT_CONNECTION_IMPL *conn) { WT_DECL_RET; WT_SESSION *wt_session; WT_SESSION_IMPL *session; session = conn->default_session; if (conn->ckpt_tid_set) { WT_TRET(__wt_cond_signal(session, conn->ckpt_cond)); WT_TRET(__wt_thread_join(session, conn->ckpt_tid)); conn->ckpt_tid_set = 0; } WT_TRET(__wt_cond_destroy(session, &conn->ckpt_cond)); __wt_free(session, conn->ckpt_config); /* Close the server thread's session. */ if (conn->ckpt_session != NULL) { wt_session = &conn->ckpt_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); } return (ret); }
/*销毁一个connection evict cache对象*/ int __wt_cache_destroy(WT_SESSION_IMPL *session) { WT_CACHE *cache; WT_CONNECTION_IMPL *conn; WT_DECL_RET; conn = S2C(session); cache = conn->cache; if (cache == NULL) return 0; WT_TRET(__wt_cond_destroy(session, &cache->evict_cond)); WT_TRET(__wt_cond_destroy(session, &cache->evict_waiter_cond)); __wt_spin_destroy(session, &cache->evict_lock); __wt_spin_destroy(session, &cache->evict_walk_lock); __wt_free(session, cache->evict); __wt_free(session, conn->cache); return ret; }
/* * __wt_cache_destroy -- * Discard the underlying cache. */ int __wt_cache_destroy(WT_SESSION_IMPL *session) { WT_CACHE *cache; WT_CONNECTION_IMPL *conn; WT_DECL_RET; conn = S2C(session); cache = conn->cache; if (cache == NULL) return (0); /* The cache should be empty at this point. Complain if not. */ if (cache->pages_inmem != cache->pages_evict) __wt_errx(session, "cache server: exiting with %" PRIu64 " pages in " "memory and %" PRIu64 " pages evicted", cache->pages_inmem, cache->pages_evict); if (cache->bytes_inmem != 0) __wt_errx(session, "cache server: exiting with %" PRIu64 " bytes in memory", cache->bytes_inmem); if (cache->bytes_dirty != 0 || cache->pages_dirty != 0) __wt_errx(session, "cache server: exiting with %" PRIu64 " bytes dirty and %" PRIu64 " pages dirty", cache->bytes_dirty, cache->pages_dirty); WT_TRET(__wt_cond_destroy(session, &cache->evict_cond)); WT_TRET(__wt_cond_destroy(session, &cache->evict_waiter_cond)); __wt_spin_destroy(session, &cache->evict_lock); __wt_spin_destroy(session, &cache->evict_walk_lock); __wt_free(session, cache->evict); __wt_free(session, conn->cache); return (ret); }
/* * __lsm_tree_discard -- * Free an LSM tree structure. */ static int __lsm_tree_discard(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_DECL_RET; WT_LSM_CHUNK *chunk; u_int i; /* We may be destroying an lsm_tree before it was added. */ if (F_ISSET(lsm_tree, WT_LSM_TREE_OPEN)) TAILQ_REMOVE(&S2C(session)->lsmqh, lsm_tree, q); __wt_free(session, lsm_tree->name); __wt_free(session, lsm_tree->config); __wt_free(session, lsm_tree->key_format); __wt_free(session, lsm_tree->value_format); __wt_free(session, lsm_tree->collator_name); __wt_free(session, lsm_tree->bloom_config); __wt_free(session, lsm_tree->file_config); WT_TRET(__wt_rwlock_destroy(session, &lsm_tree->rwlock)); WT_TRET(__wt_cond_destroy(session, &lsm_tree->work_cond)); for (i = 0; i < lsm_tree->nchunks; i++) { if ((chunk = lsm_tree->chunk[i]) == NULL) continue; __wt_free(session, chunk->bloom_uri); __wt_free(session, chunk->uri); __wt_free(session, chunk); } __wt_free(session, lsm_tree->chunk); for (i = 0; i < lsm_tree->nold_chunks; i++) { chunk = lsm_tree->old_chunks[i]; WT_ASSERT(session, chunk != NULL); __wt_free(session, chunk->bloom_uri); __wt_free(session, chunk->uri); __wt_free(session, chunk); } __wt_free(session, lsm_tree->old_chunks); __wt_free(session, lsm_tree); return (ret); }
/* * __wt_thread_group_create -- * Create a new thread group, assumes incoming group structure is * zero initialized. */ int __wt_thread_group_create( WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, const char *name, uint32_t min, uint32_t max, uint32_t flags, int (*run_func)(WT_SESSION_IMPL *session, WT_THREAD *context)) { WT_DECL_RET; bool cond_alloced; /* Check that the structure is initialized as expected */ WT_ASSERT(session, group->alloc == 0); cond_alloced = false; __wt_verbose(session, WT_VERB_THREAD_GROUP, "Creating thread group: %p", (void *)group); WT_RET(__wt_rwlock_alloc(session, &group->lock, "Thread group")); WT_ERR(__wt_cond_alloc( session, "Thread group cond", false, &group->wait_cond)); cond_alloced = true; __wt_writelock(session, group->lock); group->run_func = run_func; group->name = name; WT_TRET(__thread_group_resize(session, group, min, max, flags)); __wt_writeunlock(session, group->lock); /* Cleanup on error to avoid leaking resources */ err: if (ret != 0) { if (cond_alloced) WT_TRET(__wt_cond_destroy(session, &group->wait_cond)); __wt_rwlock_destroy(session, &group->lock); } return (ret); }
/* * __wt_logmgr_destroy -- * Destroy the log archiving server thread and logging subsystem. */ int __wt_logmgr_destroy(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_SESSION *wt_session; conn = S2C(session); if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) { /* * We always set up the log_path so printlog can work without * recovery. Therefore, always free it, even if logging isn't * on. */ __wt_free(session, conn->log_path); return (0); } if (conn->log_tid_set) { WT_TRET(__wt_cond_signal(session, conn->log_cond)); WT_TRET(__wt_thread_join(session, conn->log_tid)); conn->log_tid_set = 0; } if (conn->log_file_tid_set) { WT_TRET(__wt_cond_signal(session, conn->log_file_cond)); WT_TRET(__wt_thread_join(session, conn->log_file_tid)); conn->log_file_tid_set = 0; } if (conn->log_file_session != NULL) { wt_session = &conn->log_file_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); conn->log_file_session = NULL; } if (conn->log_wrlsn_tid_set) { WT_TRET(__wt_cond_signal(session, conn->log_wrlsn_cond)); WT_TRET(__wt_thread_join(session, conn->log_wrlsn_tid)); conn->log_wrlsn_tid_set = 0; } if (conn->log_wrlsn_session != NULL) { wt_session = &conn->log_wrlsn_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); conn->log_wrlsn_session = NULL; } WT_TRET(__wt_log_slot_destroy(session)); WT_TRET(__wt_log_close(session)); /* Close the server thread's session. */ if (conn->log_session != NULL) { wt_session = &conn->log_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); conn->log_session = NULL; } /* Destroy the condition variables now that all threads are stopped */ WT_TRET(__wt_cond_destroy(session, &conn->log_cond)); WT_TRET(__wt_cond_destroy(session, &conn->log_file_cond)); WT_TRET(__wt_cond_destroy(session, &conn->log_wrlsn_cond)); WT_TRET(__wt_cond_destroy(session, &conn->log->log_sync_cond)); WT_TRET(__wt_cond_destroy(session, &conn->log->log_write_cond)); WT_TRET(__wt_rwlock_destroy(session, &conn->log->log_archive_lock)); __wt_spin_destroy(session, &conn->log->log_lock); __wt_spin_destroy(session, &conn->log->log_slot_lock); __wt_spin_destroy(session, &conn->log->log_sync_lock); __wt_spin_destroy(session, &conn->log->log_writelsn_lock); __wt_free(session, conn->log_path); __wt_free(session, conn->log); return (ret); }
/* * __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); }