summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger')
-rw-r--r--src/third_party/wiredtiger/build_linux/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/build_posix/configure.ac.in38
-rw-r--r--src/third_party/wiredtiger/build_win/wiredtiger_config.h3
-rw-r--r--src/third_party/wiredtiger/dist/api_data.py3
-rw-r--r--src/third_party/wiredtiger/dist/filelist1
-rw-r--r--src/third_party/wiredtiger/dist/flags.py2
-rw-r--r--src/third_party/wiredtiger/dist/s_string.ok2
-rw-r--r--src/third_party/wiredtiger/dist/stat_data.py8
-rw-r--r--src/third_party/wiredtiger/import.data2
-rw-r--r--src/third_party/wiredtiger/src/async/async_worker.c5
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_cursor.c42
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_delete.c9
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_handle.c41
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_random.c3
-rw-r--r--src/third_party/wiredtiger/src/btree/bt_walk.c121
-rw-r--r--src/third_party/wiredtiger/src/config/config_def.c46
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_api.c47
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_dhandle.c19
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_log.c35
-rw-r--r--src/third_party/wiredtiger/src/conn/conn_open.c3
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_index.c4
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_join.c2
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_table.c4
-rw-r--r--src/third_party/wiredtiger/src/evict/evict_lru.c218
-rw-r--r--src/third_party/wiredtiger/src/evict/evict_page.c40
-rw-r--r--src/third_party/wiredtiger/src/include/btmem.h4
-rw-r--r--src/third_party/wiredtiger/src/include/btree.h38
-rw-r--r--src/third_party/wiredtiger/src/include/cache.h3
-rw-r--r--src/third_party/wiredtiger/src/include/connection.h7
-rw-r--r--src/third_party/wiredtiger/src/include/extern.h11
-rw-r--r--src/third_party/wiredtiger/src/include/extern_posix.h2
-rw-r--r--src/third_party/wiredtiger/src/include/extern_win.h2
-rw-r--r--src/third_party/wiredtiger/src/include/flags.h8
-rw-r--r--src/third_party/wiredtiger/src/include/misc.i39
-rw-r--r--src/third_party/wiredtiger/src/include/os.h4
-rw-r--r--src/third_party/wiredtiger/src/include/session.h6
-rw-r--r--src/third_party/wiredtiger/src/include/stat.h8
-rw-r--r--src/third_party/wiredtiger/src/include/txn.h2
-rw-r--r--src/third_party/wiredtiger/src/include/txn.i10
-rw-r--r--src/third_party/wiredtiger/src/include/wiredtiger.in78
-rw-r--r--src/third_party/wiredtiger/src/log/log.c66
-rw-r--r--src/third_party/wiredtiger/src/log/log_slot.c20
-rw-r--r--src/third_party/wiredtiger/src/lsm/lsm_manager.c4
-rw-r--r--src/third_party/wiredtiger/src/meta/meta_table.c17
-rw-r--r--src/third_party/wiredtiger/src/meta/meta_turtle.c6
-rw-r--r--src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c33
-rw-r--r--src/third_party/wiredtiger/src/os_posix/os_time.c27
-rw-r--r--src/third_party/wiredtiger/src/os_win/os_time.c15
-rw-r--r--src/third_party/wiredtiger/src/reconcile/rec_write.c218
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_alter.c13
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_create.c6
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_drop.c4
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_list.c55
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_open.c68
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_rename.c2
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_stat.c11
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_truncate.c2
-rw-r--r--src/third_party/wiredtiger/src/schema/schema_worker.c9
-rw-r--r--src/third_party/wiredtiger/src/session/session_api.c15
-rw-r--r--src/third_party/wiredtiger/src/session/session_dhandle.c5
-rw-r--r--src/third_party/wiredtiger/src/support/err.c13
-rw-r--r--src/third_party/wiredtiger/src/support/rand.c12
-rw-r--r--src/third_party/wiredtiger/src/support/stat.c29
-rw-r--r--src/third_party/wiredtiger/src/support/time.c89
-rw-r--r--src/third_party/wiredtiger/src/txn/txn.c21
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_log.c31
-rw-r--r--src/third_party/wiredtiger/src/txn/txn_recover.c38
-rw-r--r--src/third_party/wiredtiger/test/mciproject.yml14
-rw-r--r--src/third_party/wiredtiger/test/recovery/random-abort.c4
-rw-r--r--src/third_party/wiredtiger/test/suite/test_bug018.py98
-rw-r--r--src/third_party/wiredtiger/test/suite/test_inmem01.py3
-rw-r--r--src/third_party/wiredtiger/test/suite/test_las.py60
-rw-r--r--src/third_party/wiredtiger/test/suite/test_txn02.py1
-rw-r--r--src/third_party/wiredtiger/test/suite/test_txn05.py11
-rw-r--r--src/third_party/wiredtiger/test/suite/test_txn09.py4
-rw-r--r--src/third_party/wiredtiger/test/suite/test_txn16.py140
76 files changed, 1526 insertions, 561 deletions
diff --git a/src/third_party/wiredtiger/build_linux/wiredtiger_config.h b/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
index 1122e1e319d..6fffea61ad1 100644
--- a/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_linux/wiredtiger_config.h
@@ -82,6 +82,9 @@
/* Define to 1 if you have the `posix_memalign' function. */
#define HAVE_POSIX_MEMALIGN 1
+/* Define to 1 if pthread condition variables support monotonic clocks. */
+#define HAVE_PTHREAD_COND_MONOTONIC 1
+
/* Define to 1 if you have the <pthread_np.h> header file. */
/* #undef HAVE_PTHREAD_NP_H */
diff --git a/src/third_party/wiredtiger/build_posix/configure.ac.in b/src/third_party/wiredtiger/build_posix/configure.ac.in
index 0fef587b4b8..415545a0d56 100644
--- a/src/third_party/wiredtiger/build_posix/configure.ac.in
+++ b/src/third_party/wiredtiger/build_posix/configure.ac.in
@@ -160,6 +160,44 @@ AS_CASE([$host_os], [darwin*], [], [AC_CHECK_FUNCS([fdatasync])])
# the generic declaration in AC_CHECK_FUNCS is incompatible.
AX_FUNC_POSIX_MEMALIGN
+# Check for POSIX condition variables with monotonic clock support
+AC_CACHE_CHECK([for condition waits with monotonic clock support],
+ [wt_cv_pthread_cond_monotonic],
+ [AC_RUN_IFELSE([AC_LANG_SOURCE([[
+#include <errno.h>
+#include <pthread.h>
+#include <stdlib.h>
+#include <time.h>
+
+int main()
+{
+ int ret;
+ pthread_condattr_t condattr;
+ pthread_cond_t cond;
+ pthread_mutex_t mtx;
+ struct timespec ts;
+
+ if ((ret = pthread_condattr_init(&condattr)) != 0) exit(1);
+ if ((ret = pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC)) != 0) exit(1);
+ if ((ret = pthread_cond_init(&cond, &condattr)) != 0) exit(1);
+ if ((ret = pthread_mutex_init(&mtx, NULL)) != 0) exit(1);
+ if ((ret = clock_gettime(CLOCK_MONOTONIC, &ts)) != 0) exit(1);
+ ts.tv_sec += 1;
+ if ((ret = pthread_mutex_lock(&mtx)) != 0) exit(1);
+ if ((ret = pthread_cond_timedwait(&cond, &mtx, &ts)) != 0 && ret != EINTR && ret != ETIMEDOUT) exit(1);
+
+ exit(0);
+}
+ ]])],
+ [wt_pthread_cond_monotonic=yes],
+ [wt_pthread_cond_monotonic=no],
+ [wt_pthread_cond_monotonic=no])])
+AC_MSG_RESULT($wt_pthread_cond_monotonic)
+if test "$wt_pthread_cond_monotonic" = "yes" ; then
+ AC_DEFINE([HAVE_PTHREAD_COND_MONOTONIC], [1],
+ [Define to 1 if pthread condition variables support monotonic clocks.])
+fi
+
AC_SYS_LARGEFILE
AC_C_BIGENDIAN
diff --git a/src/third_party/wiredtiger/build_win/wiredtiger_config.h b/src/third_party/wiredtiger/build_win/wiredtiger_config.h
index 78d2784cb70..8babdbfdc1b 100644
--- a/src/third_party/wiredtiger/build_win/wiredtiger_config.h
+++ b/src/third_party/wiredtiger/build_win/wiredtiger_config.h
@@ -79,6 +79,9 @@
/* Define to 1 if you have the <memory.h> header file. */
/* #undef HAVE_MEMORY_H */
+/* Define to 1 if pthread condition variables support monotonic clocks. */
+/* #undef HAVE_PTHREAD_COND_MONOTONIC */
+
/* Define to 1 if you have the `posix_fadvise' function. */
/* #undef HAVE_POSIX_FADVISE */
diff --git a/src/third_party/wiredtiger/dist/api_data.py b/src/third_party/wiredtiger/dist/api_data.py
index 22600dd5e29..596099647be 100644
--- a/src/third_party/wiredtiger/dist/api_data.py
+++ b/src/third_party/wiredtiger/dist/api_data.py
@@ -753,6 +753,9 @@ wiredtiger_open_common =\
Config('session_scratch_max', '2MB', r'''
maximum memory to cache in each session''',
type='int', undoc=True),
+ Config('session_table_cache', 'true', r'''
+ Maintain a per-session cache of tables''',
+ type='boolean'),
Config('transaction_sync', '', r'''
how to sync log records when the transaction commits''',
type='category', subconfig=[
diff --git a/src/third_party/wiredtiger/dist/filelist b/src/third_party/wiredtiger/dist/filelist
index 5a3348b940a..f53509e96ec 100644
--- a/src/third_party/wiredtiger/dist/filelist
+++ b/src/third_party/wiredtiger/dist/filelist
@@ -191,6 +191,7 @@ src/support/rand.c
src/support/scratch.c
src/support/stat.c
src/support/thread_group.c
+src/support/time.c
src/txn/txn.c
src/txn/txn_ckpt.c
src/txn/txn_ext.c
diff --git a/src/third_party/wiredtiger/dist/flags.py b/src/third_party/wiredtiger/dist/flags.py
index 64b5d789e72..1ce717f3586 100644
--- a/src/third_party/wiredtiger/dist/flags.py
+++ b/src/third_party/wiredtiger/dist/flags.py
@@ -32,7 +32,6 @@ flags = {
'READ_PREV',
'READ_RESTART_OK',
'READ_SKIP_INTL',
- 'READ_SKIP_LEAF',
'READ_TRUNCATE',
'READ_WONT_NEED',
],
@@ -111,6 +110,7 @@ flags = {
'CONN_SERVER_LSM',
'CONN_SERVER_STATISTICS',
'CONN_SERVER_SWEEP',
+ 'CONN_TABLE_CACHE',
'CONN_WAS_BACKUP',
],
'session' : [
diff --git a/src/third_party/wiredtiger/dist/s_string.ok b/src/third_party/wiredtiger/dist/s_string.ok
index f3852d00ac8..fad8c2f021a 100644
--- a/src/third_party/wiredtiger/dist/s_string.ok
+++ b/src/third_party/wiredtiger/dist/s_string.ok
@@ -807,6 +807,7 @@ intl
intnum
intpack
intptr
+intr
intrin
inuse
io
@@ -1060,6 +1061,7 @@ rebalancing
recno
recnos
reconfig
+reconfigures
reconfiguring
recsize
rectype
diff --git a/src/third_party/wiredtiger/dist/stat_data.py b/src/third_party/wiredtiger/dist/stat_data.py
index 512892eb44d..b66e95ce49b 100644
--- a/src/third_party/wiredtiger/dist/stat_data.py
+++ b/src/third_party/wiredtiger/dist/stat_data.py
@@ -431,11 +431,19 @@ connection_stats = [
##########################################
YieldStat('application_cache_time', 'application thread time waiting for cache (usecs)'),
YieldStat('application_evict_time', 'application thread time evicting (usecs)'),
+ YieldStat('child_modify_blocked_page', 'page reconciliation yielded due to child modification'),
+ YieldStat('conn_close_blocked_lsm', 'connection close yielded for lsm manager shutdown'),
+ YieldStat('dhandle_lock_blocked', 'data handle lock yielded'),
+ YieldStat('log_server_sync_blocked', 'log server sync yielded for log write'),
YieldStat('page_busy_blocked', 'page acquire busy blocked'),
+ YieldStat('page_del_rollback_blocked', 'page delete rollback yielded for instantiation'),
YieldStat('page_forcible_evict_blocked', 'page acquire eviction blocked'),
+ YieldStat('page_index_slot_blocked', 'reference for page index and slot yielded'),
YieldStat('page_locked_blocked', 'page acquire locked blocked'),
YieldStat('page_read_blocked', 'page acquire read blocked'),
YieldStat('page_sleep', 'page acquire time sleeping (usecs)'),
+ YieldStat('tree_descend_blocked', 'tree descend one level yielded for split page index update'),
+ YieldStat('txn_release_blocked', 'connection close blocked waiting for transaction state stabilization'),
]
connection_stats = sorted(connection_stats, key=attrgetter('desc'))
diff --git a/src/third_party/wiredtiger/import.data b/src/third_party/wiredtiger/import.data
index 03d5746ffde..e867147e59e 100644
--- a/src/third_party/wiredtiger/import.data
+++ b/src/third_party/wiredtiger/import.data
@@ -1,5 +1,5 @@
{
- "commit": "d2f2eae6d7718a53ac5bacf7141773ee0696f3c6",
+ "commit": "0b36171f4aa0bea6ab6118b0d3bcf6329a24939e",
"github": "wiredtiger/wiredtiger.git",
"vendor": "wiredtiger",
"branch": "mongodb-3.4"
diff --git a/src/third_party/wiredtiger/src/async/async_worker.c b/src/third_party/wiredtiger/src/async/async_worker.c
index 11f59ed14f1..89877652f1e 100644
--- a/src/third_party/wiredtiger/src/async/async_worker.c
+++ b/src/third_party/wiredtiger/src/async/async_worker.c
@@ -301,11 +301,10 @@ __wt_async_worker(void *arg)
WT_ERR(__async_op_dequeue(conn, session, &op));
if (op != NULL && op != &async->flush_op) {
/*
- * If an operation fails, we want the worker thread to
- * keep running, unless there is a panic.
+ * Operation failure doesn't cause the worker thread to
+ * exit.
*/
(void)__async_worker_op(session, op, &worker);
- WT_ERR(WT_SESSION_CHECK_PANIC(session));
} else if (async->flush_state == WT_ASYNC_FLUSHING) {
/*
* Worker flushing going on. Last worker to the party
diff --git a/src/third_party/wiredtiger/src/btree/bt_cursor.c b/src/third_party/wiredtiger/src/btree/bt_cursor.c
index f0aa632551b..28977eee9f5 100644
--- a/src/third_party/wiredtiger/src/btree/bt_cursor.c
+++ b/src/third_party/wiredtiger/src/btree/bt_cursor.c
@@ -52,15 +52,18 @@ __cursor_state_restore(WT_CURSOR *cursor, WT_CURFILE_STATE *state)
/*
* __cursor_page_pinned --
- * Return if we have a page pinned and it's not been flagged for forced
- * eviction (the forced eviction test is so we periodically release pages
- * grown too large).
+ * Return if we have a page pinned.
*/
static inline bool
-__cursor_page_pinned(WT_CURSOR_BTREE *cbt)
+__cursor_page_pinned(WT_CURSOR_BTREE *cbt, bool eviction_ok)
{
+ /*
+ * Optionally fail the page-pinned test when the page is flagged for
+ * forced eviction (so we periodically release pages grown too large).
+ * The test is optional as not all callers can release pinned pages.
+ */
return (F_ISSET(cbt, WT_CBT_ACTIVE) &&
- cbt->ref->page->read_gen != WT_READGEN_OLDEST);
+ (!eviction_ok || cbt->ref->page->read_gen != WT_READGEN_OLDEST));
}
/*
@@ -156,8 +159,10 @@ __cursor_disable_bulk(WT_SESSION_IMPL *session, WT_BTREE *btree)
* into a tree. Eviction is disabled when an empty tree is opened, and
* it must only be enabled once.
*/
- if (__wt_atomic_cas8(&btree->original, 1, 0))
+ if (__wt_atomic_cas8(&btree->original, 1, 0)) {
+ btree->evict_disabled_open = false;
__wt_evict_file_exclusive_off(session);
+ }
}
/*
@@ -443,7 +448,7 @@ __wt_btcur_search(WT_CURSOR_BTREE *cbt)
* from the root.
*/
valid = false;
- if (__cursor_page_pinned(cbt)) {
+ if (__cursor_page_pinned(cbt, true)) {
__wt_txn_cursor_op(session);
WT_ERR(btree->type == BTREE_ROW ?
@@ -535,7 +540,7 @@ __wt_btcur_search_near(WT_CURSOR_BTREE *cbt, int *exactp)
* existing record.
*/
valid = false;
- if (btree->type == BTREE_ROW && __cursor_page_pinned(cbt)) {
+ if (btree->type == BTREE_ROW && __cursor_page_pinned(cbt, true)) {
__wt_txn_cursor_op(session);
WT_ERR(__cursor_row_search(session, cbt, cbt->ref, true));
@@ -665,7 +670,7 @@ __wt_btcur_insert(WT_CURSOR_BTREE *cbt)
* configured for append aren't included, regardless of whether or not
* they meet all other criteria.
*/
- if (__cursor_page_pinned(cbt) &&
+ if (__cursor_page_pinned(cbt, true) &&
F_ISSET_ALL(cursor, WT_CURSTD_KEY_INT | WT_CURSTD_OVERWRITE) &&
!append_key) {
WT_ERR(__wt_txn_autocommit_check(session));
@@ -880,8 +885,22 @@ __wt_btcur_remove(WT_CURSOR_BTREE *cbt)
* removed, and the record must exist with a positioned cursor. The
* cursor won't be positioned on a page with an external key set, but
* be sure.
+ *
+ * There's trickiness in the page-pinned check. By definition a remove
+ * operation leaves a cursor positioned if it's initially positioned.
+ * However, if every item on the page is deleted and we unpin the page,
+ * eviction might delete the page and our search will re-instantiate an
+ * empty page for us. Cursor remove returns not-found whether or not
+ * that eviction/deletion happens and it's OK unless cursor-overwrite
+ * is configured (which means we return success even if there's no item
+ * to delete). In that case, we'll fail when we try to point the cursor
+ * at the key on the page to satisfy the positioned requirement. It's
+ * arguably safe to simply leave the key initialized in the cursor (as
+ * that's all a positioned cursor implies), but it's probably safer to
+ * avoid page eviction entirely in the positioned case.
*/
- if (__cursor_page_pinned(cbt) && F_ISSET(cursor, WT_CURSTD_KEY_INT)) {
+ if (__cursor_page_pinned(cbt, !positioned) &&
+ F_ISSET(cursor, WT_CURSTD_KEY_INT)) {
WT_ERR(__wt_txn_autocommit_check(session));
/*
@@ -1024,7 +1043,8 @@ __wt_btcur_update(WT_CURSOR_BTREE *cbt)
* cursor won't be positioned on a page with an external key set, but
* be sure.
*/
- if (__cursor_page_pinned(cbt) && F_ISSET(cursor, WT_CURSTD_KEY_INT)) {
+ if (__cursor_page_pinned(cbt, true) &&
+ F_ISSET(cursor, WT_CURSTD_KEY_INT)) {
WT_ERR(__wt_txn_autocommit_check(session));
/*
* The cursor position may not be exact (the cursor's comparison
diff --git a/src/third_party/wiredtiger/src/btree/bt_delete.c b/src/third_party/wiredtiger/src/btree/bt_delete.c
index b55ad291c5e..5c4625044d3 100644
--- a/src/third_party/wiredtiger/src/btree/bt_delete.c
+++ b/src/third_party/wiredtiger/src/btree/bt_delete.c
@@ -153,6 +153,7 @@ void
__wt_delete_page_rollback(WT_SESSION_IMPL *session, WT_REF *ref)
{
WT_UPDATE **upd;
+ uint64_t yield_count;
/*
* If the page is still "deleted", it's as we left it, reset the state
@@ -160,7 +161,7 @@ __wt_delete_page_rollback(WT_SESSION_IMPL *session, WT_REF *ref)
* instantiated or being instantiated. Loop because it's possible for
* the page to return to the deleted state if instantiation fails.
*/
- for (;; __wt_yield())
+ for (yield_count = 0;; yield_count++, __wt_yield())
switch (ref->state) {
case WT_REF_DISK:
case WT_REF_READING:
@@ -173,7 +174,7 @@ __wt_delete_page_rollback(WT_SESSION_IMPL *session, WT_REF *ref)
*/
if (__wt_atomic_casv32(
&ref->state, WT_REF_DELETED, WT_REF_DISK))
- return;
+ goto done;
break;
case WT_REF_LOCKED:
/*
@@ -203,8 +204,10 @@ __wt_delete_page_rollback(WT_SESSION_IMPL *session, WT_REF *ref)
*/
__wt_free(session, ref->page_del->update_list);
__wt_free(session, ref->page_del);
- return;
+ goto done;
}
+
+done: WT_STAT_CONN_INCRV(session, page_del_rollback_blocked, yield_count);
}
/*
diff --git a/src/third_party/wiredtiger/src/btree/bt_handle.c b/src/third_party/wiredtiger/src/btree/bt_handle.c
index a0da7df0998..8637a8cd751 100644
--- a/src/third_party/wiredtiger/src/btree/bt_handle.c
+++ b/src/third_party/wiredtiger/src/btree/bt_handle.c
@@ -66,7 +66,6 @@ __wt_btree_open(WT_SESSION_IMPL *session, const char *op_cfg[])
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
size_t root_addr_size;
- uint32_t mask;
uint8_t root_addr[WT_BTREE_MAX_ADDR_COOKIE];
const char *filename;
bool creation, forced_salvage, readonly;
@@ -75,15 +74,14 @@ __wt_btree_open(WT_SESSION_IMPL *session, const char *op_cfg[])
dhandle = session->dhandle;
/*
- * This may be a re-open of an underlying object and we have to clean
- * up. We can't clear the operation flags, however, they're set by the
- * connection handle software that called us.
+ * This may be a re-open, clean up the btree structure.
+ * Clear the fields that don't persist across a re-open.
+ * Clear all flags other than the operation flags (which are set by the
+ * connection handle software that called us).
*/
WT_RET(__btree_clear(session));
-
- mask = F_MASK(btree, WT_BTREE_SPECIAL_FLAGS);
- memset(btree, 0, sizeof(*btree));
- btree->flags = mask;
+ memset(btree, 0, WT_BTREE_CLEAR_SIZE);
+ F_CLR(btree, ~WT_BTREE_SPECIAL_FLAGS);
/* Set the data handle first, our called functions reasonably use it. */
btree->dhandle = dhandle;
@@ -185,13 +183,19 @@ __wt_btree_open(WT_SESSION_IMPL *session, const char *op_cfg[])
*
* Files that can still be bulk-loaded cannot be evicted.
* Permanently cache-resident files can never be evicted.
- * Special operations don't enable eviction. (The underlying commands
- * may turn on eviction, but it's their decision.)
+ * Special operations don't enable eviction. The underlying commands may
+ * turn on eviction (for example, verify turns on eviction while working
+ * a file to keep from consuming the cache), but it's their decision. If
+ * an underlying command reconfigures eviction, it must either clear the
+ * evict-disabled-open flag or restore the eviction configuration when
+ * finished so that handle close behaves correctly.
*/
if (btree->original ||
F_ISSET(btree, WT_BTREE_IN_MEMORY | WT_BTREE_REBALANCE |
- WT_BTREE_SALVAGE | WT_BTREE_UPGRADE | WT_BTREE_VERIFY))
+ WT_BTREE_SALVAGE | WT_BTREE_UPGRADE | WT_BTREE_VERIFY)) {
WT_ERR(__wt_evict_file_exclusive_on(session));
+ btree->evict_disabled_open = true;
+ }
if (0) {
err: WT_TRET(__wt_btree_close(session));
@@ -228,6 +232,15 @@ __wt_btree_close(WT_SESSION_IMPL *session)
return (0);
F_SET(btree, WT_BTREE_CLOSED);
+ /*
+ * If we turned eviction off and never turned it back on, do that now,
+ * otherwise the counter will be off.
+ */
+ if (btree->evict_disabled_open) {
+ btree->evict_disabled_open = false;
+ __wt_evict_file_exclusive_off(session);
+ }
+
/* Discard any underlying block manager resources. */
if ((bm = btree->bm) != NULL) {
btree->bm = NULL;
@@ -447,9 +460,11 @@ __btree_conf(WT_SESSION_IMPL *session, WT_CKPT *ckpt)
WT_RET(__wt_rwlock_init(session, &btree->ovfl_lock));
WT_RET(__wt_spin_init(session, &btree->flush_lock, "btree flush"));
- btree->checkpointing = WT_CKPT_OFF; /* Not checkpointing */
btree->modified = false; /* Clean */
- btree->write_gen = ckpt->write_gen; /* Write generation */
+
+ btree->checkpointing = WT_CKPT_OFF; /* Not checkpointing */
+ btree->write_gen = ckpt->write_gen; /* Write generation */
+ btree->checkpoint_gen = S2C(session)->txn_global.checkpoint_gen;
return (0);
}
diff --git a/src/third_party/wiredtiger/src/btree/bt_random.c b/src/third_party/wiredtiger/src/btree/bt_random.c
index c5948ec4ab5..b4f05c440ba 100644
--- a/src/third_party/wiredtiger/src/btree/bt_random.c
+++ b/src/third_party/wiredtiger/src/btree/bt_random.c
@@ -395,8 +395,7 @@ __wt_btcur_next_random(WT_CURSOR_BTREE *cbt)
*/
for (skip = cbt->next_random_leaf_skip; cbt->ref == NULL || skip > 0;) {
n = skip;
- WT_ERR(__wt_tree_walk_skip(session, &cbt->ref, &skip,
- WT_READ_NO_GEN | WT_READ_SKIP_INTL | WT_READ_WONT_NEED));
+ WT_ERR(__wt_tree_walk_skip(session, &cbt->ref, &skip));
if (n == skip) {
if (skip == 0)
break;
diff --git a/src/third_party/wiredtiger/src/btree/bt_walk.c b/src/third_party/wiredtiger/src/btree/bt_walk.c
index 86484feb7c9..c22b99c55d0 100644
--- a/src/third_party/wiredtiger/src/btree/bt_walk.c
+++ b/src/third_party/wiredtiger/src/btree/bt_walk.c
@@ -18,9 +18,16 @@ __ref_index_slot(WT_SESSION_IMPL *session,
{
WT_PAGE_INDEX *pindex;
WT_REF **start, **stop, **p, **t;
+ uint64_t yield_count;
uint32_t entries, slot;
- for (;;) {
+ /*
+ * If we don't find our reference, the page split and our home
+ * pointer references the wrong page. When internal pages
+ * split, their WT_REF structure home values are updated; yield
+ * and wait for that to happen.
+ */
+ for (yield_count = 0;; yield_count++, __wt_yield()) {
/*
* Copy the parent page's index value: the page can split at
* any time, but the index's value is always valid, even if
@@ -59,18 +66,13 @@ __ref_index_slot(WT_SESSION_IMPL *session,
}
}
- /*
- * If we don't find our reference, the page split and our home
- * pointer references the wrong page. When internal pages
- * split, their WT_REF structure home values are updated; yield
- * and wait for that to happen.
- */
- __wt_yield();
}
found: WT_ASSERT(session, pindex->index[slot] == ref);
*pindexp = pindex;
*slotp = slot;
+
+ WT_STAT_CONN_INCRV(session, page_index_slot_blocked, yield_count);
}
/*
@@ -177,12 +179,13 @@ __ref_descend_prev(
WT_SESSION_IMPL *session, WT_REF *ref, WT_PAGE_INDEX **pindexp)
{
WT_PAGE_INDEX *pindex;
+ uint64_t yield_count;
/*
* We're passed a child page into which we're descending, and on which
* we have a hazard pointer.
*/
- for (;; __wt_yield()) {
+ for (yield_count = 0;; yield_count++, __wt_yield()) {
/*
* There's a split race when a cursor moving backwards through
* the tree descends the tree. If we're splitting an internal
@@ -242,6 +245,7 @@ __ref_descend_prev(
break;
}
*pindexp = pindex;
+ WT_STAT_CONN_INCRV(session, tree_descend_blocked, yield_count);
}
/*
@@ -497,29 +501,21 @@ restart: /*
}
/*
- * Optionally skip leaf pages: skip all leaf pages if
- * WT_READ_SKIP_LEAF is set, when the skip-leaf-count
- * variable is non-zero, skip some count of leaf pages.
- * If this page is disk-based, crack the cell to figure
- * out it's a leaf page without reading it.
+ * Optionally skip leaf pages: when the skip-leaf-count
+ * variable is non-zero, skip some count of leaf pages,
+ * then take the next leaf page we can.
*
- * If skipping some number of leaf pages, decrement the
- * count of pages to zero, and then take the next leaf
- * page we can. Be cautious around the page decrement,
- * if for some reason don't take this particular page,
- * we can take the next one, and, there are additional
- * tests/decrements when we're about to return a leaf
- * page.
+ * The reason to do some of this work here (rather than
+ * in our caller), is because we can look at the cell
+ * and know it's a leaf page without reading it into
+ * memory. If this page is disk-based, crack the cell
+ * to figure out it's a leaf page without reading it.
*/
- if (skipleafcntp != NULL || LF_ISSET(WT_READ_SKIP_LEAF))
- if (__ref_is_leaf(ref)) {
- if (LF_ISSET(WT_READ_SKIP_LEAF))
- break;
- if (*skipleafcntp > 0) {
- --*skipleafcntp;
- break;
- }
- }
+ if (skipleafcntp != NULL &&
+ *skipleafcntp > 0 && __ref_is_leaf(ref)) {
+ --*skipleafcntp;
+ break;
+ }
ret = __wt_page_swap(session, couple, ref,
WT_READ_NOTFOUND_OK | WT_READ_RESTART_OK | flags);
@@ -626,34 +622,18 @@ descend: empty_internal = true;
session, ref, &pindex);
slot = pindex->entries - 1;
}
- } else {
- /*
- * At the lowest tree level (considering a leaf
- * page), turn off the initial-descent state.
- * Descent race tests are different when moving
- * through the tree vs. the initial descent.
- */
- initial_descent = false;
-
- /*
- * Optionally skip leaf pages, the second half.
- * We didn't have an on-page cell to figure out
- * if it was a leaf page, we had to acquire the
- * hazard pointer and look at the page.
- */
- if (skipleafcntp != NULL ||
- LF_ISSET(WT_READ_SKIP_LEAF)) {
- if (LF_ISSET(WT_READ_SKIP_LEAF))
- break;
- if (*skipleafcntp > 0) {
- --*skipleafcntp;
- break;
- }
- }
-
- *refp = ref;
- goto done;
+ continue;
}
+
+ /*
+ * The tree-walk restart code knows we return any leaf
+ * page we acquire (never hazard-pointer coupling on
+ * after acquiring a leaf page), and asserts no restart
+ * happens while holding a leaf page. This page must be
+ * returned to our caller.
+ */
+ *refp = ref;
+ goto done;
}
}
@@ -690,8 +670,29 @@ __wt_tree_walk_count(WT_SESSION_IMPL *session,
* of leaf pages before returning.
*/
int
-__wt_tree_walk_skip(WT_SESSION_IMPL *session,
- WT_REF **refp, uint64_t *skipleafcntp, uint32_t flags)
+__wt_tree_walk_skip(
+ WT_SESSION_IMPL *session, WT_REF **refp, uint64_t *skipleafcntp)
{
- return (__tree_walk_internal(session, refp, NULL, skipleafcntp, flags));
+ /*
+ * Optionally skip leaf pages, the second half. The tree-walk function
+ * didn't have an on-page cell it could use to figure out if the page
+ * was a leaf page or not, it had to acquire the hazard pointer and look
+ * at the page. The tree-walk code never acquires a hazard pointer on a
+ * leaf page without returning it, and it's not trivial to change that.
+ * So, the tree-walk code returns all leaf pages here and we deal with
+ * decrementing the count.
+ */
+ do {
+ WT_RET(__tree_walk_internal(session, refp, NULL, skipleafcntp,
+ WT_READ_NO_GEN | WT_READ_SKIP_INTL | WT_READ_WONT_NEED));
+
+ /*
+ * The walk skipped internal pages, any page returned must be a
+ * leaf page.
+ */
+ if (*skipleafcntp > 0)
+ --*skipleafcntp;
+ } while (*skipleafcntp > 0);
+
+ return (0);
}
diff --git a/src/third_party/wiredtiger/src/config/config_def.c b/src/third_party/wiredtiger/src/config/config_def.c
index f152fbacad4..c8a8c525751 100644
--- a/src/third_party/wiredtiger/src/config/config_def.c
+++ b/src/third_party/wiredtiger/src/config/config_def.c
@@ -733,6 +733,7 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open[] = {
{ "readonly", "boolean", NULL, NULL, NULL, 0 },
{ "session_max", "int", NULL, "min=1", NULL, 0 },
{ "session_scratch_max", "int", NULL, NULL, NULL, 0 },
+ { "session_table_cache", "boolean", NULL, NULL, NULL, 0 },
{ "shared_cache", "category",
NULL, NULL,
confchk_wiredtiger_open_shared_cache_subconfigs, 5 },
@@ -820,6 +821,7 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_all[] = {
{ "readonly", "boolean", NULL, NULL, NULL, 0 },
{ "session_max", "int", NULL, "min=1", NULL, 0 },
{ "session_scratch_max", "int", NULL, NULL, NULL, 0 },
+ { "session_table_cache", "boolean", NULL, NULL, NULL, 0 },
{ "shared_cache", "category",
NULL, NULL,
confchk_wiredtiger_open_shared_cache_subconfigs, 5 },
@@ -904,6 +906,7 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_basecfg[] = {
{ "readonly", "boolean", NULL, NULL, NULL, 0 },
{ "session_max", "int", NULL, "min=1", NULL, 0 },
{ "session_scratch_max", "int", NULL, NULL, NULL, 0 },
+ { "session_table_cache", "boolean", NULL, NULL, NULL, 0 },
{ "shared_cache", "category",
NULL, NULL,
confchk_wiredtiger_open_shared_cache_subconfigs, 5 },
@@ -986,6 +989,7 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_usercfg[] = {
{ "readonly", "boolean", NULL, NULL, NULL, 0 },
{ "session_max", "int", NULL, "min=1", NULL, 0 },
{ "session_scratch_max", "int", NULL, NULL, NULL, 0 },
+ { "session_table_cache", "boolean", NULL, NULL, NULL, 0 },
{ "shared_cache", "category",
NULL, NULL,
confchk_wiredtiger_open_shared_cache_subconfigs, 5 },
@@ -1276,14 +1280,14 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"file_max=100MB,path=\".\",prealloc=true,recover=on,"
"zero_fill=false),lsm_manager=(merge=true,worker_thread_max=4),"
"lsm_merge=true,mmap=true,multiprocess=false,readonly=false,"
- "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
- ",name=,quota=0,reserve=0,size=500MB),statistics=none,"
- "statistics_log=(json=false,on_close=false,path=\".\",sources=,"
- "timestamp=\"%b %d %H:%M:%S\",wait=0),"
+ "session_max=100,session_scratch_max=2MB,session_table_cache=true"
+ ",shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
+ "statistics=none,statistics_log=(json=false,on_close=false,"
+ "path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"transaction_sync=(enabled=false,method=fsync),"
"use_environment=true,use_environment_priv=false,verbose=,"
"write_through=",
- confchk_wiredtiger_open, 40
+ confchk_wiredtiger_open, 41
},
{ "wiredtiger_open_all",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
@@ -1300,14 +1304,14 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"file_max=100MB,path=\".\",prealloc=true,recover=on,"
"zero_fill=false),lsm_manager=(merge=true,worker_thread_max=4),"
"lsm_merge=true,mmap=true,multiprocess=false,readonly=false,"
- "session_max=100,session_scratch_max=2MB,shared_cache=(chunk=10MB"
- ",name=,quota=0,reserve=0,size=500MB),statistics=none,"
- "statistics_log=(json=false,on_close=false,path=\".\",sources=,"
- "timestamp=\"%b %d %H:%M:%S\",wait=0),"
+ "session_max=100,session_scratch_max=2MB,session_table_cache=true"
+ ",shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
+ "statistics=none,statistics_log=(json=false,on_close=false,"
+ "path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
"transaction_sync=(enabled=false,method=fsync),"
"use_environment=true,use_environment_priv=false,verbose=,"
"version=(major=0,minor=0),write_through=",
- confchk_wiredtiger_open_all, 41
+ confchk_wiredtiger_open_all, 42
},
{ "wiredtiger_open_basecfg",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
@@ -1323,12 +1327,13 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"path=\".\",prealloc=true,recover=on,zero_fill=false),"
"lsm_manager=(merge=true,worker_thread_max=4),lsm_merge=true,"
"mmap=true,multiprocess=false,readonly=false,session_max=100,"
- "session_scratch_max=2MB,shared_cache=(chunk=10MB,name=,quota=0,"
- "reserve=0,size=500MB),statistics=none,statistics_log=(json=false"
- ",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
- ",wait=0),transaction_sync=(enabled=false,method=fsync),verbose=,"
+ "session_scratch_max=2MB,session_table_cache=true,"
+ "shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
+ "statistics=none,statistics_log=(json=false,on_close=false,"
+ "path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
+ "transaction_sync=(enabled=false,method=fsync),verbose=,"
"version=(major=0,minor=0),write_through=",
- confchk_wiredtiger_open_basecfg, 35
+ confchk_wiredtiger_open_basecfg, 36
},
{ "wiredtiger_open_usercfg",
"async=(enabled=false,ops_max=1024,threads=2),buffer_alignment=-1"
@@ -1344,12 +1349,13 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"path=\".\",prealloc=true,recover=on,zero_fill=false),"
"lsm_manager=(merge=true,worker_thread_max=4),lsm_merge=true,"
"mmap=true,multiprocess=false,readonly=false,session_max=100,"
- "session_scratch_max=2MB,shared_cache=(chunk=10MB,name=,quota=0,"
- "reserve=0,size=500MB),statistics=none,statistics_log=(json=false"
- ",on_close=false,path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\""
- ",wait=0),transaction_sync=(enabled=false,method=fsync),verbose=,"
+ "session_scratch_max=2MB,session_table_cache=true,"
+ "shared_cache=(chunk=10MB,name=,quota=0,reserve=0,size=500MB),"
+ "statistics=none,statistics_log=(json=false,on_close=false,"
+ "path=\".\",sources=,timestamp=\"%b %d %H:%M:%S\",wait=0),"
+ "transaction_sync=(enabled=false,method=fsync),verbose=,"
"write_through=",
- confchk_wiredtiger_open_usercfg, 34
+ confchk_wiredtiger_open_usercfg, 35
},
{ NULL, NULL, NULL, 0 }
};
diff --git a/src/third_party/wiredtiger/src/conn/conn_api.c b/src/third_party/wiredtiger/src/conn/conn_api.c
index 68d45678965..103e4a68f04 100644
--- a/src/third_party/wiredtiger/src/conn/conn_api.c
+++ b/src/third_party/wiredtiger/src/conn/conn_api.c
@@ -1086,6 +1086,41 @@ err: /*
WT_TRET(wt_session->close(wt_session, config));
}
+ /*
+ * Perform a system-wide checkpoint so that all tables are consistent
+ * with each other. Do this before shutting down all the subsystems.
+ * We have shut down all user sessions, but send in true for waiting
+ * for internal races.
+ */
+ if (!F_ISSET(conn, WT_CONN_IN_MEMORY | WT_CONN_READONLY)) {
+ s = NULL;
+ WT_TRET(__wt_open_internal_session(
+ conn, "close_ckpt", true, 0, &s));
+ if (s != NULL) {
+ const char *checkpoint_cfg[] = {
+ WT_CONFIG_BASE(session, WT_SESSION_checkpoint),
+ NULL
+ };
+ wt_session = &s->iface;
+ WT_TRET(__wt_txn_checkpoint(s, checkpoint_cfg, true));
+
+ /*
+ * Mark the metadata dirty so we flush it on close,
+ * allowing recovery to be skipped.
+ */
+ WT_WITH_DHANDLE(s, WT_SESSION_META_DHANDLE(s),
+ __wt_tree_modify_set(s));
+
+ WT_TRET(wt_session->close(wt_session, config));
+ }
+ }
+
+ if (ret != 0) {
+ __wt_err(session, ret,
+ "failure during close, disabling further writes");
+ F_SET(conn, WT_CONN_PANIC);
+ }
+
WT_TRET(__wt_connection_close(conn));
/* We no longer have a session, don't try to update it. */
@@ -2185,6 +2220,9 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
WT_ERR(__wt_config_gets(session, cfg, "readonly", &cval));
if (cval.val)
F_SET(conn, WT_CONN_READONLY);
+ WT_ERR(__wt_config_gets(session, cfg, "session_table_cache", &cval));
+ if (cval.val)
+ F_SET(conn, WT_CONN_TABLE_CACHE);
/* Configure error messages so we get them right early. */
WT_ERR(__wt_config_gets(session, cfg, "error_prefix", &cval));
@@ -2475,8 +2513,15 @@ err: /* Discard the scratch buffers. */
__wt_scr_discard(session);
__wt_scr_discard(&conn->dummy_session);
- if (ret != 0)
+ if (ret != 0) {
+ /*
+ * Set panic if we're returning the run recovery error so that
+ * we don't try to checkpoint data handles.
+ */
+ if (ret == WT_RUN_RECOVERY)
+ F_SET(conn, WT_CONN_PANIC);
WT_TRET(__wt_connection_close(conn));
+ }
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/conn/conn_dhandle.c b/src/third_party/wiredtiger/src/conn/conn_dhandle.c
index 1816e66b0b7..181f12ab2dd 100644
--- a/src/third_party/wiredtiger/src/conn/conn_dhandle.c
+++ b/src/third_party/wiredtiger/src/conn/conn_dhandle.c
@@ -317,6 +317,9 @@ __wt_conn_btree_open(
WT_ASSERT(session,
!F_ISSET(S2C(session), WT_CONN_CLOSING_NO_MORE_OPENS));
+ /* Turn off eviction. */
+ WT_RET(__wt_evict_file_exclusive_on(session));
+
/*
* If the handle is already open, it has to be closed so it can be
* reopened with a new configuration.
@@ -330,11 +333,11 @@ __wt_conn_btree_open(
* in the tree that can block the close.
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN))
- WT_RET(__wt_conn_btree_sync_and_close(session, false, false));
+ WT_ERR(__wt_conn_btree_sync_and_close(session, false, false));
/* Discard any previous configuration, set up the new configuration. */
__conn_btree_config_clear(session);
- WT_RET(__conn_btree_config_set(session));
+ WT_ERR(__conn_btree_config_set(session));
/* Set any special flags on the handle. */
F_SET(btree, LF_MASK(WT_BTREE_SPECIAL_FLAGS));
@@ -374,6 +377,8 @@ __wt_conn_btree_open(
err: F_CLR(btree, WT_BTREE_SPECIAL_FLAGS);
}
+ __wt_evict_file_exclusive_off(session);
+
return (ret);
}
@@ -577,7 +582,7 @@ __conn_dhandle_remove(WT_SESSION_IMPL *session, bool final)
WT_ASSERT(session,
F_ISSET(session, WT_SESSION_LOCKED_HANDLE_LIST_WRITE));
- WT_ASSERT(session, dhandle != conn->cache->evict_file_next);
+ WT_ASSERT(session, dhandle != conn->cache->walk_tree);
/* Check if the handle was reacquired by a session while we waited. */
if (!final &&
@@ -673,8 +678,8 @@ restart:
continue;
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(
- session, true, F_ISSET(conn, WT_CONN_IN_MEMORY))));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, true,
+ F_ISSET(conn, WT_CONN_IN_MEMORY | WT_CONN_PANIC))));
goto restart;
}
@@ -699,8 +704,8 @@ restart:
/* Close the metadata file handle. */
while ((dhandle = TAILQ_FIRST(&conn->dhqh)) != NULL)
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(
- session, true, F_ISSET(conn, WT_CONN_IN_MEMORY))));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, true,
+ F_ISSET(conn, WT_CONN_IN_MEMORY | WT_CONN_PANIC))));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/conn/conn_log.c b/src/third_party/wiredtiger/src/conn/conn_log.c
index d2ed314fd2e..8b47d3b04c0 100644
--- a/src/third_party/wiredtiger/src/conn/conn_log.c
+++ b/src/third_party/wiredtiger/src/conn/conn_log.c
@@ -375,6 +375,7 @@ __log_file_server(void *arg)
WT_LOG *log;
WT_LSN close_end_lsn, min_lsn;
WT_SESSION_IMPL *session;
+ uint64_t yield_count;
uint32_t filenum;
bool locked;
@@ -382,6 +383,7 @@ __log_file_server(void *arg)
conn = S2C(session);
log = conn->log;
locked = false;
+ yield_count = 0;
while (F_ISSET(conn, WT_CONN_SERVER_LOG)) {
/*
* If there is a log file to close, make sure any outstanding
@@ -512,6 +514,7 @@ __log_file_server(void *arg)
* thread a chance to run and try again in
* this case.
*/
+ yield_count++;
__wt_yield();
continue;
}
@@ -522,8 +525,9 @@ __log_file_server(void *arg)
}
if (0) {
-err: __wt_err(session, ret, "log close server error");
+err: WT_PANIC_MSG(session, ret, "log close server error");
}
+ WT_STAT_CONN_INCRV(session, log_server_sync_blocked, yield_count);
if (locked)
__wt_spin_unlock(session, &log->log_sync_lock);
return (WT_THREAD_RET_VALUE);
@@ -740,7 +744,8 @@ __log_wrlsn_server(void *arg)
WT_ERR(__wt_log_force_write(session, 1, NULL));
__wt_log_wrlsn(session, NULL);
if (0) {
-err: __wt_err(session, ret, "log wrlsn server error");
+err: WT_PANIC_MSG(session, ret, "log wrlsn server error");
+
}
return (WT_THREAD_RET_VALUE);
}
@@ -757,7 +762,7 @@ __log_server(void *arg)
WT_DECL_RET;
WT_LOG *log;
WT_SESSION_IMPL *session;
- uint64_t timediff;
+ uint64_t retry, timediff;
bool did_work, signalled;
session = arg;
@@ -783,6 +788,7 @@ __log_server(void *arg)
* takes to sync out an earlier file.
*/
did_work = true;
+ retry = 0;
while (F_ISSET(conn, WT_CONN_SERVER_LOG)) {
/*
* Slots depend on future activity. Force out buffered
@@ -827,7 +833,24 @@ __log_server(void *arg)
ret = __log_archive_once(session, 0);
__wt_writeunlock(
session, &log->log_archive_lock);
- WT_ERR(ret);
+ /*
+ * It is possible that an external
+ * process on some systems may prevent
+ * removal. If we get a permission
+ * error, retry a few times.
+ */
+ if (ret == EACCES &&
+ retry < WT_RETRY_MAX) {
+ retry++;
+ ret = 0;
+ } else {
+ /*
+ * Return the error if there is
+ * one or reset on success.
+ */
+ WT_ERR(ret);
+ retry = 0;
+ }
} else
__wt_verbose(session, WT_VERB_LOG,
"log_archive: Blocked due to open "
@@ -844,7 +867,7 @@ __log_server(void *arg)
}
if (0) {
-err: __wt_err(session, ret, "log server error");
+err: WT_PANIC_MSG(session, ret, "log server error");
}
return (WT_THREAD_RET_VALUE);
}
@@ -902,7 +925,7 @@ __wt_logmgr_create(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_cond_alloc(session, "log sync", &log->log_sync_cond));
WT_RET(__wt_cond_alloc(session, "log write", &log->log_write_cond));
WT_RET(__wt_log_open(session));
- WT_RET(__wt_log_slot_init(session));
+ WT_RET(__wt_log_slot_init(session, true));
return (0);
}
diff --git a/src/third_party/wiredtiger/src/conn/conn_open.c b/src/third_party/wiredtiger/src/conn/conn_open.c
index eb3c79422a0..649bfa7c81f 100644
--- a/src/third_party/wiredtiger/src/conn/conn_open.c
+++ b/src/third_party/wiredtiger/src/conn/conn_open.c
@@ -91,6 +91,7 @@ __wt_connection_close(WT_CONNECTION_IMPL *conn)
if (txn_global->oldest_id == txn_global->current &&
txn_global->metadata_pinned == txn_global->current)
break;
+ WT_STAT_CONN_INCR(session, txn_release_blocked);
__wt_yield();
}
@@ -143,7 +144,7 @@ __wt_connection_close(WT_CONNECTION_IMPL *conn)
* conditional because we allocate the log path so that printlog can
* run without running logging or recovery.
*/
- if (FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) &&
+ if (ret == 0 && FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) &&
FLD_ISSET(conn->log_flags, WT_CONN_LOG_RECOVER_DONE))
WT_TRET(__wt_txn_checkpoint_log(
session, true, WT_TXN_LOG_CKPT_STOP, NULL));
diff --git a/src/third_party/wiredtiger/src/cursor/cur_index.c b/src/third_party/wiredtiger/src/cursor/cur_index.c
index 6fc01c0421f..15c1271c992 100644
--- a/src/third_party/wiredtiger/src/cursor/cur_index.c
+++ b/src/third_party/wiredtiger/src/cursor/cur_index.c
@@ -382,7 +382,7 @@ __curindex_close(WT_CURSOR *cursor)
if (cindex->child != NULL)
WT_TRET(cindex->child->close(cindex->child));
- __wt_schema_release_table(session, cindex->table);
+ WT_TRET(__wt_schema_release_table(session, cindex->table));
/* The URI is owned by the index. */
cursor->internal_uri = NULL;
WT_TRET(__wt_cursor_close(cursor));
@@ -485,7 +485,7 @@ __wt_curindex_open(WT_SESSION_IMPL *session,
if ((ret = __wt_schema_open_index(
session, table, idxname, namesize, &idx)) != 0) {
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
WT_RET(__wt_calloc_one(session, &cindex));
diff --git a/src/third_party/wiredtiger/src/cursor/cur_join.c b/src/third_party/wiredtiger/src/cursor/cur_join.c
index 80afaf798dc..3681d36b452 100644
--- a/src/third_party/wiredtiger/src/cursor/cur_join.c
+++ b/src/third_party/wiredtiger/src/cursor/cur_join.c
@@ -325,7 +325,7 @@ __curjoin_close(WT_CURSOR *cursor)
JOINABLE_CURSOR_API_CALL(cursor, session, close, NULL);
- __wt_schema_release_table(session, cjoin->table);
+ WT_TRET(__wt_schema_release_table(session, cjoin->table));
/* This is owned by the table */
cursor->key_format = NULL;
if (cjoin->projection != NULL) {
diff --git a/src/third_party/wiredtiger/src/cursor/cur_table.c b/src/third_party/wiredtiger/src/cursor/cur_table.c
index f6855172e90..ffa9ca35926 100644
--- a/src/third_party/wiredtiger/src/cursor/cur_table.c
+++ b/src/third_party/wiredtiger/src/cursor/cur_table.c
@@ -786,7 +786,7 @@ __curtable_close(WT_CURSOR *cursor)
__wt_free(session, ctable->cg_cursors);
__wt_free(session, ctable->cg_valcopy);
__wt_free(session, ctable->idx_cursors);
- __wt_schema_release_table(session, ctable->table);
+ WT_TRET(__wt_schema_release_table(session, ctable->table));
/* The URI is owned by the table. */
cursor->internal_uri = NULL;
WT_TRET(__wt_cursor_close(cursor));
@@ -942,7 +942,7 @@ __wt_curtable_open(WT_SESSION_IMPL *session,
ret = __wt_open_cursor(session,
table->cgroups[0]->source, NULL, cfg, cursorp);
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
if (ret == 0) {
/* Fix up the public URI to match what was passed in. */
cursor = *cursorp;
diff --git a/src/third_party/wiredtiger/src/evict/evict_lru.c b/src/third_party/wiredtiger/src/evict/evict_lru.c
index 26bbf9f679b..6e850f67b3e 100644
--- a/src/third_party/wiredtiger/src/evict/evict_lru.c
+++ b/src/third_party/wiredtiger/src/evict/evict_lru.c
@@ -17,7 +17,7 @@ static int __evict_pass(WT_SESSION_IMPL *);
static int __evict_server(WT_SESSION_IMPL *, bool *);
static int __evict_tune_workers(WT_SESSION_IMPL *session);
static int __evict_walk(WT_SESSION_IMPL *, WT_EVICT_QUEUE *);
-static int __evict_walk_file(
+static int __evict_walk_tree(
WT_SESSION_IMPL *, WT_EVICT_QUEUE *, u_int, u_int *);
#define WT_EVICT_HAS_WORKERS(s) \
@@ -767,8 +767,10 @@ __evict_clear_walk(WT_SESSION_IMPL *session)
cache = S2C(session)->cache;
WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_PASS));
- if (session->dhandle == cache->evict_file_next)
- cache->evict_file_next = NULL;
+ if (session->dhandle == cache->walk_tree) {
+ cache->walk_tree = NULL;
+ cache->walk_target = 0;
+ }
if ((ref = btree->evict_ref) == NULL)
return (0);
@@ -880,10 +882,8 @@ void
__wt_evict_file_exclusive_off(WT_SESSION_IMPL *session)
{
WT_BTREE *btree;
- WT_CACHE *cache;
btree = S2BT(session);
- cache = S2C(session)->cache;
/*
* We have seen subtle bugs with multiple threads racing to turn
@@ -891,12 +891,26 @@ __wt_evict_file_exclusive_off(WT_SESSION_IMPL *session)
*/
WT_DIAGNOSTIC_YIELD;
- /* Hold the walk lock to turn on eviction. */
- __wt_spin_lock(session, &cache->evict_walk_lock);
- WT_ASSERT(session,
- btree->evict_ref == NULL && btree->evict_disabled > 0);
- --btree->evict_disabled;
- __wt_spin_unlock(session, &cache->evict_walk_lock);
+ /*
+ * Atomically decrement the evict-disabled count, without acquiring the
+ * eviction walk-lock. We can't acquire that lock here because there's
+ * a potential deadlock. When acquiring exclusive eviction access, we
+ * acquire the eviction walk-lock and then the cache's pass-intr lock.
+ * The current eviction implementation can hold the pass-intr lock and
+ * call into this function (see WT-3303 for the details), which might
+ * deadlock with another thread trying to get exclusive eviction access.
+ */
+#if defined(HAVE_DIAGNOSTIC)
+ {
+ int32_t v;
+
+ WT_ASSERT(session, btree->evict_ref == NULL);
+ v = __wt_atomic_subi32(&btree->evict_disabled, 1);
+ WT_ASSERT(session, v >= 0);
+ }
+#else
+ (void)__wt_atomic_subi32(&btree->evict_disabled, 1);
+#endif
}
#define EVICT_TUNE_BATCH 1 /* Max workers to add each period */
@@ -941,6 +955,13 @@ __evict_tune_workers(WT_SESSION_IMPL *session)
conn = S2C(session);
cache = conn->cache;
+ /*
+ * If we have a fixed number of eviction threads, there is no value in
+ * calculating if we should do any tuning.
+ */
+ if (conn->evict_threads_max == conn->evict_threads_min)
+ return (0);
+
WT_ASSERT(session, conn->evict_threads.threads[0]->session == session);
pgs_evicted_cur = pgs_evicted_persec_cur = 0;
@@ -1371,19 +1392,22 @@ retry: while (slot < max_entries) {
* scan last time through. If we don't have a saved
* handle, start from the beginning of the list.
*/
- if ((dhandle = cache->evict_file_next) != NULL)
- cache->evict_file_next = NULL;
- else
+ if ((dhandle = cache->walk_tree) != NULL)
+ cache->walk_tree = NULL;
+ else {
dhandle = TAILQ_FIRST(&conn->dhqh);
+ cache->walk_target = 0;
+ }
} else {
if (incr) {
WT_ASSERT(session, dhandle->session_inuse > 0);
(void)__wt_atomic_subi32(
&dhandle->session_inuse, 1);
incr = false;
- cache->evict_file_next = NULL;
+ cache->walk_tree = NULL;
}
dhandle = TAILQ_NEXT(dhandle, q);
+ cache->walk_target = 0;
}
/* If we reach the end of the list, we're done. */
@@ -1445,29 +1469,26 @@ retry: while (slot < max_entries) {
/*
* Re-check the "no eviction" flag, used to enforce exclusive
- * access when a handle is being closed. If not set, remember
- * the file to visit first, next loop.
+ * access when a handle is being closed.
*
* Only try to acquire the lock and simply continue if we fail;
* the lock is held while the thread turning off eviction clears
* the tree's current eviction point, and part of the process is
* waiting on this thread to acknowledge that action.
+ *
+ * If a handle is being discarded, it will still be marked open,
+ * but won't have a root page.
*/
if (btree->evict_disabled == 0 &&
!__wt_spin_trylock(session, &cache->evict_walk_lock)) {
- if (btree->evict_disabled == 0) {
+ if (btree->evict_disabled == 0 &&
+ btree->root.page != NULL) {
/*
- * Assert the handle has a root page: eviction
- * should have been locked out if the tree is
- * being discarded or the root page is changing.
- * As this has not always been the case, assert
- * to debug that change.
+ * Remember the file to visit first, next loop.
*/
- WT_ASSERT(session, btree->root.page != NULL);
-
- cache->evict_file_next = dhandle;
+ cache->walk_tree = dhandle;
WT_WITH_DHANDLE(session, dhandle,
- ret = __evict_walk_file(
+ ret = __evict_walk_tree(
session, queue, max_entries, &slot));
WT_ASSERT(session, session->split_gen == 0);
@@ -1489,7 +1510,7 @@ retry: while (slot < max_entries) {
* candidates and we aren't finding more.
*/
if (slot < max_entries && (retries < 2 ||
- (retries < 10 &&
+ (retries < WT_RETRY_MAX &&
(slot == queue->evict_entries || slot > start_slot)))) {
start_slot = slot;
++retries;
@@ -1556,45 +1577,21 @@ __evict_push_candidate(WT_SESSION_IMPL *session,
}
/*
- * __evict_walk_file --
- * Get a few page eviction candidates from a single underlying file.
+ * __evict_walk_target --
+ * Calculate how many pages to queue for a given tree.
*/
-static int
-__evict_walk_file(WT_SESSION_IMPL *session,
- WT_EVICT_QUEUE *queue, u_int max_entries, u_int *slotp)
+static uint32_t
+__evict_walk_target(
+ WT_SESSION_IMPL *session, WT_EVICT_QUEUE *queue, u_int max_entries)
{
- WT_BTREE *btree;
WT_CACHE *cache;
- WT_CONNECTION_IMPL *conn;
- WT_DECL_RET;
- WT_EVICT_ENTRY *end, *evict, *start;
- WT_PAGE *page;
- WT_PAGE_MODIFY *mod;
- WT_REF *ref;
- WT_TXN_GLOBAL *txn_global;
- uint64_t btree_inuse, bytes_per_slot, cache_inuse, min_pages;
- uint64_t pages_seen, pages_queued, refs_walked;
- uint32_t remaining_slots, total_slots, walk_flags;
+ uint64_t btree_inuse, bytes_per_slot, cache_inuse;
uint32_t target_pages_clean, target_pages_dirty, target_pages;
- int internal_pages, restarts;
- bool give_up, modified, urgent_queued;
+ uint32_t total_slots;
- conn = S2C(session);
- btree = S2BT(session);
- cache = conn->cache;
- txn_global = &conn->txn_global;
- internal_pages = restarts = 0;
- give_up = urgent_queued = false;
-
- /*
- * Figure out how many slots to fill from this tree.
- * Note that some care is taken in the calculation to avoid overflow.
- */
- start = queue->evict_queue + *slotp;
- remaining_slots = max_entries - *slotp;
- total_slots = max_entries - queue->evict_entries;
- btree_inuse = cache_inuse = 0;
+ cache = S2C(session)->cache;
target_pages_clean = target_pages_dirty = 0;
+ total_slots = max_entries - queue->evict_entries;
/*
* The number of times we should fill the queue by the end of
@@ -1640,26 +1637,16 @@ __evict_walk_file(WT_SESSION_IMPL *session,
QUEUE_FILLS_PER_PASS;
/*
- * Randomly walk trees with a small fraction of the cache in case there
- * are so many trees that none of them use enough of the cache to be
- * allocated slots.
- *
- * The chance of walking a tree is equal to the chance that a random
- * byte in cache belongs to the tree, weighted by how many times we
- * want to fill queues during a pass through all the trees in cache.
+ * Walk trees with a small fraction of the cache in case there are so
+ * many trees that none of them use enough of the cache to be allocated
+ * slots. Only skip a tree if it has no bytes of interest.
*/
if (target_pages == 0) {
- if (F_ISSET(cache, WT_CACHE_EVICT_CLEAN)) {
- btree_inuse = __wt_btree_bytes_evictable(session);
- cache_inuse = __wt_cache_bytes_inuse(cache);
- } else {
- btree_inuse = __wt_btree_dirty_leaf_inuse(session);
- cache_inuse = __wt_cache_dirty_leaf_inuse(cache);
- }
- if (btree_inuse == 0 || cache_inuse == 0)
- return (0);
- if (__wt_random64(&session->rnd) % cache_inuse >
- btree_inuse * QUEUE_FILLS_PER_PASS)
+ btree_inuse = F_ISSET(cache, WT_CACHE_EVICT_CLEAN) ?
+ __wt_btree_bytes_evictable(session) :
+ __wt_btree_dirty_leaf_inuse(session);
+
+ if (btree_inuse == 0)
return (0);
}
@@ -1670,13 +1657,64 @@ __evict_walk_file(WT_SESSION_IMPL *session,
if (target_pages < MIN_PAGES_PER_TREE)
target_pages = MIN_PAGES_PER_TREE;
+ /* If the tree is dead, take a lot of pages. */
+ if (F_ISSET(session->dhandle, WT_DHANDLE_DEAD))
+ target_pages *= 10;
+
+ return (target_pages);
+}
+
+/*
+ * __evict_walk_tree --
+ * Get a few page eviction candidates from a single underlying file.
+ */
+static int
+__evict_walk_tree(WT_SESSION_IMPL *session,
+ WT_EVICT_QUEUE *queue, u_int max_entries, u_int *slotp)
+{
+ WT_BTREE *btree;
+ WT_CACHE *cache;
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_EVICT_ENTRY *end, *evict, *start;
+ WT_PAGE *page;
+ WT_PAGE_MODIFY *mod;
+ WT_REF *ref;
+ WT_TXN_GLOBAL *txn_global;
+ uint64_t min_pages, pages_seen, pages_queued, refs_walked;
+ uint32_t remaining_slots, target_pages, walk_flags;
+ int internal_pages, restarts;
+ bool give_up, modified, urgent_queued;
+
+ conn = S2C(session);
+ btree = S2BT(session);
+ cache = conn->cache;
+ txn_global = &conn->txn_global;
+ internal_pages = restarts = 0;
+ give_up = urgent_queued = false;
+
/*
- * If the tree is dead or we're near the end of the queue, fill the
- * remaining slots.
+ * Figure out how many slots to fill from this tree.
+ * Note that some care is taken in the calculation to avoid overflow.
*/
- if (F_ISSET(session->dhandle, WT_DHANDLE_DEAD) ||
- target_pages > remaining_slots)
+ start = queue->evict_queue + *slotp;
+ remaining_slots = max_entries - *slotp;
+ if (cache->walk_target != 0) {
+ WT_ASSERT(session, cache->walk_progress <= cache->walk_target);
+ target_pages = cache->walk_target - cache->walk_progress;
+ } else {
+ target_pages = cache->walk_target =
+ __evict_walk_target(session, queue, max_entries);
+ cache->walk_progress = 0;
+ }
+
+ if (target_pages > remaining_slots)
target_pages = remaining_slots;
+
+ /* If we don't want any pages from this tree, move on. */
+ if (target_pages == 0)
+ return (0);
+
end = start + target_pages;
/*
@@ -1849,6 +1887,7 @@ fast: /* If the page can't be evicted, give up. */
continue;
++evict;
++pages_queued;
+ ++cache->walk_progress;
if (WT_PAGE_IS_INTERNAL(page))
++internal_pages;
@@ -1863,6 +1902,10 @@ fast: /* If the page can't be evicted, give up. */
WT_STAT_CONN_INCRV(
session, cache_eviction_pages_queued, (u_int)(evict - start));
+ __wt_verbose(session, WT_VERB_EVICTSERVER,
+ "%s walk: seen %" PRIu64 ", queued %" PRIu64,
+ session->dhandle->name, pages_seen, pages_queued);
+
/*
* If we couldn't find the number of pages we were looking for, skip
* the tree next time.
@@ -2445,14 +2488,23 @@ __wt_verbose_dump_cache(WT_SESSION_IMPL *session)
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
+ u_int pct;
uint64_t total_bytes, total_dirty_bytes;
conn = S2C(session);
total_bytes = total_dirty_bytes = 0;
+ pct = 0; /* [-Werror=uninitialized] */
WT_RET(__wt_msg(session, "%s", WT_DIVIDER));
WT_RET(__wt_msg(session, "cache dump"));
+ WT_RET(__wt_msg(session,
+ "cache full: %s", __wt_cache_full(session) ? "yes" : "no"));
+ WT_RET(__wt_msg(session, "cache clean check: %s (%u%%)",
+ __wt_eviction_clean_needed(session, &pct) ? "yes" : "no", pct));
+ WT_RET(__wt_msg(session, "cache dirty check: %s (%u%%)",
+ __wt_eviction_dirty_needed(session, &pct) ? "yes" : "no", pct));
+
for (dhandle = NULL;;) {
WT_WITH_HANDLE_LIST_READ_LOCK(session,
WT_DHANDLE_NEXT(session, dhandle, &conn->dhqh, q));
diff --git a/src/third_party/wiredtiger/src/evict/evict_page.c b/src/third_party/wiredtiger/src/evict/evict_page.c
index 85689efd0b1..70a16442dc4 100644
--- a/src/third_party/wiredtiger/src/evict/evict_page.c
+++ b/src/third_party/wiredtiger/src/evict/evict_page.c
@@ -156,7 +156,7 @@ __wt_evict(WT_SESSION_IMPL *session, WT_REF *ref, bool closing)
/* Update the reference and discard the page. */
if (__wt_ref_is_root(ref))
__wt_ref_out(session, ref);
- else if ((clean_page && !LF_ISSET(WT_EVICT_IN_MEMORY)) || tree_dead)
+ else if ((clean_page && !F_ISSET(conn, WT_CONN_IN_MEMORY)) || tree_dead)
/*
* Pages that belong to dead trees never write back to disk
* and can't support page splits.
@@ -202,8 +202,8 @@ __evict_delete_ref(WT_SESSION_IMPL *session, WT_REF *ref, bool closing)
return (0);
/*
- * Avoid doing reverse splits when closing the file, it is
- * wasted work and some structure may already have been freed.
+ * Avoid doing reverse splits when closing the file, it is wasted work
+ * and some structures may have already been freed.
*/
if (!closing) {
parent = ref->home;
@@ -393,11 +393,13 @@ __evict_review(
WT_SESSION_IMPL *session, WT_REF *ref, uint32_t *flagsp, bool closing)
{
WT_CACHE *cache;
+ WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_PAGE *page;
uint32_t flags;
- bool lookaside_retry, modified;
+ bool lookaside_retry, *lookaside_retryp, modified;
+ conn = S2C(session);
flags = WT_EVICTING;
*flagsp = flags;
@@ -453,7 +455,7 @@ __evict_review(
* Clean pages can't be evicted when running in memory only. This
* should be uncommon - we don't add clean pages to the queue.
*/
- if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY) && !modified && !closing)
+ if (F_ISSET(conn, WT_CONN_IN_MEMORY) && !modified && !closing)
return (EBUSY);
/* Check if the page can be evicted. */
@@ -519,11 +521,14 @@ __evict_review(
* Additionally, if we aren't trying to free space in the cache, scrub
* the page and keep it in memory.
*/
- cache = S2C(session)->cache;
+ cache = conn->cache;
+ lookaside_retry = false;
+ lookaside_retryp = NULL;
+
if (closing)
LF_SET(WT_VISIBILITY_ERR);
else if (!WT_PAGE_IS_INTERNAL(page)) {
- if (F_ISSET(S2C(session), WT_CONN_IN_MEMORY))
+ if (F_ISSET(conn, WT_CONN_IN_MEMORY))
LF_SET(WT_EVICT_IN_MEMORY |
WT_EVICT_SCRUB | WT_EVICT_UPDATE_RESTORE);
else {
@@ -531,21 +536,26 @@ __evict_review(
if (F_ISSET(cache, WT_CACHE_EVICT_SCRUB))
LF_SET(WT_EVICT_SCRUB);
+
+ /*
+ * Check if reconciliation suggests trying the
+ * lookaside table.
+ */
+ lookaside_retryp = &lookaside_retry;
}
}
/* Reconcile the page. */
- ret = __wt_reconcile(session, ref, NULL, flags, &lookaside_retry);
+ ret = __wt_reconcile(session, ref, NULL, flags, lookaside_retryp);
/*
- * If reconciliation fails, eviction is stuck and reconciliation reports
- * it might succeed if we use the lookaside table (the page didn't have
- * uncommitted updates, it was not-yet-globally visible updates causing
- * the problem), configure reconciliation to write those updates to the
- * lookaside table, allowing the eviction of pages we'd otherwise have
- * to retain in cache to support older readers.
+ * If reconciliation fails, eviction is stuck and reconciliation
+ * reports it might succeed if we use the lookaside table, then
+ * configure reconciliation to write those updates to the lookaside
+ * table, allowing the eviction of pages we'd otherwise have to retain
+ * in cache to support older readers.
*/
- if (ret == EBUSY && __wt_cache_stuck(session) && lookaside_retry) {
+ if (ret == EBUSY && lookaside_retry && __wt_cache_stuck(session)) {
LF_CLR(WT_EVICT_SCRUB | WT_EVICT_UPDATE_RESTORE);
LF_SET(WT_EVICT_LOOKASIDE);
ret = __wt_reconcile(session, ref, NULL, flags, NULL);
diff --git a/src/third_party/wiredtiger/src/include/btmem.h b/src/third_party/wiredtiger/src/include/btmem.h
index d0b21b17965..e965724dffe 100644
--- a/src/third_party/wiredtiger/src/include/btmem.h
+++ b/src/third_party/wiredtiger/src/include/btmem.h
@@ -714,7 +714,7 @@ struct __wt_page {
* Related information for fast-delete, on-disk pages.
*/
struct __wt_page_deleted {
- uint64_t txnid; /* Transaction ID */
+ volatile uint64_t txnid; /* Transaction ID */
WT_UPDATE **update_list; /* List of updates for abort */
};
@@ -904,7 +904,7 @@ struct __wt_ikey {
* list.
*/
WT_PACKED_STRUCT_BEGIN(__wt_update)
- uint64_t txnid; /* update transaction */
+ volatile uint64_t txnid; /* Transaction ID */
WT_UPDATE *next; /* forward-linked list */
diff --git a/src/third_party/wiredtiger/src/include/btree.h b/src/third_party/wiredtiger/src/include/btree.h
index 28fe1b94b23..5b1b4d68976 100644
--- a/src/third_party/wiredtiger/src/include/btree.h
+++ b/src/third_party/wiredtiger/src/include/btree.h
@@ -134,34 +134,44 @@ struct __wt_btree {
WT_BM *bm; /* Block manager reference */
u_int block_header; /* WT_PAGE_HEADER_BYTE_SIZE */
- uint64_t checkpoint_gen; /* Checkpoint generation */
- uint64_t rec_max_txn; /* Maximum txn seen (clean trees) */
uint64_t write_gen; /* Write generation */
+ uint64_t rec_max_txn; /* Maximum txn seen (clean trees) */
+ uint64_t checkpoint_gen; /* Checkpoint generation */
+ volatile enum {
+ WT_CKPT_OFF, WT_CKPT_PREPARE, WT_CKPT_RUNNING
+ } checkpointing; /* Checkpoint in progress */
uint64_t bytes_inmem; /* Cache bytes in memory. */
uint64_t bytes_dirty_intl; /* Bytes in dirty internal pages. */
uint64_t bytes_dirty_leaf; /* Bytes in dirty leaf pages. */
+ /*
+ * We flush pages from the tree (in order to make checkpoint faster),
+ * without a high-level lock. To avoid multiple threads flushing at
+ * the same time, lock the tree.
+ */
+ WT_SPINLOCK flush_lock; /* Lock to flush the tree's pages */
+
+ /*
+ * All of the following fields live at the end of the structure so it's
+ * easier to clear everything but the fields that persist.
+ */
+#define WT_BTREE_CLEAR_SIZE (offsetof(WT_BTREE, evict_ref))
+
+ /*
+ * Eviction information is maintained in the btree handle, but owned by
+ * eviction, not the btree code.
+ */
WT_REF *evict_ref; /* Eviction thread's location */
uint64_t evict_priority; /* Relative priority of cached pages */
u_int evict_walk_period; /* Skip this many LRU walks */
u_int evict_walk_saved; /* Saved walk skips for checkpoints */
u_int evict_walk_skips; /* Number of walks skipped */
- int evict_disabled; /* Eviction disabled count */
+ int32_t evict_disabled; /* Eviction disabled count */
+ bool evict_disabled_open;/* Eviction disabled on open */
volatile uint32_t evict_busy; /* Count of threads in eviction */
int evict_start_type; /* Start position for eviction walk
(see WT_EVICT_WALK_START). */
- enum {
- WT_CKPT_OFF, WT_CKPT_PREPARE, WT_CKPT_RUNNING
- } checkpointing; /* Checkpoint in progress */
-
- /*
- * We flush pages from the tree (in order to make checkpoint faster),
- * without a high-level lock. To avoid multiple threads flushing at
- * the same time, lock the tree.
- */
- WT_SPINLOCK flush_lock; /* Lock to flush the tree's pages */
-
/* Flags values up to 0xff are reserved for WT_DHANDLE_* */
#define WT_BTREE_ALLOW_SPLITS 0x000100 /* Allow splits, even with no evict */
#define WT_BTREE_BULK 0x000200 /* Bulk-load handle */
diff --git a/src/third_party/wiredtiger/src/include/cache.h b/src/third_party/wiredtiger/src/include/cache.h
index 04920c3585a..42a152e5f10 100644
--- a/src/third_party/wiredtiger/src/include/cache.h
+++ b/src/third_party/wiredtiger/src/include/cache.h
@@ -133,7 +133,8 @@ struct __wt_cache {
*/
WT_SPINLOCK evict_pass_lock; /* Eviction pass lock */
WT_SESSION_IMPL *walk_session; /* Eviction pass session */
- WT_DATA_HANDLE *evict_file_next;/* LRU next file to search */
+ WT_DATA_HANDLE *walk_tree; /* LRU walk current tree */
+ uint32_t walk_progress, walk_target;/* Progress in current tree */
WT_SPINLOCK evict_queue_lock; /* Eviction current queue lock */
WT_EVICT_QUEUE evict_queues[WT_EVICT_QUEUE_MAX];
diff --git a/src/third_party/wiredtiger/src/include/connection.h b/src/third_party/wiredtiger/src/include/connection.h
index f74732684f5..74611de1131 100644
--- a/src/third_party/wiredtiger/src/include/connection.h
+++ b/src/third_party/wiredtiger/src/include/connection.h
@@ -314,9 +314,10 @@ struct __wt_connection_impl {
#define WT_CONN_LOG_ARCHIVE 0x01 /* Archive is enabled */
#define WT_CONN_LOG_ENABLED 0x02 /* Logging is enabled */
#define WT_CONN_LOG_EXISTED 0x04 /* Log files found */
-#define WT_CONN_LOG_RECOVER_DONE 0x08 /* Recovery completed */
-#define WT_CONN_LOG_RECOVER_ERR 0x10 /* Error if recovery required */
-#define WT_CONN_LOG_ZERO_FILL 0x20 /* Manually zero files */
+#define WT_CONN_LOG_RECOVER_DIRTY 0x08 /* Recovering unclean */
+#define WT_CONN_LOG_RECOVER_DONE 0x10 /* Recovery completed */
+#define WT_CONN_LOG_RECOVER_ERR 0x20 /* Error if recovery required */
+#define WT_CONN_LOG_ZERO_FILL 0x40 /* Manually zero files */
uint32_t log_flags; /* Global logging configuration */
WT_CONDVAR *log_cond; /* Log server wait mutex */
WT_SESSION_IMPL *log_session; /* Log server session */
diff --git a/src/third_party/wiredtiger/src/include/extern.h b/src/third_party/wiredtiger/src/include/extern.h
index bf3279d0f94..3c45b290dd8 100644
--- a/src/third_party/wiredtiger/src/include/extern.h
+++ b/src/third_party/wiredtiger/src/include/extern.h
@@ -181,7 +181,7 @@ extern int __wt_verify_dsk_image(WT_SESSION_IMPL *session, const char *tag, cons
extern int __wt_verify_dsk(WT_SESSION_IMPL *session, const char *tag, WT_ITEM *buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_tree_walk(WT_SESSION_IMPL *session, WT_REF **refp, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_tree_walk_count(WT_SESSION_IMPL *session, WT_REF **refp, uint64_t *walkcntp, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern int __wt_tree_walk_skip(WT_SESSION_IMPL *session, WT_REF **refp, uint64_t *skipleafcntp, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_tree_walk_skip( WT_SESSION_IMPL *session, WT_REF **refp, uint64_t *skipleafcntp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_col_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, uint64_t recno, WT_ITEM *value, WT_UPDATE *upd_arg, bool is_remove, bool exclusive) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_col_search(WT_SESSION_IMPL *session, uint64_t search_recno, WT_REF *leaf, WT_CURSOR_BTREE *cbt) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_row_leaf_keys(WT_SESSION_IMPL *session, WT_PAGE *page) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -369,6 +369,7 @@ extern int __wt_log_needs_recovery(WT_SESSION_IMPL *session, WT_LSN *ckp_lsn, bo
extern void __wt_log_written_reset(WT_SESSION_IMPL *session);
extern int __wt_log_get_all_files(WT_SESSION_IMPL *session, char ***filesp, u_int *countp, uint32_t *maxid, bool active_only) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_extract_lognum( WT_SESSION_IMPL *session, const char *name, uint32_t *id) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_log_reset(WT_SESSION_IMPL *session, uint32_t lognum) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_acquire(WT_SESSION_IMPL *session, uint64_t recsize, WT_LOGSLOT *slot) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_allocfile( WT_SESSION_IMPL *session, uint32_t lognum, const char *dest) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_remove(WT_SESSION_IMPL *session, const char *file_prefix, uint32_t lognum) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -405,7 +406,7 @@ extern int __wt_logop_row_truncate_print(WT_SESSION_IMPL *session, const uint8_t
extern int __wt_txn_op_printlog(WT_SESSION_IMPL *session, const uint8_t **pp, const uint8_t *end, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_log_slot_activate(WT_SESSION_IMPL *session, WT_LOGSLOT *slot);
extern int __wt_log_slot_switch(WT_SESSION_IMPL *session, WT_MYSLOT *myslot, bool retry, bool forced, bool *did_work) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern int __wt_log_slot_init(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_log_slot_init(WT_SESSION_IMPL *session, bool alloc) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_slot_destroy(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_log_slot_join(WT_SESSION_IMPL *session, uint64_t mysize, uint32_t flags, WT_MYSLOT *myslot) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int64_t __wt_log_slot_release(WT_SESSION_IMPL *session, WT_MYSLOT *myslot, int64_t size);
@@ -564,12 +565,13 @@ extern int __wt_schema_index_source(WT_SESSION_IMPL *session, WT_TABLE *table, c
extern int __wt_schema_create( WT_SESSION_IMPL *session, const char *uri, const char *config) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_drop(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_get_table(WT_SESSION_IMPL *session, const char *name, size_t namelen, bool ok_incomplete, WT_TABLE **tablep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern void __wt_schema_release_table(WT_SESSION_IMPL *session, WT_TABLE *table);
+extern int __wt_schema_release_table(WT_SESSION_IMPL *session, WT_TABLE *table) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern void __wt_schema_destroy_colgroup(WT_SESSION_IMPL *session, WT_COLGROUP **colgroupp);
extern int __wt_schema_destroy_index(WT_SESSION_IMPL *session, WT_INDEX **idxp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_destroy_table(WT_SESSION_IMPL *session, WT_TABLE **tablep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_remove_table(WT_SESSION_IMPL *session, WT_TABLE *table) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_close_tables(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern int __wt_schema_sweep_tables(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_colgroup_name(WT_SESSION_IMPL *session, WT_TABLE *table, const char *cgname, size_t len, WT_ITEM *buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_open_colgroups(WT_SESSION_IMPL *session, WT_TABLE *table) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_schema_open_index(WT_SESSION_IMPL *session, WT_TABLE *table, const char *idxname, size_t len, WT_INDEX **indexp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -691,7 +693,6 @@ extern uint32_t __wt_rduppo2(uint32_t n, uint32_t po2);
extern void __wt_random_init(WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern void __wt_random_init_seed( WT_SESSION_IMPL *session, WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern uint32_t __wt_random(WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
-extern uint64_t __wt_random64(WT_RAND_STATE volatile *rnd_state) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern int __wt_buf_grow_worker(WT_SESSION_IMPL *session, WT_ITEM *buf, size_t size) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_buf_fmt(WT_SESSION_IMPL *session, WT_ITEM *buf, const char *fmt, ...) WT_GCC_FUNC_DECL_ATTRIBUTE((format (printf, 3, 4))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_buf_catfmt(WT_SESSION_IMPL *session, WT_ITEM *buf, const char *fmt, ...) WT_GCC_FUNC_DECL_ATTRIBUTE((format (printf, 3, 4))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
@@ -732,6 +733,8 @@ extern int __wt_thread_group_create( WT_SESSION_IMPL *session, WT_THREAD_GROUP *
extern int __wt_thread_group_destroy(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_group_start_one( WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, bool wait) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_group_stop_one( WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, bool wait) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
+extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
+extern void __wt_seconds(WT_SESSION_IMPL *session, time_t *timep);
extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session);
extern void __wt_txn_get_snapshot(WT_SESSION_IMPL *session);
extern int __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
diff --git a/src/third_party/wiredtiger/src/include/extern_posix.h b/src/third_party/wiredtiger/src/include/extern_posix.h
index c0ed056c7b6..9e32e86e64c 100644
--- a/src/third_party/wiredtiger/src/include/extern_posix.h
+++ b/src/third_party/wiredtiger/src/include/extern_posix.h
@@ -28,5 +28,5 @@ extern int __wt_vsnprintf_len_incr( char *buf, size_t size, size_t *retsizep, co
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_id(char *buf, size_t buflen) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
+extern void __wt_epoch_raw(WT_SESSION_IMPL *session, struct timespec *tsp);
extern void __wt_yield(void) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
diff --git a/src/third_party/wiredtiger/src/include/extern_win.h b/src/third_party/wiredtiger/src/include/extern_win.h
index d548ee0b2ec..85db8175615 100644
--- a/src/third_party/wiredtiger/src/include/extern_win.h
+++ b/src/third_party/wiredtiger/src/include/extern_win.h
@@ -26,7 +26,7 @@ extern int __wt_vsnprintf_len_incr( char *buf, size_t size, size_t *retsizep, co
extern int __wt_thread_create(WT_SESSION_IMPL *session, wt_thread_t *tidret, WT_THREAD_CALLBACK(*func)(void *), void *arg) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_join(WT_SESSION_IMPL *session, wt_thread_t tid) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_thread_id(char *buf, size_t buflen) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
-extern void __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp);
+extern void __wt_epoch_raw(WT_SESSION_IMPL *session, struct timespec *tsp);
extern int __wt_to_utf16_string( WT_SESSION_IMPL *session, const char*utf8, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern int __wt_to_utf8_string( WT_SESSION_IMPL *session, const wchar_t*wide, WT_ITEM **outbuf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern DWORD __wt_getlasterror(void);
diff --git a/src/third_party/wiredtiger/src/include/flags.h b/src/third_party/wiredtiger/src/include/flags.h
index f26a45c68f5..0e6cf7657ed 100644
--- a/src/third_party/wiredtiger/src/include/flags.h
+++ b/src/third_party/wiredtiger/src/include/flags.h
@@ -21,7 +21,8 @@
#define WT_CONN_SERVER_LSM 0x00008000
#define WT_CONN_SERVER_STATISTICS 0x00010000
#define WT_CONN_SERVER_SWEEP 0x00020000
-#define WT_CONN_WAS_BACKUP 0x00040000
+#define WT_CONN_TABLE_CACHE 0x00040000
+#define WT_CONN_WAS_BACKUP 0x00080000
#define WT_EVICTING 0x00000002
#define WT_EVICT_INMEM_SPLIT 0x00000004
#define WT_EVICT_IN_MEMORY 0x00000008
@@ -47,9 +48,8 @@
#define WT_READ_PREV 0x00000080
#define WT_READ_RESTART_OK 0x00000100
#define WT_READ_SKIP_INTL 0x00000200
-#define WT_READ_SKIP_LEAF 0x00000400
-#define WT_READ_TRUNCATE 0x00000800
-#define WT_READ_WONT_NEED 0x00001000
+#define WT_READ_TRUNCATE 0x00000400
+#define WT_READ_WONT_NEED 0x00000800
#define WT_SESSION_CAN_WAIT 0x00000001
#define WT_SESSION_INTERNAL 0x00000002
#define WT_SESSION_LOCKED_CHECKPOINT 0x00000004
diff --git a/src/third_party/wiredtiger/src/include/misc.i b/src/third_party/wiredtiger/src/include/misc.i
index fad10f01103..eb99de3dcab 100644
--- a/src/third_party/wiredtiger/src/include/misc.i
+++ b/src/third_party/wiredtiger/src/include/misc.i
@@ -41,45 +41,6 @@ __wt_strdup(WT_SESSION_IMPL *session, const char *str, void *retp)
}
/*
- * __wt_seconds --
- * Return the seconds since the Epoch.
- */
-static inline void
-__wt_seconds(WT_SESSION_IMPL *session, time_t *timep)
-{
- struct timespec t;
-
- __wt_epoch(session, &t);
-
- *timep = t.tv_sec;
-}
-
-/*
- * __wt_time_check_monotonic --
- * Check and prevent time running backward. If we detect that it has, we
- * set the time structure to the previous values, making time stand still
- * until we see a time in the future of the highest value seen so far.
- */
-static inline void
-__wt_time_check_monotonic(WT_SESSION_IMPL *session, struct timespec *tsp)
-{
- /*
- * Detect time going backward. If so, use the last
- * saved timestamp.
- */
- if (session == NULL)
- return;
-
- if (tsp->tv_sec < session->last_epoch.tv_sec ||
- (tsp->tv_sec == session->last_epoch.tv_sec &&
- tsp->tv_nsec < session->last_epoch.tv_nsec)) {
- WT_STAT_CONN_INCR(session, time_travel);
- *tsp = session->last_epoch;
- } else
- session->last_epoch = *tsp;
-}
-
-/*
* __wt_verbose --
* Verbose message.
*
diff --git a/src/third_party/wiredtiger/src/include/os.h b/src/third_party/wiredtiger/src/include/os.h
index 73d89268392..2c03b115e7c 100644
--- a/src/third_party/wiredtiger/src/include/os.h
+++ b/src/third_party/wiredtiger/src/include/os.h
@@ -34,9 +34,11 @@
(ret) = __wt_errno(); \
} while (0)
+#define WT_RETRY_MAX 10
+
#define WT_SYSCALL_RETRY(call, ret) do { \
int __retry; \
- for (__retry = 0; __retry < 10; ++__retry) { \
+ for (__retry = 0; __retry < WT_RETRY_MAX; ++__retry) { \
WT_SYSCALL(call, ret); \
switch (ret) { \
case EAGAIN: \
diff --git a/src/third_party/wiredtiger/src/include/session.h b/src/third_party/wiredtiger/src/include/session.h
index 0074b4a9d43..d05dee68641 100644
--- a/src/third_party/wiredtiger/src/include/session.h
+++ b/src/third_party/wiredtiger/src/include/session.h
@@ -98,6 +98,12 @@ struct __wt_session_impl {
*/
TAILQ_HEAD(__tables, __wt_table) tables;
+ /*
+ * Updated when the table cache is swept of all tables older than the
+ * current schema generation.
+ */
+ uint64_t table_sweep_gen;
+
/* Current rwlock for callback. */
WT_RWLOCK *current_rwlock;
uint8_t current_rwticket;
diff --git a/src/third_party/wiredtiger/src/include/stat.h b/src/third_party/wiredtiger/src/include/stat.h
index db48a841571..01e622a5695 100644
--- a/src/third_party/wiredtiger/src/include/stat.h
+++ b/src/third_party/wiredtiger/src/include/stat.h
@@ -475,11 +475,19 @@ struct __wt_connection_stats {
int64_t thread_write_active;
int64_t application_evict_time;
int64_t application_cache_time;
+ int64_t txn_release_blocked;
+ int64_t conn_close_blocked_lsm;
+ int64_t dhandle_lock_blocked;
+ int64_t log_server_sync_blocked;
int64_t page_busy_blocked;
int64_t page_forcible_evict_blocked;
int64_t page_locked_blocked;
int64_t page_read_blocked;
int64_t page_sleep;
+ int64_t page_del_rollback_blocked;
+ int64_t child_modify_blocked_page;
+ int64_t page_index_slot_blocked;
+ int64_t tree_descend_blocked;
int64_t txn_snapshots_created;
int64_t txn_snapshots_dropped;
int64_t txn_begin;
diff --git a/src/third_party/wiredtiger/src/include/txn.h b/src/third_party/wiredtiger/src/include/txn.h
index 7e802c188ab..fdf9c714afa 100644
--- a/src/third_party/wiredtiger/src/include/txn.h
+++ b/src/third_party/wiredtiger/src/include/txn.h
@@ -93,6 +93,8 @@ struct __wt_txn_global {
* the global transaction state.
*/
WT_RWLOCK scan_rwlock;
+ /* Protects logging, checkpoints and transaction visibility. */
+ WT_RWLOCK visibility_rwlock;
/*
* Track information about the running checkpoint. The transaction
diff --git a/src/third_party/wiredtiger/src/include/txn.i b/src/third_party/wiredtiger/src/include/txn.i
index 314c948e4d1..39273a1995c 100644
--- a/src/third_party/wiredtiger/src/include/txn.i
+++ b/src/third_party/wiredtiger/src/include/txn.i
@@ -148,16 +148,6 @@ __wt_txn_oldest_id(WT_SESSION_IMPL *session)
}
/*
- * __wt_txn_committed --
- * Return if a transaction has been committed.
- */
-static inline bool
-__wt_txn_committed(WT_SESSION_IMPL *session, uint64_t id)
-{
- return (WT_TXNID_LT(id, S2C(session)->txn_global.last_running));
-}
-
-/*
* __wt_txn_visible_all --
* Check if a given transaction ID is "globally visible". This is, if
* all sessions in the system will see the transaction ID including the
diff --git a/src/third_party/wiredtiger/src/include/wiredtiger.in b/src/third_party/wiredtiger/src/include/wiredtiger.in
index 821efdf5fa1..30bff37017a 100644
--- a/src/third_party/wiredtiger/src/include/wiredtiger.in
+++ b/src/third_party/wiredtiger/src/include/wiredtiger.in
@@ -2458,6 +2458,8 @@ struct __wt_connection {
* readonly for more information., a boolean flag; default \c false.}
* @config{session_max, maximum expected number of sessions (including server
* threads)., an integer greater than or equal to 1; default \c 100.}
+ * @config{session_table_cache, Maintain a per-session cache of tables., a
+ * boolean flag; default \c true.}
* @config{shared_cache = (, shared cache configuration options. A database
* should configure either a cache_size or a shared_cache not both. Enabling a
* shared cache uses a session from the configured session_max., a set of
@@ -4806,72 +4808,94 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection);
#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1216
/*! thread-yield: application thread time waiting for cache (usecs) */
#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1217
+/*!
+ * thread-yield: connection close blocked waiting for transaction state
+ * stabilization
+ */
+#define WT_STAT_CONN_TXN_RELEASE_BLOCKED 1218
+/*! thread-yield: connection close yielded for lsm manager shutdown */
+#define WT_STAT_CONN_CONN_CLOSE_BLOCKED_LSM 1219
+/*! thread-yield: data handle lock yielded */
+#define WT_STAT_CONN_DHANDLE_LOCK_BLOCKED 1220
+/*! thread-yield: log server sync yielded for log write */
+#define WT_STAT_CONN_LOG_SERVER_SYNC_BLOCKED 1221
/*! thread-yield: page acquire busy blocked */
-#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1218
+#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1222
/*! thread-yield: page acquire eviction blocked */
-#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1219
+#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1223
/*! thread-yield: page acquire locked blocked */
-#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1220
+#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1224
/*! thread-yield: page acquire read blocked */
-#define WT_STAT_CONN_PAGE_READ_BLOCKED 1221
+#define WT_STAT_CONN_PAGE_READ_BLOCKED 1225
/*! thread-yield: page acquire time sleeping (usecs) */
-#define WT_STAT_CONN_PAGE_SLEEP 1222
+#define WT_STAT_CONN_PAGE_SLEEP 1226
+/*! thread-yield: page delete rollback yielded for instantiation */
+#define WT_STAT_CONN_PAGE_DEL_ROLLBACK_BLOCKED 1227
+/*! thread-yield: page reconciliation yielded due to child modification */
+#define WT_STAT_CONN_CHILD_MODIFY_BLOCKED_PAGE 1228
+/*! thread-yield: reference for page index and slot yielded */
+#define WT_STAT_CONN_PAGE_INDEX_SLOT_BLOCKED 1229
+/*!
+ * thread-yield: tree descend one level yielded for split page index
+ * update
+ */
+#define WT_STAT_CONN_TREE_DESCEND_BLOCKED 1230
/*! transaction: number of named snapshots created */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1223
+#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1231
/*! transaction: number of named snapshots dropped */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1224
+#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1232
/*! transaction: transaction begins */
-#define WT_STAT_CONN_TXN_BEGIN 1225
+#define WT_STAT_CONN_TXN_BEGIN 1233
/*! transaction: transaction checkpoint currently running */
-#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1226
+#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1234
/*! transaction: transaction checkpoint generation */
-#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1227
+#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1235
/*! transaction: transaction checkpoint max time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1228
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1236
/*! transaction: transaction checkpoint min time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1229
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1237
/*! transaction: transaction checkpoint most recent time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1230
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1238
/*! transaction: transaction checkpoint scrub dirty target */
-#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1231
+#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1239
/*! transaction: transaction checkpoint scrub time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1232
+#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1240
/*! transaction: transaction checkpoint total time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1233
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1241
/*! transaction: transaction checkpoints */
-#define WT_STAT_CONN_TXN_CHECKPOINT 1234
+#define WT_STAT_CONN_TXN_CHECKPOINT 1242
/*!
* transaction: transaction checkpoints skipped because database was
* clean
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1235
+#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1243
/*! transaction: transaction failures due to cache overflow */
-#define WT_STAT_CONN_TXN_FAIL_CACHE 1236
+#define WT_STAT_CONN_TXN_FAIL_CACHE 1244
/*!
* transaction: transaction fsync calls for checkpoint after allocating
* the transaction ID
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1237
+#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1245
/*!
* transaction: transaction fsync duration for checkpoint after
* allocating the transaction ID (usecs)
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1238
+#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1246
/*! transaction: transaction range of IDs currently pinned */
-#define WT_STAT_CONN_TXN_PINNED_RANGE 1239
+#define WT_STAT_CONN_TXN_PINNED_RANGE 1247
/*! transaction: transaction range of IDs currently pinned by a checkpoint */
-#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1240
+#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1248
/*!
* transaction: transaction range of IDs currently pinned by named
* snapshots
*/
-#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1241
+#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1249
/*! transaction: transaction sync calls */
-#define WT_STAT_CONN_TXN_SYNC 1242
+#define WT_STAT_CONN_TXN_SYNC 1250
/*! transaction: transactions committed */
-#define WT_STAT_CONN_TXN_COMMIT 1243
+#define WT_STAT_CONN_TXN_COMMIT 1251
/*! transaction: transactions rolled back */
-#define WT_STAT_CONN_TXN_ROLLBACK 1244
+#define WT_STAT_CONN_TXN_ROLLBACK 1252
/*!
* @}
diff --git a/src/third_party/wiredtiger/src/log/log.c b/src/third_party/wiredtiger/src/log/log.c
index 803d3e8dfab..da179400755 100644
--- a/src/third_party/wiredtiger/src/log/log.c
+++ b/src/third_party/wiredtiger/src/log/log.c
@@ -8,6 +8,7 @@
#include "wt_internal.h"
+static int __log_newfile(WT_SESSION_IMPL *, bool, bool *);
static int __log_openfile(
WT_SESSION_IMPL *, WT_FH **, const char *, uint32_t, uint32_t);
static int __log_write_internal(
@@ -442,6 +443,59 @@ __wt_log_extract_lognum(
}
/*
+ * __wt_log_reset --
+ * Reset the existing log file to after the given file number.
+ * Called from recovery when toggling logging back on, it was off
+ * the previous open but it was on earlier before that toggle.
+ */
+int
+__wt_log_reset(WT_SESSION_IMPL *session, uint32_t lognum)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_LOG *log;
+ uint32_t old_lognum;
+ u_int i, logcount;
+ char **logfiles;
+
+ conn = S2C(session);
+ log = conn->log;
+
+ if (!FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) ||
+ log->fileid > lognum)
+ return (0);
+
+ WT_ASSERT(session, F_ISSET(conn, WT_CONN_RECOVERING));
+ WT_ASSERT(session, !F_ISSET(conn, WT_CONN_READONLY));
+ /*
+ * We know we're single threaded and called from recovery only when
+ * toggling logging back on. Therefore the only log files we have are
+ * old and outdated and the new one created when logging opened before
+ * recovery. We have to remove all old log files first and then create
+ * the new one so that log file numbers are contiguous in the file
+ * system.
+ */
+ WT_RET(__wt_close(session, &log->log_fh));
+ WT_RET(__log_get_files(session,
+ WT_LOG_FILENAME, &logfiles, &logcount));
+ for (i = 0; i < logcount; i++) {
+ WT_ERR(__wt_log_extract_lognum(
+ session, logfiles[i], &old_lognum));
+ WT_ASSERT(session, old_lognum < lognum || lognum == 1);
+ WT_ERR(__wt_log_remove(session, WT_LOG_FILENAME, old_lognum));
+ }
+ log->fileid = lognum;
+
+ /* Send in true to update connection creation LSNs. */
+ WT_WITH_SLOT_LOCK(session, log,
+ ret = __log_newfile(session, true, NULL));
+ WT_ERR(__wt_log_slot_init(session, false));
+err: WT_TRET(
+ __wt_fs_directory_list_free(session, &logfiles, logcount));
+ return (ret);
+}
+
+/*
* __log_zero --
* Zero a log file.
*/
@@ -1611,11 +1665,6 @@ __wt_log_scan(WT_SESSION_IMPL *session, WT_LSN *lsnp, uint32_t flags,
if (func == NULL)
return (0);
- if (LF_ISSET(WT_LOGSCAN_RECOVER))
- __wt_verbose(session, WT_VERB_LOG,
- "__wt_log_scan truncating to %" PRIu32 "/%" PRIu32,
- log->trunc_lsn.l.file, log->trunc_lsn.l.offset);
-
if (log != NULL) {
allocsize = log->allocsize;
@@ -1709,9 +1758,14 @@ advance:
/*
* Truncate this log file before we move to the next.
*/
- if (LF_ISSET(WT_LOGSCAN_RECOVER))
+ if (LF_ISSET(WT_LOGSCAN_RECOVER) &&
+ __wt_log_cmp(&rd_lsn, &log->trunc_lsn) < 0) {
+ __wt_verbose(session, WT_VERB_LOG,
+ "Truncate end of log %" PRIu32 "/%" PRIu32,
+ rd_lsn.l.file, rd_lsn.l.offset);
WT_ERR(__log_truncate(session,
&rd_lsn, WT_LOG_FILENAME, 1));
+ }
/*
* If we had a partial record, we'll want to break
* now after closing and truncating. Although for now
diff --git a/src/third_party/wiredtiger/src/log/log_slot.c b/src/third_party/wiredtiger/src/log/log_slot.c
index 97e317ce68c..b23d589c8e2 100644
--- a/src/third_party/wiredtiger/src/log/log_slot.c
+++ b/src/third_party/wiredtiger/src/log/log_slot.c
@@ -401,7 +401,7 @@ __wt_log_slot_switch(WT_SESSION_IMPL *session,
* Initialize the slot array.
*/
int
-__wt_log_slot_init(WT_SESSION_IMPL *session)
+__wt_log_slot_init(WT_SESSION_IMPL *session, bool alloc)
{
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
@@ -423,15 +423,17 @@ __wt_log_slot_init(WT_SESSION_IMPL *session)
* switch log files very aggressively. Scale back the buffer for
* small log file sizes.
*/
- log->slot_buf_size = (uint32_t)WT_MIN(
- (size_t)conn->log_file_max / 10, WT_LOG_SLOT_BUF_SIZE);
- for (i = 0; i < WT_SLOT_POOL; i++) {
- WT_ERR(__wt_buf_init(session,
- &log->slot_pool[i].slot_buf, log->slot_buf_size));
- F_SET(&log->slot_pool[i], WT_SLOT_INIT_FLAGS);
+ if (alloc) {
+ log->slot_buf_size = (uint32_t)WT_MIN(
+ (size_t)conn->log_file_max / 10, WT_LOG_SLOT_BUF_SIZE);
+ for (i = 0; i < WT_SLOT_POOL; i++) {
+ WT_ERR(__wt_buf_init(session,
+ &log->slot_pool[i].slot_buf, log->slot_buf_size));
+ F_SET(&log->slot_pool[i], WT_SLOT_INIT_FLAGS);
+ }
+ WT_STAT_CONN_SET(session,
+ log_buffer_size, log->slot_buf_size * WT_SLOT_POOL);
}
- WT_STAT_CONN_SET(session,
- log_buffer_size, log->slot_buf_size * WT_SLOT_POOL);
/*
* Set up the available slot from the pool the first time.
*/
diff --git a/src/third_party/wiredtiger/src/lsm/lsm_manager.c b/src/third_party/wiredtiger/src/lsm/lsm_manager.c
index b7d9086d10e..62da094b5f7 100644
--- a/src/third_party/wiredtiger/src/lsm/lsm_manager.c
+++ b/src/third_party/wiredtiger/src/lsm/lsm_manager.c
@@ -295,8 +295,10 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
manager->lsm_workers == 0);
if (manager->lsm_workers > 0) {
/* Wait for the main LSM manager thread to finish. */
- while (!F_ISSET(manager, WT_LSM_MANAGER_SHUTDOWN))
+ while (!F_ISSET(manager, WT_LSM_MANAGER_SHUTDOWN)) {
+ WT_STAT_CONN_INCR(session, conn_close_blocked_lsm);
__wt_yield();
+ }
/* Clean up open LSM handles. */
ret = __wt_lsm_tree_close_all(session);
diff --git a/src/third_party/wiredtiger/src/meta/meta_table.c b/src/third_party/wiredtiger/src/meta/meta_table.c
index aca69d0e6a2..a970694b9d7 100644
--- a/src/third_party/wiredtiger/src/meta/meta_table.c
+++ b/src/third_party/wiredtiger/src/meta/meta_table.c
@@ -230,12 +230,23 @@ __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key)
WT_RET_MSG(session, EINVAL,
"%s: remove not supported on the turtle file", key);
+ /*
+ * Take, release, and reacquire the metadata cursor. It's complicated,
+ * but that way the underlying meta-tracking function doesn't have to
+ * open a second metadata cursor, it can use the session's cached one.
+ */
WT_RET(__wt_metadata_cursor(session, &cursor));
cursor->set_key(cursor, key);
WT_ERR(cursor->search(cursor));
+ WT_ERR(__wt_metadata_cursor_release(session, &cursor));
+
if (WT_META_TRACKING(session))
WT_ERR(__wt_meta_track_update(session, key));
- WT_ERR(cursor->remove(cursor));
+
+ WT_ERR(__wt_metadata_cursor(session, &cursor));
+ cursor->set_key(cursor, key);
+ ret = cursor->remove(cursor);
+
err: WT_TRET(__wt_metadata_cursor_release(session, &cursor));
return (ret);
}
@@ -266,7 +277,9 @@ __wt_metadata_search(WT_SESSION_IMPL *session, const char *key, char **valuep)
* that Coverity complains a lot, add an error check to get some
* peace and quiet.
*/
- if ((ret = __wt_turtle_read(session, key, valuep)) != 0)
+ WT_WITH_TURTLE_LOCK(session,
+ ret = __wt_turtle_read(session, key, valuep));
+ if (ret != 0)
__wt_free(session, *valuep);
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/meta/meta_turtle.c b/src/third_party/wiredtiger/src/meta/meta_turtle.c
index 5a089471059..f7ea6fe99c5 100644
--- a/src/third_party/wiredtiger/src/meta/meta_turtle.c
+++ b/src/third_party/wiredtiger/src/meta/meta_turtle.c
@@ -246,6 +246,9 @@ __wt_turtle_read(WT_SESSION_IMPL *session, const char *key, char **valuep)
*valuep = NULL;
+ /* Require single-threading. */
+ WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TURTLE));
+
/*
* Open the turtle file; there's one case where we won't find the turtle
* file, yet still succeed. We create the metadata file before creating
@@ -302,6 +305,9 @@ __wt_turtle_update(WT_SESSION_IMPL *session, const char *key, const char *value)
fs = NULL;
+ /* Require single-threading. */
+ WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TURTLE));
+
/*
* Create the turtle setup file: we currently re-write it from scratch
* every time.
diff --git a/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c b/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c
index fe010b62305..e4a6683dee9 100644
--- a/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c
+++ b/src/third_party/wiredtiger/src/os_posix/os_mtx_cond.c
@@ -19,11 +19,19 @@ __wt_cond_alloc(WT_SESSION_IMPL *session, const char *name, WT_CONDVAR **condp)
WT_DECL_RET;
WT_RET(__wt_calloc_one(session, &cond));
-
WT_ERR(pthread_mutex_init(&cond->mtx, NULL));
- /* Initialize the condition variable to permit self-blocking. */
+#ifdef HAVE_PTHREAD_COND_MONOTONIC
+ {
+ pthread_condattr_t condattr;
+
+ WT_ERR(pthread_condattr_init(&condattr));
+ WT_ERR(pthread_condattr_setclock(&condattr, CLOCK_MONOTONIC));
+ WT_ERR(pthread_cond_init(&cond->cond, &condattr));
+ }
+#else
WT_ERR(pthread_cond_init(&cond->cond, NULL));
+#endif
cond->name = name;
cond->waiters = 0;
@@ -79,7 +87,26 @@ __wt_cond_wait_signal(WT_SESSION_IMPL *session, WT_CONDVAR *cond,
goto skipping;
if (usecs > 0) {
- __wt_epoch(session, &ts);
+ /*
+ * Get the current time as the basis for calculating when the
+ * wait should end. Prefer a monotonic clock source to avoid
+ * unexpectedly long sleeps when the system clock is adjusted.
+ *
+ * Failing that, query the time directly and don't attempt to
+ * correct for the clock moving backwards, which would result
+ * in a sleep that is too long by however much the clock is
+ * updated. This isn't as good as a monotonic clock source but
+ * makes the window of vulnerability smaller (i.e., the
+ * calculated time is only incorrect if the system clock
+ * changes in between us querying it and waiting).
+ */
+#ifdef HAVE_PTHREAD_COND_MONOTONIC
+ WT_SYSCALL_RETRY(clock_gettime(CLOCK_MONOTONIC, &ts), ret);
+ if (ret != 0)
+ WT_PANIC_MSG(session, ret, "clock_gettime");
+#else
+ __wt_epoch_raw(session, &ts);
+#endif
ts.tv_sec += (time_t)
(((uint64_t)ts.tv_nsec + WT_THOUSAND * usecs) / WT_BILLION);
ts.tv_nsec = (long)
diff --git a/src/third_party/wiredtiger/src/os_posix/os_time.c b/src/third_party/wiredtiger/src/os_posix/os_time.c
index fe337fea7cf..25a08d62355 100644
--- a/src/third_party/wiredtiger/src/os_posix/os_time.c
+++ b/src/third_party/wiredtiger/src/os_posix/os_time.c
@@ -9,14 +9,12 @@
#include "wt_internal.h"
/*
- * __wt_epoch --
- * Return the time since the Epoch.
+ * __wt_epoch_raw --
+ * Return the time since the Epoch as reported by a system call.
*/
void
-__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
- WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
+__wt_epoch_raw(WT_SESSION_IMPL *session, struct timespec *tsp)
{
- struct timespec tmp;
WT_DECL_RET;
/*
@@ -28,19 +26,10 @@ __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
tsp->tv_sec = 0;
tsp->tv_nsec = 0;
- /*
- * Read into a local variable so that we're comparing the correct
- * value when we check for monotonic increasing time. There are
- * many places we read into an unlocked global variable.
- */
#if defined(HAVE_CLOCK_GETTIME)
- WT_SYSCALL_RETRY(clock_gettime(CLOCK_REALTIME, &tmp), ret);
- if (ret == 0) {
- __wt_time_check_monotonic(session, &tmp);
- tsp->tv_sec = tmp.tv_sec;
- tsp->tv_nsec = tmp.tv_nsec;
+ WT_SYSCALL_RETRY(clock_gettime(CLOCK_REALTIME, tsp), ret);
+ if (ret == 0)
return;
- }
WT_PANIC_MSG(session, ret, "clock_gettime");
#elif defined(HAVE_GETTIMEOFDAY)
{
@@ -48,10 +37,8 @@ __wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
WT_SYSCALL_RETRY(gettimeofday(&v, NULL), ret);
if (ret == 0) {
- tmp.tv_sec = v.tv_sec;
- tmp.tv_nsec = v.tv_usec * WT_THOUSAND;
- __wt_time_check_monotonic(session, &tmp);
- *tsp = tmp;
+ tsp->tv_sec = v.tv_sec;
+ tsp->tv_nsec = v.tv_usec * WT_THOUSAND;
return;
}
WT_PANIC_MSG(session, ret, "gettimeofday");
diff --git a/src/third_party/wiredtiger/src/os_win/os_time.c b/src/third_party/wiredtiger/src/os_win/os_time.c
index ba71341ab22..84c06bed6e5 100644
--- a/src/third_party/wiredtiger/src/os_win/os_time.c
+++ b/src/third_party/wiredtiger/src/os_win/os_time.c
@@ -9,24 +9,23 @@
#include "wt_internal.h"
/*
- * __wt_epoch --
- * Return the time since the Epoch.
+ * __wt_epoch_raw --
+ * Return the time since the Epoch as reported by the system.
*/
void
-__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
+__wt_epoch_raw(WT_SESSION_IMPL *session, struct timespec *tsp)
{
- struct timespec tmp;
FILETIME time;
uint64_t ns100;
+ WT_UNUSED(session);
+
GetSystemTimeAsFileTime(&time);
ns100 = (((int64_t)time.dwHighDateTime << 32) + time.dwLowDateTime)
- 116444736000000000LL;
- tmp.tv_sec = ns100 / 10000000;
- tmp.tv_nsec = (long)((ns100 % 10000000) * 100);
- __wt_time_check_monotonic(session, &tmp);
- *tsp = tmp;
+ tsp->tv_sec = ns100 / 10000000;
+ tsp->tv_nsec = (long)((ns100 % 10000000) * 100);
}
/*
diff --git a/src/third_party/wiredtiger/src/reconcile/rec_write.c b/src/third_party/wiredtiger/src/reconcile/rec_write.c
index e59d9796352..688efa10398 100644
--- a/src/third_party/wiredtiger/src/reconcile/rec_write.c
+++ b/src/third_party/wiredtiger/src/reconcile/rec_write.c
@@ -45,12 +45,14 @@ typedef struct {
uint64_t orig_btree_checkpoint_gen;
uint64_t orig_txn_checkpoint_gen;
- /* Track the page's maximum transaction ID. */
+ /* Track the oldest transaction running when reconciliation starts. */
+ uint64_t last_running;
+
uint64_t max_txn;
- /* Track if all updates were skipped. */
- uint64_t update_cnt;
- uint64_t update_skip_cnt;
+ uint64_t update_mem_all; /* Total update memory size */
+ uint64_t update_mem_saved; /* Saved update memory size */
+ uint64_t update_mem_uncommitted;/* Uncommitted update memory size */
/*
* When we can't mark the page clean (for example, checkpoint found some
@@ -338,7 +340,8 @@ static int __rec_split_write(WT_SESSION_IMPL *,
WT_RECONCILE *, WT_BOUNDARY *, WT_ITEM *, bool);
static int __rec_update_las(
WT_SESSION_IMPL *, WT_RECONCILE *, uint32_t, WT_BOUNDARY *);
-static int __rec_write_check_complete(WT_SESSION_IMPL *, WT_RECONCILE *);
+static int __rec_write_check_complete(
+ WT_SESSION_IMPL *, WT_RECONCILE *, bool *);
static int __rec_write_init(WT_SESSION_IMPL *,
WT_REF *, uint32_t, WT_SALVAGE_COOKIE *, void *);
static void __rec_write_page_status(WT_SESSION_IMPL *, WT_RECONCILE *);
@@ -437,7 +440,7 @@ __wt_reconcile(WT_SESSION_IMPL *session, WT_REF *ref,
/* Checks for a successful reconciliation. */
if (ret == 0)
- ret = __rec_write_check_complete(session, r);
+ ret = __rec_write_check_complete(session, r, lookaside_retryp);
/* Wrap up the page reconciliation. */
if (ret == 0 && (ret = __rec_write_wrapup(session, r, page)) == 0)
@@ -448,14 +451,6 @@ __wt_reconcile(WT_SESSION_IMPL *session, WT_REF *ref,
/* Release the reconciliation lock. */
WT_PAGE_UNLOCK(session, page);
- /*
- * If our caller can configure lookaside table reconciliation, flag if
- * that's worth trying. The lookaside table doesn't help if we skipped
- * updates, it can only help with older readers preventing eviction.
- */
- if (lookaside_retryp != NULL && r->update_cnt == r->update_skip_cnt)
- *lookaside_retryp = true;
-
/* Update statistics. */
WT_STAT_CONN_INCR(session, rec_pages);
WT_STAT_DATA_INCR(session, rec_pages);
@@ -558,13 +553,21 @@ __rec_las_checkpoint_test(WT_SESSION_IMPL *session, WT_RECONCILE *r)
/*
* __rec_write_check_complete --
- * Check that reconciliation should complete
+ * Check that reconciliation should complete.
*/
static int
-__rec_write_check_complete(WT_SESSION_IMPL *session, WT_RECONCILE *r)
+__rec_write_check_complete(
+ WT_SESSION_IMPL *session, WT_RECONCILE *r, bool *lookaside_retryp)
{
- WT_BOUNDARY *bnd;
- size_t i;
+ /*
+ * Tests in this function are lookaside tests and tests to decide if
+ * rewriting a page in memory is worth doing. In-memory configurations
+ * can't use a lookaside table, and we ignore page rewrite desirability
+ * checks for in-memory eviction because a small cache can force us to
+ * rewrite every possible page.
+ */
+ if (F_ISSET(r, WT_EVICT_IN_MEMORY))
+ return (0);
/*
* If we have used the lookaside table, check for a lookaside table and
@@ -574,19 +577,62 @@ __rec_write_check_complete(WT_SESSION_IMPL *session, WT_RECONCILE *r)
return (EBUSY);
/*
- * If we are doing update/restore based eviction, confirm part of the
- * page is being discarded, or at least 10% of the updates won't have
- * to be re-instantiated. Otherwise, it isn't progress, don't bother.
+ * Eviction can configure lookaside table reconciliation, consider if
+ * it's worth giving up this reconciliation attempt and falling back to
+ * using the lookaside table. We continue with evict/restore if
+ * switching to the lookaside doesn't make sense for any reason: we
+ * won't retry an evict/restore reconciliation until/unless the
+ * transactional system moves forward, so at worst it's a single wasted
+ * effort.
+ *
+ * First, check if the lookaside table is a possible alternative.
*/
- if (F_ISSET(r, WT_EVICT_UPDATE_RESTORE)) {
- for (bnd = r->bnd, i = 0; i < r->bnd_entries; ++bnd, ++i)
- if (bnd->supd == NULL)
- break;
- if (i == r->bnd_entries &&
- r->update_cnt / 10 >= r->update_skip_cnt)
- return (EBUSY);
- }
- return (0);
+ if (lookaside_retryp == NULL)
+ return (0);
+
+ /*
+ * We only suggest lookaside if currently in an evict/restore attempt
+ * and some updates were saved. Our caller sets the evict/restore flag
+ * based on various conditions (like if this is a leaf page), which is
+ * why we're testing that flag instead of a set of other conditions.
+ * If no updates were saved, eviction will succeed without needing to
+ * restore anything.
+ */
+ if (!F_ISSET(r, WT_EVICT_UPDATE_RESTORE) || r->bnd->supd == NULL)
+ return (0);
+
+ /*
+ * Check if this reconciliation attempt is making progress. If there's
+ * any sign of progress, don't fall back to the lookaside table.
+ *
+ * Check if the current reconciliation split, in which case we'll
+ * likely get to write at least one of the blocks. If that page is
+ * empty, that's also progress.
+ */
+ if (r->bnd_next != 1)
+ return (0);
+
+ /*
+ * Check if the current reconciliation applied some updates, in which
+ * case evict/restore should gain us some space.
+ */
+ if (r->update_mem_saved != r->update_mem_all)
+ return (0);
+
+ /*
+ * Check if lookaside eviction is possible. If any of the updates we
+ * saw were uncommitted, the lookaside table cannot be used: it only
+ * helps with older readers preventing eviction.
+ */
+ if (r->update_mem_uncommitted != 0)
+ return (0);
+
+ /*
+ * The current evict/restore approach shows no signs of being useful,
+ * lookaside is possible, suggest the lookaside table.
+ */
+ *lookaside_retryp = true;
+ return (EBUSY);
}
/*
@@ -849,6 +895,16 @@ __rec_write_init(WT_SESSION_IMPL *session,
WT_ORDERED_READ(r->orig_write_gen, page->modify->write_gen);
/*
+ * Cache the oldest running transaction ID. This is used to check
+ * whether updates seen by reconciliation have committed. We keep a
+ * cached copy to avoid races where a concurrent transaction could
+ * abort while reconciliation is examining its updates. This way, any
+ * transaction running when reconciliation starts is considered
+ * uncommitted.
+ */
+ WT_ORDERED_READ(r->last_running, S2C(session)->txn_global.last_running);
+
+ /*
* Lookaside table eviction is configured when eviction gets aggressive,
* adjust the flags for cases we don't support.
*/
@@ -891,7 +947,7 @@ __rec_write_init(WT_SESSION_IMPL *session,
r->max_txn = WT_TXN_NONE;
/* Track if all updates were skipped. */
- r->update_cnt = r->update_skip_cnt = 0;
+ r->update_mem_all = r->update_mem_saved = r->update_mem_uncommitted = 0;
/* Track if the page can be marked clean. */
r->leave_dirty = false;
@@ -1115,7 +1171,7 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
WT_DECL_ITEM(tmp);
WT_PAGE *page;
WT_UPDATE *append, *upd, *upd_list;
- size_t notused;
+ size_t notused, update_mem;
uint64_t max_txn, min_txn, txnid;
bool append_origv, skipped;
@@ -1136,36 +1192,64 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
} else
upd_list = ins->upd;
- ++r->update_cnt;
- for (skipped = false,
- max_txn = WT_TXN_NONE, min_txn = UINT64_MAX,
- upd = upd_list; upd != NULL; upd = upd->next) {
- if ((txnid = upd->txnid) == WT_TXN_ABORTED)
- continue;
+ skipped = false;
+ update_mem = 0;
+ max_txn = WT_TXN_NONE;
+ min_txn = UINT64_MAX;
- /* Track the largest/smallest transaction IDs on the list. */
- if (WT_TXNID_LT(max_txn, txnid))
- max_txn = txnid;
- if (WT_TXNID_LT(txnid, min_txn))
- min_txn = txnid;
+ if (F_ISSET(r, WT_EVICTING)) {
+ /* Discard obsolete updates. */
+ if ((upd = __wt_update_obsolete_check(
+ session, page, upd_list->next)) != NULL)
+ __wt_update_obsolete_free(session, page, upd);
+
+ for (upd = upd_list; upd != NULL; upd = upd->next) {
+ /* Track the total memory in the update chain. */
+ update_mem += WT_UPDATE_MEMSIZE(upd);
+
+ if ((txnid = upd->txnid) == WT_TXN_ABORTED)
+ continue;
- /*
- * Find the first update we can use.
- */
- if (F_ISSET(r, WT_EVICTING)) {
/*
+ * Track the largest/smallest transaction IDs on the
+ * list.
+ */
+ if (WT_TXNID_LT(max_txn, txnid))
+ max_txn = txnid;
+ if (WT_TXNID_LT(txnid, min_txn))
+ min_txn = txnid;
+
+ /*
+ * Find the first update we can use.
+ *
* Eviction can write any committed update.
*
* When reconciling for eviction, track whether any
* uncommitted updates are found.
+ *
+ * When reconciling for eviction, track the memory held
+ * by the update chain.
*/
- if (__wt_txn_committed(session, txnid)) {
- if (*updp == NULL)
- *updp = upd;
- } else
+ if (WT_TXNID_LE(r->last_running, txnid)) {
skipped = true;
- } else {
+ continue;
+ }
+
+ if (*updp == NULL)
+ *updp = upd;
+ }
+ } else
+ for (upd = upd_list; upd != NULL; upd = upd->next) {
+ if ((txnid = upd->txnid) == WT_TXN_ABORTED)
+ continue;
+
+ /* Track the largest transaction ID on the list. */
+ if (WT_TXNID_LT(max_txn, txnid))
+ max_txn = txnid;
+
/*
+ * Find the first update we can use.
+ *
* Checkpoint can only write updates visible as of its
* snapshot.
*
@@ -1180,7 +1264,8 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
skipped = true;
}
}
- }
+
+ r->update_mem_all += update_mem;
/*
* If all of the updates were aborted, quit. This test is not strictly
@@ -1227,12 +1312,6 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
txnid != S2C(session)->txn_global.checkpoint_txnid ||
WT_SESSION_IS_CHECKPOINT(session));
#endif
-
- /*
- * Track how many update chains we saw vs. how many update
- * chains had an entry we skipped.
- */
- ++r->update_skip_cnt;
return (0);
}
@@ -1276,6 +1355,23 @@ __rec_txn_read(WT_SESSION_IMPL *session, WT_RECONCILE *r,
if (skipped && !F_ISSET(r, WT_EVICT_UPDATE_RESTORE))
return (EBUSY);
+ /*
+ * Track the memory required by the update chain.
+ *
+ * A page with no uncommitted (skipped) updates, that can't be evicted
+ * because some updates aren't yet globally visible, can be evicted by
+ * writing previous versions of the updates to the lookaside file. That
+ * test is just checking if the skipped updates memory is zero.
+ *
+ * If that's not possible (there are skipped updates), we can rewrite
+ * the pages in-memory, but we don't want to unless there's memory to
+ * recover. That test is comparing the memory we'd recover to the memory
+ * we'd have to re-instantiate as part of the rewrite.
+ */
+ r->update_mem_saved += update_mem;
+ if (skipped)
+ r->update_mem_uncommitted += update_mem;
+
append_origv = false;
if (F_ISSET(r, WT_EVICT_UPDATE_RESTORE)) {
/*
@@ -1562,7 +1658,7 @@ __rec_child_modify(WT_SESSION_IMPL *session,
* not reserved for our exclusive use, there are other page states that
* must be considered.
*/
- for (;; __wt_yield())
+ for (;; __wt_yield()) {
switch (r->tested_ref_state = ref->state) {
case WT_REF_DISK:
/* On disk, not modified by definition. */
@@ -1673,6 +1769,8 @@ __rec_child_modify(WT_SESSION_IMPL *session,
WT_ILLEGAL_VALUE(session);
}
+ WT_STAT_CONN_INCR(session, child_modify_blocked_page);
+ }
in_memory:
/*
diff --git a/src/third_party/wiredtiger/src/schema/schema_alter.c b/src/third_party/wiredtiger/src/schema/schema_alter.c
index 26d800aa98e..edb3c6f77ae 100644
--- a/src/third_party/wiredtiger/src/schema/schema_alter.c
+++ b/src/third_party/wiredtiger/src/schema/schema_alter.c
@@ -61,13 +61,16 @@ __alter_colgroup(
{
WT_COLGROUP *colgroup;
WT_DECL_RET;
+ WT_TABLE *table;
WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE));
/* If we can get the colgroup, perform any potential alterations. */
if ((ret = __wt_schema_get_colgroup(
- session, uri, false, NULL, &colgroup)) == 0)
+ session, uri, false, &table, &colgroup)) == 0) {
WT_TRET(__wt_schema_alter(session, colgroup->source, cfg));
+ WT_TRET(__wt_schema_release_table(session, table));
+ }
return (ret);
}
@@ -82,11 +85,14 @@ __alter_index(
{
WT_INDEX *idx;
WT_DECL_RET;
+ WT_TABLE *table;
/* If we can get the index, perform any potential alterations. */
if ((ret = __wt_schema_get_index(
- session, uri, false, NULL, &idx)) == 0)
+ session, uri, false, &table, &idx)) == 0) {
WT_TRET(__wt_schema_alter(session, idx->source, cfg));
+ WT_TRET(__wt_schema_release_table(session, table));
+ }
return (ret);
}
@@ -127,7 +133,8 @@ __alter_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
WT_ERR(__wt_schema_alter(
session, colgroup->source, cfg));
}
-err: __wt_schema_release_table(session, table);
+
+err: WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/schema/schema_create.c b/src/third_party/wiredtiger/src/schema/schema_create.c
index 0677fa711a5..49c0274994c 100644
--- a/src/third_party/wiredtiger/src/schema/schema_create.c
+++ b/src/third_party/wiredtiger/src/schema/schema_create.c
@@ -273,7 +273,7 @@ err: __wt_free(session, cgconf);
__wt_buf_free(session, &fmt);
__wt_buf_free(session, &namebuf);
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
@@ -540,7 +540,7 @@ err: __wt_free(session, idxconf);
__wt_buf_free(session, &fmt);
__wt_buf_free(session, &namebuf);
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
@@ -615,7 +615,7 @@ err: if (table != NULL) {
}
}
if (table != NULL)
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
__wt_free(session, cgname);
__wt_free(session, tableconf);
return (ret);
diff --git a/src/third_party/wiredtiger/src/schema/schema_drop.c b/src/third_party/wiredtiger/src/schema/schema_drop.c
index 49801e4e5f9..18817c4fa2d 100644
--- a/src/third_party/wiredtiger/src/schema/schema_drop.c
+++ b/src/third_party/wiredtiger/src/schema/schema_drop.c
@@ -67,6 +67,7 @@ __drop_colgroup(
session, uri, force, &table, &colgroup)) == 0) {
table->cg_complete = false;
WT_TRET(__wt_schema_drop(session, colgroup->source, cfg));
+ WT_TRET(__wt_schema_release_table(session, table));
}
WT_TRET(__wt_metadata_remove(session, uri));
@@ -90,6 +91,7 @@ __drop_index(
session, uri, force, &table, &idx)) == 0) {
table->idx_complete = false;
WT_TRET(__wt_schema_drop(session, idx->source, cfg));
+ WT_TRET(__wt_schema_release_table(session, table));
}
WT_TRET(__wt_metadata_remove(session, uri));
@@ -151,7 +153,7 @@ __drop_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
WT_ERR(__wt_metadata_remove(session, uri));
err: if (table != NULL)
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/schema/schema_list.c b/src/third_party/wiredtiger/src/schema/schema_list.c
index 74ef5135a4a..434038c6bc8 100644
--- a/src/third_party/wiredtiger/src/schema/schema_list.c
+++ b/src/third_party/wiredtiger/src/schema/schema_list.c
@@ -30,9 +30,12 @@ __schema_add_table(WT_SESSION_IMPL *session,
session, name, namelen, ok_incomplete, &table));
WT_RET(ret);
- bucket = table->name_hash % WT_HASH_ARRAY_SIZE;
- TAILQ_INSERT_HEAD(&session->tables, table, q);
- TAILQ_INSERT_HEAD(&session->tablehash[bucket], table, hashq);
+ if (!table->is_simple || F_ISSET(S2C(session), WT_CONN_TABLE_CACHE)) {
+ bucket = table->name_hash % WT_HASH_ARRAY_SIZE;
+ TAILQ_INSERT_HEAD(&session->tables, table, q);
+ TAILQ_INSERT_HEAD(&session->tablehash[bucket], table, hashq);
+ }
+
*tablep = table;
return (0);
@@ -112,11 +115,14 @@ __wt_schema_get_table(WT_SESSION_IMPL *session,
* __wt_schema_release_table --
* Release a table handle.
*/
-void
+int
__wt_schema_release_table(WT_SESSION_IMPL *session, WT_TABLE *table)
{
WT_ASSERT(session, table->refcnt > 0);
- --table->refcnt;
+ if (--table->refcnt == 0 &&
+ table->is_simple && !F_ISSET(S2C(session), WT_CONN_TABLE_CACHE))
+ WT_RET(__wt_schema_destroy_table(session, &table));
+ return (0);
}
/*
@@ -229,9 +235,11 @@ __wt_schema_remove_table(WT_SESSION_IMPL *session, WT_TABLE *table)
uint64_t bucket;
WT_ASSERT(session, table->refcnt <= 1);
- bucket = table->name_hash % WT_HASH_ARRAY_SIZE;
- TAILQ_REMOVE(&session->tables, table, q);
- TAILQ_REMOVE(&session->tablehash[bucket], table, hashq);
+ if (!table->is_simple || F_ISSET(S2C(session), WT_CONN_TABLE_CACHE)) {
+ bucket = table->name_hash % WT_HASH_ARRAY_SIZE;
+ TAILQ_REMOVE(&session->tables, table, q);
+ TAILQ_REMOVE(&session->tablehash[bucket], table, hashq);
+ }
return (__wt_schema_destroy_table(session, &table));
}
@@ -249,3 +257,34 @@ __wt_schema_close_tables(WT_SESSION_IMPL *session)
WT_TRET(__wt_schema_remove_table(session, table));
return (ret);
}
+
+/*
+ * __wt_schema_sweep_tables --
+ * Close all idle, obsolete tables in a session.
+ */
+int
+__wt_schema_sweep_tables(WT_SESSION_IMPL *session)
+{
+ WT_TABLE *table, *next;
+ uint64_t schema_gen;
+ bool old_table_busy;
+
+ WT_ORDERED_READ(schema_gen, S2C(session)->schema_gen);
+ if (schema_gen == session->table_sweep_gen)
+ return (0);
+
+ old_table_busy = false;
+ TAILQ_FOREACH_SAFE(table, &session->tables, q, next)
+ if (table->schema_gen != schema_gen) {
+ if (table->refcnt == 0)
+ WT_RET(__wt_schema_remove_table(
+ session, table));
+ else
+ old_table_busy = true;
+ }
+
+ if (!old_table_busy)
+ session->table_sweep_gen = schema_gen;
+
+ return (0);
+}
diff --git a/src/third_party/wiredtiger/src/schema/schema_open.c b/src/third_party/wiredtiger/src/schema/schema_open.c
index 44bd66e011a..2df6bae45f3 100644
--- a/src/third_party/wiredtiger/src/schema/schema_open.c
+++ b/src/third_party/wiredtiger/src/schema/schema_open.c
@@ -425,37 +425,40 @@ __schema_open_table(WT_SESSION_IMPL *session,
WT_DECL_RET;
WT_TABLE *table;
const char *tconfig;
- char *tablename;
*tablep = NULL;
cursor = NULL;
table = NULL;
- tablename = NULL;
WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE));
+ WT_ERR(__wt_calloc_one(session, &table));
+ table->name_hash = __wt_hash_city64(name, namelen);
+
WT_ERR(__wt_scr_alloc(session, 0, &buf));
WT_ERR(__wt_buf_fmt(session, buf, "table:%.*s", (int)namelen, name));
- WT_ERR(__wt_strndup(session, buf->data, buf->size, &tablename));
+ WT_ERR(__wt_strndup(session, buf->data, buf->size, &table->name));
+ /*
+ * Don't hold the metadata cursor pinned, we call functions that use it
+ * to retrieve column group information.
+ */
WT_ERR(__wt_metadata_cursor(session, &cursor));
- cursor->set_key(cursor, tablename);
- WT_ERR(cursor->search(cursor));
- WT_ERR(cursor->get_value(cursor, &tconfig));
-
- WT_ERR(__wt_calloc_one(session, &table));
- table->name = tablename;
- tablename = NULL;
- table->name_hash = __wt_hash_city64(name, namelen);
-
- WT_ERR(__wt_config_getones(session, tconfig, "columns", &cval));
+ cursor->set_key(cursor, table->name);
+ if ((ret = cursor->search(cursor)) == 0 &&
+ (ret = cursor->get_value(cursor, &tconfig)) == 0)
+ ret = __wt_strdup(session, tconfig, &table->config);
+ WT_TRET(__wt_metadata_cursor_release(session, &cursor));
+ WT_ERR(ret);
- WT_ERR(__wt_config_getones(session, tconfig, "key_format", &cval));
+ WT_ERR(__wt_config_getones(session, table->config, "columns", &cval));
+ WT_ERR(__wt_config_getones(
+ session, table->config, "key_format", &cval));
WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->key_format));
- WT_ERR(__wt_config_getones(session, tconfig, "value_format", &cval));
+ WT_ERR(__wt_config_getones(
+ session, table->config, "value_format", &cval));
WT_ERR(__wt_strndup(session, cval.str, cval.len, &table->value_format));
- WT_ERR(__wt_strdup(session, tconfig, &table->config));
/* Point to some items in the copy to save re-parsing. */
WT_ERR(__wt_config_getones(session, table->config,
@@ -491,7 +494,7 @@ __schema_open_table(WT_SESSION_IMPL *session,
if (table->ncolgroups > 0 && table->is_simple)
WT_ERR_MSG(session, EINVAL,
- "%s requires a table with named columns", tablename);
+ "%s requires a table with named columns", table->name);
WT_ERR(__wt_calloc_def(session, WT_COLGROUPS(table), &table->cgroups));
WT_ERR(__wt_schema_open_colgroups(session, table));
@@ -509,9 +512,7 @@ __schema_open_table(WT_SESSION_IMPL *session,
if (0) {
err: WT_TRET(__wt_schema_destroy_table(session, &table));
}
- WT_TRET(__wt_metadata_cursor_release(session, &cursor));
- __wt_free(session, tablename);
__wt_scr_free(session, &buf);
return (ret);
}
@@ -529,8 +530,8 @@ __wt_schema_get_colgroup(WT_SESSION_IMPL *session,
const char *tablename, *tend;
u_int i;
- if (tablep != NULL)
- *tablep = NULL;
+ WT_ASSERT(session, tablep != NULL);
+ *tablep = NULL;
*colgroupp = NULL;
tablename = uri;
@@ -547,15 +548,12 @@ __wt_schema_get_colgroup(WT_SESSION_IMPL *session,
colgroup = table->cgroups[i];
if (strcmp(colgroup->name, uri) == 0) {
*colgroupp = colgroup;
- if (tablep != NULL)
- *tablep = table;
- else
- __wt_schema_release_table(session, table);
+ *tablep = table;
return (0);
}
}
- __wt_schema_release_table(session, table);
+ WT_RET(__wt_schema_release_table(session, table));
if (quiet)
WT_RET(ENOENT);
WT_RET_MSG(session, ENOENT, "%s not found in table", uri);
@@ -575,8 +573,8 @@ __wt_schema_get_index(WT_SESSION_IMPL *session,
const char *tablename, *tend;
u_int i;
- if (tablep != NULL)
- *tablep = NULL;
+ WT_ASSERT(session, tablep != NULL);
+ *tablep = NULL;
*indexp = NULL;
tablename = uri;
@@ -591,11 +589,8 @@ __wt_schema_get_index(WT_SESSION_IMPL *session,
for (i = 0; i < table->nindices; i++) {
idx = table->indices[i];
if (idx != NULL && strcmp(idx->name, uri) == 0) {
- if (tablep != NULL)
- *tablep = table;
- else
- __wt_schema_release_table(session, table);
*indexp = idx;
+ *tablep = table;
return (0);
}
}
@@ -603,15 +598,12 @@ __wt_schema_get_index(WT_SESSION_IMPL *session,
/* Otherwise, open it. */
WT_ERR(__wt_schema_open_index(
session, table, tend + 1, strlen(tend + 1), indexp));
- if (tablep != NULL)
- *tablep = table;
+ *tablep = table;
+ return (0);
-err: __wt_schema_release_table(session, table);
+err: WT_TRET(__wt_schema_release_table(session, table));
WT_RET(ret);
- if (*indexp != NULL)
- return (0);
-
if (quiet)
WT_RET(ENOENT);
WT_RET_MSG(session, ENOENT, "%s not found in table", uri);
diff --git a/src/third_party/wiredtiger/src/schema/schema_rename.c b/src/third_party/wiredtiger/src/schema/schema_rename.c
index a374f4c2831..9effedd2cde 100644
--- a/src/third_party/wiredtiger/src/schema/schema_rename.c
+++ b/src/third_party/wiredtiger/src/schema/schema_rename.c
@@ -233,7 +233,7 @@ __rename_table(WT_SESSION_IMPL *session,
WT_ERR(__metadata_rename(session, uri, newuri));
err: if (table != NULL)
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/schema/schema_stat.c b/src/third_party/wiredtiger/src/schema/schema_stat.c
index 345f9164e9b..9bcd2439619 100644
--- a/src/third_party/wiredtiger/src/schema/schema_stat.c
+++ b/src/third_party/wiredtiger/src/schema/schema_stat.c
@@ -19,14 +19,17 @@ __wt_curstat_colgroup_init(WT_SESSION_IMPL *session,
WT_COLGROUP *colgroup;
WT_DECL_ITEM(buf);
WT_DECL_RET;
+ WT_TABLE *table;
- WT_RET(__wt_schema_get_colgroup(session, uri, false, NULL, &colgroup));
+ WT_RET(__wt_schema_get_colgroup(
+ session, uri, false, &table, &colgroup));
WT_RET(__wt_scr_alloc(session, 0, &buf));
WT_ERR(__wt_buf_fmt(session, buf, "statistics:%s", colgroup->source));
ret = __wt_curstat_init(session, buf->data, NULL, cfg, cst);
err: __wt_scr_free(session, &buf);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
@@ -41,14 +44,16 @@ __wt_curstat_index_init(WT_SESSION_IMPL *session,
WT_DECL_ITEM(buf);
WT_DECL_RET;
WT_INDEX *idx;
+ WT_TABLE *table;
- WT_RET(__wt_schema_get_index(session, uri, false, NULL, &idx));
+ WT_RET(__wt_schema_get_index(session, uri, false, &table, &idx));
WT_RET(__wt_scr_alloc(session, 0, &buf));
WT_ERR(__wt_buf_fmt(session, buf, "statistics:%s", idx->source));
ret = __wt_curstat_init(session, buf->data, NULL, cfg, cst);
err: __wt_scr_free(session, &buf);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
@@ -184,7 +189,7 @@ __wt_curstat_table_init(WT_SESSION_IMPL *session,
__wt_curstat_dsrc_final(cst);
-err: __wt_schema_release_table(session, table);
+err: WT_TRET(__wt_schema_release_table(session, table));
__wt_scr_free(session, &buf);
return (ret);
diff --git a/src/third_party/wiredtiger/src/schema/schema_truncate.c b/src/third_party/wiredtiger/src/schema/schema_truncate.c
index 563bafa8ffc..3046305e819 100644
--- a/src/third_party/wiredtiger/src/schema/schema_truncate.c
+++ b/src/third_party/wiredtiger/src/schema/schema_truncate.c
@@ -33,7 +33,7 @@ __truncate_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[])
WT_ERR(__wt_schema_truncate(
session, table->indices[i]->source, cfg));
-err: __wt_schema_release_table(session, table);
+err: WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/schema/schema_worker.c b/src/third_party/wiredtiger/src/schema/schema_worker.c
index 62cdd7d367b..9fb68720723 100644
--- a/src/third_party/wiredtiger/src/schema/schema_worker.c
+++ b/src/third_party/wiredtiger/src/schema/schema_worker.c
@@ -64,14 +64,17 @@ __wt_schema_worker(WT_SESSION_IMPL *session,
}
} else if (WT_PREFIX_MATCH(uri, "colgroup:")) {
WT_ERR(__wt_schema_get_colgroup(
- session, uri, false, NULL, &colgroup));
+ session, uri, false, &table, &colgroup));
WT_ERR(__wt_schema_worker(session,
colgroup->source, file_func, name_func, cfg, open_flags));
+ WT_ERR(__wt_schema_release_table(session, table));
} else if (WT_PREFIX_SKIP(tablename, "index:")) {
idx = NULL;
- WT_ERR(__wt_schema_get_index(session, uri, false, NULL, &idx));
+ WT_ERR(__wt_schema_get_index(
+ session, uri, false, &table, &idx));
WT_ERR(__wt_schema_worker(session, idx->source,
file_func, name_func, cfg, open_flags));
+ WT_ERR(__wt_schema_release_table(session, table));
} else if (WT_PREFIX_MATCH(uri, "lsm:")) {
WT_ERR(__wt_lsm_tree_worker(session,
uri, file_func, name_func, cfg, open_flags));
@@ -128,6 +131,6 @@ __wt_schema_worker(WT_SESSION_IMPL *session,
WT_ERR(__wt_bad_object_type(session, uri));
err: if (table != NULL)
- __wt_schema_release_table(session, table);
+ WT_TRET(__wt_schema_release_table(session, table));
return (ret);
}
diff --git a/src/third_party/wiredtiger/src/session/session_api.c b/src/third_party/wiredtiger/src/session/session_api.c
index 89a5a2c633d..386084b78d9 100644
--- a/src/third_party/wiredtiger/src/session/session_api.c
+++ b/src/third_party/wiredtiger/src/session/session_api.c
@@ -328,6 +328,7 @@ __session_open_cursor_int(WT_SESSION_IMPL *session, const char *uri,
WT_COLGROUP *colgroup;
WT_DATA_SOURCE *dsrc;
WT_DECL_RET;
+ WT_TABLE *table;
*cursorp = NULL;
@@ -355,9 +356,10 @@ __session_open_cursor_int(WT_SESSION_IMPL *session, const char *uri,
* the underlying data source.
*/
WT_RET(__wt_schema_get_colgroup(
- session, uri, false, NULL, &colgroup));
+ session, uri, false, &table, &colgroup));
WT_RET(__wt_open_cursor(
session, colgroup->source, owner, cfg, cursorp));
+ WT_RET(__wt_schema_release_table(session, table));
} else if (WT_PREFIX_MATCH(uri, "config:"))
WT_RET(__wt_curconfig_open(
session, uri, cfg, cursorp));
@@ -818,6 +820,8 @@ __session_reset(WT_SESSION *wt_session)
WT_TRET(__wt_session_reset_cursors(session, true));
+ WT_TRET(__wt_schema_sweep_tables(session));
+
/* Release common session resources. */
WT_TRET(__wt_session_release_resources(session));
@@ -1209,12 +1213,15 @@ __wt_session_range_truncate(WT_SESSION_IMPL *session,
done:
err: /*
- * Close any locally-opened start cursor. Reset application cursors,
- * they've possibly moved and the application cannot use them.
+ * Close any locally-opened start cursor.
+ *
+ * Reset application cursors, they've possibly moved and the
+ * application cannot use them. Note that we can make it here with a
+ * NULL start cursor (e.g., if the truncate range is empty).
*/
if (local_start)
WT_TRET(start->close(start));
- else
+ else if (start != NULL)
WT_TRET(start->reset(start));
if (stop != NULL)
WT_TRET(stop->reset(stop));
diff --git a/src/third_party/wiredtiger/src/session/session_dhandle.c b/src/third_party/wiredtiger/src/session/session_dhandle.c
index ffeb6137766..707e07ac11f 100644
--- a/src/third_party/wiredtiger/src/session/session_dhandle.c
+++ b/src/third_party/wiredtiger/src/session/session_dhandle.c
@@ -235,6 +235,7 @@ __wt_session_lock_dhandle(
lock_busy = true;
/* Give other threads a chance to make progress. */
+ WT_STAT_CONN_INCR(session, dhandle_lock_blocked);
__wt_yield();
}
}
@@ -597,7 +598,9 @@ __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *checkpoint)
* the underlying file are visible to the in-memory pages.
*/
WT_ERR(__wt_evict_file_exclusive_on(session));
- WT_ERR(__wt_cache_op(session, WT_SYNC_DISCARD));
+ ret = __wt_cache_op(session, WT_SYNC_DISCARD);
+ __wt_evict_file_exclusive_off(session);
+ WT_ERR(ret);
/*
* We lock checkpoint handles that we are overwriting, so the handle
diff --git a/src/third_party/wiredtiger/src/support/err.c b/src/third_party/wiredtiger/src/support/err.c
index 57efde72b23..f98b1943449 100644
--- a/src/third_party/wiredtiger/src/support/err.c
+++ b/src/third_party/wiredtiger/src/support/err.c
@@ -494,7 +494,18 @@ __wt_panic(WT_SESSION_IMPL *session)
WT_GCC_FUNC_ATTRIBUTE((cold))
WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
{
- F_SET(S2C(session), WT_CONN_PANIC);
+ WT_CONNECTION_IMPL *conn;
+
+ conn = S2C(session);
+
+ /*
+ * If the connection has already be marked for panic, just return the
+ * error.
+ */
+ if (F_ISSET(conn, WT_CONN_PANIC))
+ return (WT_PANIC);
+
+ F_SET(conn, WT_CONN_PANIC);
__wt_err(session, WT_PANIC, "the process must exit and restart");
#if defined(HAVE_DIAGNOSTIC)
diff --git a/src/third_party/wiredtiger/src/support/rand.c b/src/third_party/wiredtiger/src/support/rand.c
index 4fae43edc8e..a5b229b9abc 100644
--- a/src/third_party/wiredtiger/src/support/rand.c
+++ b/src/third_party/wiredtiger/src/support/rand.c
@@ -120,15 +120,3 @@ __wt_random(WT_RAND_STATE volatile * rnd_state)
return ((z << 16) + (w & 65535));
}
-
-/*
- * __wt_random64 --
- * Return a 64-bit pseudo-random number.
- */
-uint64_t
-__wt_random64(WT_RAND_STATE volatile * rnd_state)
- WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
-{
- return (((uint64_t)__wt_random(rnd_state) << 32) +
- __wt_random(rnd_state));
-}
diff --git a/src/third_party/wiredtiger/src/support/stat.c b/src/third_party/wiredtiger/src/support/stat.c
index 8b72e653658..c9e577ac3b6 100644
--- a/src/third_party/wiredtiger/src/support/stat.c
+++ b/src/third_party/wiredtiger/src/support/stat.c
@@ -842,11 +842,19 @@ static const char * const __stats_connection_desc[] = {
"thread-state: active filesystem write calls",
"thread-yield: application thread time evicting (usecs)",
"thread-yield: application thread time waiting for cache (usecs)",
+ "thread-yield: connection close blocked waiting for transaction state stabilization",
+ "thread-yield: connection close yielded for lsm manager shutdown",
+ "thread-yield: data handle lock yielded",
+ "thread-yield: log server sync yielded for log write",
"thread-yield: page acquire busy blocked",
"thread-yield: page acquire eviction blocked",
"thread-yield: page acquire locked blocked",
"thread-yield: page acquire read blocked",
"thread-yield: page acquire time sleeping (usecs)",
+ "thread-yield: page delete rollback yielded for instantiation",
+ "thread-yield: page reconciliation yielded due to child modification",
+ "thread-yield: reference for page index and slot yielded",
+ "thread-yield: tree descend one level yielded for split page index update",
"transaction: number of named snapshots created",
"transaction: number of named snapshots dropped",
"transaction: transaction begins",
@@ -1129,11 +1137,19 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
/* not clearing thread_write_active */
stats->application_evict_time = 0;
stats->application_cache_time = 0;
+ stats->txn_release_blocked = 0;
+ stats->conn_close_blocked_lsm = 0;
+ stats->dhandle_lock_blocked = 0;
+ stats->log_server_sync_blocked = 0;
stats->page_busy_blocked = 0;
stats->page_forcible_evict_blocked = 0;
stats->page_locked_blocked = 0;
stats->page_read_blocked = 0;
stats->page_sleep = 0;
+ stats->page_del_rollback_blocked = 0;
+ stats->child_modify_blocked_page = 0;
+ stats->page_index_slot_blocked = 0;
+ stats->tree_descend_blocked = 0;
stats->txn_snapshots_created = 0;
stats->txn_snapshots_dropped = 0;
stats->txn_begin = 0;
@@ -1475,12 +1491,25 @@ __wt_stat_connection_aggregate(
WT_STAT_READ(from, application_evict_time);
to->application_cache_time +=
WT_STAT_READ(from, application_cache_time);
+ to->txn_release_blocked += WT_STAT_READ(from, txn_release_blocked);
+ to->conn_close_blocked_lsm +=
+ WT_STAT_READ(from, conn_close_blocked_lsm);
+ to->dhandle_lock_blocked += WT_STAT_READ(from, dhandle_lock_blocked);
+ to->log_server_sync_blocked +=
+ WT_STAT_READ(from, log_server_sync_blocked);
to->page_busy_blocked += WT_STAT_READ(from, page_busy_blocked);
to->page_forcible_evict_blocked +=
WT_STAT_READ(from, page_forcible_evict_blocked);
to->page_locked_blocked += WT_STAT_READ(from, page_locked_blocked);
to->page_read_blocked += WT_STAT_READ(from, page_read_blocked);
to->page_sleep += WT_STAT_READ(from, page_sleep);
+ to->page_del_rollback_blocked +=
+ WT_STAT_READ(from, page_del_rollback_blocked);
+ to->child_modify_blocked_page +=
+ WT_STAT_READ(from, child_modify_blocked_page);
+ to->page_index_slot_blocked +=
+ WT_STAT_READ(from, page_index_slot_blocked);
+ to->tree_descend_blocked += WT_STAT_READ(from, tree_descend_blocked);
to->txn_snapshots_created +=
WT_STAT_READ(from, txn_snapshots_created);
to->txn_snapshots_dropped +=
diff --git a/src/third_party/wiredtiger/src/support/time.c b/src/third_party/wiredtiger/src/support/time.c
new file mode 100644
index 00000000000..0e4562c0234
--- /dev/null
+++ b/src/third_party/wiredtiger/src/support/time.c
@@ -0,0 +1,89 @@
+/*-
+ * Public Domain 2014-2017 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"
+
+/*
+ * __time_check_monotonic --
+ * Check and prevent time running backward. If we detect that it has, we
+ * set the time structure to the previous values, making time stand still
+ * until we see a time in the future of the highest value seen so far.
+ */
+static void
+__time_check_monotonic(WT_SESSION_IMPL *session, struct timespec *tsp)
+{
+ /*
+ * Detect time going backward. If so, use the last
+ * saved timestamp.
+ */
+ if (session == NULL)
+ return;
+
+ if (tsp->tv_sec < session->last_epoch.tv_sec ||
+ (tsp->tv_sec == session->last_epoch.tv_sec &&
+ tsp->tv_nsec < session->last_epoch.tv_nsec)) {
+ WT_STAT_CONN_INCR(session, time_travel);
+ *tsp = session->last_epoch;
+ } else
+ session->last_epoch = *tsp;
+}
+
+/*
+ * __wt_epoch --
+ * Return the time since the Epoch, adjusted so it never appears to go
+ * backwards.
+ */
+void
+__wt_epoch(WT_SESSION_IMPL *session, struct timespec *tsp)
+ WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
+{
+ struct timespec tmp;
+
+ /*
+ * Read into a local variable so that we're comparing the correct
+ * value when we check for monotonic increasing time. There are
+ * many places we read into an unlocked global variable.
+ */
+ __wt_epoch_raw(session, &tmp);
+ __time_check_monotonic(session, &tmp);
+ *tsp = tmp;
+}
+
+/*
+ * __wt_seconds --
+ * Return the seconds since the Epoch.
+ */
+void
+__wt_seconds(WT_SESSION_IMPL *session, time_t *timep)
+{
+ struct timespec t;
+
+ __wt_epoch(session, &t);
+
+ *timep = t.tv_sec;
+}
diff --git a/src/third_party/wiredtiger/src/txn/txn.c b/src/third_party/wiredtiger/src/txn/txn.c
index ea7faa2e966..7665ba56adc 100644
--- a/src/third_party/wiredtiger/src/txn/txn.c
+++ b/src/third_party/wiredtiger/src/txn/txn.c
@@ -503,13 +503,17 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_TXN *txn;
+ WT_TXN_GLOBAL *txn_global;
WT_TXN_OP *op;
u_int i;
- bool did_update;
+ bool did_update, locked;
txn = &session->txn;
conn = S2C(session);
+ txn_global = &conn->txn_global;
did_update = txn->mod_count != 0;
+ locked = false;
+
WT_ASSERT(session, !F_ISSET(txn, WT_TXN_ERROR) || !did_update);
if (!F_ISSET(txn, WT_TXN_RUNNING))
@@ -580,6 +584,14 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* This is particularly important for checkpoints.
*/
__wt_txn_release_snapshot(session);
+ /*
+ * We hold the visibility lock for reading from the time
+ * we write our log record until the time we release our
+ * transaction so that the LSN any checkpoint gets will
+ * always reflect visible data.
+ */
+ __wt_readlock(session, &txn_global->visibility_rwlock);
+ locked = true;
ret = __wt_txn_log_commit(session, cfg);
}
@@ -590,6 +602,9 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
* Nothing can fail after this point.
*/
if (ret != 0) {
+ if (locked)
+ __wt_readunlock(session,
+ &txn_global->visibility_rwlock);
WT_TRET(__wt_txn_rollback(session, cfg));
return (ret);
}
@@ -600,6 +615,8 @@ __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[])
txn->mod_count = 0;
__wt_txn_release(session);
+ if (locked)
+ __wt_readunlock(session, &txn_global->visibility_rwlock);
return (0);
}
@@ -770,6 +787,7 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
&txn_global->id_lock, "transaction id lock"));
WT_RET(__wt_rwlock_init(session, &txn_global->scan_rwlock));
WT_RET(__wt_rwlock_init(session, &txn_global->nsnap_rwlock));
+ WT_RET(__wt_rwlock_init(session, &txn_global->visibility_rwlock));
txn_global->nsnap_oldest_id = WT_TXN_NONE;
TAILQ_INIT(&txn_global->nsnaph);
@@ -801,6 +819,7 @@ __wt_txn_global_destroy(WT_SESSION_IMPL *session)
__wt_spin_destroy(session, &txn_global->id_lock);
__wt_rwlock_destroy(session, &txn_global->scan_rwlock);
__wt_rwlock_destroy(session, &txn_global->nsnap_rwlock);
+ __wt_rwlock_destroy(session, &txn_global->visibility_rwlock);
__wt_free(session, txn_global->states);
}
diff --git a/src/third_party/wiredtiger/src/txn/txn_log.c b/src/third_party/wiredtiger/src/txn/txn_log.c
index 2931dc1ce82..09a8c4d9663 100644
--- a/src/third_party/wiredtiger/src/txn/txn_log.c
+++ b/src/third_party/wiredtiger/src/txn/txn_log.c
@@ -289,16 +289,20 @@ int
__wt_txn_checkpoint_log(
WT_SESSION_IMPL *session, bool full, uint32_t flags, WT_LSN *lsnp)
{
+ WT_CONNECTION_IMPL *conn;
WT_DECL_ITEM(logrec);
WT_DECL_RET;
WT_ITEM *ckpt_snapshot, empty;
WT_LSN *ckpt_lsn;
WT_TXN *txn;
+ WT_TXN_GLOBAL *txn_global;
uint8_t *end, *p;
size_t recsize;
uint32_t i, rectype = WT_LOGREC_CHECKPOINT;
const char *fmt = WT_UNCHECKED_STRING(IIIIu);
+ conn = S2C(session);
+ txn_global = &conn->txn_global;
txn = &session->txn;
ckpt_lsn = &txn->ckpt_lsn;
@@ -320,6 +324,15 @@ __wt_txn_checkpoint_log(
txn->full_ckpt = true;
WT_ERR(__wt_log_flush_lsn(session, ckpt_lsn, true));
/*
+ * We take and immediately release the visibility lock.
+ * Acquiring the write lock guarantees that any transaction
+ * that has written to the log has also made its transaction
+ * visible at this time.
+ */
+ __wt_writelock(session, &txn_global->visibility_rwlock);
+ __wt_writeunlock(session, &txn_global->visibility_rwlock);
+
+ /*
* We need to make sure that the log records in the checkpoint
* LSN are on disk. In particular to make sure that the
* current log file exists.
@@ -363,20 +376,20 @@ __wt_txn_checkpoint_log(
txn->ckpt_nsnapshot, ckpt_snapshot));
logrec->size += (uint32_t)recsize;
WT_ERR(__wt_log_write(session, logrec, lsnp,
- F_ISSET(S2C(session), WT_CONN_CKPT_SYNC) ?
+ F_ISSET(conn, WT_CONN_CKPT_SYNC) ?
WT_LOG_FSYNC : 0));
/*
* If this full checkpoint completed successfully and there is
- * no hot backup in progress and this is not recovery, tell
- * the logging subsystem the checkpoint LSN so that it can
- * archive. Do not update the logging checkpoint LSN if this
- * is during a clean connection close, only during a full
- * checkpoint. A clean close may not update any metadata LSN
- * and we do not want to archive in that case.
+ * no hot backup in progress and this is not an unclean
+ * recovery, tell the logging subsystem the checkpoint LSN so
+ * that it can archive. Do not update the logging checkpoint
+ * LSN if this is during a clean connection close, only during
+ * a full checkpoint. A clean close may not update any
+ * metadata LSN and we do not want to archive in that case.
*/
- if (!S2C(session)->hot_backup &&
- !F_ISSET(S2C(session), WT_CONN_RECOVERING) &&
+ if (!conn->hot_backup &&
+ !FLD_ISSET(conn->log_flags, WT_CONN_LOG_RECOVER_DIRTY) &&
txn->full_ckpt)
__wt_log_ckpt(session, ckpt_lsn);
diff --git a/src/third_party/wiredtiger/src/txn/txn_recover.c b/src/third_party/wiredtiger/src/txn/txn_recover.c
index 30932195b1e..29f4dee5199 100644
--- a/src/third_party/wiredtiger/src/txn/txn_recover.c
+++ b/src/third_party/wiredtiger/src/txn/txn_recover.c
@@ -20,6 +20,7 @@ typedef struct {
} *files;
size_t file_alloc; /* Allocated size of files array. */
u_int max_fileid; /* Maximum file ID seen. */
+ WT_LSN max_lsn; /* Maximum checkpoint LSN seen. */
u_int nfiles; /* Number of files in the metadata. */
WT_LSN ckpt_lsn; /* Start LSN for main recovery loop. */
@@ -342,6 +343,10 @@ __recovery_setup_file(WT_RECOVERY *r, const char *uri, const char *config)
"Recovering %s with id %" PRIu32 " @ (%" PRIu32 ", %" PRIu32 ")",
uri, fileid, lsn.l.file, lsn.l.offset);
+ if ((!WT_IS_MAX_LSN(&lsn) && !WT_IS_INIT_LSN(&lsn)) &&
+ (WT_IS_MAX_LSN(&r->max_lsn) || __wt_log_cmp(&lsn, &r->max_lsn) > 0))
+ r->max_lsn = lsn;
+
return (0);
}
@@ -428,6 +433,7 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
WT_RET(__wt_open_internal_session(conn, "txn-recover",
false, WT_SESSION_NO_LOGGING, &session));
r.session = session;
+ WT_MAX_LSN(&r.max_lsn);
F_SET(conn, WT_CONN_RECOVERING);
WT_ERR(__wt_metadata_search(session, WT_METAFILE_URI, &config));
@@ -443,9 +449,29 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
*/
if (!FLD_ISSET(S2C(session)->log_flags, WT_CONN_LOG_EXISTED) ||
WT_IS_MAX_LSN(&metafile->ckpt_lsn)) {
+ /*
+ * Detect if we're going from logging disabled to enabled.
+ * We need to know this to verify LSNs and start at the correct
+ * log file later. If someone ran with logging, then disabled
+ * it and removed all the log files and then turned logging back
+ * on, we have to start logging in the log file number that is
+ * larger than any checkpoint LSN we have from the earlier time.
+ */
WT_ERR(__recovery_file_scan(&r));
+ /*
+ * The array can be re-allocated in recovery_file_scan. Reset
+ * our pointer after scanning all the files.
+ */
+ metafile = &r.files[WT_METAFILE_ID];
conn->next_file_id = r.max_fileid;
- goto done;
+
+ if (FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED) &&
+ WT_IS_MAX_LSN(&metafile->ckpt_lsn) &&
+ !WT_IS_MAX_LSN(&r.max_lsn)) {
+ WT_ERR(__wt_log_reset(session, r.max_lsn.l.file));
+ goto ckpt;
+ } else
+ goto done;
}
/*
@@ -488,6 +514,11 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
/* Scan the metadata to find the live files and their IDs. */
WT_ERR(__recovery_file_scan(&r));
+ /*
+ * Clear this out. We no longer need it and it could have been
+ * re-allocated when scanning the files.
+ */
+ metafile = NULL;
/*
* We no longer need the metadata cursor: close it to avoid pinning any
@@ -535,6 +566,8 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
* this is not a read-only connection.
* We can consider skipping it in the future.
*/
+ if (needs_rec)
+ FLD_SET(conn->log_flags, WT_CONN_LOG_RECOVER_DIRTY);
if (WT_IS_INIT_LSN(&r.ckpt_lsn))
WT_ERR(__wt_log_scan(session, NULL,
WT_LOGSCAN_FIRST | WT_LOGSCAN_RECOVER,
@@ -554,11 +587,12 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
* open is fast and keep the metadata up to date with the checkpoint
* LSN and archiving.
*/
- WT_ERR(session->iface.checkpoint(&session->iface, "force=1"));
+ckpt: WT_ERR(session->iface.checkpoint(&session->iface, "force=1"));
done: FLD_SET(conn->log_flags, WT_CONN_LOG_RECOVER_DONE);
err: WT_TRET(__recovery_free(&r));
__wt_free(session, config);
+ FLD_CLR(conn->log_flags, WT_CONN_LOG_RECOVER_DIRTY);
if (ret != 0)
__wt_err(session, ret, "Recovery failed");
diff --git a/src/third_party/wiredtiger/test/mciproject.yml b/src/third_party/wiredtiger/test/mciproject.yml
index 6456475aa00..50a910d9e58 100644
--- a/src/third_party/wiredtiger/test/mciproject.yml
+++ b/src/third_party/wiredtiger/test/mciproject.yml
@@ -157,20 +157,6 @@ buildvariants:
- name: unit-test
- name: fops
-- name: solaris
- display_name: Solaris
- run_on:
- - solaris
- expansions:
- make_command: PATH=/opt/mongodbtoolchain/bin:$PATH gmake
- test_env_vars: LD_LIBRARY_PATH=`pwd`/.libs
- smp_command: -j $(kstat cpu | sort -u | grep -c "^module")
- configure_env_vars: PATH=/opt/mongodbtoolchain/bin:$PATH CFLAGS="-m64"
- tasks:
- - name: compile
- - name: unit-test
- - name: fops
-
- name: windows-64
display_name: Windows 64-bit
run_on:
diff --git a/src/third_party/wiredtiger/test/recovery/random-abort.c b/src/third_party/wiredtiger/test/recovery/random-abort.c
index febe6530534..b53383e5730 100644
--- a/src/third_party/wiredtiger/test/recovery/random-abort.c
+++ b/src/third_party/wiredtiger/test/recovery/random-abort.c
@@ -47,9 +47,9 @@ static bool inmem;
#define RECORDS_FILE "records-%" PRIu32
#define ENV_CONFIG_DEF \
- "create,log=(file_max=10M,archive=false,enabled)"
+ "create,log=(file_max=10M,enabled)"
#define ENV_CONFIG_TXNSYNC \
- "create,log=(file_max=10M,archive=false,enabled)," \
+ "create,log=(file_max=10M,enabled)," \
"transaction_sync=(enabled,method=none)"
#define ENV_CONFIG_REC "log=(recover=on)"
#define MAX_VAL 4096
diff --git a/src/third_party/wiredtiger/test/suite/test_bug018.py b/src/third_party/wiredtiger/test/suite/test_bug018.py
new file mode 100644
index 00000000000..7d20ebcaacb
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_bug018.py
@@ -0,0 +1,98 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2017 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.
+
+from helper import copy_wiredtiger_home
+import os
+import wiredtiger, wttest
+
+# test_bug018.py
+# JIRA WT-3590: if writing table data fails during close then tables
+# that were updated within the same transaction could get out of sync with
+# each other.
+class test_bug018(wttest.WiredTigerTestCase):
+ '''Test closing/reopening/recovering tables when writes fail'''
+
+ conn_config = 'log=(enabled)'
+
+ def setUp(self):
+ # This test uses Linux-specific code so skip on any other system.
+ if os.name != 'posix' or os.uname()[0] != 'Linux':
+ self.skipTest('Linux-specific test skipped on ' + os.name)
+ super(test_bug018, self).setUp()
+
+ def create_table(self, uri):
+ self.session.create(uri, 'key_format=S,value_format=S')
+ return self.session.open_cursor(uri)
+
+ def test_bug018(self):
+ '''Test closing multiple tables'''
+ basename = 'bug018.'
+ baseuri = 'file:' + basename
+ c1 = self.create_table(baseuri + '01.wt')
+ c2 = self.create_table(baseuri + '02.wt')
+
+ self.session.begin_transaction()
+ c1['key'] = 'value'
+ c2['key'] = 'value'
+ self.session.commit_transaction()
+
+ # Simulate a write failure by closing the file descriptor for the second
+ # table out from underneath WiredTiger. We do this right before
+ # closing the connection so that the write error happens during close
+ # when writing out the final data. Allow table 1 to succeed and force
+ # an erorr writing out table 2.
+ #
+ # This is Linux-specific code to figure out the file descriptor.
+ for f in os.listdir('/proc/self/fd'):
+ try:
+ if os.readlink('/proc/self/fd/' + f).endswith(basename + '02.wt'):
+ os.close(int(f))
+ except OSError:
+ pass
+
+ # Expect an error and messages, so turn off stderr checking.
+ with self.expectedStderrPattern(''):
+ try:
+ self.close_conn()
+ except wiredtiger.WiredTigerError:
+ self.conn = None
+
+ # Make a backup for forensics in case something goes wrong.
+ backup_dir = 'BACKUP'
+ copy_wiredtiger_home('.', backup_dir, True)
+
+ # After reopening and running recovery both tables should be in
+ # sync even though table 1 was successfully written and table 2
+ # had an error on close.
+ self.open_conn()
+ c1 = self.session.open_cursor(baseuri + '01.wt')
+ c2 = self.session.open_cursor(baseuri + '02.wt')
+ self.assertEqual(list(c1), list(c2))
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/src/third_party/wiredtiger/test/suite/test_inmem01.py b/src/third_party/wiredtiger/test/suite/test_inmem01.py
index 388485db29b..d280642942a 100644
--- a/src/third_party/wiredtiger/test/suite/test_inmem01.py
+++ b/src/third_party/wiredtiger/test/suite/test_inmem01.py
@@ -108,12 +108,15 @@ class test_inmem01(wttest.WiredTigerTestCase):
cursor.reset()
# Spin inserting to give eviction a chance to reclaim space
+ sleeps = 0
inserted = False
for i in range(1, 1000):
try:
cursor[ds.key(1)] = ds.value(1)
except wiredtiger.WiredTigerError:
cursor.reset()
+ sleeps = sleeps + 1
+ self.assertLess(sleeps, 60 * 5)
sleep(1)
continue
inserted = True
diff --git a/src/third_party/wiredtiger/test/suite/test_las.py b/src/third_party/wiredtiger/test/suite/test_las.py
new file mode 100644
index 00000000000..d0bd1d108fa
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_las.py
@@ -0,0 +1,60 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2017 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.
+
+import wiredtiger, wttest
+from wtdataset import SimpleDataSet
+
+# test_las.py
+# Smoke tests to ensure lookaside tables are working.
+class test_las(wttest.WiredTigerTestCase):
+ # Force a small cache.
+ def conn_config(self):
+ return 'cache_size=1GB'
+
+ @wttest.longtest('lookaside table smoke test')
+ def test_las(self):
+ # Create a small table.
+ uri = "table:test_las"
+ nrows = 100
+ ds = SimpleDataSet(self, uri, nrows, key_format="S")
+ ds.populate()
+
+ # Take a snapshot.
+ self.session.snapshot("name=xxx")
+
+ # Insert a large number of records, we'll hang if the lookaside table
+ # isn't doing its thing.
+ c = self.session.open_cursor(uri)
+ bigvalue = "abcde" * 100
+ for i in range(1, 1000000):
+ c.set_key(ds.key(nrows + i))
+ c.set_value(bigvalue)
+ self.assertEquals(c.insert(), 0)
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/src/third_party/wiredtiger/test/suite/test_txn02.py b/src/third_party/wiredtiger/test/suite/test_txn02.py
index 01626057b9e..76a325743e9 100644
--- a/src/third_party/wiredtiger/test/suite/test_txn02.py
+++ b/src/third_party/wiredtiger/test/suite/test_txn02.py
@@ -169,7 +169,6 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
try:
session = backup_conn.open_session()
finally:
- session.checkpoint("force")
self.check(backup_conn.open_session(), None, committed)
# Sleep long enough so that the archive thread is guaranteed
# to run before we close the connection.
diff --git a/src/third_party/wiredtiger/test/suite/test_txn05.py b/src/third_party/wiredtiger/test/suite/test_txn05.py
index 7aaff221ba4..7099bc972aa 100644
--- a/src/third_party/wiredtiger/test/suite/test_txn05.py
+++ b/src/third_party/wiredtiger/test/suite/test_txn05.py
@@ -134,12 +134,12 @@ class test_txn05(wttest.WiredTigerTestCase, suite_subprocess):
session = backup_conn.open_session()
finally:
self.check(session, None, committed)
- # Force a checkpoint because we don't record the recovery
- # checkpoint as available for archiving.
- session.checkpoint("force")
# Sleep long enough so that the archive thread is guaranteed
# to run before we close the connection.
time.sleep(1.0)
+ if count == 0:
+ first_logs = \
+ fnmatch.filter(os.listdir(self.backup_dir), "*Log*")
backup_conn.close()
count += 1
#
@@ -149,6 +149,11 @@ class test_txn05(wttest.WiredTigerTestCase, suite_subprocess):
#
cur_logs = fnmatch.filter(os.listdir(self.backup_dir), "*Log*")
for o in orig_logs:
+ # Creating the backup was effectively an unclean shutdown so
+ # even after sleeping, we should never archive log files
+ # because a checkpoint has not run. Later opens and runs of
+ # recovery will detect a clean shutdown and allow archiving.
+ self.assertEqual(True, o in first_logs)
if self.archive == 'true':
self.assertEqual(False, o in cur_logs)
else:
diff --git a/src/third_party/wiredtiger/test/suite/test_txn09.py b/src/third_party/wiredtiger/test/suite/test_txn09.py
index 768d714e248..b8a3d7f38ae 100644
--- a/src/third_party/wiredtiger/test/suite/test_txn09.py
+++ b/src/third_party/wiredtiger/test/suite/test_txn09.py
@@ -26,8 +26,8 @@
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# OTHER DEALINGS IN THE SOFTWARE.
#
-# test_txn02.py
-# Transactions: commits and rollbacks
+# test_txn09.py
+# Transactions: recovery toggling logging
#
import fnmatch, os, shutil, time
diff --git a/src/third_party/wiredtiger/test/suite/test_txn16.py b/src/third_party/wiredtiger/test/suite/test_txn16.py
new file mode 100644
index 00000000000..929da2291c7
--- /dev/null
+++ b/src/third_party/wiredtiger/test/suite/test_txn16.py
@@ -0,0 +1,140 @@
+#!/usr/bin/env python
+#
+# Public Domain 2014-2017 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.
+#
+# test_txn16.py
+# Recovery: Test that toggling between logging and not logging does not
+# continue to generate more log files.
+#
+
+import fnmatch, os, shutil, time
+from suite_subprocess import suite_subprocess
+import wttest
+
+class test_txn16(wttest.WiredTigerTestCase, suite_subprocess):
+ t1 = 'table:test_txn16_1'
+ t2 = 'table:test_txn16_2'
+ t3 = 'table:test_txn16_3'
+ nentries = 1000
+ create_params = 'key_format=i,value_format=i'
+ # Set the log file size small so we generate checkpoints
+ # with LSNs in different files.
+ conn_config = 'config_base=false,' + \
+ 'log=(archive=false,enabled,file_max=100K),' + \
+ 'transaction_sync=(method=dsync,enabled)'
+ conn_on = 'config_base=false,' + \
+ 'log=(archive=false,enabled,file_max=100K),' + \
+ 'transaction_sync=(method=dsync,enabled)'
+ conn_off = 'config_base=false,log=(enabled=false)'
+
+ def populate_table(self, uri):
+ self.session.create(uri, self.create_params)
+ c = self.session.open_cursor(uri, None, None)
+ # Populate with an occasional checkpoint to generate
+ # some varying LSNs.
+ for i in range(self.nentries):
+ c[i] = i + 1
+ if i % 900 == 0:
+ self.session.checkpoint()
+ c.close()
+
+ def copy_dir(self, olddir, newdir):
+ ''' Simulate a crash from olddir and restart in newdir. '''
+ # with the connection still open, copy files to new directory
+ shutil.rmtree(newdir, ignore_errors=True)
+ os.mkdir(newdir)
+ for fname in os.listdir(olddir):
+ fullname = os.path.join(olddir, fname)
+ # Skip lock file on Windows since it is locked
+ if os.path.isfile(fullname) and \
+ "WiredTiger.lock" not in fullname and \
+ "Tmplog" not in fullname and \
+ "Preplog" not in fullname:
+ shutil.copy(fullname, newdir)
+ # close the original connection.
+ self.close_conn()
+
+ def run_toggle(self, homedir):
+ loop = 0
+ # Record original log files. There should never be overlap
+ # with these even after they're removed.
+ orig_logs = fnmatch.filter(os.listdir(homedir), "*Log*")
+ while loop < 3:
+ # Reopen with logging on to run recovery first time
+ on_conn = self.wiredtiger_open(homedir, self.conn_on)
+ on_conn.close()
+ if loop > 0:
+ # Get current log files.
+ cur_logs = fnmatch.filter(os.listdir(homedir), "*Log*")
+ scur = set(cur_logs)
+ sorig = set(orig_logs)
+ # There should never be overlap with the log files that
+ # were there originally. Mostly this checks that after
+ # opening with logging disabled and then re-enabled, we
+ # don't see log file 1.
+ self.assertEqual(scur.isdisjoint(sorig), True)
+ if loop > 1:
+ # We should be creating the same log files each time.
+ for l in cur_logs:
+ self.assertEqual(l in last_logs, True)
+ for l in last_logs:
+ self.assertEqual(l in cur_logs, True)
+ last_logs = cur_logs
+ loop += 1
+ # Remove all log files before opening without logging.
+ cur_logs = fnmatch.filter(os.listdir(homedir), "*Log*")
+ for l in cur_logs:
+ path=homedir + "/" + l
+ os.remove(path)
+ off_conn = self.wiredtiger_open(homedir, self.conn_off)
+ off_conn.close()
+
+ def test_recovery(self):
+ ''' Check log file creation when toggling. '''
+
+ # Here's the strategy:
+ # - With logging populate 4 tables. Checkpoint
+ # them at different times.
+ # - Copy to a new directory to simulate a crash.
+ # - Close the original connection.
+ # On both a "copy" to simulate a crash and the original (3x):
+ # - Record log files existing.
+ # - Reopen with logging to run recovery. Close connection.
+ # - Record log files existing.
+ # - Remove all log files.
+ # - Open connection with logging disabled.
+ # - Record log files existing. Verify we don't keep adding.
+ #
+ self.populate_table(self.t1)
+ self.populate_table(self.t2)
+ self.populate_table(self.t3)
+ self.copy_dir(".", "RESTART")
+ self.run_toggle(".")
+ self.run_toggle("RESTART")
+
+if __name__ == '__main__':
+ wttest.run()