/* * wts_ops -- * Perform a number of operations in a set of threads. */ void wts_ops(int lastrun) { TINFO *tinfo, total; WT_CONNECTION *conn; WT_SESSION *session; pthread_t backup_tid, compact_tid; int64_t fourths, thread_ops; uint32_t i; int ret, running; conn = g.wts_conn; session = NULL; /* -Wconditional-uninitialized */ memset(&backup_tid, 0, sizeof(backup_tid)); memset(&compact_tid, 0, sizeof(compact_tid)); /* * There are two mechanisms to specify the length of the run, a number * of operations and a timer, when either expire the run terminates. * Each thread does an equal share of the total operations (and make * sure that it's not 0). * * Calculate how many fourth-of-a-second sleeps until any timer expires. */ if (g.c_ops == 0) thread_ops = -1; else { if (g.c_ops < g.c_threads) g.c_ops = g.c_threads; thread_ops = g.c_ops / g.c_threads; } if (g.c_timer == 0) fourths = -1; else fourths = ((int64_t)g.c_timer * 4 * 60) / FORMAT_OPERATION_REPS; /* Initialize the table extension code. */ table_append_init(); /* * We support replay of threaded runs, but don't log random numbers * after threaded operations start, there's no point. */ if (!SINGLETHREADED) g.rand_log_stop = 1; /* Open a session. */ if (g.logging != 0) { if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); (void)g.wt_api->msg_printf(g.wt_api, session, "=============== thread ops start ==============="); } /* Create thread structure; start the worker threads. */ if ((tinfo = calloc((size_t)g.c_threads, sizeof(*tinfo))) == NULL) die(errno, "calloc"); for (i = 0; i < g.c_threads; ++i) { tinfo[i].id = (int)i + 1; tinfo[i].state = TINFO_RUNNING; if ((ret = pthread_create(&tinfo[i].tid, NULL, ops, &tinfo[i])) != 0) die(ret, "pthread_create"); } /* If a multi-threaded run, start backup and compaction threads. */ if (g.c_backups && (ret = pthread_create(&backup_tid, NULL, backup, NULL)) != 0) die(ret, "pthread_create: backup"); if (g.c_compact && (ret = pthread_create(&compact_tid, NULL, compact, NULL)) != 0) die(ret, "pthread_create: compaction"); /* Spin on the threads, calculating the totals. */ for (;;) { /* Clear out the totals each pass. */ memset(&total, 0, sizeof(total)); for (i = 0, running = 0; i < g.c_threads; ++i) { total.commit += tinfo[i].commit; total.deadlock += tinfo[i].deadlock; total.insert += tinfo[i].insert; total.remove += tinfo[i].remove; total.rollback += tinfo[i].rollback; total.search += tinfo[i].search; total.update += tinfo[i].update; switch (tinfo[i].state) { case TINFO_RUNNING: running = 1; break; case TINFO_COMPLETE: tinfo[i].state = TINFO_JOINED; (void)pthread_join(tinfo[i].tid, NULL); break; case TINFO_JOINED: break; } /* * If the timer has expired or this thread has completed * its operations, notify the thread it should quit. */ if (fourths == 0 || (thread_ops != -1 && tinfo[i].ops >= (uint64_t)thread_ops)) { /* * On the last execution, optionally drop core * for recovery testing. */ if (lastrun && g.c_abort) { static char *core = NULL; *core = 0; } tinfo[i].quit = 1; } } track("ops", 0ULL, &total); if (!running) break; (void)usleep(250000); /* 1/4th of a second */ if (fourths != -1) --fourths; } free(tinfo); /* Wait for the backup, compaction thread. */ g.workers_finished = 1; if (g.c_backups) (void)pthread_join(backup_tid, NULL); if (g.c_compact) (void)pthread_join(compact_tid, NULL); if (g.logging != 0) { (void)g.wt_api->msg_printf(g.wt_api, session, "=============== thread ops stop ==============="); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); } }
/* * wts_ops -- * Perform a number of operations in a set of threads. */ void wts_ops(void) { TINFO *tinfo, total; WT_CONNECTION *conn; WT_SESSION *session; pthread_t backup_tid, compact_tid; int ret, running; uint32_t i; conn = g.wts_conn; /* * We support replay of threaded runs, but don't log random numbers * after threaded operations start, there's no point. */ if (!SINGLETHREADED) g.rand_log_stop = 1; /* Initialize the table extension code. */ table_append_init(); /* Open a session. */ if (g.logging != 0) { if ((ret = conn->open_session(conn, NULL, NULL, &session)) != 0) die(ret, "connection.open_session"); (void)g.wt_api->msg_printf(g.wt_api, session, "=============== thread ops start ==============="); } if (SINGLETHREADED) { memset(&total, 0, sizeof(total)); total.id = 1; (void)ops(&total); } else { g.threads_finished = 0; /* * Create thread structure; start worker, backup, compaction * threads. */ if ((tinfo = calloc((size_t)g.c_threads, sizeof(*tinfo))) == NULL) die(errno, "calloc"); for (i = 0; i < g.c_threads; ++i) { tinfo[i].id = (int)i + 1; tinfo[i].state = TINFO_RUNNING; if ((ret = pthread_create( &tinfo[i].tid, NULL, ops, &tinfo[i])) != 0) die(ret, "pthread_create"); } if ((ret = pthread_create(&backup_tid, NULL, hot_backup, NULL)) != 0) die(ret, "pthread_create"); if (g.c_compact && (ret = pthread_create(&compact_tid, NULL, compact, NULL)) != 0) die(ret, "pthread_create"); /* Wait for the threads. */ for (;;) { total.commit = total.deadlock = total.insert = total.remove = total.rollback = total.search = total.update = 0; for (i = 0, running = 0; i < g.c_threads; ++i) { total.commit += tinfo[i].commit; total.deadlock += tinfo[i].deadlock; total.insert += tinfo[i].insert; total.remove += tinfo[i].remove; total.rollback += tinfo[i].rollback; total.search += tinfo[i].search; total.update += tinfo[i].update; switch (tinfo[i].state) { case TINFO_RUNNING: running = 1; break; case TINFO_COMPLETE: tinfo[i].state = TINFO_JOINED; (void)pthread_join(tinfo[i].tid, NULL); break; case TINFO_JOINED: break; } } track("ops", 0ULL, &total); if (!running) break; (void)usleep(100000); /* 1/10th of a second */ } free(tinfo); /* Wait for the backup, compaction thread. */ g.threads_finished = 1; (void)pthread_join(backup_tid, NULL); if (g.c_compact) (void)pthread_join(compact_tid, NULL); } if (g.logging != 0) { (void)g.wt_api->msg_printf(g.wt_api, session, "=============== thread ops stop ==============="); if ((ret = session->close(session, NULL)) != 0) die(ret, "session.close"); } }