/* * __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_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_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); }
/* * start_workers -- * Setup the configuration for the tables being populated, then start * the worker thread(s) and wait for them to finish. */ int start_workers(table_type type) { struct timeval start, stop; WT_SESSION *session; wt_thread_t *tids; double seconds; int i, ret; ret = 0; /* Create statistics and thread structures. */ if ((tids = calloc((size_t)(g.nworkers), sizeof(*tids))) == NULL) return (log_print_err("calloc", errno, 1)); if ((ret = g.conn->open_session(g.conn, NULL, NULL, &session)) != 0) { (void)log_print_err("conn.open_session", ret, 1); goto err; } /* Setup the cookies */ for (i = 0; i < g.ntables; ++i) { g.cookies[i].id = i; if (type == MIX) g.cookies[i].type = (table_type)((i % MAX_TABLE_TYPE) + 1); else g.cookies[i].type = type; testutil_check(__wt_snprintf( g.cookies[i].uri, sizeof(g.cookies[i].uri), "%s%04d", URI_BASE, g.cookies[i].id)); /* Should probably be atomic to avoid races. */ if ((ret = create_table(session, &g.cookies[i])) != 0) goto err; } (void)gettimeofday(&start, NULL); /* Create threads. */ for (i = 0; i < g.nworkers; ++i) testutil_check(__wt_thread_create( NULL, &tids[i], worker, &g.cookies[i])); /* Wait for the threads. */ for (i = 0; i < g.nworkers; ++i) testutil_check(__wt_thread_join(NULL, tids[i])); (void)gettimeofday(&stop, NULL); seconds = (stop.tv_sec - start.tv_sec) + (stop.tv_usec - start.tv_usec) * 1e-6; printf("Ran workers for: %f seconds\n", seconds); err: free(tids); return (ret); }
/* * __thread_group_shrink -- * Decrease the number of running threads in the group, and free any * memory associated with slots larger than the new count. */ static int __thread_group_shrink(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, uint32_t new_count) { WT_DECL_RET; WT_SESSION *wt_session; WT_THREAD *thread; uint32_t current_slot; WT_ASSERT(session, __wt_rwlock_islocked(session, group->lock)); for (current_slot = group->alloc; current_slot > new_count; ) { /* * The offset value is a counter not an array index, * so adjust it before finding the last thread in the group. */ thread = group->threads[--current_slot]; if (thread == NULL) continue; /* Wake threads to ensure they notice the state change */ if (thread->tid != 0) { __wt_verbose(session, WT_VERB_THREAD_GROUP, "Stopping utility thread: %p:%" PRIu32, (void *)group, thread->id); F_CLR(thread, WT_THREAD_RUN); __wt_cond_signal(session, group->wait_cond); WT_TRET(__wt_thread_join(session, thread->tid)); thread->tid = 0; } if (thread->session != NULL) { wt_session = (WT_SESSION *)thread->session; WT_TRET(wt_session->close(wt_session, NULL)); thread->session = NULL; } __wt_free(session, thread); group->threads[current_slot] = NULL; } /* Update the thread group state to match our changes */ group->current_threads = current_slot; 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); }
/* * __lsm_tree_close -- * Close an LSM tree structure. */ static int __lsm_tree_close(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_DECL_RET; WT_SESSION *wt_session; WT_SESSION_IMPL *s; uint32_t i; if (F_ISSET(lsm_tree, WT_LSM_TREE_WORKING)) { F_CLR(lsm_tree, WT_LSM_TREE_WORKING); if (F_ISSET(S2C(session), WT_CONN_LSM_MERGE)) for (i = 0; i < lsm_tree->merge_threads; i++) WT_TRET(__wt_thread_join( session, lsm_tree->worker_tids[i])); WT_TRET(__wt_thread_join(session, lsm_tree->ckpt_tid)); if (FLD_ISSET(lsm_tree->bloom, WT_LSM_BLOOM_NEWEST)) WT_TRET(__wt_thread_join(session, lsm_tree->bloom_tid)); } /* * Close the worker thread sessions and free their hazard arrays * (necessary because we set WT_SESSION_INTERNAL to simplify shutdown * ordering). * * Do this in the main thread to avoid deadlocks. */ for (i = 0; i < lsm_tree->merge_threads; i++) { if ((s = lsm_tree->worker_sessions[i]) == NULL) continue; lsm_tree->worker_sessions[i] = NULL; F_SET(s, F_ISSET(session, WT_SESSION_SCHEMA_LOCKED)); wt_session = &s->iface; WT_TRET(wt_session->close(wt_session, NULL)); /* * This is safe after the close because session handles are * not freed, but are managed by the connection. */ __wt_free(NULL, s->hazard); } if (lsm_tree->bloom_session != NULL) { F_SET(lsm_tree->bloom_session, F_ISSET(session, WT_SESSION_SCHEMA_LOCKED)); wt_session = &lsm_tree->bloom_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); /* * This is safe after the close because session handles are * not freed, but are managed by the connection. */ __wt_free(NULL, lsm_tree->bloom_session->hazard); } if (lsm_tree->ckpt_session != NULL) { F_SET(lsm_tree->ckpt_session, F_ISSET(session, WT_SESSION_SCHEMA_LOCKED)); wt_session = &lsm_tree->ckpt_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); /* * This is safe after the close because session handles are * not freed, but are managed by the connection. */ __wt_free(NULL, lsm_tree->ckpt_session->hazard); } if (ret != 0) { __wt_err(session, ret, "shutdown error while cleaning up LSM"); (void)__wt_panic(session); } return (ret); }
static void run_workload(uint32_t nth) { WT_CONNECTION *conn; WT_SESSION *session; WT_THREAD_DATA *td; wt_thread_t *thr; uint32_t i; int ret; char envconf[512]; thr = dcalloc(nth+1, sizeof(*thr)); td = dcalloc(nth+1, sizeof(WT_THREAD_DATA)); if (chdir(home) != 0) testutil_die(errno, "Child chdir: %s", home); if (inmem) strcpy(envconf, ENV_CONFIG_DEF); else strcpy(envconf, ENV_CONFIG_TXNSYNC); if (compat) strcat(envconf, ENV_CONFIG_COMPAT); if ((ret = wiredtiger_open(NULL, NULL, envconf, &conn)) != 0) testutil_die(ret, "wiredtiger_open"); if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) testutil_die(ret, "WT_CONNECTION:open_session"); /* * Create all the tables. */ if ((ret = session->create(session, uri_collection, "key_format=S,value_format=u,log=(enabled=false)")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri_collection); if ((ret = session->create(session, uri_local, "key_format=S,value_format=u")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri_local); if ((ret = session->create(session, uri_oplog, "key_format=S,value_format=u")) != 0) testutil_die(ret, "WT_SESSION.create: %s", uri_oplog); /* * Don't log the stable timestamp table so that we know what timestamp * was stored at the checkpoint. */ if ((ret = session->create(session, stable_store, "key_format=Q,value_format=Q,log=(enabled=false)")) != 0) testutil_die(ret, "WT_SESSION.create: %s", stable_store); if ((ret = session->close(session, NULL)) != 0) testutil_die(ret, "WT_SESSION:close"); /* * Thread 0 is the checkpoint thread. */ td[0].conn = conn; td[0].id = 0; printf("Create checkpoint thread\n"); testutil_check(__wt_thread_create( NULL, &thr[0], thread_ckpt_run, &td[0])); for (i = 1; i <= nth; ++i) { td[i].conn = conn; td[i].start = (UINT64_MAX / nth) * (i - 1); td[i].id = i; testutil_check(__wt_thread_create( NULL, &thr[i], thread_run, &td[i])); } /* * The threads never exit, so the child will just wait here until * it is killed. */ printf("Create %" PRIu32 " writer threads\n", nth); fflush(stdout); for (i = 0; i <= nth; ++i) testutil_check(__wt_thread_join(NULL, thr[i])); /* * NOTREACHED */ free(thr); free(td); exit(EXIT_SUCCESS); }
static void run_workload(uint32_t nth) { WT_CONNECTION *conn; WT_SESSION *session; THREAD_DATA *td; wt_thread_t *thr; uint32_t ckpt_id, i, ts_id; char envconf[512], uri[128]; thr = dcalloc(nth+2, sizeof(*thr)); td = dcalloc(nth+2, sizeof(THREAD_DATA)); if (chdir(home) != 0) testutil_die(errno, "Child chdir: %s", home); if (inmem) (void)__wt_snprintf(envconf, sizeof(envconf), ENV_CONFIG_DEF, SESSION_MAX); else (void)__wt_snprintf(envconf, sizeof(envconf), ENV_CONFIG_TXNSYNC, SESSION_MAX); if (compat) strcat(envconf, ENV_CONFIG_COMPAT); testutil_check(wiredtiger_open(NULL, NULL, envconf, &conn)); testutil_check(conn->open_session(conn, NULL, NULL, &session)); /* * Create all the tables. */ testutil_check(__wt_snprintf( uri, sizeof(uri), "%s:%s", table_pfx, uri_collection)); testutil_check(session->create(session, uri, "key_format=S,value_format=u,log=(enabled=false)")); testutil_check(__wt_snprintf( uri, sizeof(uri), "%s:%s", table_pfx, uri_local)); testutil_check(session->create(session, uri, "key_format=S,value_format=u")); testutil_check(__wt_snprintf( uri, sizeof(uri), "%s:%s", table_pfx, uri_oplog)); testutil_check(session->create(session, uri, "key_format=S,value_format=u")); /* * Don't log the stable timestamp table so that we know what timestamp * was stored at the checkpoint. */ testutil_check(session->close(session, NULL)); /* * The checkpoint thread and the timestamp threads are added at the end. */ ckpt_id = nth; td[ckpt_id].conn = conn; td[ckpt_id].info = nth; printf("Create checkpoint thread\n"); testutil_check(__wt_thread_create( NULL, &thr[ckpt_id], thread_ckpt_run, &td[ckpt_id])); ts_id = nth + 1; if (use_ts) { td[ts_id].conn = conn; td[ts_id].info = nth; printf("Create timestamp thread\n"); testutil_check(__wt_thread_create( NULL, &thr[ts_id], thread_ts_run, &td[ts_id])); } printf("Create %" PRIu32 " writer threads\n", nth); for (i = 0; i < nth; ++i) { td[i].conn = conn; td[i].start = WT_BILLION * (uint64_t)i; td[i].info = i; testutil_check(__wt_thread_create( NULL, &thr[i], thread_run, &td[i])); } /* * The threads never exit, so the child will just wait here until * it is killed. */ fflush(stdout); for (i = 0; i <= ts_id; ++i) testutil_check(__wt_thread_join(NULL, &thr[i])); /* * NOTREACHED */ free(thr); free(td); exit(EXIT_SUCCESS); }
/* * __lsm_tree_close -- * Close an LSM tree structure. */ static int __lsm_tree_close(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_DECL_RET; WT_SESSION *wt_session; WT_SESSION_IMPL *s; uint32_t i; if (F_ISSET(lsm_tree, WT_LSM_TREE_WORKING)) { F_CLR(lsm_tree, WT_LSM_TREE_WORKING); /* * Signal all threads to wake them up, then wait for them to * exit. * * !!! * If we have the schema lock, have the LSM worker sessions * inherit the flag before we do anything. The thread may * already be waiting for the schema lock, but the loop in the * WT_WITH_SCHEMA_LOCK macro takes care of that. */ if (F_ISSET(S2C(session), WT_CONN_LSM_MERGE)) for (i = 0; i < lsm_tree->merge_threads; i++) { if ((s = lsm_tree->worker_sessions[i]) == NULL) continue; if (F_ISSET(session, WT_SESSION_SCHEMA_LOCKED)) s->skip_schema_lock = 1; WT_TRET(__wt_cond_signal( session, lsm_tree->work_cond)); WT_TRET(__wt_thread_join( session, lsm_tree->worker_tids[i])); } if (F_ISSET(session, WT_SESSION_SCHEMA_LOCKED)) lsm_tree->ckpt_session->skip_schema_lock = 1; WT_TRET(__wt_cond_signal(session, lsm_tree->work_cond)); WT_TRET(__wt_thread_join(session, lsm_tree->ckpt_tid)); } /* * Close the worker thread sessions. Do this in the main thread to * avoid deadlocks. */ for (i = 0; i < lsm_tree->merge_threads; i++) { if ((s = lsm_tree->worker_sessions[i]) == NULL) continue; lsm_tree->worker_sessions[i] = NULL; wt_session = &s->iface; WT_TRET(wt_session->close(wt_session, NULL)); } if (lsm_tree->ckpt_session != NULL) { wt_session = &lsm_tree->ckpt_session->iface; WT_TRET(wt_session->close(wt_session, NULL)); } if (ret != 0) { __wt_err(session, ret, "shutdown error while cleaning up LSM"); (void)__wt_panic(session); } return (ret); }