summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorsueloverso <sue@mongodb.com>2016-03-10 08:52:18 -0500
committersueloverso <sue@mongodb.com>2016-03-10 08:52:18 -0500
commit42df2d9541066933128a19d73b18e6dec2babf96 (patch)
tree6febd07f65d4e822ec1e1ce47cd39c0697f1f945
parent140d34a3129bc12fc31dfb72e5cc8b78079899fc (diff)
parent2d22b037201a85564f3073aa86900709ae7f5ddc (diff)
downloadmongo-42df2d9541066933128a19d73b18e6dec2babf96.tar.gz
Merge pull request #2550 from wiredtiger/wt-2318-auto-cond-var
WT-2318 Add implementation for auto adjusting condition variables.
-rw-r--r--build_posix/Make.subdirs1
-rw-r--r--build_win/filelist.win1
-rw-r--r--dist/filelist1
-rw-r--r--dist/s_string.ok5
-rw-r--r--dist/stat_data.py5
-rw-r--r--src/conn/conn_cache.c6
-rw-r--r--src/conn/conn_log.c82
-rw-r--r--src/cursor/cur_log.c2
-rw-r--r--src/evict/evict_lru.c11
-rw-r--r--src/include/extern.h7
-rw-r--r--src/include/mutex.h7
-rw-r--r--src/include/stat.h5
-rw-r--r--src/include/wiredtiger.in190
-rw-r--r--src/log/log.c27
-rw-r--r--src/log/log_slot.c2
-rw-r--r--src/support/cond_auto.c136
-rw-r--r--src/support/stat.c15
-rw-r--r--test/manydbs/Makefile.am13
-rw-r--r--test/manydbs/manydbs.c237
-rwxr-xr-xtest/manydbs/smoke.sh18
20 files changed, 636 insertions, 135 deletions
diff --git a/build_posix/Make.subdirs b/build_posix/Make.subdirs
index 14258666d84..775df0c203a 100644
--- a/build_posix/Make.subdirs
+++ b/build_posix/Make.subdirs
@@ -30,6 +30,7 @@ test/cursor_order
test/fops
test/format
test/huge
+test/manydbs
test/packing
test/readonly
test/recovery
diff --git a/build_win/filelist.win b/build_win/filelist.win
index 0a313026793..b6a9caf4a74 100644
--- a/build_win/filelist.win
+++ b/build_win/filelist.win
@@ -155,6 +155,7 @@ src/session/session_compact.c
src/session/session_dhandle.c
src/session/session_salvage.c
src/support/cksum.c
+src/support/cond_auto.c
src/support/crypto.c
src/support/err.c
src/support/filename.c
diff --git a/dist/filelist b/dist/filelist
index 4ed7d7e3beb..350e0c50087 100644
--- a/dist/filelist
+++ b/dist/filelist
@@ -153,6 +153,7 @@ src/session/session_compact.c
src/session/session_dhandle.c
src/session/session_salvage.c
src/support/cksum.c
+src/support/cond_auto.c
src/support/crypto.c
src/support/err.c
src/support/filename.c
diff --git a/dist/s_string.ok b/dist/s_string.ok
index 9e091d89c4d..c582f3380bd 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -758,6 +758,8 @@ majorp
malloc
marshall
marshalled
+maxcpu
+maxdbs
mbll
mbss
mem
@@ -845,8 +847,11 @@ parserp
patchp
pathname
pathnames
+pclose
+pcpu
perf
pfx
+popen
poptable
popthreads
portably
diff --git a/dist/stat_data.py b/dist/stat_data.py
index 43d4474ac61..bd951e64999 100644
--- a/dist/stat_data.py
+++ b/dist/stat_data.py
@@ -109,6 +109,8 @@ connection_stats = [
##########################################
# System statistics
##########################################
+ ConnStat('cond_auto_wait', 'auto adjusting condition wait calls'),
+ ConnStat('cond_auto_wait_reset', 'auto adjusting condition resets'),
ConnStat('cond_wait', 'pthread mutex condition wait calls'),
ConnStat('file_open', 'files currently open', 'no_clear,no_scale'),
ConnStat('memory_allocation', 'memory allocations'),
@@ -218,6 +220,8 @@ connection_stats = [
LogStat('log_compress_write_fails', 'log records not compressed'),
LogStat('log_compress_writes', 'log records compressed'),
LogStat('log_flush', 'log flush operations'),
+ LogStat('log_force_write', 'log force write operations'),
+ LogStat('log_force_write_skip', 'log force write operations skipped'),
LogStat('log_max_filesize', 'maximum log file size', 'no_clear,no_scale,size'),
LogStat('log_prealloc_files', 'pre-allocated log files prepared'),
LogStat('log_prealloc_max', 'number of pre-allocated log files to create', 'no_clear,no_scale'),
@@ -238,6 +242,7 @@ connection_stats = [
LogStat('log_sync', 'log sync operations'),
LogStat('log_sync_dir', 'log sync_dir operations'),
LogStat('log_write_lsn', 'log server thread advances write LSN'),
+ LogStat('log_write_lsn_skip', 'log server thread write LSN walk skipped'),
LogStat('log_writes', 'log write operations'),
LogStat('log_zero_fills', 'log files manually zero-filled'),
diff --git a/src/conn/conn_cache.c b/src/conn/conn_cache.c
index 8a7064cbb35..9a2c394e9a6 100644
--- a/src/conn/conn_cache.c
+++ b/src/conn/conn_cache.c
@@ -153,8 +153,8 @@ __wt_cache_create(WT_SESSION_IMPL *session, const char *cfg[])
WT_ERR_MSG(session, EINVAL,
"eviction target must be lower than the eviction trigger");
- WT_ERR(__wt_cond_alloc(session,
- "cache eviction server", false, &cache->evict_cond));
+ WT_ERR(__wt_cond_auto_alloc(session, "cache eviction server",
+ false, 10000, WT_MILLION, &cache->evict_cond));
WT_ERR(__wt_cond_alloc(session,
"eviction waiters", false, &cache->evict_waiter_cond));
WT_ERR(__wt_spin_init(session, &cache->evict_lock, "cache eviction"));
@@ -252,7 +252,7 @@ __wt_cache_destroy(WT_SESSION_IMPL *session)
" 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_auto_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);
diff --git a/src/conn/conn_log.c b/src/conn/conn_log.c
index 5999cf20b3b..757d69bf240 100644
--- a/src/conn/conn_log.c
+++ b/src/conn/conn_log.c
@@ -142,6 +142,8 @@ __logmgr_config(
}
WT_RET(__logmgr_sync_cfg(session, cfg));
+ if (conn->log_cond != NULL)
+ WT_RET(__wt_cond_auto_signal(session, conn->log_cond));
return (0);
}
@@ -468,7 +470,7 @@ __log_file_server(void *arg)
locked = false;
__wt_spin_unlock(session, &log->log_sync_lock);
} else {
- WT_ERR(__wt_cond_signal(
+ WT_ERR(__wt_cond_auto_signal(
session, conn->log_wrlsn_cond));
/*
* We do not want to wait potentially a second
@@ -667,31 +669,54 @@ __log_wrlsn_server(void *arg)
{
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
+ WT_LOG *log;
+ WT_LSN prev;
WT_SESSION_IMPL *session;
int yield;
+ bool did_work;
session = arg;
conn = S2C(session);
+ log = conn->log;
yield = 0;
+ WT_INIT_LSN(&prev);
+ did_work = false;
while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
/*
- * Write out any log record buffers.
+ * Write out any log record buffers if anything was done
+ * since last time. Only call the function to walk the
+ * slots if the system is not idle. On an idle system
+ * the alloc_lsn will not advance and the written lsn will
+ * match the alloc_lsn.
*/
- WT_ERR(__wt_log_wrlsn(session, &yield));
+ if (__wt_log_cmp(&prev, &log->alloc_lsn) != 0 ||
+ __wt_log_cmp(&log->write_lsn, &log->alloc_lsn) != 0)
+ WT_ERR(__wt_log_wrlsn(session, &yield));
+ else
+ WT_STAT_FAST_CONN_INCR(session, log_write_lsn_skip);
+ prev = log->alloc_lsn;
+ if (yield == 0)
+ did_work = true;
+ else
+ did_work = false;
/*
* If __wt_log_wrlsn did work we want to yield instead of sleep.
*/
if (yield++ < WT_THOUSAND)
__wt_yield();
else
- WT_ERR(__wt_cond_wait(
- session, conn->log_wrlsn_cond, 10000));
+ /*
+ * Send in false because if we did any work we would
+ * not be on this path.
+ */
+ WT_ERR(__wt_cond_auto_wait(
+ session, conn->log_wrlsn_cond, did_work));
}
/*
* On close we need to do this one more time because there could
* be straggling log writes that need to be written.
*/
- WT_ERR(__wt_log_force_write(session, 1));
+ WT_ERR(__wt_log_force_write(session, 1, NULL));
WT_ERR(__wt_log_wrlsn(session, NULL));
if (0) {
err: __wt_err(session, ret, "log wrlsn server error");
@@ -706,12 +731,13 @@ err: __wt_err(session, ret, "log wrlsn server error");
static WT_THREAD_RET
__log_server(void *arg)
{
+ struct timespec start, now;
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_LOG *log;
WT_SESSION_IMPL *session;
- int freq_per_sec;
- bool locked, signalled;
+ uint64_t timediff;
+ bool did_work, locked, signalled;
session = arg;
conn = S2C(session);
@@ -719,11 +745,10 @@ __log_server(void *arg)
locked = signalled = false;
/*
- * Set this to the number of times per second we want to force out the
- * log slot buffer.
+ * Set this to the number of milliseconds we want to run archive and
+ * pre-allocation. Start it so that we run on the first time through.
*/
-#define WT_FORCE_PER_SECOND 20
- freq_per_sec = WT_FORCE_PER_SECOND;
+ timediff = WT_THOUSAND;
/*
* The log server thread does a variety of work. It forces out any
@@ -736,6 +761,7 @@ __log_server(void *arg)
* don't want log records sitting in the buffer over the time it
* takes to sync out an earlier file.
*/
+ did_work = true;
while (F_ISSET(conn, WT_CONN_LOG_SERVER_RUN)) {
/*
* Slots depend on future activity. Force out buffered
@@ -744,15 +770,14 @@ __log_server(void *arg)
* and a buffer may need to wait for the write_lsn to advance
* in the case of a synchronous buffer. We end up with a hang.
*/
- WT_ERR_BUSY_OK(__wt_log_force_write(session, 0));
+ WT_ERR_BUSY_OK(__wt_log_force_write(session, 0, &did_work));
/*
* We don't want to archive or pre-allocate files as often as
* we want to force out log buffers. Only do it once per second
* or if the condition was signalled.
*/
- if (--freq_per_sec <= 0 || signalled) {
- freq_per_sec = WT_FORCE_PER_SECOND;
+ if (timediff >= WT_THOUSAND || signalled) {
/*
* Perform log pre-allocation.
@@ -793,8 +818,12 @@ __log_server(void *arg)
}
/* Wait until the next event. */
- WT_ERR(__wt_cond_wait_signal(session, conn->log_cond,
- WT_MILLION / WT_FORCE_PER_SECOND, &signalled));
+
+ WT_ERR(__wt_epoch(session, &start));
+ WT_ERR(__wt_cond_auto_wait_signal(session, conn->log_cond,
+ did_work, &signalled));
+ WT_ERR(__wt_epoch(session, &now));
+ timediff = WT_TIMEDIFF_MS(now, start);
}
if (0) {
@@ -906,8 +935,9 @@ __wt_logmgr_open(WT_SESSION_IMPL *session)
*/
WT_RET(__wt_open_internal_session(conn, "log-wrlsn-server",
false, session_flags, &conn->log_wrlsn_session));
- WT_RET(__wt_cond_alloc(conn->log_wrlsn_session,
- "log write lsn server", false, &conn->log_wrlsn_cond));
+ WT_RET(__wt_cond_auto_alloc(conn->log_wrlsn_session,
+ "log write lsn server", false, 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;
@@ -921,13 +951,13 @@ __wt_logmgr_open(WT_SESSION_IMPL *session)
if (conn->log_session != NULL) {
WT_ASSERT(session, conn->log_cond != NULL);
WT_ASSERT(session, conn->log_tid_set == true);
- WT_RET(__wt_cond_signal(session, conn->log_cond));
+ WT_RET(__wt_cond_auto_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_alloc(conn->log_session,
- "log server", false, &conn->log_cond));
+ WT_RET(__wt_cond_auto_alloc(conn->log_session,
+ "log server", false, 50000, WT_MILLION, &conn->log_cond));
/*
* Start the thread.
@@ -963,7 +993,7 @@ __wt_logmgr_destroy(WT_SESSION_IMPL *session)
return (0);
}
if (conn->log_tid_set) {
- WT_TRET(__wt_cond_signal(session, conn->log_cond));
+ WT_TRET(__wt_cond_auto_signal(session, conn->log_cond));
WT_TRET(__wt_thread_join(session, conn->log_tid));
conn->log_tid_set = false;
}
@@ -978,7 +1008,7 @@ __wt_logmgr_destroy(WT_SESSION_IMPL *session)
conn->log_file_session = NULL;
}
if (conn->log_wrlsn_tid_set) {
- WT_TRET(__wt_cond_signal(session, conn->log_wrlsn_cond));
+ WT_TRET(__wt_cond_auto_signal(session, conn->log_wrlsn_cond));
WT_TRET(__wt_thread_join(session, conn->log_wrlsn_tid));
conn->log_wrlsn_tid_set = false;
}
@@ -999,9 +1029,9 @@ __wt_logmgr_destroy(WT_SESSION_IMPL *session)
}
/* Destroy the condition variables now that all threads are stopped */
- WT_TRET(__wt_cond_destroy(session, &conn->log_cond));
+ WT_TRET(__wt_cond_auto_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_auto_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));
diff --git a/src/cursor/cur_log.c b/src/cursor/cur_log.c
index 47436ac7237..0a13803da5d 100644
--- a/src/cursor/cur_log.c
+++ b/src/cursor/cur_log.c
@@ -397,7 +397,7 @@ __wt_curlog_open(WT_SESSION_IMPL *session,
* The user may be trying to read a log record they just wrote.
* Log records may be buffered, so force out any now.
*/
- WT_ERR(__wt_log_force_write(session, 1));
+ WT_ERR(__wt_log_force_write(session, 1, NULL));
/* Log cursors block archiving. */
WT_ERR(__wt_readlock(session, log->log_archive_lock));
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index 3b9a7c9db62..21ebe921f0a 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -159,7 +159,7 @@ __wt_evict_server_wake(WT_SESSION_IMPL *session)
bytes_max / WT_MEGABYTE));
}
- return (__wt_cond_signal(session, cache->evict_cond));
+ return (__wt_cond_auto_signal(session, cache->evict_cond));
}
/*
@@ -175,8 +175,8 @@ __evict_server(void *arg)
WT_SESSION_IMPL *session;
#ifdef HAVE_DIAGNOSTIC
struct timespec now, stuck_ts;
- uint64_t pages_evicted = 0;
#endif
+ uint64_t pages_evicted = 0;
u_int spins;
session = arg;
@@ -219,11 +219,11 @@ __evict_server(void *arg)
/* Next time we wake up, reverse the sweep direction. */
cache->flags ^= WT_CACHE_WALK_REVERSE;
-#ifdef HAVE_DIAGNOSTIC
pages_evicted = 0;
} else if (pages_evicted != cache->pages_evict) {
- WT_ERR(__wt_epoch(session, &stuck_ts));
pages_evicted = cache->pages_evict;
+#ifdef HAVE_DIAGNOSTIC
+ WT_ERR(__wt_epoch(session, &stuck_ts));
} else {
/* After being stuck for 5 minutes, give up. */
WT_ERR(__wt_epoch(session, &now));
@@ -238,7 +238,8 @@ __evict_server(void *arg)
WT_ERR(__wt_verbose(session, WT_VERB_EVICTSERVER, "sleeping"));
/* Don't rely on signals: check periodically. */
- WT_ERR(__wt_cond_wait(session, cache->evict_cond, 100000));
+ WT_ERR(__wt_cond_auto_wait(
+ session, cache->evict_cond, pages_evicted != 0));
WT_ERR(__wt_verbose(session, WT_VERB_EVICTSERVER, "waking"));
}
diff --git a/src/include/extern.h b/src/include/extern.h
index 9ebfc399f59..ba2c0af1058 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -364,7 +364,7 @@ extern int __wt_log_open(WT_SESSION_IMPL *session);
extern int __wt_log_close(WT_SESSION_IMPL *session);
extern int __wt_log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot, bool *freep);
extern int __wt_log_scan(WT_SESSION_IMPL *session, WT_LSN *lsnp, uint32_t flags, int (*func)(WT_SESSION_IMPL *session, WT_ITEM *record, WT_LSN *lsnp, WT_LSN *next_lsnp, void *cookie, int firstrecord), void *cookie);
-extern int __wt_log_force_write(WT_SESSION_IMPL *session, bool retry);
+extern int __wt_log_force_write(WT_SESSION_IMPL *session, bool retry, bool *did_work);
extern int __wt_log_write(WT_SESSION_IMPL *session, WT_ITEM *record, WT_LSN *lsnp, uint32_t flags);
extern int __wt_log_vprintf(WT_SESSION_IMPL *session, const char *fmt, va_list ap);
extern int __wt_log_flush(WT_SESSION_IMPL *session, uint32_t flags);
@@ -639,6 +639,11 @@ extern int __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *ch
extern int __wt_salvage(WT_SESSION_IMPL *session, const char *cfg[]);
extern uint32_t __wt_cksum(const void *chunk, size_t len);
extern void __wt_cksum_init(void);
+extern int __wt_cond_auto_alloc( WT_SESSION_IMPL *session, const char *name, bool is_signalled, uint64_t min, uint64_t max, WT_CONDVAR **condp);
+extern int __wt_cond_auto_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond);
+extern int __wt_cond_auto_wait_signal( WT_SESSION_IMPL *session, WT_CONDVAR *cond, bool progress, bool *signalled);
+extern int __wt_cond_auto_wait( WT_SESSION_IMPL *session, WT_CONDVAR *cond, bool progress);
+extern int __wt_cond_auto_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp);
extern int __wt_decrypt(WT_SESSION_IMPL *session, WT_ENCRYPTOR *encryptor, size_t skip, WT_ITEM *in, WT_ITEM *out);
extern int __wt_encrypt(WT_SESSION_IMPL *session, WT_KEYED_ENCRYPTOR *kencryptor, size_t skip, WT_ITEM *in, WT_ITEM *out);
extern void __wt_encrypt_size(WT_SESSION_IMPL *session, WT_KEYED_ENCRYPTOR *kencryptor, size_t incoming_size, size_t *sizep);
diff --git a/src/include/mutex.h b/src/include/mutex.h
index f798bfb3ece..04679884930 100644
--- a/src/include/mutex.h
+++ b/src/include/mutex.h
@@ -20,6 +20,13 @@ struct __wt_condvar {
int waiters; /* Numbers of waiters, or
-1 if signalled with no waiters. */
+ /*
+ * The following fields are only used for automatically adjusting
+ * condition variables. They could be in a separate structure.
+ */
+ uint64_t min_wait; /* Minimum wait duration */
+ uint64_t max_wait; /* Maximum wait duration */
+ uint64_t prev_wait; /* Wait duration used last time */
};
/*
diff --git a/src/include/stat.h b/src/include/stat.h
index 8bc6c37b53e..f9170dc1a79 100644
--- a/src/include/stat.h
+++ b/src/include/stat.h
@@ -299,6 +299,8 @@ struct __wt_connection_stats {
int64_t cache_bytes_dirty;
int64_t cache_pages_dirty;
int64_t cache_eviction_clean;
+ int64_t cond_auto_wait_reset;
+ int64_t cond_auto_wait;
int64_t file_open;
int64_t memory_allocation;
int64_t memory_free;
@@ -337,6 +339,8 @@ struct __wt_connection_stats {
int64_t log_bytes_written;
int64_t log_zero_fills;
int64_t log_flush;
+ int64_t log_force_write;
+ int64_t log_force_write_skip;
int64_t log_compress_writes;
int64_t log_compress_write_fails;
int64_t log_compress_small;
@@ -344,6 +348,7 @@ struct __wt_connection_stats {
int64_t log_scans;
int64_t log_scan_rereads;
int64_t log_write_lsn;
+ int64_t log_write_lsn_skip;
int64_t log_sync;
int64_t log_sync_dir;
int64_t log_writes;
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index 0d328668e10..1e263f22880 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -3850,187 +3850,197 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection);
#define WT_STAT_CONN_CACHE_PAGES_DIRTY 1070
/*! cache: unmodified pages evicted */
#define WT_STAT_CONN_CACHE_EVICTION_CLEAN 1071
+/*! connection: auto adjusting condition resets */
+#define WT_STAT_CONN_COND_AUTO_WAIT_RESET 1072
+/*! connection: auto adjusting condition wait calls */
+#define WT_STAT_CONN_COND_AUTO_WAIT 1073
/*! connection: files currently open */
-#define WT_STAT_CONN_FILE_OPEN 1072
+#define WT_STAT_CONN_FILE_OPEN 1074
/*! connection: memory allocations */
-#define WT_STAT_CONN_MEMORY_ALLOCATION 1073
+#define WT_STAT_CONN_MEMORY_ALLOCATION 1075
/*! connection: memory frees */
-#define WT_STAT_CONN_MEMORY_FREE 1074
+#define WT_STAT_CONN_MEMORY_FREE 1076
/*! connection: memory re-allocations */
-#define WT_STAT_CONN_MEMORY_GROW 1075
+#define WT_STAT_CONN_MEMORY_GROW 1077
/*! connection: pthread mutex condition wait calls */
-#define WT_STAT_CONN_COND_WAIT 1076
+#define WT_STAT_CONN_COND_WAIT 1078
/*! connection: pthread mutex shared lock read-lock calls */
-#define WT_STAT_CONN_RWLOCK_READ 1077
+#define WT_STAT_CONN_RWLOCK_READ 1079
/*! connection: pthread mutex shared lock write-lock calls */
-#define WT_STAT_CONN_RWLOCK_WRITE 1078
+#define WT_STAT_CONN_RWLOCK_WRITE 1080
/*! connection: total read I/Os */
-#define WT_STAT_CONN_READ_IO 1079
+#define WT_STAT_CONN_READ_IO 1081
/*! connection: total write I/Os */
-#define WT_STAT_CONN_WRITE_IO 1080
+#define WT_STAT_CONN_WRITE_IO 1082
/*! cursor: cursor create calls */
-#define WT_STAT_CONN_CURSOR_CREATE 1081
+#define WT_STAT_CONN_CURSOR_CREATE 1083
/*! cursor: cursor insert calls */
-#define WT_STAT_CONN_CURSOR_INSERT 1082
+#define WT_STAT_CONN_CURSOR_INSERT 1084
/*! cursor: cursor next calls */
-#define WT_STAT_CONN_CURSOR_NEXT 1083
+#define WT_STAT_CONN_CURSOR_NEXT 1085
/*! cursor: cursor prev calls */
-#define WT_STAT_CONN_CURSOR_PREV 1084
+#define WT_STAT_CONN_CURSOR_PREV 1086
/*! cursor: cursor remove calls */
-#define WT_STAT_CONN_CURSOR_REMOVE 1085
+#define WT_STAT_CONN_CURSOR_REMOVE 1087
/*! cursor: cursor reset calls */
-#define WT_STAT_CONN_CURSOR_RESET 1086
+#define WT_STAT_CONN_CURSOR_RESET 1088
/*! cursor: cursor restarted searches */
-#define WT_STAT_CONN_CURSOR_RESTART 1087
+#define WT_STAT_CONN_CURSOR_RESTART 1089
/*! cursor: cursor search calls */
-#define WT_STAT_CONN_CURSOR_SEARCH 1088
+#define WT_STAT_CONN_CURSOR_SEARCH 1090
/*! cursor: cursor search near calls */
-#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1089
+#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1091
/*! cursor: cursor update calls */
-#define WT_STAT_CONN_CURSOR_UPDATE 1090
+#define WT_STAT_CONN_CURSOR_UPDATE 1092
/*! cursor: truncate calls */
-#define WT_STAT_CONN_CURSOR_TRUNCATE 1091
+#define WT_STAT_CONN_CURSOR_TRUNCATE 1093
/*! data-handle: connection data handles currently active */
-#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1092
+#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1094
/*! data-handle: connection sweep candidate became referenced */
-#define WT_STAT_CONN_DH_SWEEP_REF 1093
+#define WT_STAT_CONN_DH_SWEEP_REF 1095
/*! data-handle: connection sweep dhandles closed */
-#define WT_STAT_CONN_DH_SWEEP_CLOSE 1094
+#define WT_STAT_CONN_DH_SWEEP_CLOSE 1096
/*! data-handle: connection sweep dhandles removed from hash list */
-#define WT_STAT_CONN_DH_SWEEP_REMOVE 1095
+#define WT_STAT_CONN_DH_SWEEP_REMOVE 1097
/*! data-handle: connection sweep time-of-death sets */
-#define WT_STAT_CONN_DH_SWEEP_TOD 1096
+#define WT_STAT_CONN_DH_SWEEP_TOD 1098
/*! data-handle: connection sweeps */
-#define WT_STAT_CONN_DH_SWEEPS 1097
+#define WT_STAT_CONN_DH_SWEEPS 1099
/*! data-handle: session dhandles swept */
-#define WT_STAT_CONN_DH_SESSION_HANDLES 1098
+#define WT_STAT_CONN_DH_SESSION_HANDLES 1100
/*! data-handle: session sweep attempts */
-#define WT_STAT_CONN_DH_SESSION_SWEEPS 1099
+#define WT_STAT_CONN_DH_SESSION_SWEEPS 1101
/*! log: busy returns attempting to switch slots */
-#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1100
+#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1102
/*! log: consolidated slot closures */
-#define WT_STAT_CONN_LOG_SLOT_CLOSES 1101
+#define WT_STAT_CONN_LOG_SLOT_CLOSES 1103
/*! log: consolidated slot join races */
-#define WT_STAT_CONN_LOG_SLOT_RACES 1102
+#define WT_STAT_CONN_LOG_SLOT_RACES 1104
/*! log: consolidated slot join transitions */
-#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1103
+#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1105
/*! log: consolidated slot joins */
-#define WT_STAT_CONN_LOG_SLOT_JOINS 1104
+#define WT_STAT_CONN_LOG_SLOT_JOINS 1106
/*! log: consolidated slot unbuffered writes */
-#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1105
+#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1107
/*! log: log bytes of payload data */
-#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1106
+#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1108
/*! log: log bytes written */
-#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1107
+#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1109
/*! log: log files manually zero-filled */
-#define WT_STAT_CONN_LOG_ZERO_FILLS 1108
+#define WT_STAT_CONN_LOG_ZERO_FILLS 1110
/*! log: log flush operations */
-#define WT_STAT_CONN_LOG_FLUSH 1109
+#define WT_STAT_CONN_LOG_FLUSH 1111
+/*! log: log force write operations */
+#define WT_STAT_CONN_LOG_FORCE_WRITE 1112
+/*! log: log force write operations skipped */
+#define WT_STAT_CONN_LOG_FORCE_WRITE_SKIP 1113
/*! log: log records compressed */
-#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1110
+#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1114
/*! log: log records not compressed */
-#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1111
+#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1115
/*! log: log records too small to compress */
-#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1112
+#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1116
/*! log: log release advances write LSN */
-#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1113
+#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1117
/*! log: log scan operations */
-#define WT_STAT_CONN_LOG_SCANS 1114
+#define WT_STAT_CONN_LOG_SCANS 1118
/*! log: log scan records requiring two reads */
-#define WT_STAT_CONN_LOG_SCAN_REREADS 1115
+#define WT_STAT_CONN_LOG_SCAN_REREADS 1119
/*! log: log server thread advances write LSN */
-#define WT_STAT_CONN_LOG_WRITE_LSN 1116
+#define WT_STAT_CONN_LOG_WRITE_LSN 1120
+/*! log: log server thread write LSN walk skipped */
+#define WT_STAT_CONN_LOG_WRITE_LSN_SKIP 1121
/*! log: log sync operations */
-#define WT_STAT_CONN_LOG_SYNC 1117
+#define WT_STAT_CONN_LOG_SYNC 1122
/*! log: log sync_dir operations */
-#define WT_STAT_CONN_LOG_SYNC_DIR 1118
+#define WT_STAT_CONN_LOG_SYNC_DIR 1123
/*! log: log write operations */
-#define WT_STAT_CONN_LOG_WRITES 1119
+#define WT_STAT_CONN_LOG_WRITES 1124
/*! log: logging bytes consolidated */
-#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1120
+#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1125
/*! log: maximum log file size */
-#define WT_STAT_CONN_LOG_MAX_FILESIZE 1121
+#define WT_STAT_CONN_LOG_MAX_FILESIZE 1126
/*! log: number of pre-allocated log files to create */
-#define WT_STAT_CONN_LOG_PREALLOC_MAX 1122
+#define WT_STAT_CONN_LOG_PREALLOC_MAX 1127
/*! log: pre-allocated log files not ready and missed */
-#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1123
+#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1128
/*! log: pre-allocated log files prepared */
-#define WT_STAT_CONN_LOG_PREALLOC_FILES 1124
+#define WT_STAT_CONN_LOG_PREALLOC_FILES 1129
/*! log: pre-allocated log files used */
-#define WT_STAT_CONN_LOG_PREALLOC_USED 1125
+#define WT_STAT_CONN_LOG_PREALLOC_USED 1130
/*! log: records processed by log scan */
-#define WT_STAT_CONN_LOG_SCAN_RECORDS 1126
+#define WT_STAT_CONN_LOG_SCAN_RECORDS 1131
/*! log: total in-memory size of compressed records */
-#define WT_STAT_CONN_LOG_COMPRESS_MEM 1127
+#define WT_STAT_CONN_LOG_COMPRESS_MEM 1132
/*! log: total log buffer size */
-#define WT_STAT_CONN_LOG_BUFFER_SIZE 1128
+#define WT_STAT_CONN_LOG_BUFFER_SIZE 1133
/*! log: total size of compressed records */
-#define WT_STAT_CONN_LOG_COMPRESS_LEN 1129
+#define WT_STAT_CONN_LOG_COMPRESS_LEN 1134
/*! log: written slots coalesced */
-#define WT_STAT_CONN_LOG_SLOT_COALESCED 1130
+#define WT_STAT_CONN_LOG_SLOT_COALESCED 1135
/*! log: yields waiting for previous log file close */
-#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1131
+#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1136
/*! reconciliation: fast-path pages deleted */
-#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1132
+#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1137
/*! reconciliation: page reconciliation calls */
-#define WT_STAT_CONN_REC_PAGES 1133
+#define WT_STAT_CONN_REC_PAGES 1138
/*! reconciliation: page reconciliation calls for eviction */
-#define WT_STAT_CONN_REC_PAGES_EVICTION 1134
+#define WT_STAT_CONN_REC_PAGES_EVICTION 1139
/*! reconciliation: pages deleted */
-#define WT_STAT_CONN_REC_PAGE_DELETE 1135
+#define WT_STAT_CONN_REC_PAGE_DELETE 1140
/*! reconciliation: split bytes currently awaiting free */
-#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1136
+#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1141
/*! reconciliation: split objects currently awaiting free */
-#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1137
+#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1142
/*! session: open cursor count */
-#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1138
+#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1143
/*! session: open session count */
-#define WT_STAT_CONN_SESSION_OPEN 1139
+#define WT_STAT_CONN_SESSION_OPEN 1144
/*! thread-yield: page acquire busy blocked */
-#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1140
+#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1145
/*! thread-yield: page acquire eviction blocked */
-#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1141
+#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1146
/*! thread-yield: page acquire locked blocked */
-#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1142
+#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1147
/*! thread-yield: page acquire read blocked */
-#define WT_STAT_CONN_PAGE_READ_BLOCKED 1143
+#define WT_STAT_CONN_PAGE_READ_BLOCKED 1148
/*! thread-yield: page acquire time sleeping (usecs) */
-#define WT_STAT_CONN_PAGE_SLEEP 1144
+#define WT_STAT_CONN_PAGE_SLEEP 1149
/*! transaction: number of named snapshots created */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1145
+#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1150
/*! transaction: number of named snapshots dropped */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1146
+#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1151
/*! transaction: transaction begins */
-#define WT_STAT_CONN_TXN_BEGIN 1147
+#define WT_STAT_CONN_TXN_BEGIN 1152
/*! transaction: transaction checkpoint currently running */
-#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1148
+#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1153
/*! transaction: transaction checkpoint generation */
-#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1149
+#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1154
/*! transaction: transaction checkpoint max time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1150
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1155
/*! transaction: transaction checkpoint min time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1151
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1156
/*! transaction: transaction checkpoint most recent time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1152
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1157
/*! transaction: transaction checkpoint total time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1153
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1158
/*! transaction: transaction checkpoints */
-#define WT_STAT_CONN_TXN_CHECKPOINT 1154
+#define WT_STAT_CONN_TXN_CHECKPOINT 1159
/*! transaction: transaction failures due to cache overflow */
-#define WT_STAT_CONN_TXN_FAIL_CACHE 1155
+#define WT_STAT_CONN_TXN_FAIL_CACHE 1160
/*! transaction: transaction range of IDs currently pinned */
-#define WT_STAT_CONN_TXN_PINNED_RANGE 1156
+#define WT_STAT_CONN_TXN_PINNED_RANGE 1161
/*! transaction: transaction range of IDs currently pinned by a checkpoint */
-#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1157
+#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1162
/*! transaction: transaction range of IDs currently pinned by named
* snapshots */
-#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1158
+#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1163
/*! transaction: transaction sync calls */
-#define WT_STAT_CONN_TXN_SYNC 1159
+#define WT_STAT_CONN_TXN_SYNC 1164
/*! transaction: transactions committed */
-#define WT_STAT_CONN_TXN_COMMIT 1160
+#define WT_STAT_CONN_TXN_COMMIT 1165
/*! transaction: transactions rolled back */
-#define WT_STAT_CONN_TXN_ROLLBACK 1161
+#define WT_STAT_CONN_TXN_ROLLBACK 1166
/*!
* @}
diff --git a/src/log/log.c b/src/log/log.c
index 03145d8408c..0b84b5b2b19 100644
--- a/src/log/log.c
+++ b/src/log/log.c
@@ -29,7 +29,7 @@ __wt_log_ckpt(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn)
log = conn->log;
log->ckpt_lsn = *ckp_lsn;
if (conn->log_cond != NULL)
- WT_RET(__wt_cond_signal(session, conn->log_cond));
+ WT_RET(__wt_cond_auto_signal(session, conn->log_cond));
return (0);
}
@@ -46,7 +46,7 @@ __wt_log_flush_lsn(WT_SESSION_IMPL *session, WT_LSN *lsn, bool start)
conn = S2C(session);
log = conn->log;
- WT_RET(__wt_log_force_write(session, 1));
+ WT_RET(__wt_log_force_write(session, 1, NULL));
WT_RET(__wt_log_wrlsn(session, NULL));
if (start)
*lsn = log->write_start_lsn;
@@ -273,7 +273,7 @@ __wt_log_get_all_files(WT_SESSION_IMPL *session,
* These may be files needed by backup. Force the current slot
* to get written to the file.
*/
- WT_RET(__wt_log_force_write(session, 1));
+ WT_RET(__wt_log_force_write(session, 1, NULL));
WT_RET(__log_get_files(session, WT_LOG_FILENAME, &files, &count));
/* Filter out any files that are below the checkpoint LSN. */
@@ -824,7 +824,7 @@ __log_newfile(WT_SESSION_IMPL *session, bool conn_open, bool *created)
if (create_log) {
WT_STAT_FAST_CONN_INCR(session, log_prealloc_missed);
if (conn->log_cond != NULL)
- WT_RET(__wt_cond_signal(
+ WT_RET(__wt_cond_auto_signal(
session, conn->log_cond));
}
}
@@ -1338,7 +1338,7 @@ __wt_log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot, bool *freep)
*/
if (F_ISSET(session, WT_SESSION_LOCKED_SLOT))
__wt_spin_unlock(session, &log->log_slot_lock);
- WT_ERR(__wt_cond_signal(session, conn->log_wrlsn_cond));
+ WT_ERR(__wt_cond_auto_signal(session, conn->log_wrlsn_cond));
if (++yield_count < WT_THOUSAND)
__wt_yield();
else
@@ -1758,14 +1758,25 @@ err: WT_STAT_FAST_CONN_INCR(session, log_scans);
* Wrapper function that takes the lock.
*/
int
-__wt_log_force_write(WT_SESSION_IMPL *session, bool retry)
+__wt_log_force_write(WT_SESSION_IMPL *session, bool retry, bool *did_work)
{
WT_LOG *log;
WT_MYSLOT myslot;
+ uint32_t joined;
log = S2C(session)->log;
memset(&myslot, 0, sizeof(myslot));
+ WT_STAT_FAST_CONN_INCR(session, log_force_write);
+ if (did_work != NULL)
+ *did_work = true;
myslot.slot = log->active_slot;
+ joined = WT_LOG_SLOT_JOINED(log->active_slot->slot_state);
+ if (joined == 0) {
+ WT_STAT_FAST_CONN_INCR(session, log_force_write_skip);
+ if (did_work != NULL)
+ *did_work = false;
+ return (0);
+ }
return (__wt_log_slot_switch(session, &myslot, retry, true));
}
@@ -1998,10 +2009,10 @@ __log_write_internal(WT_SESSION_IMPL *session, WT_ITEM *record, WT_LSN *lsnp,
* XXX I've seen times when conditions are NULL.
*/
if (conn->log_cond != NULL) {
- WT_ERR(__wt_cond_signal(session, conn->log_cond));
+ WT_ERR(__wt_cond_auto_signal(session, conn->log_cond));
__wt_yield();
} else
- WT_ERR(__wt_log_force_write(session, 1));
+ WT_ERR(__wt_log_force_write(session, 1, NULL));
}
if (LF_ISSET(WT_LOG_FLUSH)) {
/* Wait for our writes to reach the OS */
diff --git a/src/log/log_slot.c b/src/log/log_slot.c
index 2844516e78f..570d1c9ce48 100644
--- a/src/log/log_slot.c
+++ b/src/log/log_slot.c
@@ -253,7 +253,7 @@ __wt_log_slot_new(WT_SESSION_IMPL *session)
/*
* If we didn't find any free slots signal the worker thread.
*/
- (void)__wt_cond_signal(session, conn->log_wrlsn_cond);
+ (void)__wt_cond_auto_signal(session, conn->log_wrlsn_cond);
__wt_yield();
}
/* NOTREACHED */
diff --git a/src/support/cond_auto.c b/src/support/cond_auto.c
new file mode 100644
index 00000000000..ec95622f333
--- /dev/null
+++ b/src/support/cond_auto.c
@@ -0,0 +1,136 @@
+/*-
+ * Public Domain 2014-2016 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include "wt_internal.h"
+
+/*
+ * This is an implementation of condition variables that automatically adjust
+ * the wait time depending on whether the wake is resulting in useful work.
+ */
+
+/*
+ * __wt_cond_auto_alloc --
+ * Allocate and initialize an automatically adjusting condition variable.
+ */
+int
+__wt_cond_auto_alloc(
+ WT_SESSION_IMPL *session, const char *name,
+ bool is_signalled, uint64_t min, uint64_t max, WT_CONDVAR **condp)
+{
+ WT_CONDVAR *cond;
+
+ WT_RET(__wt_cond_alloc(session, name, is_signalled, condp));
+ cond = *condp;
+
+ cond->min_wait = min;
+ cond->max_wait = max;
+ cond->prev_wait = min;
+
+ return (0);
+}
+
+/*
+ * __wt_cond_auto_signal --
+ * Signal a condition variable.
+ */
+int
+__wt_cond_auto_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond)
+{
+
+ WT_ASSERT(session, cond->min_wait != 0);
+ return (__wt_cond_signal(session, cond));
+}
+
+/*
+ * __wt_cond_auto_wait_signal --
+ * Wait on a mutex, optionally timing out. If we get it before the time
+ * out period expires, let the caller know.
+ * TODO: Can this version of the API be removed, now that we have the
+ * auto adjusting condition variables?
+ */
+int
+__wt_cond_auto_wait_signal(
+ WT_SESSION_IMPL *session, WT_CONDVAR *cond, bool progress, bool *signalled)
+{
+ uint64_t delta;
+
+ /*
+ * Catch cases where this function is called with a condition variable
+ * that was initialized non-auto.
+ */
+ WT_ASSERT(session, cond->min_wait != 0);
+
+ WT_STAT_FAST_CONN_INCR(session, cond_auto_wait);
+ if (progress)
+ cond->prev_wait = cond->min_wait;
+ else {
+ delta = WT_MAX(1, (cond->max_wait - cond->min_wait) / 10);
+ cond->prev_wait = WT_MIN(
+ cond->max_wait, cond->prev_wait + delta);
+ }
+
+ WT_RET(__wt_cond_wait_signal(
+ session, cond, cond->prev_wait, signalled));
+
+ if (progress || *signalled)
+ WT_STAT_FAST_CONN_INCR(session, cond_auto_wait_reset);
+ if (*signalled)
+ cond->prev_wait = cond->min_wait;
+
+ return (0);
+}
+
+/*
+ * __wt_cond_auto_wait --
+ * Wait on a mutex, optionally timing out. If we get it before the time
+ * out period expires, let the caller know.
+ */
+int
+__wt_cond_auto_wait(
+ WT_SESSION_IMPL *session, WT_CONDVAR *cond, bool progress)
+{
+ bool signalled;
+
+ /*
+ * Call the signal version so the wait period is reset if the
+ * condition is woken explicitly.
+ */
+ WT_RET(__wt_cond_auto_wait_signal(session, cond, progress, &signalled));
+
+ return (0);
+}
+
+/*
+ * __wt_cond_auto_destroy --
+ * Destroy a condition variable.
+ */
+int
+__wt_cond_auto_destroy(WT_SESSION_IMPL *session, WT_CONDVAR **condp)
+{
+ return (__wt_cond_destroy(session, condp));
+}
diff --git a/src/support/stat.c b/src/support/stat.c
index 0df38bfe6b0..2a826eda962 100644
--- a/src/support/stat.c
+++ b/src/support/stat.c
@@ -581,6 +581,8 @@ static const char * const __stats_connection_desc[] = {
"cache: tracked dirty bytes in the cache",
"cache: tracked dirty pages in the cache",
"cache: unmodified pages evicted",
+ "connection: auto adjusting condition resets",
+ "connection: auto adjusting condition wait calls",
"connection: files currently open",
"connection: memory allocations",
"connection: memory frees",
@@ -619,6 +621,8 @@ static const char * const __stats_connection_desc[] = {
"log: log bytes written",
"log: log files manually zero-filled",
"log: log flush operations",
+ "log: log force write operations",
+ "log: log force write operations skipped",
"log: log records compressed",
"log: log records not compressed",
"log: log records too small to compress",
@@ -626,6 +630,7 @@ static const char * const __stats_connection_desc[] = {
"log: log scan operations",
"log: log scan records requiring two reads",
"log: log server thread advances write LSN",
+ "log: log server thread write LSN walk skipped",
"log: log sync operations",
"log: log sync_dir operations",
"log: log write operations",
@@ -773,6 +778,8 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
/* not clearing cache_bytes_dirty */
/* not clearing cache_pages_dirty */
stats->cache_eviction_clean = 0;
+ stats->cond_auto_wait_reset = 0;
+ stats->cond_auto_wait = 0;
/* not clearing file_open */
stats->memory_allocation = 0;
stats->memory_free = 0;
@@ -811,6 +818,8 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
stats->log_bytes_written = 0;
stats->log_zero_fills = 0;
stats->log_flush = 0;
+ stats->log_force_write = 0;
+ stats->log_force_write_skip = 0;
stats->log_compress_writes = 0;
stats->log_compress_write_fails = 0;
stats->log_compress_small = 0;
@@ -818,6 +827,7 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
stats->log_scans = 0;
stats->log_scan_rereads = 0;
stats->log_write_lsn = 0;
+ stats->log_write_lsn_skip = 0;
stats->log_sync = 0;
stats->log_sync_dir = 0;
stats->log_writes = 0;
@@ -974,6 +984,8 @@ __wt_stat_connection_aggregate(
to->cache_bytes_dirty += WT_STAT_READ(from, cache_bytes_dirty);
to->cache_pages_dirty += WT_STAT_READ(from, cache_pages_dirty);
to->cache_eviction_clean += WT_STAT_READ(from, cache_eviction_clean);
+ to->cond_auto_wait_reset += WT_STAT_READ(from, cond_auto_wait_reset);
+ to->cond_auto_wait += WT_STAT_READ(from, cond_auto_wait);
to->file_open += WT_STAT_READ(from, file_open);
to->memory_allocation += WT_STAT_READ(from, memory_allocation);
to->memory_free += WT_STAT_READ(from, memory_free);
@@ -1012,6 +1024,8 @@ __wt_stat_connection_aggregate(
to->log_bytes_written += WT_STAT_READ(from, log_bytes_written);
to->log_zero_fills += WT_STAT_READ(from, log_zero_fills);
to->log_flush += WT_STAT_READ(from, log_flush);
+ to->log_force_write += WT_STAT_READ(from, log_force_write);
+ to->log_force_write_skip += WT_STAT_READ(from, log_force_write_skip);
to->log_compress_writes += WT_STAT_READ(from, log_compress_writes);
to->log_compress_write_fails +=
WT_STAT_READ(from, log_compress_write_fails);
@@ -1021,6 +1035,7 @@ __wt_stat_connection_aggregate(
to->log_scans += WT_STAT_READ(from, log_scans);
to->log_scan_rereads += WT_STAT_READ(from, log_scan_rereads);
to->log_write_lsn += WT_STAT_READ(from, log_write_lsn);
+ to->log_write_lsn_skip += WT_STAT_READ(from, log_write_lsn_skip);
to->log_sync += WT_STAT_READ(from, log_sync);
to->log_sync_dir += WT_STAT_READ(from, log_sync_dir);
to->log_writes += WT_STAT_READ(from, log_writes);
diff --git a/test/manydbs/Makefile.am b/test/manydbs/Makefile.am
new file mode 100644
index 00000000000..53559b25243
--- /dev/null
+++ b/test/manydbs/Makefile.am
@@ -0,0 +1,13 @@
+AM_CPPFLAGS = -I$(top_builddir) -I$(top_srcdir)/src/include \
+ -I$(top_srcdir)/test/utility
+
+noinst_PROGRAMS = t
+t_SOURCES = manydbs.c
+t_LDADD = $(top_builddir)/libwiredtiger.la
+t_LDFLAGS = -static
+
+# Run this during a "make check" smoke test.
+TESTS = smoke.sh
+
+clean-local:
+ rm -rf WiredTiger* *.core __*
diff --git a/test/manydbs/manydbs.c b/test/manydbs/manydbs.c
new file mode 100644
index 00000000000..07fcb06adff
--- /dev/null
+++ b/test/manydbs/manydbs.c
@@ -0,0 +1,237 @@
+/*-
+ * Public Domain 2014-2016 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#include <sys/wait.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#ifndef _WIN32
+#include <unistd.h>
+#endif
+
+#include <wiredtiger.h>
+
+#include "test_util.i"
+
+#define HOME_SIZE 512
+#define HOME_BASE "WT_HOME"
+static char home[HOME_SIZE]; /* Base home directory */
+static char hometmp[HOME_SIZE]; /* Each conn home directory */
+static const char *progname; /* Program name */
+static const char * const uri = "table:main";
+
+#define WTOPEN_CFG_COMMON \
+ "create,log=(file_max=10M,archive=false,enabled)," \
+ "statistics=(fast),statistics_log=(wait=5),"
+#define WT_CONFIG0 \
+ WTOPEN_CFG_COMMON \
+ "transaction_sync=(enabled=false)"
+#define WT_CONFIG1 \
+ WTOPEN_CFG_COMMON \
+ "transaction_sync=(enabled,method=none)"
+#define WT_CONFIG2 \
+ WTOPEN_CFG_COMMON \
+ "transaction_sync=(enabled,method=fsync)"
+
+#define MAX_CPU 10.0
+#define MAX_DBS 10
+#define MAX_IDLE_TIME 30
+#define IDLE_INCR 5
+
+#define MAX_KV 100
+#define MAX_VAL 128
+
+static void
+usage(void)
+{
+ fprintf(stderr,
+ "usage: %s [-I] [-C maxcpu%%] [-D maxdbs] [-h dir]\n", progname);
+ exit(EXIT_FAILURE);
+}
+
+extern int __wt_optind;
+extern char *__wt_optarg;
+
+void (*custom_die)(void) = NULL;
+
+WT_CONNECTION **conn = NULL;
+WT_CURSOR **cursor = NULL;
+WT_RAND_STATE rnd;
+WT_SESSION **session = NULL;
+
+static int
+run_ops(int dbs)
+{
+ WT_ITEM data;
+ int db, db_set, i, key;
+ uint8_t buf[MAX_VAL];
+
+ memset(buf, 0, sizeof(buf));
+ /*
+ * First time through, set up sessions, create the tables and
+ * open cursors.
+ */
+ if (session == NULL) {
+ __wt_random_init(&rnd);
+ if ((session = calloc(sizeof(WT_SESSION *), dbs)) == NULL)
+ testutil_die(ENOMEM, "session array malloc");
+ if ((cursor = calloc(sizeof(WT_CURSOR *), dbs)) == NULL)
+ testutil_die(ENOMEM, "cursor array malloc");
+ for (i = 0; i < dbs; ++i) {
+ testutil_check(conn[i]->open_session(conn[i],
+ NULL, NULL, &session[i]));
+ testutil_check(session[i]->create(session[i],
+ uri, "key_format=Q,value_format=u"));
+ testutil_check(session[i]->open_cursor(session[i],
+ uri, NULL, NULL, &cursor[i]));
+ }
+ }
+ for (i = 0; i < MAX_VAL; ++i)
+ buf[i] = (uint8_t)__wt_random(&rnd);
+ data.data = buf;
+ /*
+ * Write a small amount of data into a random subset of the databases.
+ */
+ db_set = dbs / 4;
+ for (i = 0; i < db_set; ++i) {
+ db = __wt_random(&rnd) % dbs;
+ printf("Write to database %d\n", db);
+ for (key = 0; key < MAX_KV; ++key) {
+ data.size = __wt_random(&rnd) % MAX_VAL;
+ cursor[db]->set_key(cursor[db], key);
+ cursor[db]->set_value(cursor[db], &data);
+ testutil_check(cursor[db]->insert(cursor[db]));
+ }
+ }
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ FILE *fp;
+ float cpu, max;
+ int cfg, ch, dbs, i;
+ const char *working_dir;
+ bool idle, setmax;
+ const char *wt_cfg;
+ char cmd[128];
+
+ if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL)
+ progname = argv[0];
+ else
+ ++progname;
+ dbs = MAX_DBS;
+ working_dir = HOME_BASE;
+ max = (float)dbs;
+ idle = setmax = false;
+ while ((ch = __wt_getopt(progname, argc, argv, "C:D:h:I")) != EOF)
+ switch (ch) {
+ case 'C':
+ max = (float)atof(__wt_optarg);
+ setmax = true;
+ break;
+ case 'D':
+ dbs = atoi(__wt_optarg);
+ break;
+ case 'h':
+ working_dir = __wt_optarg;
+ break;
+ case 'I':
+ idle = true;
+ break;
+ default:
+ usage();
+ }
+ argc -= __wt_optind;
+ argv += __wt_optind;
+ /*
+ * Adjust the maxcpu in relation to the number of databases, unless
+ * the user set it explicitly.
+ */
+ if (!setmax)
+ max = (float)dbs;
+ if (argc != 0)
+ usage();
+
+ if ((conn = calloc(sizeof(WT_CONNECTION *), dbs)) == NULL)
+ testutil_die(ENOMEM, "connection array malloc");
+ memset(cmd, 0, sizeof(cmd));
+ /*
+ * Set up all the directory names.
+ */
+ testutil_work_dir_from_path(home, HOME_SIZE, working_dir);
+ testutil_make_work_dir(home);
+ for (i = 0; i < dbs; ++i) {
+ snprintf(hometmp, HOME_SIZE, "%s/%s.%d", home, HOME_BASE, i);
+ testutil_make_work_dir(hometmp);
+ /*
+ * Open each database. Rotate different configurations
+ * among them.
+ */
+ cfg = i % 3;
+ if (cfg == 0)
+ wt_cfg = WT_CONFIG0;
+ else if (cfg == 1)
+ wt_cfg = WT_CONFIG1;
+ else
+ wt_cfg = WT_CONFIG2;
+ testutil_check(wiredtiger_open(
+ hometmp, NULL, wt_cfg, &conn[i]));
+ }
+
+ sleep(10);
+ for (i = 0; i < MAX_IDLE_TIME; i += IDLE_INCR) {
+ if (!idle)
+ testutil_check(run_ops(dbs));
+ printf("Sleep %d (%d of %d)\n", IDLE_INCR, i, MAX_IDLE_TIME);
+ sleep(IDLE_INCR);
+ }
+
+ /*
+ * Check CPU after all idling or work is done.
+ */
+ (void)snprintf(cmd, sizeof(cmd),
+ "ps -p %lu -o pcpu=", (unsigned long)getpid());
+ if ((fp = popen(cmd, "r")) == NULL)
+ testutil_die(errno, "popen");
+ fscanf(fp, "%f", &cpu);
+ printf("Final CPU %f, max %f\n", cpu, max);
+ if (cpu > max) {
+ fprintf(stderr, "ERROR: CPU usage: %f, max %f\n", cpu, max);
+ testutil_die(ERANGE, "CPU");
+ }
+ if (pclose(fp) != 0)
+ testutil_die(errno, "pclose");
+ for (i = 0; i < dbs; ++i)
+ testutil_check(conn[i]->close(conn[i], NULL));
+
+ return (EXIT_SUCCESS);
+}
diff --git a/test/manydbs/smoke.sh b/test/manydbs/smoke.sh
new file mode 100755
index 00000000000..c0e2976f154
--- /dev/null
+++ b/test/manydbs/smoke.sh
@@ -0,0 +1,18 @@
+#!/bin/sh
+
+set -e
+
+# Smoke-test format as part of running "make check".
+# Run with:
+# 1. The defaults
+# 2. Set idle flag to turn off operations.
+# 3. More dbs.
+#
+echo "manydbs: default with operations turned on"
+$TEST_WRAPPER ./t
+echo "manydbs: totally idle databases"
+$TEST_WRAPPER ./t -I
+echo "manydbs: 40 databases with operations"
+$TEST_WRAPPER ./t -D 40
+echo "manydbs: 40 idle databases"
+$TEST_WRAPPER ./t -I -D 40