/* * __ckpt_server_start -- * Start the checkpoint server thread. */ static int __ckpt_server_start(WT_CONNECTION_IMPL *conn) { WT_SESSION_IMPL *session; /* Nothing to do if the server is already running. */ if (conn->ckpt_session != NULL) return (0); F_SET(conn, WT_CONN_SERVER_CHECKPOINT); /* The checkpoint server gets its own session. */ WT_RET(__wt_open_internal_session( conn, "checkpoint-server", 1, 1, &conn->ckpt_session)); session = conn->ckpt_session; /* * Checkpoint does enough I/O it may be called upon to perform slow * operations for the block manager. */ F_SET(session, WT_SESSION_CAN_WAIT); WT_RET( __wt_cond_alloc(session, "checkpoint server", 0, &conn->ckpt_cond)); /* * Start the thread. */ WT_RET(__wt_thread_create( session, &conn->ckpt_tid, __ckpt_server, session)); conn->ckpt_tid_set = 1; return (0); }
/* * __wt_lsm_worker_start -- * A wrapper around the LSM worker thread start. */ int __wt_lsm_worker_start(WT_SESSION_IMPL *session, WT_LSM_WORKER_ARGS *args) { WT_RET(__wt_verbose(session, WT_VERB_LSM, "Start LSM worker %d type 0x%x", args->id, args->type)); return (__wt_thread_create(session, &args->tid, __lsm_worker, args)); }
/* * __wt_sweep_create -- * Start the handle sweep thread. */ int __wt_sweep_create(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; conn = S2C(session); /* Set first, the thread might run before we finish up. */ F_SET(conn, WT_CONN_SERVER_SWEEP); WT_RET(__wt_open_internal_session( conn, "sweep-server", 1, 1, &conn->sweep_session)); session = conn->sweep_session; /* * Handle sweep does enough I/O it may be called upon to perform slow * operations for the block manager. */ F_SET(session, WT_SESSION_CAN_WAIT); WT_RET(__wt_cond_alloc( session, "handle sweep server", 0, &conn->sweep_cond)); WT_RET(__wt_thread_create( session, &conn->sweep_tid, __sweep_server, session)); conn->sweep_tid_set = 1; return (0); }
/* * __thread_group_grow -- * Increase the number of running threads in the group. */ static int __thread_group_grow( WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, uint32_t new_count) { WT_THREAD *thread; WT_ASSERT(session, __wt_rwlock_islocked(session, group->lock)); /* * Any bounds checking is done by the caller so we know that * there is space in the array for new threads. */ while (group->current_threads < new_count) { thread = group->threads[group->current_threads++]; __wt_verbose(session, WT_VERB_THREAD_GROUP, "Starting utility thread: %p:%" PRIu32, (void *)group, thread->id); F_SET(thread, WT_THREAD_RUN); WT_ASSERT(session, thread->session != NULL); WT_RET(__wt_thread_create(thread->session, &thread->tid, __wt_thread_run, thread)); } return (0); }
/* * __ckpt_server_start -- * Start the checkpoint server thread. */ static int __ckpt_server_start(WT_CONNECTION_IMPL *conn) { WT_SESSION_IMPL *session; session = conn->default_session; /* Nothing to do if the server is already running. */ if (conn->ckpt_session != NULL) return (0); F_SET(conn, WT_CONN_SERVER_CHECKPOINT); /* The checkpoint server gets its own session. */ WT_RET(__wt_open_internal_session( conn, "checkpoint-server", 1, 1, &conn->ckpt_session)); WT_RET( __wt_cond_alloc(session, "checkpoint server", 0, &conn->ckpt_cond)); /* * Start the thread. */ WT_RET(__wt_thread_create( session, &conn->ckpt_tid, __ckpt_server, conn->ckpt_session)); conn->ckpt_tid_set = 1; return (0); }
/* * __wt_checkpoint_create -- * Start the checkpoint server thread. */ int __wt_checkpoint_create(WT_CONNECTION_IMPL *conn, const char *cfg[]) { WT_SESSION_IMPL *session; int run; session = conn->default_session; /* Handle configuration. */ WT_RET(__ckpt_server_config(session, cfg, &run)); /* If not configured, we're done. */ if (!run) return (0); /* The checkpoint server gets its own session. */ WT_RET(__wt_open_session(conn, 1, NULL, NULL, &conn->ckpt_session)); conn->ckpt_session->name = "checkpoint-server"; WT_RET( __wt_cond_alloc(session, "checkpoint server", 0, &conn->ckpt_cond)); /* * Start the thread. */ WT_RET(__wt_thread_create( session, &conn->ckpt_tid, __ckpt_server, conn->ckpt_session)); conn->ckpt_tid_set = 1; return (0); }
/* * __wt_lsm_start_worker -- * Start the worker thread for an LSM tree. */ static int __lsm_tree_start_worker(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_CONNECTION *wt_conn; WT_LSM_WORKER_ARGS *wargs; WT_SESSION *wt_session; WT_SESSION_IMPL *s; uint32_t i; wt_conn = &S2C(session)->iface; WT_RET(wt_conn->open_session(wt_conn, NULL, NULL, &wt_session)); lsm_tree->ckpt_session = (WT_SESSION_IMPL *)wt_session; F_SET(lsm_tree->ckpt_session, WT_SESSION_INTERNAL); F_SET(lsm_tree, WT_LSM_TREE_WORKING); /* The new thread will rely on the WORKING value being visible. */ WT_FULL_BARRIER(); if (F_ISSET(S2C(session), WT_CONN_LSM_MERGE)) for (i = 0; i < lsm_tree->merge_threads; i++) { WT_RET(wt_conn->open_session( wt_conn, NULL, NULL, &wt_session)); s = (WT_SESSION_IMPL *)wt_session; F_SET(s, WT_SESSION_INTERNAL); lsm_tree->worker_sessions[i] = s; WT_RET(__wt_calloc_def(session, 1, &wargs)); wargs->lsm_tree = lsm_tree; wargs->id = i; WT_RET(__wt_thread_create(session, &lsm_tree->worker_tids[i], __wt_lsm_merge_worker, wargs)); } if (FLD_ISSET(lsm_tree->bloom, WT_LSM_BLOOM_NEWEST)) { WT_RET(wt_conn->open_session(wt_conn, NULL, NULL, &wt_session)); lsm_tree->bloom_session = (WT_SESSION_IMPL *)wt_session; F_SET(lsm_tree->bloom_session, WT_SESSION_INTERNAL); WT_RET(__wt_thread_create(session, &lsm_tree->bloom_tid, __wt_lsm_bloom_worker, lsm_tree)); } WT_RET(__wt_thread_create(session, &lsm_tree->ckpt_tid, __wt_lsm_checkpoint_worker, lsm_tree)); return (0); }
/* * __lsm_tree_start_worker -- * Start the worker thread for an LSM tree. */ static int __lsm_tree_start_worker(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) { WT_CONNECTION *wt_conn; WT_LSM_WORKER_ARGS *wargs; WT_SESSION *wt_session; WT_SESSION_IMPL *s; uint32_t i; wt_conn = &S2C(session)->iface; /* * All the LSM worker threads do their operations on read-only files. * Use read-uncommitted isolation to avoid keeping updates in cache * unnecessarily. */ WT_RET(wt_conn->open_session( wt_conn, NULL, "isolation=read-uncommitted", &wt_session)); lsm_tree->ckpt_session = (WT_SESSION_IMPL *)wt_session; F_SET(lsm_tree->ckpt_session, WT_SESSION_INTERNAL); F_SET(lsm_tree, WT_LSM_TREE_WORKING); /* The new thread will rely on the WORKING value being visible. */ WT_FULL_BARRIER(); if (F_ISSET(S2C(session), WT_CONN_LSM_MERGE)) for (i = 0; i < lsm_tree->merge_threads; i++) { WT_RET(wt_conn->open_session( wt_conn, NULL, "isolation=read-uncommitted", &wt_session)); s = (WT_SESSION_IMPL *)wt_session; F_SET(s, WT_SESSION_INTERNAL); lsm_tree->worker_sessions[i] = s; WT_RET(__wt_calloc_def(session, 1, &wargs)); wargs->lsm_tree = lsm_tree; wargs->id = i; WT_RET(__wt_thread_create(session, &lsm_tree->worker_tids[i], __wt_lsm_merge_worker, wargs)); } WT_RET(__wt_thread_create(session, &lsm_tree->ckpt_tid, __wt_lsm_checkpoint_worker, lsm_tree)); return (0); }
/* * 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); }
/* * __wt_sweep_create -- * Start the handle sweep thread. */ int __wt_sweep_create(WT_CONNECTION_IMPL *conn) { WT_SESSION_IMPL *session; session = conn->default_session; F_SET(conn, WT_CONN_SERVER_SWEEP); WT_RET(__wt_open_session(conn, 1, NULL, NULL, &conn->sweep_session)); conn->sweep_session->name = "sweep-server"; session = conn->sweep_session; WT_RET(__wt_cond_alloc( session, "handle sweep server", 0, &conn->sweep_cond)); WT_RET(__wt_thread_create( session, &conn->sweep_tid, __sweep_server, session)); conn->sweep_tid_set = 1; return (0); }
/* * __wt_logmgr_open -- * Start the log service threads. */ int __wt_logmgr_open(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; conn = S2C(session); /* If no log thread services are configured, we're done. */ if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) return (0); /* * Start the log close thread. It is not configurable. * If logging is enabled, this thread runs. */ WT_RET(__wt_open_internal_session( conn, "log-close-server", 0, 0, &conn->log_file_session)); WT_RET(__wt_cond_alloc(conn->log_file_session, "log close server", 0, &conn->log_file_cond)); /* * Start the log file close thread. */ WT_RET(__wt_thread_create(conn->log_file_session, &conn->log_file_tid, __log_file_server, conn->log_file_session)); conn->log_file_tid_set = 1; /* * Start the log write LSN thread. It is not configurable. * If logging is enabled, this thread runs. */ WT_RET(__wt_open_internal_session( conn, "log-wrlsn-server", 0, 0, &conn->log_wrlsn_session)); WT_RET(__wt_cond_alloc(conn->log_wrlsn_session, "log write lsn server", 0, &conn->log_wrlsn_cond)); WT_RET(__wt_thread_create(conn->log_wrlsn_session, &conn->log_wrlsn_tid, __log_wrlsn_server, conn->log_wrlsn_session)); conn->log_wrlsn_tid_set = 1; /* If no log thread services are configured, we're done. */ if (!FLD_ISSET(conn->log_flags, (WT_CONN_LOG_ARCHIVE | WT_CONN_LOG_PREALLOC))) return (0); /* * If a log server thread exists, the user may have reconfigured * archiving or pre-allocation. Signal the thread. Otherwise the * user wants archiving and/or allocation and we need to start up * the thread. */ if (conn->log_session != NULL) { WT_ASSERT(session, conn->log_cond != NULL); WT_ASSERT(session, conn->log_tid_set != 0); WT_RET(__wt_cond_signal(session, conn->log_cond)); } else { /* The log server gets its own session. */ WT_RET(__wt_open_internal_session( conn, "log-server", 0, 0, &conn->log_session)); WT_RET(__wt_cond_alloc(conn->log_session, "log server", 0, &conn->log_cond)); /* * Start the thread. */ WT_RET(__wt_thread_create(conn->log_session, &conn->log_tid, __log_server, conn->log_session)); conn->log_tid_set = 1; } return (0); }
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); }
/* * __wt_logmgr_open -- * Start the log service threads. */ int __wt_logmgr_open(WT_SESSION_IMPL *session) { WT_CONNECTION_IMPL *conn; uint32_t session_flags; conn = S2C(session); /* If no log thread services are configured, we're done. */ if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED)) return (0); F_SET(conn, WT_CONN_SERVER_LOG); /* * Start the log close thread. It is not configurable. * If logging is enabled, this thread runs. */ session_flags = WT_SESSION_NO_DATA_HANDLES; WT_RET(__wt_open_internal_session(conn, "log-close-server", false, session_flags, &conn->log_file_session)); WT_RET(__wt_cond_alloc( conn->log_file_session, "log close server", &conn->log_file_cond)); /* * Start the log file close thread. */ WT_RET(__wt_thread_create(conn->log_file_session, &conn->log_file_tid, __log_file_server, conn->log_file_session)); conn->log_file_tid_set = true; /* * Start the log write LSN thread. It is not configurable. * If logging is enabled, this thread runs. */ WT_RET(__wt_open_internal_session(conn, "log-wrlsn-server", false, session_flags, &conn->log_wrlsn_session)); WT_RET(__wt_cond_auto_alloc(conn->log_wrlsn_session, "log write lsn server", 10000, WT_MILLION, &conn->log_wrlsn_cond)); WT_RET(__wt_thread_create(conn->log_wrlsn_session, &conn->log_wrlsn_tid, __log_wrlsn_server, conn->log_wrlsn_session)); conn->log_wrlsn_tid_set = true; /* * If a log server thread exists, the user may have reconfigured * archiving or pre-allocation. Signal the thread. Otherwise the * user wants archiving and/or allocation and we need to start up * the thread. */ if (conn->log_session != NULL) { WT_ASSERT(session, conn->log_cond != NULL); WT_ASSERT(session, conn->log_tid_set == true); __wt_cond_signal(session, conn->log_cond); } else { /* The log server gets its own session. */ WT_RET(__wt_open_internal_session(conn, "log-server", false, session_flags, &conn->log_session)); WT_RET(__wt_cond_auto_alloc(conn->log_session, "log server", 50000, WT_MILLION, &conn->log_cond)); /* * Start the thread. */ WT_RET(__wt_thread_create(conn->log_session, &conn->log_tid, __log_server, conn->log_session)); conn->log_tid_set = true; } return (0); }