summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Hows <david.hows@mongodb.com>2017-01-23 16:05:51 +1100
committerDavid Hows <david.hows@mongodb.com>2017-01-23 16:06:16 +1100
commit48a3cbc17fa902528217287fd075c87efb44aebc (patch)
treefff4f814ab9fbd7f3eb4c45684f581a5da1c058c
parent8d2324943364286056ae399043f70b8a937de312 (diff)
parentbf8de9767982da9ae0f1542f3744c8aa8544fb82 (diff)
downloadmongo-48a3cbc17fa902528217287fd075c87efb44aebc.tar.gz
Merge branch 'develop' into mongodb-3.6mongodb-3.5.3mongodb-3.5.2
-rw-r--r--NEWS50
-rw-r--r--README6
-rw-r--r--RELEASE_INFO2
-rw-r--r--SConstruct1
-rw-r--r--bench/wtperf/config.c87
-rw-r--r--bench/wtperf/runners/500m-btree-50r50u.wtperf2
-rw-r--r--bench/wtperf/runners/500m-btree-80r20u.wtperf2
-rw-r--r--bench/wtperf/runners/500m-btree-populate.wtperf2
-rw-r--r--bench/wtperf/runners/500m-btree-rdonly.wtperf2
-rw-r--r--bench/wtperf/runners/checkpoint-stress.wtperf2
-rw-r--r--bench/wtperf/runners/evict-btree-1.wtperf2
-rw-r--r--bench/wtperf/runners/evict-btree-readonly.wtperf2
-rw-r--r--bench/wtperf/runners/evict-btree-stress-multi.wtperf2
-rw-r--r--bench/wtperf/runners/evict-btree-stress.wtperf2
-rw-r--r--bench/wtperf/runners/evict-btree.wtperf2
-rw-r--r--bench/wtperf/runners/evict-lsm-1.wtperf2
-rw-r--r--bench/wtperf/runners/evict-lsm-readonly.wtperf2
-rw-r--r--bench/wtperf/runners/evict-lsm.wtperf2
-rw-r--r--bench/wtperf/runners/log.wtperf2
-rw-r--r--bench/wtperf/runners/mongodb-secondary-apply.wtperf2
-rw-r--r--bench/wtperf/runners/multi-btree-read-heavy-stress.wtperf2
-rw-r--r--bench/wtperf/runners/multi-btree-stress.wtperf2
-rw-r--r--bench/wtperf/runners/multi-btree-zipfian-populate.wtperf2
-rw-r--r--bench/wtperf/runners/multi-btree-zipfian-workload.wtperf2
-rw-r--r--bench/wtperf/stress/btree-split-stress.wtperf2
-rw-r--r--bench/wtperf/wtperf.c120
-rw-r--r--build_posix/Make.base1
-rw-r--r--build_posix/aclocal/options.m42
-rw-r--r--build_posix/aclocal/version-set.m44
-rw-r--r--build_posix/aclocal/version.m42
-rw-r--r--build_posix/configure.ac.in8
-rw-r--r--dist/api_data.py3
-rw-r--r--dist/flags.py1
-rw-r--r--dist/package/wiredtiger.spec2
-rwxr-xr-xdist/s_all19
-rwxr-xr-xdist/s_docs3
-rw-r--r--dist/s_funcs.list1
-rw-r--r--dist/s_string.ok3
-rw-r--r--dist/stat_data.py5
-rw-r--r--lang/python/Makefile.am3
-rw-r--r--src/block/block_write.c4
-rw-r--r--src/btree/bt_curnext.c4
-rw-r--r--src/btree/bt_curprev.c8
-rw-r--r--src/btree/bt_cursor.c15
-rw-r--r--src/btree/bt_debug.c13
-rw-r--r--src/btree/bt_delete.c7
-rw-r--r--src/btree/bt_discard.c9
-rw-r--r--src/btree/bt_handle.c3
-rw-r--r--src/btree/bt_ovfl.c8
-rw-r--r--src/btree/bt_page.c28
-rw-r--r--src/btree/bt_rebalance.c2
-rw-r--r--src/btree/bt_ret.c4
-rw-r--r--src/btree/bt_slvg.c31
-rw-r--r--src/btree/bt_split.c6
-rw-r--r--src/btree/bt_stat.c5
-rw-r--r--src/btree/bt_vrfy.c8
-rw-r--r--src/btree/col_modify.c5
-rw-r--r--src/btree/col_srch.c7
-rw-r--r--src/btree/row_key.c12
-rw-r--r--src/btree/row_modify.c9
-rw-r--r--src/btree/row_srch.c24
-rw-r--r--src/config/config_def.c45
-rw-r--r--src/conn/conn_api.c25
-rw-r--r--src/conn/conn_cache.c3
-rw-r--r--src/conn/conn_dhandle.c2
-rw-r--r--src/conn/conn_handle.c3
-rw-r--r--src/conn/conn_log.c26
-rw-r--r--src/conn/conn_sweep.c8
-rw-r--r--src/cursor/cur_backup.c16
-rw-r--r--src/cursor/cur_index.c4
-rw-r--r--src/cursor/cur_json.c16
-rw-r--r--src/cursor/cur_log.c4
-rw-r--r--src/cursor/cur_std.c1
-rw-r--r--src/cursor/cur_table.c2
-rw-r--r--src/docs/Doxyfile8
-rwxr-xr-xsrc/docs/build-pydoc.sh2
-rw-r--r--src/docs/command-line.dox13
-rw-r--r--src/docs/file-formats.dox6
-rw-r--r--src/docs/programming.dox3
-rw-r--r--src/docs/spell.ok2
-rw-r--r--src/docs/testing.dox2
-rw-r--r--src/docs/top/main.dox8
-rw-r--r--src/docs/transactions.dox2
-rw-r--r--src/docs/tune-compression.dox62
-rw-r--r--src/docs/tune-page-size-and-comp.dox426
-rw-r--r--src/docs/tune-page-sizes.dox142
-rw-r--r--src/docs/upgrading.dox28
-rw-r--r--src/evict/evict_lru.c473
-rw-r--r--src/include/btmem.h110
-rw-r--r--src/include/btree.h3
-rw-r--r--src/include/btree.i50
-rw-r--r--src/include/column.i23
-rw-r--r--src/include/connection.h17
-rw-r--r--src/include/cursor.h4
-rw-r--r--src/include/dhandle.h2
-rw-r--r--src/include/extern.h27
-rw-r--r--src/include/flags.h19
-rw-r--r--src/include/log.h2
-rw-r--r--src/include/lsm.h2
-rw-r--r--src/include/mutex.h18
-rw-r--r--src/include/mutex.i19
-rw-r--r--src/include/schema.h2
-rw-r--r--src/include/stat.h5
-rw-r--r--src/include/thread_group.h2
-rw-r--r--src/include/txn.h4
-rw-r--r--src/include/verify_build.h1
-rw-r--r--src/include/wiredtiger.in526
-rw-r--r--src/include/wt_internal.h6
-rw-r--r--src/log/log.c26
-rw-r--r--src/lsm/lsm_cursor.c2
-rw-r--r--src/lsm/lsm_tree.c10
-rw-r--r--src/os_posix/os_yield.c8
-rw-r--r--src/os_win/os_yield.c8
-rw-r--r--src/reconcile/rec_track.c8
-rw-r--r--src/reconcile/rec_write.c9
-rw-r--r--src/schema/schema_util.c6
-rw-r--r--src/session/session_api.c4
-rw-r--r--src/session/session_dhandle.c21
-rw-r--r--src/support/mtx_rw.c93
-rw-r--r--src/support/stat.c20
-rw-r--r--src/support/thread_group.c83
-rw-r--r--src/txn/txn.c22
-rw-r--r--src/txn/txn_ckpt.c10
-rw-r--r--src/txn/txn_log.c16
-rw-r--r--src/txn/txn_nsnap.c12
-rw-r--r--src/txn/txn_recover.c2
-rw-r--r--src/utilities/util.h1
-rw-r--r--src/utilities/util_dump.c212
-rw-r--r--src/utilities/util_main.c5
-rw-r--r--src/utilities/util_truncate.c51
-rw-r--r--test/format/config.c104
-rw-r--r--test/format/config.h18
-rw-r--r--test/format/format.h1
-rw-r--r--test/recovery/random-abort.c27
-rw-r--r--test/recovery/truncated-log.c4
-rw-r--r--test/suite/run.py3
-rw-r--r--test/suite/test_async01.py2
-rw-r--r--test/suite/test_async02.py2
-rw-r--r--test/suite/test_backup03.py2
-rw-r--r--test/suite/test_backup04.py2
-rw-r--r--test/suite/test_bug011.py2
-rw-r--r--test/suite/test_collator.py32
-rw-r--r--test/suite/test_compress01.py20
-rw-r--r--test/suite/test_config03.py2
-rw-r--r--test/suite/test_cursor07.py2
-rw-r--r--test/suite/test_cursor08.py20
-rw-r--r--test/suite/test_dump.py54
-rw-r--r--test/suite/test_encrypt01.py39
-rw-r--r--test/suite/test_encrypt02.py48
-rw-r--r--test/suite/test_encrypt03.py37
-rw-r--r--test/suite/test_encrypt04.py43
-rw-r--r--test/suite/test_encrypt05.py39
-rw-r--r--test/suite/test_encrypt06.py39
-rw-r--r--test/suite/test_encrypt07.py35
-rw-r--r--test/suite/test_intpack.py4
-rw-r--r--test/suite/test_join01.py2
-rw-r--r--test/suite/test_join03.py30
-rw-r--r--test/suite/test_join04.py30
-rw-r--r--test/suite/test_join07.py30
-rw-r--r--test/suite/test_jsondump02.py18
-rw-r--r--test/suite/test_lsm01.py2
-rw-r--r--test/suite/test_perf001.py3
-rw-r--r--test/suite/test_readonly01.py3
-rw-r--r--test/suite/test_reconfig01.py12
-rw-r--r--test/suite/test_reconfig02.py1
-rw-r--r--test/suite/test_schema05.py30
-rw-r--r--test/suite/test_schema07.py3
-rw-r--r--test/suite/test_stat02.py2
-rw-r--r--test/suite/test_truncate01.py9
-rw-r--r--test/suite/test_truncate02.py3
-rw-r--r--test/suite/test_txn02.py26
-rw-r--r--test/suite/test_txn04.py22
-rw-r--r--test/suite/test_txn05.py28
-rw-r--r--test/suite/test_txn06.py4
-rw-r--r--test/suite/test_txn07.py56
-rw-r--r--test/suite/test_txn08.py2
-rw-r--r--test/suite/test_txn09.py17
-rw-r--r--test/suite/test_txn11.py2
-rw-r--r--test/suite/test_txn13.py2
-rw-r--r--test/suite/test_txn15.py2
-rw-r--r--test/suite/test_util14.py92
-rw-r--r--test/suite/test_util15.py71
-rw-r--r--test/suite/test_util16.py71
-rw-r--r--test/suite/test_util17.py57
-rw-r--r--test/suite/wtdataset.py92
-rw-r--r--test/suite/wttest.py85
-rw-r--r--test/wtperf/test_conf_dump.py296
-rw-r--r--tools/wtstats/stat_data.py4
188 files changed, 3362 insertions, 1704 deletions
diff --git a/NEWS b/NEWS
index bdc84ed6ef5..268949b119f 100644
--- a/NEWS
+++ b/NEWS
@@ -1,3 +1,53 @@
+WiredTiger release 2.9.1, 2016-12-22
+------------------------------------
+
+New features and API changes; refer to the API documentation for full details:
+
+* SERVER-26545 Remove fixed-size limitation on WiredTiger hazard pointers. See the upgrading documentation for details
+* WT-283 Add a new WT_SESSION::alter method that can be used to reconfigure table metadata
+* WT-2670 Change the default file system access pattern advice for data files from random to no advice. Add access_pattern_hint configuration option for WT_SESSION::create API that can be used to advise the file system of expected access semantics. See the upgrading documentation for details.
+* WT-3034 Add support for including updates when reading from named snapshots
+
+Significant changes and bug fixes:
+
+* WT-2960 Reduce likelihood of using the lookaside file, especially when inserting multi-megabyte values
+* WT-3056 Allow projected table and join cursors to use primary keys
+* WT-3070 Fix a bug in search_near on indexes
+
+Other noteworthy changes since the previous release:
+
+* WT-2336 Add a test validating schema operations via file system call monitoring
+* WT-2402 Pad structures to avoid cache line sharing
+* WT-2771 Add a statistic to track per-btree dirty cache usage
+* WT-2833 Add projections to wt dump utility
+* WT-2969 Possible snapshot corruption during compaction
+* WT-3014 Add GCC/clang support for ELF symbol visibility
+* WT-3021 Fixes for java log example, raw mode in java, and raw mode in log cursors
+* WT-3025 Fix error path in log_force_sync
+* WT-3028 Don't check for blocked eviction with in-memory workloads
+* WT-3030 Fix a race between scans and splits reading the index hint
+* WT-3037 Clean up some log slot comments
+* WT-3048 WiredTiger maximum size warning uses the wrong format
+* WT-3051 Remove external __wt_hex symbol
+* WT-3052 Improve search if index hint is wrong
+* WT-3053 Make Python use internal memory allocation again
+* WT-3054 Make a PackOutputStream constructor that is compatible with the previous interface.
+* WT-3055 When an AsyncOp is created, cache the whether the cursor is "raw"
+* WT-3057 WiredTiger hazard pointers should use the WT_REF, not the WT_PAGE
+* WT-3061 Syscall testing should support pwrite64 on Linux
+* WT-3064 Minor tree cleanups: .gitignore, NEWS misspelling
+* WT-3066 Minor code cleanups
+* WT-3068 Copy artifacts of test runs in wtperf_run script
+* WT-3068 Have Jenkins include specific files for copy rather than exclude
+* WT-3069 Fix LevelDB APIs build failures
+* WT-3071 Fixed sign-conversion compiler errors in Java and Python SWIG code
+* WT-3075 Document and enforce that WiredTiger now depends on Python 2.7
+* WT-3078 Test reconfiguration hang in the statlog server
+* WT-3080 Python test suite: add elapsed time for tests
+* WT-3082 Python test suite: shorten default run to avoid timeouts
+* WT-3084 Fix Coverity resource leak complaint
+* WT-3091 Add stats to test_perf001 test, so we can investigate what happened when it failed
+
WiredTiger release 2.9.0, 2016-09-06
------------------------------------
diff --git a/README b/README
index 55e9058826a..f7edae2835d 100644
--- a/README
+++ b/README
@@ -1,6 +1,6 @@
-WiredTiger 2.9.1: (December 7, 2016)
+WiredTiger 2.9.2: (December 23, 2016)
-This is version 2.9.1 of WiredTiger.
+This is version 2.9.2 of WiredTiger.
WiredTiger release packages and documentation can be found at:
@@ -8,7 +8,7 @@ WiredTiger release packages and documentation can be found at:
The documentation for this specific release can be found at:
- http://source.wiredtiger.com/2.9.1/index.html
+ http://source.wiredtiger.com/2.9.2/index.html
The WiredTiger source code can be found at:
diff --git a/RELEASE_INFO b/RELEASE_INFO
index 502b17188ce..b7145aa2cb3 100644
--- a/RELEASE_INFO
+++ b/RELEASE_INFO
@@ -1,6 +1,6 @@
WIREDTIGER_VERSION_MAJOR=2
WIREDTIGER_VERSION_MINOR=9
-WIREDTIGER_VERSION_PATCH=1
+WIREDTIGER_VERSION_PATCH=2
WIREDTIGER_VERSION="$WIREDTIGER_VERSION_MAJOR.$WIREDTIGER_VERSION_MINOR.$WIREDTIGER_VERSION_PATCH"
WIREDTIGER_RELEASE_DATE=`date "+%B %e, %Y"`
diff --git a/SConstruct b/SConstruct
index df7a66238e8..e9e72630b11 100644
--- a/SConstruct
+++ b/SConstruct
@@ -313,6 +313,7 @@ wtbin = env.Program("wt", [
"src/utilities/util_rename.c",
"src/utilities/util_salvage.c",
"src/utilities/util_stat.c",
+ "src/utilities/util_truncate.c",
"src/utilities/util_upgrade.c",
"src/utilities/util_verbose.c",
"src/utilities/util_verify.c",
diff --git a/bench/wtperf/config.c b/bench/wtperf/config.c
index 5b14a4cdf68..a15a3485dde 100644
--- a/bench/wtperf/config.c
+++ b/bench/wtperf/config.c
@@ -622,17 +622,9 @@ config_opt_str(WTPERF *wtperf, const char *optstr)
return (ret);
}
- /*
- * Append the current line to our copy of the config. The config is
- * stored in the order it is processed, so added options will be after
- * any parsed from the original config. We allocate len + 1 to allow for
- * a null byte to be added.
- */
- config_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1);
- config_line->string = dstrdup(optstr);
- TAILQ_INSERT_TAIL(&opts->config_head, config_line, q);
-
while (ret == 0) {
+ size_t pos;
+
if ((ret = scan->next(scan, &k, &v)) != 0) {
/* Any parse error has already been reported. */
if (ret == WT_NOTFOUND)
@@ -640,6 +632,46 @@ config_opt_str(WTPERF *wtperf, const char *optstr)
break;
}
ret = config_opt(wtperf, &k, &v);
+
+ /*
+ * Append the key-value pair to our copy of the config.
+ * The config is stored in the order it is processed, so added
+ * options will be after any parsed from the original config.
+ */
+ config_line = dcalloc(sizeof(CONFIG_QUEUE_ENTRY), 1);
+ /*
+ * If key or value is a string, consider extra space for the
+ * quotes. Add 2 to the required space for '=' and the ending
+ * null character in "key=value".
+ */
+ config_line->string = dcalloc(
+ k.len + (k.type == WT_CONFIG_ITEM_STRING ? 2 : 0) +
+ v.len + (v.type == WT_CONFIG_ITEM_STRING ? 2 : 0) + 2, 1);
+ pos = 0;
+ if (k.type == WT_CONFIG_ITEM_STRING) {
+ config_line->string[pos] = '"';
+ pos++;
+ }
+ strncpy(config_line->string + pos, k.str, k.len);
+ pos += k.len;
+ if (k.type == WT_CONFIG_ITEM_STRING) {
+ config_line->string[pos] = '"';
+ pos++;
+ }
+ config_line->string[pos] = '=';
+ pos++;
+ if (v.type == WT_CONFIG_ITEM_STRING) {
+ config_line->string[pos] = '"';
+ pos++;
+ }
+ strncpy(config_line->string + pos, v.str, v.len);
+ pos += v.len;
+ if (v.type == WT_CONFIG_ITEM_STRING) {
+ config_line->string[pos] = '"';
+ pos++;
+ }
+ config_line->string[pos] = '\0';
+ TAILQ_INSERT_TAIL(&opts->config_head, config_line, q);
}
if ((t_ret = scan->close(scan)) != 0) {
lprintf(wtperf, ret, 0, "Error in config_scan_end");
@@ -754,8 +786,11 @@ config_consolidate(CONFIG_OPTS *opts)
/*
* This loop iterates over the config queue and for each entry checks if
- * a later queue entry has the same key. If there's a match, the current
- * queue entry is removed and we continue.
+ * a later queue entry has the same key. If there's a match, and key is
+ * "conn_config" or "table_config", the later queue entry is replaced
+ * with a concatenated entry of the two queue entries, the current queue
+ * entry is removed. For any other key, if there is a match, the current
+ * queue entry is removed.
*/
conf_line = TAILQ_FIRST(&opts->config_head);
while (conf_line != NULL) {
@@ -771,6 +806,34 @@ config_consolidate(CONFIG_OPTS *opts)
if (strncmp(conf_line->string, test_line->string,
(size_t)((string_key - conf_line->string) + 1))
== 0) {
+ if ((strncmp("conn_config=", conf_line->string,
+ (size_t)((string_key - conf_line->string) +
+ 1)) == 0) ||
+ (strncmp("table_config=", conf_line->string,
+ (size_t)((string_key - conf_line->string) +
+ 1)) == 0)) {
+ char *concat_str, *val_pointer;
+
+ /*
+ * To concatenate the two config
+ * strings, copy the first string to a
+ * new one, replace the ending '"' with
+ * a ',' and then concatenate the second
+ * string's value after its starting '"'
+ */
+ val_pointer =
+ strchr(test_line->string, '=') + 2;
+ concat_str =
+ dmalloc(strlen(conf_line->string) +
+ strlen(val_pointer) + 1);
+ strcpy(concat_str, conf_line->string);
+ concat_str[strlen(concat_str) - 1] =
+ ',';
+ strcat(concat_str, val_pointer);
+ free(test_line->string);
+ test_line->string = concat_str;
+ }
+
TAILQ_REMOVE(&opts->config_head, conf_line, q);
free(conf_line->string);
free(conf_line);
diff --git a/bench/wtperf/runners/500m-btree-50r50u.wtperf b/bench/wtperf/runners/500m-btree-50r50u.wtperf
index 536127f0dd8..4d2a70f1107 100644
--- a/bench/wtperf/runners/500m-btree-50r50u.wtperf
+++ b/bench/wtperf/runners/500m-btree-50r50u.wtperf
@@ -5,7 +5,7 @@
#
# Set cache to half of memory of AWS perf instance. Enable logging and
# checkpoints. Collect wiredtiger stats for ftdc.
-conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=4)"
+conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=8)"
create=false
compression="snappy"
sess_config="isolation=snapshot"
diff --git a/bench/wtperf/runners/500m-btree-80r20u.wtperf b/bench/wtperf/runners/500m-btree-80r20u.wtperf
index d6218c44af0..6645df835df 100644
--- a/bench/wtperf/runners/500m-btree-80r20u.wtperf
+++ b/bench/wtperf/runners/500m-btree-80r20u.wtperf
@@ -5,7 +5,7 @@
#
# Set cache to half of memory of AWS perf instance. Enable logging and
# checkpoints. Collect wiredtiger stats for ftdc.
-conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=4)"
+conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=8)"
create=false
compression="snappy"
# close_conn as false allows this test to close/finish faster, but if running
diff --git a/bench/wtperf/runners/500m-btree-populate.wtperf b/bench/wtperf/runners/500m-btree-populate.wtperf
index f9aed094aa1..ab7b17ca683 100644
--- a/bench/wtperf/runners/500m-btree-populate.wtperf
+++ b/bench/wtperf/runners/500m-btree-populate.wtperf
@@ -9,7 +9,7 @@
#
# This generates about 80 Gb of uncompressed data. But it should compress
# well and be small on disk.
-conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=4)"
+conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=8)"
compact=true
compression="snappy"
sess_config="isolation=snapshot"
diff --git a/bench/wtperf/runners/500m-btree-rdonly.wtperf b/bench/wtperf/runners/500m-btree-rdonly.wtperf
index 2c9540ff589..e8958d20e2c 100644
--- a/bench/wtperf/runners/500m-btree-rdonly.wtperf
+++ b/bench/wtperf/runners/500m-btree-rdonly.wtperf
@@ -5,7 +5,7 @@
#
# Set cache to half of memory of AWS perf instance. Enable logging and
# checkpoints. Collect wiredtiger stats for ftdc.
-conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=4)"
+conn_config="cache_size=16G,checkpoint=(wait=60,log_size=2GB),session_max=20000,log=(enabled),statistics=(fast),statistics_log=(wait=30,json),eviction=(threads_max=8)"
create=false
compression="snappy"
sess_config="isolation=snapshot"
diff --git a/bench/wtperf/runners/checkpoint-stress.wtperf b/bench/wtperf/runners/checkpoint-stress.wtperf
index bbd3a3ba5ed..5daa276e622 100644
--- a/bench/wtperf/runners/checkpoint-stress.wtperf
+++ b/bench/wtperf/runners/checkpoint-stress.wtperf
@@ -1,6 +1,6 @@
# A stress configuration to create long running checkpoints while doing a lot
# of updates.
-conn_config="cache_size=16GB,eviction=(threads_max=4),log=(enabled=false)"
+conn_config="cache_size=16GB,eviction=(threads_max=8),log=(enabled=false)"
table_config="leaf_page_max=32k,internal_page_max=16k,allocation_size=4k,split_pct=90,type=file"
# Enough data to fill the cache. 150 million 1k records results in two ~11GB
# tables
diff --git a/bench/wtperf/runners/evict-btree-1.wtperf b/bench/wtperf/runners/evict-btree-1.wtperf
index 24da4dd7902..741101d083f 100644
--- a/bench/wtperf/runners/evict-btree-1.wtperf
+++ b/bench/wtperf/runners/evict-btree-1.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict btree configuration
-conn_config="cache_size=50M"
+conn_config="cache_size=50M,eviction=(threads_max=1)"
table_config="type=file"
icount=10000000
report_interval=5
diff --git a/bench/wtperf/runners/evict-btree-readonly.wtperf b/bench/wtperf/runners/evict-btree-readonly.wtperf
index 25599fadd8d..972bc371f2d 100644
--- a/bench/wtperf/runners/evict-btree-readonly.wtperf
+++ b/bench/wtperf/runners/evict-btree-readonly.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict btree configuration
-conn_config="cache_size=50M,eviction=(threads_max=4),mmap=false"
+conn_config="cache_size=50M,eviction=(threads_max=8),mmap=false"
table_config="type=file"
icount=10000000
report_interval=5
diff --git a/bench/wtperf/runners/evict-btree-stress-multi.wtperf b/bench/wtperf/runners/evict-btree-stress-multi.wtperf
index a5a29f66fa0..5a2cad6d78e 100644
--- a/bench/wtperf/runners/evict-btree-stress-multi.wtperf
+++ b/bench/wtperf/runners/evict-btree-stress-multi.wtperf
@@ -1,4 +1,4 @@
-conn_config="cache_size=1G,eviction=(threads_max=4),session_max=2000"
+conn_config="cache_size=1G,eviction=(threads_max=8),session_max=2000"
table_config="type=file"
table_count=100
close_conn=false
diff --git a/bench/wtperf/runners/evict-btree-stress.wtperf b/bench/wtperf/runners/evict-btree-stress.wtperf
index 740fb88c050..96e3f01b325 100644
--- a/bench/wtperf/runners/evict-btree-stress.wtperf
+++ b/bench/wtperf/runners/evict-btree-stress.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict btree configuration
-conn_config="cache_size=50M,eviction=(threads_max=4)"
+conn_config="cache_size=50M,eviction=(threads_max=8)"
table_config="type=file"
icount=10000000
report_interval=5
diff --git a/bench/wtperf/runners/evict-btree.wtperf b/bench/wtperf/runners/evict-btree.wtperf
index e7d967e5c63..3810e6a8294 100644
--- a/bench/wtperf/runners/evict-btree.wtperf
+++ b/bench/wtperf/runners/evict-btree.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict btree configuration
-conn_config="cache_size=50M,eviction=(threads_max=4)"
+conn_config="cache_size=50M,eviction=(threads_max=8)"
table_config="type=file"
icount=10000000
report_interval=5
diff --git a/bench/wtperf/runners/evict-lsm-1.wtperf b/bench/wtperf/runners/evict-lsm-1.wtperf
index ad885d98eb7..641a85dc889 100644
--- a/bench/wtperf/runners/evict-lsm-1.wtperf
+++ b/bench/wtperf/runners/evict-lsm-1.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict lsm configuration
-conn_config="cache_size=50M,lsm_manager=(worker_thread_max=6)"
+conn_config="cache_size=50M,eviction=(threads_max=1),lsm_manager=(worker_thread_max=6)"
table_config="type=lsm,lsm=(chunk_size=2M),os_cache_dirty_max=16MB"
compact=true
icount=10000000
diff --git a/bench/wtperf/runners/evict-lsm-readonly.wtperf b/bench/wtperf/runners/evict-lsm-readonly.wtperf
index 661b8e21924..470dca695dd 100644
--- a/bench/wtperf/runners/evict-lsm-readonly.wtperf
+++ b/bench/wtperf/runners/evict-lsm-readonly.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict lsm configuration
-conn_config="cache_size=50M,lsm_manager=(worker_thread_max=6),eviction=(threads_max=4)"
+conn_config="cache_size=50M,lsm_manager=(worker_thread_max=6),eviction=(threads_max=8)"
table_config="type=lsm,lsm=(chunk_size=2M),os_cache_dirty_max=16MB"
compact=true
icount=10000000
diff --git a/bench/wtperf/runners/evict-lsm.wtperf b/bench/wtperf/runners/evict-lsm.wtperf
index b872d429046..a0f2a78d013 100644
--- a/bench/wtperf/runners/evict-lsm.wtperf
+++ b/bench/wtperf/runners/evict-lsm.wtperf
@@ -1,5 +1,5 @@
# wtperf options file: evict lsm configuration
-conn_config="cache_size=50M,lsm_manager=(worker_thread_max=6),eviction=(threads_max=4)"
+conn_config="cache_size=50M,lsm_manager=(worker_thread_max=6),eviction=(threads_max=8)"
table_config="type=lsm,lsm=(chunk_size=2M),os_cache_dirty_max=16MB"
compact=true
icount=10000000
diff --git a/bench/wtperf/runners/log.wtperf b/bench/wtperf/runners/log.wtperf
index 6cf50dfb5a5..4379ba22373 100644
--- a/bench/wtperf/runners/log.wtperf
+++ b/bench/wtperf/runners/log.wtperf
@@ -16,7 +16,7 @@
# - Config + "-C "checkpoint=(wait=0)": no checkpoints
# - Config + "-C "log=(enabled,prealloc=false,file_max=1M)": no pre-allocation
#
-conn_config="cache_size=5G,log=(enabled=true),checkpoint=(log_size=500M),eviction=(threads_max=4)"
+conn_config="cache_size=5G,log=(enabled=true),checkpoint=(log_size=500M),eviction=(threads_max=8)"
table_config="type=file"
icount=1000000
report_interval=5
diff --git a/bench/wtperf/runners/mongodb-secondary-apply.wtperf b/bench/wtperf/runners/mongodb-secondary-apply.wtperf
index f9e41184f95..58bd1a76b97 100644
--- a/bench/wtperf/runners/mongodb-secondary-apply.wtperf
+++ b/bench/wtperf/runners/mongodb-secondary-apply.wtperf
@@ -1,5 +1,5 @@
# Simulate the MongoDB oplog apply threads on a secondary.
-conn_config="cache_size=10GB,session_max=1000,eviction=(threads_min=4,threads_max=4),log=(enabled=false),transaction_sync=(enabled=false),checkpoint_sync=true,checkpoint=(wait=60),statistics=(fast),statistics_log=(json,wait=1)"
+conn_config="cache_size=10GB,session_max=1000,eviction=(threads_min=4,threads_max=8),log=(enabled=false),transaction_sync=(enabled=false),checkpoint_sync=true,checkpoint=(wait=60),statistics=(fast),statistics_log=(json,wait=1)"
table_config="allocation_size=4k,memory_page_max=5MB,prefix_compression=false,split_pct=75,leaf_page_max=32k,internal_page_max=16k,type=file"
# Spread the workload out over several tables.
table_count=4
diff --git a/bench/wtperf/runners/multi-btree-read-heavy-stress.wtperf b/bench/wtperf/runners/multi-btree-read-heavy-stress.wtperf
index d7b27f8fda4..f07e6c80b39 100644
--- a/bench/wtperf/runners/multi-btree-read-heavy-stress.wtperf
+++ b/bench/wtperf/runners/multi-btree-read-heavy-stress.wtperf
@@ -2,7 +2,7 @@
# up by dividing the workload across a lot of threads. This needs to be
# tuned to the particular machine so the workload is close to capacity in the
# steady state, but not overwhelming.
-conn_config="cache_size=20GB,session_max=1000,eviction=(threads_min=4,threads_max=4),log=(enabled=false),transaction_sync=(enabled=false),checkpoint_sync=true,checkpoint=(wait=60),statistics=(fast),statistics_log=(json,wait=1)"
+conn_config="cache_size=20GB,session_max=1000,eviction=(threads_min=4,threads_max=8),log=(enabled=false),transaction_sync=(enabled=false),checkpoint_sync=true,checkpoint=(wait=60),statistics=(fast),statistics_log=(json,wait=1)"
table_config="allocation_size=4k,memory_page_max=10MB,prefix_compression=false,split_pct=90,leaf_page_max=32k,internal_page_max=16k,type=file"
# Divide original icount by database_count.
table_count=8
diff --git a/bench/wtperf/runners/multi-btree-stress.wtperf b/bench/wtperf/runners/multi-btree-stress.wtperf
index b10b08f6035..bee1f431043 100644
--- a/bench/wtperf/runners/multi-btree-stress.wtperf
+++ b/bench/wtperf/runners/multi-btree-stress.wtperf
@@ -1,7 +1,7 @@
# wtperf options file: multi-database configuration attempting to
# trigger slow operations by overloading CPU and disk.
# References Jira WT-2131
-conn_config="cache_size=2GB,eviction=(threads_min=2,threads_max=2),log=(enabled=false),direct_io=(data,checkpoint),buffer_alignment=4096,checkpoint_sync=true,checkpoint=(wait=60)"
+conn_config="cache_size=2GB,eviction=(threads_min=2,threads_max=8),log=(enabled=false),direct_io=(data,checkpoint),buffer_alignment=4096,checkpoint_sync=true,checkpoint=(wait=60)"
table_config="allocation_size=4k,prefix_compression=false,split_pct=75,leaf_page_max=4k,internal_page_max=16k,leaf_item_max=1433,internal_item_max=3100,type=file"
# Divide original icount by database_count.
database_count=5
diff --git a/bench/wtperf/runners/multi-btree-zipfian-populate.wtperf b/bench/wtperf/runners/multi-btree-zipfian-populate.wtperf
index ddd9c055eac..1fdba049779 100644
--- a/bench/wtperf/runners/multi-btree-zipfian-populate.wtperf
+++ b/bench/wtperf/runners/multi-btree-zipfian-populate.wtperf
@@ -1,5 +1,5 @@
# Create a set of tables with uneven distribution of data
-conn_config="cache_size=1G,eviction=(threads_max=4),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics=(fast),statistics_log=(wait=5,json),session_max=1000"
+conn_config="cache_size=1G,eviction=(threads_max=8),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics=(fast),statistics_log=(wait=5,json),session_max=1000"
table_config="type=file"
table_count=100
icount=0
diff --git a/bench/wtperf/runners/multi-btree-zipfian-workload.wtperf b/bench/wtperf/runners/multi-btree-zipfian-workload.wtperf
index 380350c88c8..dfb3306a7a5 100644
--- a/bench/wtperf/runners/multi-btree-zipfian-workload.wtperf
+++ b/bench/wtperf/runners/multi-btree-zipfian-workload.wtperf
@@ -1,5 +1,5 @@
# Read from a set of tables with uneven distribution of data
-conn_config="cache_size=1G,eviction=(threads_max=4),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics=(fast),statistics_log=(wait=5,json),session_max=1000"
+conn_config="cache_size=1G,eviction=(threads_max=8),file_manager=(close_idle_time=100000),checkpoint=(wait=60,log_size=2GB),statistics=(fast),statistics_log=(wait=5,json),session_max=1000"
table_config="type=file"
table_count=100
icount=0
diff --git a/bench/wtperf/stress/btree-split-stress.wtperf b/bench/wtperf/stress/btree-split-stress.wtperf
index deb8c70d12f..86bb288fc6d 100644
--- a/bench/wtperf/stress/btree-split-stress.wtperf
+++ b/bench/wtperf/stress/btree-split-stress.wtperf
@@ -1,4 +1,4 @@
-conn_config="cache_size=2GB,statistics=[fast,clear],statistics_log=(wait=10),eviction=(threads_max=4,threads_min=4)"
+conn_config="cache_size=2GB,statistics=[fast,clear],statistics_log=(wait=10),eviction=(threads_max=8,threads_min=4)"
table_config="type=file,leaf_page_max=8k,internal_page_max=8k,memory_page_max=2MB,split_deepen_min_child=250"
icount=200000
report_interval=5
diff --git a/bench/wtperf/wtperf.c b/bench/wtperf/wtperf.c
index 8c7f0053388..baa259f8817 100644
--- a/bench/wtperf/wtperf.c
+++ b/bench/wtperf/wtperf.c
@@ -2361,11 +2361,11 @@ main(int argc, char *argv[])
{
CONFIG_OPTS *opts;
WTPERF *wtperf, _wtperf;
- size_t req_len, sreq_len;
+ size_t pos, req_len, sreq_len;
bool monitor_set;
int ch, ret;
const char *cmdflags = "C:h:m:O:o:T:";
- const char *config_opts;
+ const char *append_comma, *config_opts;
char *cc_buf, *path, *sess_cfg, *tc_buf, *user_cconfig, *user_tconfig;
/* The first WTPERF structure (from which all others are derived). */
@@ -2502,53 +2502,101 @@ main(int argc, char *argv[])
__wt_stream_set_line_buffer(stdout);
/* Concatenate non-default configuration strings. */
- if (opts->verbose > 1 || user_cconfig != NULL ||
- opts->session_count_idle > 0 || wtperf->compress_ext != NULL ||
- wtperf->async_config != NULL) {
- req_len = strlen(debug_cconfig) + 20;
- if (user_cconfig != NULL)
- req_len += strlen(user_cconfig);
- if (wtperf->async_config != NULL)
- req_len += strlen(wtperf->async_config);
- if (wtperf->compress_ext != NULL)
- req_len += strlen(wtperf->compress_ext);
+ if ((opts->verbose > 1 && strlen(debug_cconfig) != 0) ||
+ user_cconfig != NULL || opts->session_count_idle > 0 ||
+ wtperf->compress_ext != NULL || wtperf->async_config != NULL) {
+ req_len = 20;
+ req_len += wtperf->async_config != NULL ?
+ strlen(wtperf->async_config) : 0;
+ req_len += wtperf->compress_ext != NULL ?
+ strlen(wtperf->compress_ext) : 0;
if (opts->session_count_idle > 0) {
- sreq_len = strlen(",session_max=") + 6;
+ sreq_len = strlen("session_max=") + 6;
req_len += sreq_len;
sess_cfg = dmalloc(sreq_len);
snprintf(sess_cfg, sreq_len,
- ",session_max=%" PRIu32,
+ "session_max=%" PRIu32,
opts->session_count_idle +
wtperf->workers_cnt + opts->populate_threads + 10);
}
+ req_len += user_cconfig != NULL ? strlen(user_cconfig) : 0;
+ req_len += debug_cconfig != NULL ? strlen(debug_cconfig) : 0;
cc_buf = dmalloc(req_len);
- snprintf(cc_buf, req_len, "%s,%s,%s,%s,%s",
- wtperf->async_config ? wtperf->async_config : "",
- wtperf->compress_ext ? wtperf->compress_ext : "",
- opts->verbose > 1 ? debug_cconfig : "",
- sess_cfg != NULL ? sess_cfg : "",
- user_cconfig != NULL ? user_cconfig : "");
- if (strlen(cc_buf) && (ret =
+
+ pos = 0;
+ append_comma = "";
+ if (wtperf->async_config != NULL &&
+ strlen(wtperf->async_config) != 0) {
+ pos += (size_t)snprintf(
+ cc_buf + pos, req_len - pos, "%s%s",
+ append_comma, wtperf->async_config);
+ append_comma = ",";
+ }
+ if (wtperf->compress_ext != NULL &&
+ strlen(wtperf->compress_ext) != 0) {
+ pos += (size_t)snprintf(
+ cc_buf + pos, req_len - pos, "%s%s",
+ append_comma, wtperf->compress_ext);
+ append_comma = ",";
+ }
+ if (sess_cfg != NULL && strlen(sess_cfg) != 0) {
+ pos += (size_t)snprintf(
+ cc_buf + pos, req_len - pos, "%s%s",
+ append_comma, sess_cfg);
+ append_comma = ",";
+ }
+ if (user_cconfig != NULL && strlen(user_cconfig) != 0) {
+ pos += (size_t)snprintf(
+ cc_buf + pos, req_len - pos, "%s%s",
+ append_comma, user_cconfig);
+ append_comma = ",";
+ }
+ if (opts->verbose > 1 && strlen(debug_cconfig) != 0)
+ pos += (size_t)snprintf(
+ cc_buf + pos, req_len - pos, "%s%s",
+ append_comma, debug_cconfig);
+
+ if (strlen(cc_buf) != 0 && (ret =
config_opt_name_value(wtperf, "conn_config", cc_buf)) != 0)
goto err;
}
- if (opts->verbose > 1 || opts->index ||
+ if ((opts->verbose > 1 && strlen(debug_tconfig) != 0) || opts->index ||
user_tconfig != NULL || wtperf->compress_table != NULL) {
- req_len = strlen(debug_tconfig) + 20;
- if (user_tconfig != NULL)
- req_len += strlen(user_tconfig);
- if (wtperf->compress_table != NULL)
- req_len += strlen(wtperf->compress_table);
- if (opts->index)
- req_len += strlen(INDEX_COL_NAMES);
+ req_len = 20;
+ req_len += wtperf->compress_table != NULL ?
+ strlen(wtperf->compress_table) : 0;
+ req_len += opts->index ? strlen(INDEX_COL_NAMES) : 0;
+ req_len += user_tconfig != NULL ? strlen(user_tconfig) : 0;
+ req_len += debug_tconfig != NULL ? strlen(debug_tconfig) : 0;
tc_buf = dmalloc(req_len);
- snprintf(tc_buf, req_len, "%s,%s,%s,%s",
- opts->index ? INDEX_COL_NAMES : "",
- wtperf->compress_table != NULL ?
- wtperf->compress_table : "",
- opts->verbose > 1 ? debug_tconfig : "",
- user_tconfig ? user_tconfig : "");
- if (strlen(tc_buf) && (ret =
+
+ pos = 0;
+ append_comma = "";
+ if (wtperf->compress_table != NULL &&
+ strlen(wtperf->compress_table) != 0) {
+ pos += (size_t)snprintf(
+ tc_buf + pos, req_len - pos, "%s%s",
+ append_comma, wtperf->compress_table);
+ append_comma = ",";
+ }
+ if (opts->index) {
+ pos += (size_t)snprintf(
+ tc_buf + pos, req_len - pos, "%s%s",
+ append_comma, INDEX_COL_NAMES);
+ append_comma = ",";
+ }
+ if (user_tconfig != NULL && strlen(user_tconfig) != 0) {
+ pos += (size_t)snprintf(
+ tc_buf + pos, req_len - pos, "%s%s",
+ append_comma, user_tconfig);
+ append_comma = ",";
+ }
+ if (opts->verbose > 1 && strlen(debug_tconfig) != 0)
+ pos += (size_t)snprintf(
+ tc_buf + pos, req_len - pos, "%s%s",
+ append_comma, debug_tconfig);
+
+ if (strlen(tc_buf) != 0 && (ret =
config_opt_name_value(wtperf, "table_config", tc_buf)) != 0)
goto err;
}
diff --git a/build_posix/Make.base b/build_posix/Make.base
index 9354eb4b183..e5228fac885 100644
--- a/build_posix/Make.base
+++ b/build_posix/Make.base
@@ -36,6 +36,7 @@ wt_SOURCES =\
src/utilities/util_rename.c \
src/utilities/util_salvage.c \
src/utilities/util_stat.c \
+ src/utilities/util_truncate.c \
src/utilities/util_upgrade.c \
src/utilities/util_verbose.c \
src/utilities/util_verify.c \
diff --git a/build_posix/aclocal/options.m4 b/build_posix/aclocal/options.m4
index 7043430a6d6..bc4b31dfee3 100644
--- a/build_posix/aclocal/options.m4
+++ b/build_posix/aclocal/options.m4
@@ -57,7 +57,7 @@ AH_TEMPLATE(
HAVE_CRC32_HARDWARE, [Define to 1 to configure CRC32 hardware support.])
AC_MSG_CHECKING(if --enable-crc32-hardware option specified)
AC_ARG_ENABLE(crc32-hardware,
- AC_HELP_STRING([--enable-crc32-hardware],
+ AS_HELP_STRING([--enable-crc32-hardware],
[Enable CRC32 hardware support.]), r=$enableval, r=yes)
case "$r" in
no) wt_cv_enable_crc32_hardware=no;;
diff --git a/build_posix/aclocal/version-set.m4 b/build_posix/aclocal/version-set.m4
index ecb45b5e73e..c677ce41192 100644
--- a/build_posix/aclocal/version-set.m4
+++ b/build_posix/aclocal/version-set.m4
@@ -2,8 +2,8 @@ dnl build by dist/s_version
VERSION_MAJOR=2
VERSION_MINOR=9
-VERSION_PATCH=1
-VERSION_STRING='"WiredTiger 2.9.1: (December 7, 2016)"'
+VERSION_PATCH=2
+VERSION_STRING='"WiredTiger 2.9.2: (December 23, 2016)"'
AC_SUBST(VERSION_MAJOR)
AC_SUBST(VERSION_MINOR)
diff --git a/build_posix/aclocal/version.m4 b/build_posix/aclocal/version.m4
index a75ba93e405..29782a22f82 100644
--- a/build_posix/aclocal/version.m4
+++ b/build_posix/aclocal/version.m4
@@ -1,2 +1,2 @@
dnl WiredTiger product version for AC_INIT. Maintained by dist/s_version
-2.9.1
+2.9.2
diff --git a/build_posix/configure.ac.in b/build_posix/configure.ac.in
index b7c39b5da8b..0fef587b4b8 100644
--- a/build_posix/configure.ac.in
+++ b/build_posix/configure.ac.in
@@ -91,6 +91,9 @@ fi
# Linux requires _GNU_SOURCE to be defined
AS_CASE([$host_os], [linux*], [AM_CFLAGS="$AM_CFLAGS -D_GNU_SOURCE"])
+# Configure options.
+AM_OPTIONS
+
# If enable-strict is configured, turn on as much error checking as we can for
# this compiler. Intended for developers, and only works for gcc/clang, but it
# fills a need.
@@ -109,9 +112,6 @@ if test "$wt_cv_enable_strict" = "yes"; then
AM_CFLAGS="$AM_CFLAGS $wt_cv_strict_warnings"
fi
-# Configure options.
-AM_OPTIONS
-
# Java and Python APIs
if test "$wt_cv_enable_java" = "yes" -o "$wt_cv_enable_python" = "yes"; then
# Only a warning, we need to build release packages without SWIG.
@@ -133,7 +133,7 @@ if test "$wt_cv_enable_java" = "yes"; then
fi
if test "$wt_cv_enable_python" = "yes"; then
- AM_PATH_PYTHON([2.7])
+ AM_PATH_PYTHON([2.6])
if test -n "$with_python_prefix" ; then
PYTHON_INSTALL_ARG="-d $with_python_prefix"
fi
diff --git a/dist/api_data.py b/dist/api_data.py
index 98f9b5a230a..324d1e4f281 100644
--- a/dist/api_data.py
+++ b/dist/api_data.py
@@ -406,7 +406,7 @@ connection_runtime_config = [
Config('eviction', '', r'''
eviction configuration options''',
type='category', subconfig=[
- Config('threads_max', '1', r'''
+ Config('threads_max', '8', r'''
maximum number of threads WiredTiger will start to help evict
pages from cache. The number of threads started will vary
depending on the current eviction load. Each eviction worker
@@ -537,6 +537,7 @@ connection_runtime_config = [
'rebalance',
'reconcile',
'recovery',
+ 'recovery_progress',
'salvage',
'shared_cache',
'split',
diff --git a/dist/flags.py b/dist/flags.py
index 320bd8f6fb9..70e18712839 100644
--- a/dist/flags.py
+++ b/dist/flags.py
@@ -76,6 +76,7 @@ flags = {
'VERB_REBALANCE',
'VERB_RECONCILE',
'VERB_RECOVERY',
+ 'VERB_RECOVERY_PROGRESS',
'VERB_SALVAGE',
'VERB_SHARED_CACHE',
'VERB_SPLIT',
diff --git a/dist/package/wiredtiger.spec b/dist/package/wiredtiger.spec
index ca88f76b06b..aacdf327c98 100644
--- a/dist/package/wiredtiger.spec
+++ b/dist/package/wiredtiger.spec
@@ -1,5 +1,5 @@
Name: wiredtiger
-Version: 2.9.1
+Version: 2.9.2
Release: 1%{?dist}
Summary: WiredTiger data storage engine
diff --git a/dist/s_all b/dist/s_all
index 4c9d4eccebb..be33657e640 100755
--- a/dist/s_all
+++ b/dist/s_all
@@ -57,7 +57,7 @@ errchk()
# Some tests shouldn't return an error, we exclude them here.
case "$1" in
*s_export|*s_tags)
- break;;
+ ;;
*)
errfound=1;;
esac
@@ -97,10 +97,10 @@ COMMANDS="
2>&1 ./s_string > ${t_pfx}s_string
2>&1 ./s_tags > ${t_pfx}tags
2>&1 ./s_typedef -c > ${t_pfx}s_typedef_c
-2>&1 ./s_void > ${t_pfx}s_void"
+2>&1 ./s_void > ${t_pfx}s_void
2>&1 ./s_whitespace > ${t_pfx}s_whitespace
2>&1 ./s_win > ${t_pfx}s_win
-2>&1 python style.py > ${t_pfx}py_style
+2>&1 python style.py > ${t_pfx}py_style"
# Parallelize if possible.
xp=""
@@ -111,14 +111,13 @@ fi
echo "$COMMANDS" | xargs $xp -I{} /bin/sh -c {}
for f in `find . -name ${t_pfx}\*`; do
- if ! `test -s $f`; then
- continue
+ if `test -s $f`; then
+ LOCAL_NAME=`basename $f`
+ # Find original command and trim redirect garbage
+ FAILED_CMD=`echo "$COMMANDS" | grep $LOCAL_NAME | \
+ sed -e 's/ >.*//' -e 's/.* //'`
+ errchk "$FAILED_CMD" $f
fi
- LOCAL_NAME=`basename $f`
- # Find original command and trim redirect garbage
- FAILED_CMD=`echo "$COMMANDS" | grep $LOCAL_NAME | \
- sed -e 's/ >.*//' -e 's/.* //'`
- errchk "$FAILED_CMD" $f
done
echo 'dist/s_all run finished'
diff --git a/dist/s_docs b/dist/s_docs
index f4332257193..6ebffb947ec 100755
--- a/dist/s_docs
+++ b/dist/s_docs
@@ -96,7 +96,8 @@ spellchk()
type aspell > /dev/null 2>&1 || return
(cd ../src/docs &&
- cat *.dox | aspell --lang=en --personal=./spell.ok list) |
+ cat *.dox |
+ aspell --encoding=iso-8859-1 --lang=en --personal=./spell.ok list) |
sort -u > $t
test -s $t && {
echo "=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-="
diff --git a/dist/s_funcs.list b/dist/s_funcs.list
index 01835390997..b73767cad13 100644
--- a/dist/s_funcs.list
+++ b/dist/s_funcs.list
@@ -13,7 +13,6 @@ __wt_bloom_get
__wt_bulk_insert_fix
__wt_bulk_insert_row
__wt_bulk_insert_var
-__wt_cache_dump
__wt_config_getone
__wt_cursor_get_raw_value
__wt_debug_addr
diff --git a/dist/s_string.ok b/dist/s_string.ok
index f2429237f21..2b998c27813 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -21,6 +21,7 @@ Alakuijala
Alexandrescu's
Alloc
Async
+AsyncOp
Athanassoulis
Athlon
BBBBB
@@ -276,6 +277,7 @@ PRNG
PTHREAD
PTR
PackInputStream
+PackOutputStream
Pandis
Phong
PlatformSDK
@@ -339,6 +341,7 @@ Split's
Stoica
StoreLoad
StoreStore
+Syscall
TAILQ
TCMalloc
TESTUTIL
diff --git a/dist/stat_data.py b/dist/stat_data.py
index 022810d5c49..0af5d6d017e 100644
--- a/dist/stat_data.py
+++ b/dist/stat_data.py
@@ -193,6 +193,7 @@ connection_stats = [
CacheStat('cache_bytes_other', 'bytes not belonging to page images in the cache', 'no_clear,no_scale,size'),
CacheStat('cache_bytes_read', 'bytes read into cache', 'size'),
CacheStat('cache_bytes_write', 'bytes written from cache', 'size'),
+ CacheStat('cache_eviction_active_workers', 'eviction worker thread active', 'no_clear'),
CacheStat('cache_eviction_aggressive_set', 'eviction currently operating in aggressive mode', 'no_clear,no_scale'),
CacheStat('cache_eviction_app', 'pages evicted by application threads'),
CacheStat('cache_eviction_app_dirty', 'modified pages evicted by application threads'),
@@ -222,12 +223,15 @@ connection_stats = [
CacheStat('cache_eviction_slow', 'eviction server unable to reach eviction goal'),
CacheStat('cache_eviction_split_internal', 'internal pages split during eviction'),
CacheStat('cache_eviction_split_leaf', 'leaf pages split during eviction'),
+ CacheStat('cache_eviction_stable_state_workers', 'eviction worker thread stable number', 'no_clear'),
CacheStat('cache_eviction_state', 'eviction state', 'no_clear,no_scale'),
CacheStat('cache_eviction_walk', 'pages walked for eviction'),
CacheStat('cache_eviction_walks_abandoned', 'eviction walks abandoned'),
CacheStat('cache_eviction_walks_active', 'files with active eviction walks', 'no_clear,no_scale'),
CacheStat('cache_eviction_walks_started', 'files with new eviction walks started'),
CacheStat('cache_eviction_worker_evicting', 'eviction worker thread evicting pages'),
+ CacheStat('cache_eviction_worker_created', 'eviction worker thread created'),
+ CacheStat('cache_eviction_worker_removed', 'eviction worker thread removed'),
CacheStat('cache_hazard_checks', 'hazard pointer check calls'),
CacheStat('cache_hazard_max', 'hazard pointer maximum array length', 'max_aggregate,no_scale'),
CacheStat('cache_hazard_walks', 'hazard pointer check entries walked'),
@@ -477,6 +481,7 @@ dsrc_stats = [
##########################################
# Cache and eviction statistics
##########################################
+ CacheStat('cache_bytes_dirty', 'tracked dirty bytes in the cache', 'no_clear,no_scale,size'),
CacheStat('cache_bytes_inuse', 'bytes currently in the cache', 'no_clear,no_scale,size'),
CacheStat('cache_bytes_read', 'bytes read into cache', 'size'),
CacheStat('cache_bytes_write', 'bytes written from cache', 'size'),
diff --git a/lang/python/Makefile.am b/lang/python/Makefile.am
index 03c65a57028..b32d0321194 100644
--- a/lang/python/Makefile.am
+++ b/lang/python/Makefile.am
@@ -17,7 +17,8 @@ install-exec-local:
(cd $(PYSRC) && \
$(PYTHON) setup.py build_py -d $(abs_builddir)/build && \
$(PYTHON) setup.py build_ext -f -b $(abs_builddir)/build $(PYDIRS) && \
- $(PYTHON) setup.py install_lib -b $(abs_builddir)/build --skip-build $(PYTHON_INSTALL_ARG))
+ $(PYTHON) setup.py install_lib -b $(abs_builddir)/build --skip-build $(PYTHON_INSTALL_ARG) && \
+ rm -rf $(abs_builddir)/build)
# We build in different places for an install vs running from the tree:
# clean up both. Don't rely on "setup.py clean" -- everything that should
diff --git a/src/block/block_write.c b/src/block/block_write.c
index d08aba45920..ea7859d6a38 100644
--- a/src/block/block_write.c
+++ b/src/block/block_write.c
@@ -43,10 +43,10 @@ __wt_block_truncate(WT_SESSION_IMPL *session, WT_BLOCK *block, wt_off_t len)
* more targeted solution at some point.
*/
if (!conn->hot_backup) {
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
if (!conn->hot_backup)
ret = __wt_ftruncate(session, block->fh, len);
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
}
/*
diff --git a/src/btree/bt_curnext.c b/src/btree/bt_curnext.c
index 4d3976f9647..ba5fceae7c7 100644
--- a/src/btree/bt_curnext.c
+++ b/src/btree/bt_curnext.c
@@ -338,7 +338,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
}
/* Check for the end of the page. */
- if (cbt->row_iteration_slot >= page->pg_row_entries * 2 + 1)
+ if (cbt->row_iteration_slot >= page->entries * 2 + 1)
return (WT_NOTFOUND);
++cbt->row_iteration_slot;
@@ -356,7 +356,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
cbt->ins = NULL;
cbt->slot = cbt->row_iteration_slot / 2 - 1;
- rip = &page->pg_row_d[cbt->slot];
+ rip = &page->pg_row[cbt->slot];
upd = __wt_txn_read(session, WT_ROW_UPDATE(page, rip));
if (upd != NULL && WT_UPDATE_DELETED_ISSET(upd)) {
if (__wt_txn_visible_all(session, upd->txnid))
diff --git a/src/btree/bt_curprev.c b/src/btree/bt_curprev.c
index 2dd443ffac1..602c01b60eb 100644
--- a/src/btree/bt_curprev.c
+++ b/src/btree/bt_curprev.c
@@ -458,13 +458,13 @@ __cursor_row_prev(WT_CURSOR_BTREE *cbt, bool newpage)
if (!F_ISSET_ATOMIC(page, WT_PAGE_BUILD_KEYS))
WT_RET(__wt_row_leaf_keys(session, page));
- if (page->pg_row_entries == 0)
+ if (page->entries == 0)
cbt->ins_head = WT_ROW_INSERT_SMALLEST(page);
else
cbt->ins_head =
- WT_ROW_INSERT_SLOT(page, page->pg_row_entries - 1);
+ WT_ROW_INSERT_SLOT(page, page->entries - 1);
cbt->ins = WT_SKIP_LAST(cbt->ins_head);
- cbt->row_iteration_slot = page->pg_row_entries * 2 + 1;
+ cbt->row_iteration_slot = page->entries * 2 + 1;
cbt->rip_saved = NULL;
goto new_insert;
}
@@ -515,7 +515,7 @@ new_insert: if ((ins = cbt->ins) != NULL) {
cbt->ins = NULL;
cbt->slot = cbt->row_iteration_slot / 2 - 1;
- rip = &page->pg_row_d[cbt->slot];
+ rip = &page->pg_row[cbt->slot];
upd = __wt_txn_read(session, WT_ROW_UPDATE(page, rip));
if (upd != NULL && WT_UPDATE_DELETED_ISSET(upd)) {
if (__wt_txn_visible_all(session, upd->txnid))
diff --git a/src/btree/bt_cursor.c b/src/btree/bt_cursor.c
index 650289f2cd8..d18b9b76992 100644
--- a/src/btree/bt_cursor.c
+++ b/src/btree/bt_cursor.c
@@ -163,7 +163,7 @@ __cursor_valid(WT_CURSOR_BTREE *cbt, WT_UPDATE **updp)
* column-store pages don't have slots, but map one-to-one to
* keys, check for retrieval past the end of the page.
*/
- if (cbt->recno >= cbt->ref->ref_recno + page->pg_fix_entries)
+ if (cbt->recno >= cbt->ref->ref_recno + page->entries)
return (false);
/*
@@ -173,9 +173,9 @@ __cursor_valid(WT_CURSOR_BTREE *cbt, WT_UPDATE **updp)
break;
case BTREE_COL_VAR:
/* The search function doesn't check for empty pages. */
- if (page->pg_var_entries == 0)
+ if (page->entries == 0)
return (false);
- WT_ASSERT(session, cbt->slot < page->pg_var_entries);
+ WT_ASSERT(session, cbt->slot < page->entries);
/*
* Column-store updates are stored as "insert" objects. If
@@ -191,16 +191,16 @@ __cursor_valid(WT_CURSOR_BTREE *cbt, WT_UPDATE **updp)
* backing store; check the cell for a record already deleted
* when read.
*/
- cip = &page->pg_var_d[cbt->slot];
+ cip = &page->pg_var[cbt->slot];
if ((cell = WT_COL_PTR(page, cip)) == NULL ||
__wt_cell_type(cell) == WT_CELL_DEL)
return (false);
break;
case BTREE_ROW:
/* The search function doesn't check for empty pages. */
- if (page->pg_row_entries == 0)
+ if (page->entries == 0)
return (false);
- WT_ASSERT(session, cbt->slot < page->pg_row_entries);
+ WT_ASSERT(session, cbt->slot < page->entries);
/*
* See above: for row-store, no insert object can have the same
@@ -418,8 +418,7 @@ __wt_btcur_search_near(WT_CURSOR_BTREE *cbt, int *exactp)
* might be legitimately positioned after the last page slot).
* Ignore those cases, it makes things too complicated.
*/
- if (cbt->slot != 0 &&
- cbt->slot != cbt->ref->page->pg_row_entries - 1)
+ if (cbt->slot != 0 && cbt->slot != cbt->ref->page->entries - 1)
valid = __cursor_valid(cbt, &upd);
}
if (!valid) {
diff --git a/src/btree/bt_debug.c b/src/btree/bt_debug.c
index d507cc0e396..b62125e069d 100644
--- a/src/btree/bt_debug.c
+++ b/src/btree/bt_debug.c
@@ -662,25 +662,28 @@ __debug_page_metadata(WT_DBG *ds, WT_REF *ref)
break;
case WT_PAGE_COL_FIX:
WT_RET(ds->f(ds, " recno %" PRIu64, ref->ref_recno));
- entries = page->pg_fix_entries;
+ entries = page->entries;
break;
case WT_PAGE_COL_VAR:
WT_RET(ds->f(ds, " recno %" PRIu64, ref->ref_recno));
- entries = page->pg_var_entries;
+ entries = page->entries;
break;
case WT_PAGE_ROW_INT:
WT_INTL_INDEX_GET(session, page, pindex);
entries = pindex->entries;
break;
case WT_PAGE_ROW_LEAF:
- entries = page->pg_row_entries;
+ entries = page->entries;
break;
WT_ILLEGAL_VALUE(session);
}
WT_RET(ds->f(ds, ": %s\n", __wt_page_type_string(page->type)));
- WT_RET(ds->f(ds,
- "\t" "disk %p, entries %" PRIu32, (void *)page->dsk, entries));
+ WT_RET(ds->f(ds, "\t" "disk %p", (void *)page->dsk));
+ if (page->dsk != NULL)
+ WT_RET(ds->f(
+ ds, ", dsk_mem_size %" PRIu32, page->dsk->mem_size));
+ WT_RET(ds->f(ds, ", entries %" PRIu32, entries));
WT_RET(ds->f(ds,
", %s", __wt_page_is_modified(page) ? "dirty" : "clean"));
WT_RET(ds->f(ds, ", %s", __wt_rwlock_islocked(
diff --git a/src/btree/bt_delete.c b/src/btree/bt_delete.c
index 00e41475de9..b55ad291c5e 100644
--- a/src/btree/bt_delete.c
+++ b/src/btree/bt_delete.c
@@ -318,13 +318,12 @@ __wt_delete_page_instantiate(WT_SESSION_IMPL *session, WT_REF *ref)
* hard case is if a page splits: the update structures might be moved
* to different pages, and we still have to find them all for an abort.
*/
-
if (page_del != NULL)
WT_RET(__wt_calloc_def(
- session, page->pg_row_entries + 1, &page_del->update_list));
+ session, page->entries + 1, &page_del->update_list));
/* Allocate the per-page update array. */
- WT_ERR(__wt_calloc_def(session, page->pg_row_entries, &upd_array));
+ WT_ERR(__wt_calloc_def(session, page->entries, &upd_array));
page->modify->mod_row_update = upd_array;
/*
@@ -332,7 +331,7 @@ __wt_delete_page_instantiate(WT_SESSION_IMPL *session, WT_REF *ref)
* structures, fill in the per-page update array with references to
* deleted items.
*/
- for (i = 0, size = 0; i < page->pg_row_entries; ++i) {
+ for (i = 0, size = 0; i < page->entries; ++i) {
WT_ERR(__wt_calloc_one(session, &upd));
WT_UPDATE_DELETED_SET(upd);
diff --git a/src/btree/bt_discard.c b/src/btree/bt_discard.c
index c2733d6567b..d2beb84fee9 100644
--- a/src/btree/bt_discard.c
+++ b/src/btree/bt_discard.c
@@ -206,8 +206,7 @@ __free_page_modify(WT_SESSION_IMPL *session, WT_PAGE *page)
if (mod->mod_col_update != NULL)
__free_skip_array(session, mod->mod_col_update,
page->type ==
- WT_PAGE_COL_FIX ? 1 : page->pg_var_entries,
- update_ignore);
+ WT_PAGE_COL_FIX ? 1 : page->entries, update_ignore);
break;
case WT_PAGE_ROW_LEAF:
/*
@@ -219,12 +218,12 @@ __free_page_modify(WT_SESSION_IMPL *session, WT_PAGE *page)
*/
if (mod->mod_row_insert != NULL)
__free_skip_array(session, mod->mod_row_insert,
- page->pg_row_entries + 1, update_ignore);
+ page->entries + 1, update_ignore);
/* Free the update array. */
if (mod->mod_row_update != NULL)
__free_update(session, mod->mod_row_update,
- page->pg_row_entries, update_ignore);
+ page->entries, update_ignore);
break;
}
@@ -332,7 +331,7 @@ static void
__free_page_col_var(WT_SESSION_IMPL *session, WT_PAGE *page)
{
/* Free the RLE lookup array. */
- __wt_free(session, page->pg_var_repeats);
+ __wt_free(session, page->u.col_var.repeats);
}
/*
diff --git a/src/btree/bt_handle.c b/src/btree/bt_handle.c
index 47c7972dd57..6ed70788759 100644
--- a/src/btree/bt_handle.c
+++ b/src/btree/bt_handle.c
@@ -359,8 +359,7 @@ __btree_conf(WT_SESSION_IMPL *session, WT_CKPT *ckpt)
}
/* Initialize locks. */
- WT_RET(__wt_rwlock_alloc(
- session, &btree->ovfl_lock, "btree overflow lock"));
+ __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 */
diff --git a/src/btree/bt_ovfl.c b/src/btree/bt_ovfl.c
index 29ea561db3a..ae0da62af57 100644
--- a/src/btree/bt_ovfl.c
+++ b/src/btree/bt_ovfl.c
@@ -67,11 +67,11 @@ __wt_ovfl_read(WT_SESSION_IMPL *session,
* Acquire the overflow lock, and retest the on-page cell's value inside
* the lock.
*/
- __wt_readlock(session, S2BT(session)->ovfl_lock);
+ __wt_readlock(session, &S2BT(session)->ovfl_lock);
ret = __wt_cell_type_raw(unpack->cell) == WT_CELL_VALUE_OVFL_RM ?
__wt_ovfl_txnc_search(page, unpack->data, unpack->size, store) :
__ovfl_read(session, unpack->data, unpack->size, store);
- __wt_readunlock(session, S2BT(session)->ovfl_lock);
+ __wt_readunlock(session, &S2BT(session)->ovfl_lock);
return (ret);
}
@@ -249,7 +249,7 @@ __wt_ovfl_discard(WT_SESSION_IMPL *session, WT_CELL *cell)
* Acquire the overflow lock to avoid racing with a thread reading the
* backing overflow blocks.
*/
- __wt_writelock(session, btree->ovfl_lock);
+ __wt_writelock(session, &btree->ovfl_lock);
switch (unpack->raw) {
case WT_CELL_KEY_OVFL:
@@ -263,7 +263,7 @@ __wt_ovfl_discard(WT_SESSION_IMPL *session, WT_CELL *cell)
WT_ILLEGAL_VALUE(session);
}
- __wt_writeunlock(session, btree->ovfl_lock);
+ __wt_writeunlock(session, &btree->ovfl_lock);
/* Free the backing disk blocks. */
return (bm->free(bm, session, unpack->data, unpack->size));
diff --git a/src/btree/bt_page.c b/src/btree/bt_page.c
index 7bac7079fe8..f20f6398e37 100644
--- a/src/btree/bt_page.c
+++ b/src/btree/bt_page.c
@@ -67,7 +67,7 @@ __wt_page_alloc(WT_SESSION_IMPL *session,
switch (type) {
case WT_PAGE_COL_FIX:
- page->pg_fix_entries = alloc_entries;
+ page->entries = alloc_entries;
break;
case WT_PAGE_COL_INT:
case WT_PAGE_ROW_INT:
@@ -102,12 +102,12 @@ err: if ((pindex = WT_INTL_INDEX_GET_SAFE(page)) != NULL) {
}
break;
case WT_PAGE_COL_VAR:
- page->pg_var_d = (WT_COL *)((uint8_t *)page + sizeof(WT_PAGE));
- page->pg_var_entries = alloc_entries;
+ page->pg_var = (WT_COL *)((uint8_t *)page + sizeof(WT_PAGE));
+ page->entries = alloc_entries;
break;
case WT_PAGE_ROW_LEAF:
- page->pg_row_d = (WT_ROW *)((uint8_t *)page + sizeof(WT_PAGE));
- page->pg_row_entries = alloc_entries;
+ page->pg_row = (WT_ROW *)((uint8_t *)page + sizeof(WT_PAGE));
+ page->entries = alloc_entries;
break;
WT_ILLEGAL_VALUE(session);
}
@@ -333,9 +333,10 @@ __inmem_col_var(
WT_CELL *cell;
WT_CELL_UNPACK *unpack, _unpack;
const WT_PAGE_HEADER *dsk;
+ size_t size;
uint64_t rle;
- size_t bytes_allocated;
uint32_t i, indx, n, repeat_off;
+ void *p;
btree = S2BT(session);
dsk = page->dsk;
@@ -343,7 +344,6 @@ __inmem_col_var(
repeats = NULL;
repeat_off = 0;
unpack = &_unpack;
- bytes_allocated = 0;
/*
* Walk the page, building references: the page contains unsorted value
@@ -351,7 +351,7 @@ __inmem_col_var(
* (WT_CELL_VALUE_OVFL) or deleted items (WT_CELL_DEL).
*/
indx = 0;
- cip = page->pg_var_d;
+ cip = page->pg_var;
WT_CELL_FOREACH(btree, dsk, cell, unpack, i) {
__wt_cell_unpack(cell, unpack);
WT_COL_PTR_SET(cip, WT_PAGE_DISK_OFFSET(page, cell));
@@ -367,12 +367,14 @@ __inmem_col_var(
if (rle > 1) {
if (repeats == NULL) {
__inmem_col_var_repeats(session, page, &n);
- WT_RET(__wt_realloc_def(session,
- &bytes_allocated, n + 1, &repeats));
+ size = sizeof(WT_COL_VAR_REPEAT) +
+ (n + 1) * sizeof(WT_COL_RLE);
+ WT_RET(__wt_calloc(session, 1, size, &p));
+ *sizep += size;
- page->pg_var_repeats = repeats;
+ page->u.col_var.repeats = p;
page->pg_var_nrepeats = n;
- *sizep += bytes_allocated;
+ repeats = page->pg_var_repeats;
}
repeats[repeat_off].indx = indx;
repeats[repeat_off].recno = recno;
@@ -569,7 +571,7 @@ __inmem_row_leaf(WT_SESSION_IMPL *session, WT_PAGE *page)
unpack = &_unpack;
/* Walk the page, building indices. */
- rip = page->pg_row_d;
+ rip = page->pg_row;
WT_CELL_FOREACH(btree, dsk, cell, unpack, i) {
__wt_cell_unpack(cell, unpack);
switch (unpack->type) {
diff --git a/src/btree/bt_rebalance.c b/src/btree/bt_rebalance.c
index 29380459b94..24b4f7bb33d 100644
--- a/src/btree/bt_rebalance.c
+++ b/src/btree/bt_rebalance.c
@@ -265,7 +265,7 @@ __rebalance_row_leaf_key(WT_SESSION_IMPL *session,
*/
WT_RET(__wt_bt_read(session, rs->tmp1, addr, addr_len));
WT_RET(__wt_page_inmem(session, NULL, rs->tmp1->data, 0, 0, &page));
- ret = __wt_row_leaf_key_copy(session, page, &page->pg_row_d[0], key);
+ ret = __wt_row_leaf_key_copy(session, page, &page->pg_row[0], key);
__wt_page_out(session, &page);
return (ret);
}
diff --git a/src/btree/bt_ret.c b/src/btree/bt_ret.c
index 8ef2db67e7b..6409a1a180c 100644
--- a/src/btree/bt_ret.c
+++ b/src/btree/bt_ret.c
@@ -64,10 +64,10 @@ __wt_kv_return(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt, WT_UPDATE *upd)
}
/* Take the value from the original page cell. */
- cell = WT_COL_PTR(page, &page->pg_var_d[cbt->slot]);
+ cell = WT_COL_PTR(page, &page->pg_var[cbt->slot]);
break;
case WT_PAGE_ROW_LEAF:
- rip = &page->pg_row_d[cbt->slot];
+ rip = &page->pg_row[cbt->slot];
/*
* If the cursor references a WT_INSERT item, take its key.
diff --git a/src/btree/bt_slvg.c b/src/btree/bt_slvg.c
index fde4d4fb9de..fea979cac6e 100644
--- a/src/btree/bt_slvg.c
+++ b/src/btree/bt_slvg.c
@@ -603,9 +603,9 @@ __slvg_trk_leaf(WT_SESSION_IMPL *session,
*/
WT_ERR(__wt_page_inmem(session, NULL, dsk, 0, 0, &page));
WT_ERR(__wt_row_leaf_key_copy(session,
- page, &page->pg_row_d[0], &trk->row_start));
- WT_ERR(__wt_row_leaf_key_copy(session, page,
- &page->pg_row_d[page->pg_row_entries - 1], &trk->row_stop));
+ page, &page->pg_row[0], &trk->row_start));
+ WT_ERR(__wt_row_leaf_key_copy(session,
+ page, &page->pg_row[page->entries - 1], &trk->row_stop));
__wt_verbose(session, WT_VERB_SALVAGE,
"%s start key %s",
@@ -1235,7 +1235,7 @@ __slvg_col_build_leaf(WT_SESSION_IMPL *session, WT_TRACK *trk, WT_REF *ref)
WT_PAGE *page;
WT_SALVAGE_COOKIE *cookie, _cookie;
uint64_t recno, skip, take;
- uint32_t *entriesp, save_entries;
+ uint32_t save_entries;
cookie = &_cookie;
WT_CLEAR(*cookie);
@@ -1244,11 +1244,8 @@ __slvg_col_build_leaf(WT_SESSION_IMPL *session, WT_TRACK *trk, WT_REF *ref)
WT_RET(__wt_page_in(session, ref, 0));
page = ref->page;
- entriesp = page->type == WT_PAGE_COL_VAR ?
- &page->pg_var_entries : &page->pg_fix_entries;
-
- save_col_var = page->pg_var_d;
- save_entries = *entriesp;
+ save_col_var = page->pg_var;
+ save_entries = page->entries;
/*
* Calculate the number of K/V entries we are going to skip, and
@@ -1303,8 +1300,8 @@ __slvg_col_build_leaf(WT_SESSION_IMPL *session, WT_TRACK *trk, WT_REF *ref)
WT_ERR(__wt_reconcile(session, ref, cookie, WT_VISIBILITY_ERR, NULL));
/* Reset the page. */
- page->pg_var_d = save_col_var;
- *entriesp = save_entries;
+ page->pg_var = save_col_var;
+ page->entries = save_entries;
ret = __wt_page_release(session, ref, 0);
if (ret == 0)
@@ -1973,14 +1970,14 @@ __slvg_row_build_leaf(
/* We should have selected some entries, but not the entire page. */
WT_ASSERT(session,
skip_start + skip_stop > 0 &&
- skip_start + skip_stop < page->pg_row_entries);
+ skip_start + skip_stop < page->entries);
/*
* Take a copy of this page's first key to define the start of
* its range. The key may require processing, otherwise, it's
* a copy from the page.
*/
- rip = page->pg_row_d + skip_start;
+ rip = page->pg_row + skip_start;
WT_ERR(__wt_row_leaf_key(session, page, rip, key, false));
WT_ERR(__wt_row_ikey_incr(
session, ref->home, 0, key->data, key->size, ref));
@@ -1988,14 +1985,14 @@ __slvg_row_build_leaf(
/* Set the referenced flag on overflow pages we're using. */
if (trk->trk_ovfl_cnt != 0)
WT_ERR(__slvg_row_ovfl(session,
- trk, page, skip_start, page->pg_row_entries - skip_stop));
+ trk, page, skip_start, page->entries - skip_stop));
/*
* Change the page to reflect the correct record count: there is no
* need to copy anything on the page itself, the entries value limits
* the number of page items.
*/
- page->pg_row_entries -= skip_stop;
+ page->entries -= skip_stop;
cookie->skip = skip_start;
/*
@@ -2014,7 +2011,7 @@ __slvg_row_build_leaf(
WT_ERR(__wt_reconcile(session, ref, cookie, WT_VISIBILITY_ERR, NULL));
/* Reset the page. */
- page->pg_row_entries += skip_stop;
+ page->entries += skip_stop;
/*
* Discard our hazard pointer and evict the page, updating the
@@ -2081,7 +2078,7 @@ __slvg_row_ovfl(WT_SESSION_IMPL *session,
* We're merging a row-store page, and we took some number of records,
* figure out which (if any) overflow records we used.
*/
- for (rip = page->pg_row_d + start; start < stop; ++start, ++rip) {
+ for (rip = page->pg_row + start; start < stop; ++start, ++rip) {
copy = WT_ROW_KEY_COPY(rip);
(void)__wt_row_leaf_key_info(
page, copy, NULL, &cell, NULL, NULL);
diff --git a/src/btree/bt_split.c b/src/btree/bt_split.c
index fe49f937719..6b0b8a08c02 100644
--- a/src/btree/bt_split.c
+++ b/src/btree/bt_split.c
@@ -1770,9 +1770,9 @@ __split_insert(WT_SESSION_IMPL *session, WT_REF *ref)
/* Find the last item on the page. */
if (type == WT_PAGE_ROW_LEAF)
- ins_head = page->pg_row_entries == 0 ?
+ ins_head = page->entries == 0 ?
WT_ROW_INSERT_SMALLEST(page) :
- WT_ROW_INSERT_SLOT(page, page->pg_row_entries - 1);
+ WT_ROW_INSERT_SLOT(page, page->entries - 1);
else
ins_head = WT_COL_APPEND(page);
moved_ins = WT_SKIP_LAST(ins_head);
@@ -1822,7 +1822,7 @@ __split_insert(WT_SESSION_IMPL *session, WT_REF *ref)
key->size = WT_INSERT_KEY_SIZE(ins);
} else
WT_ERR(__wt_row_leaf_key(
- session, page, &page->pg_row_d[0], key, true));
+ session, page, &page->pg_row[0], key, true));
WT_ERR(__wt_row_ikey(session, 0, key->data, key->size, child));
parent_incr += sizeof(WT_IKEY) + key->size;
__wt_scr_free(session, &key);
diff --git a/src/btree/bt_stat.c b/src/btree/bt_stat.c
index 06428b87f6e..0da0e0807bd 100644
--- a/src/btree/bt_stat.c
+++ b/src/btree/bt_stat.c
@@ -40,6 +40,8 @@ __wt_btree_stat_init(WT_SESSION_IMPL *session, WT_CURSOR_STAT *cst)
WT_STAT_SET(session, stats, btree_maxleafpage, btree->maxleafpage);
WT_STAT_SET(session, stats, btree_maxleafvalue, btree->maxleafvalue);
+ WT_STAT_SET(session, stats, cache_bytes_dirty,
+ __wt_btree_dirty_inuse(session));
WT_STAT_SET(session, stats, cache_bytes_inuse,
__wt_btree_bytes_inuse(session));
@@ -104,8 +106,7 @@ __stat_page(WT_SESSION_IMPL *session, WT_PAGE *page, WT_DSRC_STATS **stats)
switch (page->type) {
case WT_PAGE_COL_FIX:
WT_STAT_INCR(session, stats, btree_column_fix);
- WT_STAT_INCRV(
- session, stats, btree_entries, page->pg_fix_entries);
+ WT_STAT_INCRV(session, stats, btree_entries, page->entries);
break;
case WT_PAGE_COL_INT:
WT_STAT_INCR(session, stats, btree_column_internal);
diff --git a/src/btree/bt_vrfy.c b/src/btree/bt_vrfy.c
index 340f9bb6f0e..05990918215 100644
--- a/src/btree/bt_vrfy.c
+++ b/src/btree/bt_vrfy.c
@@ -386,7 +386,7 @@ recno_chk: if (recno != vs->record_total + 1)
}
switch (page->type) {
case WT_PAGE_COL_FIX:
- vs->record_total += page->pg_fix_entries;
+ vs->record_total += page->entries;
break;
case WT_PAGE_COL_VAR:
recno = 0;
@@ -614,7 +614,7 @@ __verify_row_leaf_key_order(
* If a tree is empty (just created), it won't have keys; if there
* are no keys, we're done.
*/
- if (page->pg_row_entries == 0)
+ if (page->entries == 0)
return (0);
/*
@@ -624,7 +624,7 @@ __verify_row_leaf_key_order(
*/
if (vs->max_addr->size != 0) {
WT_RET(__wt_row_leaf_key_copy(
- session, page, page->pg_row_d, vs->tmp1));
+ session, page, page->pg_row, vs->tmp1));
/*
* Compare the key against the largest key we've seen so far.
@@ -653,7 +653,7 @@ __verify_row_leaf_key_order(
/* Update the largest key we've seen to the last key on this page. */
WT_RET(__wt_row_leaf_key_copy(session, page,
- page->pg_row_d + (page->pg_row_entries - 1), vs->max_key));
+ page->pg_row + (page->entries - 1), vs->max_key));
(void)__wt_page_addr_string(session, ref, vs->max_addr);
return (0);
diff --git a/src/btree/col_modify.c b/src/btree/col_modify.c
index a7920da5267..9ccb9728189 100644
--- a/src/btree/col_modify.c
+++ b/src/btree/col_modify.c
@@ -115,9 +115,8 @@ __wt_col_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
page, mod->mod_col_update, ins_headp, 1);
ins_headp = &mod->mod_col_update[0];
} else {
- WT_PAGE_ALLOC_AND_SWAP(session,
- page, mod->mod_col_update, ins_headp,
- page->pg_var_entries);
+ WT_PAGE_ALLOC_AND_SWAP(session, page,
+ mod->mod_col_update, ins_headp, page->entries);
ins_headp = &mod->mod_col_update[cbt->slot];
}
diff --git a/src/btree/col_srch.c b/src/btree/col_srch.c
index 64ee9e94f4c..c72d66f8796 100644
--- a/src/btree/col_srch.c
+++ b/src/btree/col_srch.c
@@ -240,8 +240,8 @@ leaf_only:
cbt->compare = 1;
return (0);
}
- if (recno >= current->ref_recno + page->pg_fix_entries) {
- cbt->recno = current->ref_recno + page->pg_fix_entries;
+ if (recno >= current->ref_recno + page->entries) {
+ cbt->recno = current->ref_recno + page->entries;
goto past_end;
} else {
cbt->recno = recno;
@@ -257,8 +257,7 @@ leaf_only:
}
if ((cip = __col_var_search(current, recno, NULL)) == NULL) {
cbt->recno = __col_var_last_recno(current);
- cbt->slot = page->pg_var_entries == 0 ?
- 0 : page->pg_var_entries - 1;
+ cbt->slot = page->entries == 0 ? 0 : page->entries - 1;
goto past_end;
} else {
cbt->recno = recno;
diff --git a/src/btree/row_key.c b/src/btree/row_key.c
index 99ee34a6c5d..032fdf7d897 100644
--- a/src/btree/row_key.c
+++ b/src/btree/row_key.c
@@ -26,7 +26,7 @@ __wt_row_leaf_keys(WT_SESSION_IMPL *session, WT_PAGE *page)
btree = S2BT(session);
- if (page->pg_row_entries == 0) { /* Just checking... */
+ if (page->entries == 0) { /* Just checking... */
F_SET_ATOMIC(page, WT_PAGE_BUILD_KEYS);
return (0);
}
@@ -51,15 +51,15 @@ __wt_row_leaf_keys(WT_SESSION_IMPL *session, WT_PAGE *page)
*/
WT_RET(__wt_scr_alloc(session, 0, &key));
WT_RET(__wt_scr_alloc(session,
- (uint32_t)__bitstr_size(page->pg_row_entries), &tmp));
+ (uint32_t)__bitstr_size(page->entries), &tmp));
memset(tmp->mem, 0, tmp->memsize);
if ((gap = btree->key_gap) == 0)
gap = 1;
- __inmem_row_leaf_slots(tmp->mem, 0, page->pg_row_entries, gap);
+ __inmem_row_leaf_slots(tmp->mem, 0, page->entries, gap);
/* Instantiate the keys. */
- for (rip = page->pg_row_d, i = 0; i < page->pg_row_entries; ++rip, ++i)
+ for (rip = page->pg_row, i = 0; i < page->entries; ++rip, ++i)
if (__bit_test(tmp->mem, i))
WT_ERR(__wt_row_leaf_key_work(
session, page, rip, key, true));
@@ -282,7 +282,7 @@ switch_and_jump: /* Switching to a forward roll. */
* the tracking cache.
*/
if (slot_offset == 0) {
- __wt_readlock(session, btree->ovfl_lock);
+ __wt_readlock(session, &btree->ovfl_lock);
copy = WT_ROW_KEY_COPY(rip);
if (!__wt_row_leaf_key_info(page, copy,
NULL, &cell, &keyb->data, &keyb->size)) {
@@ -290,7 +290,7 @@ switch_and_jump: /* Switching to a forward roll. */
ret = __wt_dsk_cell_data_ref(session,
WT_PAGE_ROW_LEAF, unpack, keyb);
}
- __wt_readunlock(session, btree->ovfl_lock);
+ __wt_readunlock(session, &btree->ovfl_lock);
WT_ERR(ret);
break;
}
diff --git a/src/btree/row_modify.c b/src/btree/row_modify.c
index a1c214e5b8b..b1a81ca3d9f 100644
--- a/src/btree/row_modify.c
+++ b/src/btree/row_modify.c
@@ -85,9 +85,8 @@ __wt_row_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
if (cbt->compare == 0) {
if (cbt->ins == NULL) {
/* Allocate an update array as necessary. */
- WT_PAGE_ALLOC_AND_SWAP(session,
- page, mod->mod_row_update,
- upd_entry, page->pg_row_entries);
+ WT_PAGE_ALLOC_AND_SWAP(session, page,
+ mod->mod_row_update, upd_entry, page->entries);
/* Set the WT_UPDATE array reference. */
upd_entry = &mod->mod_row_update[cbt->slot];
@@ -147,10 +146,10 @@ __wt_row_modify(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt,
* slot. That's hard, so we set a flag.
*/
WT_PAGE_ALLOC_AND_SWAP(session, page,
- mod->mod_row_insert, ins_headp, page->pg_row_entries + 1);
+ mod->mod_row_insert, ins_headp, page->entries + 1);
ins_slot = F_ISSET(cbt, WT_CBT_SEARCH_SMALLEST) ?
- page->pg_row_entries: cbt->slot;
+ page->entries: cbt->slot;
ins_headp = &mod->mod_row_insert[ins_slot];
/* Allocate the WT_INSERT_HEAD structure as necessary. */
diff --git a/src/btree/row_srch.c b/src/btree/row_srch.c
index d4e82c458d4..aa299a161da 100644
--- a/src/btree/row_srch.c
+++ b/src/btree/row_srch.c
@@ -486,14 +486,14 @@ leaf_only:
if (insert && descend_right) {
cbt->append_tree = 1;
- if (page->pg_row_entries == 0) {
- cbt->slot = WT_ROW_SLOT(page, page->pg_row_d);
+ if (page->entries == 0) {
+ cbt->slot = WT_ROW_SLOT(page, page->pg_row);
F_SET(cbt, WT_CBT_SEARCH_SMALLEST);
ins_head = WT_ROW_INSERT_SMALLEST(page);
} else {
cbt->slot = WT_ROW_SLOT(page,
- page->pg_row_d + (page->pg_row_entries - 1));
+ page->pg_row + (page->entries - 1));
ins_head = WT_ROW_INSERT_SLOT(page, cbt->slot);
}
@@ -511,11 +511,11 @@ leaf_only:
* doing the tests and error handling inside the loop costs about 5%.
*/
base = 0;
- limit = page->pg_row_entries;
+ limit = page->entries;
if (collator == NULL && srch_key->size <= WT_COMPARE_SHORT_MAXLEN)
for (; limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
- rip = page->pg_row_d + indx;
+ rip = page->pg_row + indx;
WT_ERR(
__wt_row_leaf_key(session, page, rip, item, true));
@@ -529,7 +529,7 @@ leaf_only:
else if (collator == NULL)
for (; limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
- rip = page->pg_row_d + indx;
+ rip = page->pg_row + indx;
WT_ERR(
__wt_row_leaf_key(session, page, rip, item, true));
@@ -547,7 +547,7 @@ leaf_only:
else
for (; limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
- rip = page->pg_row_d + indx;
+ rip = page->pg_row + indx;
WT_ERR(
__wt_row_leaf_key(session, page, rip, item, true));
@@ -591,13 +591,13 @@ leaf_match: cbt->compare = 0;
*/
if (base == 0) {
cbt->compare = 1;
- cbt->slot = WT_ROW_SLOT(page, page->pg_row_d);
+ cbt->slot = WT_ROW_SLOT(page, page->pg_row);
F_SET(cbt, WT_CBT_SEARCH_SMALLEST);
ins_head = WT_ROW_INSERT_SMALLEST(page);
} else {
cbt->compare = -1;
- cbt->slot = WT_ROW_SLOT(page, page->pg_row_d + (base - 1));
+ cbt->slot = WT_ROW_SLOT(page, page->pg_row + (base - 1));
ins_head = WT_ROW_INSERT_SLOT(page, cbt->slot);
}
@@ -645,16 +645,16 @@ __wt_row_random_leaf(WT_SESSION_IMPL *session, WT_CURSOR_BTREE *cbt)
__cursor_pos_clear(cbt);
/* If the page has disk-based entries, select from them. */
- if (page->pg_row_entries != 0) {
+ if (page->entries != 0) {
cbt->compare = 0;
- cbt->slot = __wt_random(&session->rnd) % page->pg_row_entries;
+ cbt->slot = __wt_random(&session->rnd) % page->entries;
/*
* The real row-store search function builds the key, so we
* have to as well.
*/
return (__wt_row_leaf_key(session,
- page, page->pg_row_d + cbt->slot, cbt->tmp, false));
+ page, page->pg_row + cbt->slot, cbt->tmp, false));
}
/*
diff --git a/src/config/config_def.c b/src/config/config_def.c
index e4fd7937a40..6a93c1d05e2 100644
--- a/src/config/config_def.c
+++ b/src/config/config_def.c
@@ -149,9 +149,10 @@ static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
"\"lsm\",\"lsm_manager\",\"metadata\",\"mutex\",\"overflow\","
- "\"read\",\"rebalance\",\"reconcile\",\"recovery\",\"salvage\","
- "\"shared_cache\",\"split\",\"temporary\",\"thread_group\","
- "\"transaction\",\"verify\",\"version\",\"write\"]",
+ "\"read\",\"rebalance\",\"reconcile\",\"recovery\","
+ "\"recovery_progress\",\"salvage\",\"shared_cache\",\"split\","
+ "\"temporary\",\"thread_group\",\"transaction\",\"verify\","
+ "\"version\",\"write\"]",
NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
@@ -751,9 +752,10 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open[] = {
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
"\"lsm\",\"lsm_manager\",\"metadata\",\"mutex\",\"overflow\","
- "\"read\",\"rebalance\",\"reconcile\",\"recovery\",\"salvage\","
- "\"shared_cache\",\"split\",\"temporary\",\"thread_group\","
- "\"transaction\",\"verify\",\"version\",\"write\"]",
+ "\"read\",\"rebalance\",\"reconcile\",\"recovery\","
+ "\"recovery_progress\",\"salvage\",\"shared_cache\",\"split\","
+ "\"temporary\",\"thread_group\",\"transaction\",\"verify\","
+ "\"version\",\"write\"]",
NULL, 0 },
{ "write_through", "list",
NULL, "choices=[\"data\",\"log\"]",
@@ -837,9 +839,10 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_all[] = {
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
"\"lsm\",\"lsm_manager\",\"metadata\",\"mutex\",\"overflow\","
- "\"read\",\"rebalance\",\"reconcile\",\"recovery\",\"salvage\","
- "\"shared_cache\",\"split\",\"temporary\",\"thread_group\","
- "\"transaction\",\"verify\",\"version\",\"write\"]",
+ "\"read\",\"rebalance\",\"reconcile\",\"recovery\","
+ "\"recovery_progress\",\"salvage\",\"shared_cache\",\"split\","
+ "\"temporary\",\"thread_group\",\"transaction\",\"verify\","
+ "\"version\",\"write\"]",
NULL, 0 },
{ "version", "string", NULL, NULL, NULL, 0 },
{ "write_through", "list",
@@ -918,9 +921,10 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_basecfg[] = {
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
"\"lsm\",\"lsm_manager\",\"metadata\",\"mutex\",\"overflow\","
- "\"read\",\"rebalance\",\"reconcile\",\"recovery\",\"salvage\","
- "\"shared_cache\",\"split\",\"temporary\",\"thread_group\","
- "\"transaction\",\"verify\",\"version\",\"write\"]",
+ "\"read\",\"rebalance\",\"reconcile\",\"recovery\","
+ "\"recovery_progress\",\"salvage\",\"shared_cache\",\"split\","
+ "\"temporary\",\"thread_group\",\"transaction\",\"verify\","
+ "\"version\",\"write\"]",
NULL, 0 },
{ "version", "string", NULL, NULL, NULL, 0 },
{ "write_through", "list",
@@ -999,9 +1003,10 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_usercfg[] = {
NULL, "choices=[\"api\",\"block\",\"checkpoint\",\"compact\","
"\"evict\",\"evictserver\",\"fileops\",\"handleops\",\"log\","
"\"lsm\",\"lsm_manager\",\"metadata\",\"mutex\",\"overflow\","
- "\"read\",\"rebalance\",\"reconcile\",\"recovery\",\"salvage\","
- "\"shared_cache\",\"split\",\"temporary\",\"thread_group\","
- "\"transaction\",\"verify\",\"version\",\"write\"]",
+ "\"read\",\"rebalance\",\"reconcile\",\"recovery\","
+ "\"recovery_progress\",\"salvage\",\"shared_cache\",\"split\","
+ "\"temporary\",\"thread_group\",\"transaction\",\"verify\","
+ "\"version\",\"write\"]",
NULL, 0 },
{ "write_through", "list",
NULL, "choices=[\"data\",\"log\"]",
@@ -1050,7 +1055,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
{ "WT_CONNECTION.reconfigure",
"async=(enabled=false,ops_max=1024,threads=2),cache_overhead=8,"
"cache_size=100MB,checkpoint=(log_size=0,wait=0),error_prefix=,"
- "eviction=(threads_max=1,threads_min=1),"
+ "eviction=(threads_max=8,threads_min=1),"
"eviction_checkpoint_target=5,eviction_dirty_target=5,"
"eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
",file_manager=(close_handle_minimum=250,close_idle_time=30,"
@@ -1261,7 +1266,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
"config_base=true,create=false,direct_io=,encryption=(keyid=,"
- "name=,secretkey=),error_prefix=,eviction=(threads_max=1,"
+ "name=,secretkey=),error_prefix=,eviction=(threads_max=8,"
"threads_min=1),eviction_checkpoint_target=5,"
"eviction_dirty_target=5,eviction_dirty_trigger=20,"
"eviction_target=80,eviction_trigger=95,exclusive=false,"
@@ -1285,7 +1290,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,"
"config_base=true,create=false,direct_io=,encryption=(keyid=,"
- "name=,secretkey=),error_prefix=,eviction=(threads_max=1,"
+ "name=,secretkey=),error_prefix=,eviction=(threads_max=8,"
"threads_min=1),eviction_checkpoint_target=5,"
"eviction_dirty_target=5,eviction_dirty_trigger=20,"
"eviction_target=80,eviction_trigger=95,exclusive=false,"
@@ -1309,7 +1314,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,direct_io=,"
"encryption=(keyid=,name=,secretkey=),error_prefix=,"
- "eviction=(threads_max=1,threads_min=1),"
+ "eviction=(threads_max=8,threads_min=1),"
"eviction_checkpoint_target=5,eviction_dirty_target=5,"
"eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
",extensions=,file_extend=,file_manager=(close_handle_minimum=250"
@@ -1330,7 +1335,7 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",builtin_extension_config=,cache_overhead=8,cache_size=100MB,"
"checkpoint=(log_size=0,wait=0),checkpoint_sync=true,direct_io=,"
"encryption=(keyid=,name=,secretkey=),error_prefix=,"
- "eviction=(threads_max=1,threads_min=1),"
+ "eviction=(threads_max=8,threads_min=1),"
"eviction_checkpoint_target=5,eviction_dirty_target=5,"
"eviction_dirty_trigger=20,eviction_target=80,eviction_trigger=95"
",extensions=,file_extend=,file_manager=(close_handle_minimum=250"
diff --git a/src/conn/conn_api.c b/src/conn/conn_api.c
index 474b8bbad8a..f691a76b1f2 100644
--- a/src/conn/conn_api.c
+++ b/src/conn/conn_api.c
@@ -1811,6 +1811,7 @@ __wt_verbose_config(WT_SESSION_IMPL *session, const char *cfg[])
{ "rebalance", WT_VERB_REBALANCE },
{ "reconcile", WT_VERB_RECONCILE },
{ "recovery", WT_VERB_RECOVERY },
+ { "recovery_progress", WT_VERB_RECOVERY_PROGRESS },
{ "salvage", WT_VERB_SALVAGE },
{ "shared_cache", WT_VERB_SHARED_CACHE },
{ "split", WT_VERB_SPLIT },
@@ -2174,6 +2175,15 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
if (cval.val)
F_SET(conn, WT_CONN_READONLY);
+ /* Configure error messages so we get them right early. */
+ WT_ERR(__wt_config_gets(session, cfg, "error_prefix", &cval));
+ if (cval.len != 0)
+ WT_ERR(__wt_strndup(
+ session, cval.str, cval.len, &conn->error_prefix));
+
+ /* Set the database home so extensions have access to it. */
+ WT_ERR(__conn_home(session, home, cfg));
+
/*
* Load early extensions before doing further initialization (one early
* extension is to configure a file system).
@@ -2197,6 +2207,9 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
WT_ERR(
__conn_chk_file_system(session, F_ISSET(conn, WT_CONN_READONLY)));
+ /* Make sure no other thread of control already owns this database. */
+ WT_ERR(__conn_single(session, cfg));
+
/*
* Capture the config_base setting file for later use. Again, if the
* application doesn't want us to read the base configuration file,
@@ -2206,18 +2219,6 @@ wiredtiger_open(const char *home, WT_EVENT_HANDLER *event_handler,
WT_ERR(__wt_config_gets(session, cfg, "config_base", &cval));
config_base_set = cval.val != 0;
- /* Configure error messages so we get them right early. */
- WT_ERR(__wt_config_gets(session, cfg, "error_prefix", &cval));
- if (cval.len != 0)
- WT_ERR(__wt_strndup(
- session, cval.str, cval.len, &conn->error_prefix));
-
- /* Get the database home. */
- WT_ERR(__conn_home(session, home, cfg));
-
- /* Make sure no other thread of control already owns this database. */
- WT_ERR(__conn_single(session, cfg));
-
/*
* Build the real configuration stack, in the following order (where
* later entries override earlier entries):
diff --git a/src/conn/conn_cache.c b/src/conn/conn_cache.c
index fe5f94ea03d..2b0e5081f04 100644
--- a/src/conn/conn_cache.c
+++ b/src/conn/conn_cache.c
@@ -143,7 +143,8 @@ __wt_cache_config(WT_SESSION_IMPL *session, bool reconfigure, const char *cfg[])
if (reconfigure)
WT_RET(__wt_thread_group_resize(
session, &conn->evict_threads,
- conn->evict_threads_min, conn->evict_threads_max,
+ conn->evict_threads_min,
+ conn->evict_threads_max,
WT_THREAD_CAN_WAIT | WT_THREAD_PANIC_FAIL));
return (0);
diff --git a/src/conn/conn_dhandle.c b/src/conn/conn_dhandle.c
index e9e3925c57e..b2f4bb04ce4 100644
--- a/src/conn/conn_dhandle.c
+++ b/src/conn/conn_dhandle.c
@@ -42,7 +42,7 @@ __conn_dhandle_alloc(WT_SESSION_IMPL *session,
WT_RET(__wt_calloc_one(session, &dhandle));
- WT_ERR(__wt_rwlock_alloc(session, &dhandle->rwlock, "data handle"));
+ __wt_rwlock_init(session, &dhandle->rwlock);
dhandle->name_hash = __wt_hash_city64(uri, strlen(uri));
WT_ERR(__wt_strdup(session, uri, &dhandle->name));
WT_ERR(__wt_strdup(session, checkpoint, &dhandle->checkpoint));
diff --git a/src/conn/conn_handle.c b/src/conn/conn_handle.c
index 02182daa7dc..3f7fc9bb2a7 100644
--- a/src/conn/conn_handle.c
+++ b/src/conn/conn_handle.c
@@ -64,8 +64,7 @@ __wt_connection_init(WT_CONNECTION_IMPL *conn)
WT_RET(__wt_spin_init(session, &conn->turtle_lock, "turtle file"));
/* Read-write locks */
- WT_RET(__wt_rwlock_alloc(
- session, &conn->hot_backup_lock, "hot backup"));
+ __wt_rwlock_init(session, &conn->hot_backup_lock);
WT_RET(__wt_calloc_def(session, WT_PAGE_LOCKS, &conn->page_lock));
for (i = 0; i < WT_PAGE_LOCKS; ++i)
diff --git a/src/conn/conn_log.c b/src/conn/conn_log.c
index 8198b3a1a02..8f8f8614ba8 100644
--- a/src/conn/conn_log.c
+++ b/src/conn/conn_log.c
@@ -237,7 +237,7 @@ __log_archive_once(WT_SESSION_IMPL *session, uint32_t backup_file)
* We can only archive files if a hot backup is not in progress or
* if we are the backup.
*/
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
locked = true;
if (!conn->hot_backup || backup_file != 0) {
for (i = 0; i < logcount; i++) {
@@ -248,7 +248,7 @@ __log_archive_once(WT_SESSION_IMPL *session, uint32_t backup_file)
session, WT_LOG_FILENAME, lognum));
}
}
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
locked = false;
/*
@@ -260,7 +260,7 @@ __log_archive_once(WT_SESSION_IMPL *session, uint32_t backup_file)
if (0)
err: __wt_err(session, ret, "log archive server error");
if (locked)
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
WT_TRET(__wt_fs_directory_list_free(session, &logfiles, logcount));
return (ret);
}
@@ -355,9 +355,9 @@ __wt_log_truncate_files(
__wt_verbose(session, WT_VERB_LOG,
"log_truncate_files: Archive once up to %" PRIu32, backup_file);
- __wt_writelock(session, log->log_archive_lock);
+ __wt_writelock(session, &log->log_archive_lock);
ret = __log_archive_once(session, backup_file);
- __wt_writeunlock(session, log->log_archive_lock);
+ __wt_writeunlock(session, &log->log_archive_lock);
return (ret);
}
@@ -433,7 +433,7 @@ __log_file_server(void *arg)
*/
if (!conn->hot_backup) {
__wt_readlock(
- session, conn->hot_backup_lock);
+ session, &conn->hot_backup_lock);
if (!conn->hot_backup)
WT_ERR_ERROR_OK(
__wt_ftruncate(session,
@@ -441,7 +441,7 @@ __log_file_server(void *arg)
close_end_lsn.l.offset),
ENOTSUP);
__wt_readunlock(
- session, conn->hot_backup_lock);
+ session, &conn->hot_backup_lock);
}
WT_SET_LSN(&close_end_lsn,
close_end_lsn.l.file + 1, 0);
@@ -814,10 +814,11 @@ __log_server(void *arg)
* agreed not to rename or remove any files in
* the database directory.
*/
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
if (!conn->hot_backup)
ret = __log_prealloc_once(session);
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(
+ session, &conn->hot_backup_lock);
WT_ERR(ret);
}
@@ -826,10 +827,10 @@ __log_server(void *arg)
*/
if (FLD_ISSET(conn->log_flags, WT_CONN_LOG_ARCHIVE)) {
if (__wt_try_writelock(
- session, log->log_archive_lock) == 0) {
+ session, &log->log_archive_lock) == 0) {
ret = __log_archive_once(session, 0);
__wt_writeunlock(
- session, log->log_archive_lock);
+ session, &log->log_archive_lock);
WT_ERR(ret);
} else
__wt_verbose(session, WT_VERB_LOG,
@@ -884,8 +885,7 @@ __wt_logmgr_create(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_spin_init(session, &log->log_sync_lock, "log sync"));
WT_RET(__wt_spin_init(session, &log->log_writelsn_lock,
"log write LSN"));
- WT_RET(__wt_rwlock_alloc(session,
- &log->log_archive_lock, "log archive lock"));
+ __wt_rwlock_init(session, &log->log_archive_lock);
if (FLD_ISSET(conn->direct_io, WT_DIRECT_IO_LOG))
log->allocsize = (uint32_t)
WT_MAX(conn->buffer_alignment, WT_LOG_ALIGN);
diff --git a/src/conn/conn_sweep.c b/src/conn/conn_sweep.c
index d1254d8afcc..7d5cb7d7c72 100644
--- a/src/conn/conn_sweep.c
+++ b/src/conn/conn_sweep.c
@@ -81,7 +81,7 @@ __sweep_expire_one(WT_SESSION_IMPL *session)
* handle list lock so that connection-level handle searches
* never need to retry.
*/
- WT_RET(__wt_try_writelock(session, dhandle->rwlock));
+ WT_RET(__wt_try_writelock(session, &dhandle->rwlock));
/* Only sweep clean trees where all updates are visible. */
if (btree->modified ||
@@ -95,7 +95,7 @@ __sweep_expire_one(WT_SESSION_IMPL *session)
*/
ret = __wt_conn_btree_sync_and_close(session, false, true);
-err: __wt_writeunlock(session, dhandle->rwlock);
+err: __wt_writeunlock(session, &dhandle->rwlock);
return (ret);
}
@@ -188,7 +188,7 @@ __sweep_remove_one(WT_SESSION_IMPL *session, WT_DATA_HANDLE *dhandle)
WT_DECL_RET;
/* Try to get exclusive access. */
- WT_RET(__wt_try_writelock(session, dhandle->rwlock));
+ WT_RET(__wt_try_writelock(session, &dhandle->rwlock));
/*
* If there are no longer any references to the handle in any
@@ -205,7 +205,7 @@ __sweep_remove_one(WT_SESSION_IMPL *session, WT_DATA_HANDLE *dhandle)
* don't retry the discard until it times out again.
*/
if (ret != 0) {
-err: __wt_writeunlock(session, dhandle->rwlock);
+err: __wt_writeunlock(session, &dhandle->rwlock);
}
return (ret);
diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c
index 456aa2e0f02..08b15e6ca5e 100644
--- a/src/cursor/cur_backup.c
+++ b/src/cursor/cur_backup.c
@@ -230,10 +230,10 @@ __backup_start(
* We are holding the checkpoint and schema locks so schema operations
* will not see the backup file list until it is complete and valid.
*/
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup = true;
conn->hot_backup_list = NULL;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
/* We're the lock holder, we own cleanup. */
F_SET(cb, WT_CURBACKUP_LOCKER);
@@ -297,9 +297,9 @@ err: /* Close the hot backup file. */
if (ret == 0) {
WT_ASSERT(session, dest != NULL);
WT_TRET(__wt_fs_rename(session, WT_BACKUP_TMP, dest, false));
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup_list = cb->list;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
}
return (ret);
@@ -319,9 +319,9 @@ __backup_stop(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
conn = S2C(session);
/* Release all btree names held by the backup. */
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup_list = NULL;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
if (cb->list != NULL) {
for (i = 0; cb->list[i] != NULL; ++i)
__wt_free(session, cb->list[i]);
@@ -332,9 +332,9 @@ __backup_stop(WT_SESSION_IMPL *session, WT_CURSOR_BACKUP *cb)
WT_TRET(__wt_backup_file_remove(session));
/* Checkpoint deletion can proceed, as can the next hot backup. */
- __wt_writelock(session, conn->hot_backup_lock);
+ __wt_writelock(session, &conn->hot_backup_lock);
conn->hot_backup = false;
- __wt_writeunlock(session, conn->hot_backup_lock);
+ __wt_writeunlock(session, &conn->hot_backup_lock);
return (ret);
}
diff --git a/src/cursor/cur_index.c b/src/cursor/cur_index.c
index 0ab992bc88c..4786b0524bc 100644
--- a/src/cursor/cur_index.c
+++ b/src/cursor/cur_index.c
@@ -520,8 +520,8 @@ __wt_curindex_open(WT_SESSION_IMPL *session,
WT_ERR(__curindex_open_colgroups(session, cindex, cfg));
if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON))
- __wt_json_column_init(
- cursor, table->key_format, &idx->colconf, &table->colconf);
+ __wt_json_column_init(cursor, uri, table->key_format,
+ &idx->colconf, &table->colconf);
if (0) {
err: WT_TRET(__curindex_close(cursor));
diff --git a/src/cursor/cur_json.c b/src/cursor/cur_json.c
index a0a3ffdd974..5870d14273e 100644
--- a/src/cursor/cur_json.c
+++ b/src/cursor/cur_json.c
@@ -369,11 +369,11 @@ __wt_json_unpack_char(u_char ch, u_char *buf, size_t bufsz, bool force_unicode)
* of column names.
*/
void
-__wt_json_column_init(WT_CURSOR *cursor, const char *keyformat,
+__wt_json_column_init(WT_CURSOR *cursor, const char *uri, const char *keyformat,
const WT_CONFIG_ITEM *idxconf, const WT_CONFIG_ITEM *colconf)
{
WT_CURSOR_JSON *json;
- const char *p, *end, *beginkey;
+ const char *beginkey, *end, *lparen, *p;
uint32_t keycnt, nkeys;
json = (WT_CURSOR_JSON *)cursor->json_private;
@@ -400,8 +400,16 @@ __wt_json_column_init(WT_CURSOR *cursor, const char *keyformat,
keycnt++;
p++;
}
- json->value_names.str = p;
- json->value_names.len = WT_PTRDIFF(end, p);
+ if ((lparen = strchr(uri, '(')) != NULL) {
+ /* This cursor is a projection. */
+ json->value_names.str = lparen;
+ json->value_names.len = strlen(lparen) - 1;
+ WT_ASSERT((WT_SESSION_IMPL *)cursor->session,
+ json->value_names.str[json->value_names.len] == ')');
+ } else {
+ json->value_names.str = p;
+ json->value_names.len = WT_PTRDIFF(end, p);
+ }
if (idxconf == NULL) {
if (p > beginkey)
p--;
diff --git a/src/cursor/cur_log.c b/src/cursor/cur_log.c
index 3ee6554b3c0..e5b56aa406f 100644
--- a/src/cursor/cur_log.c
+++ b/src/cursor/cur_log.c
@@ -305,7 +305,7 @@ __curlog_close(WT_CURSOR *cursor)
WT_ASSERT(session, FLD_ISSET(conn->log_flags, WT_CONN_LOG_ENABLED));
if (F_ISSET(cl, WT_CURLOG_ARCHIVE_LOCK))
- __wt_readunlock(session, conn->log->log_archive_lock);
+ __wt_readunlock(session, &conn->log->log_archive_lock);
__wt_free(session, cl->cur_lsn);
__wt_free(session, cl->next_lsn);
@@ -383,7 +383,7 @@ __wt_curlog_open(WT_SESSION_IMPL *session,
WT_ERR(__wt_log_force_write(session, 1, NULL));
/* Log cursors block archiving. */
- __wt_readlock(session, log->log_archive_lock);
+ __wt_readlock(session, &log->log_archive_lock);
F_SET(cl, WT_CURLOG_ARCHIVE_LOCK);
if (0) {
diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c
index 6264de89df9..7ace6d49cf0 100644
--- a/src/cursor/cur_std.c
+++ b/src/cursor/cur_std.c
@@ -144,6 +144,7 @@ __wt_cursor_set_notsup(WT_CURSOR *cursor)
*/
int
__wt_cursor_kv_not_set(WT_CURSOR *cursor, bool key)
+ WT_GCC_FUNC_ATTRIBUTE((cold))
{
WT_SESSION_IMPL *session;
diff --git a/src/cursor/cur_table.c b/src/cursor/cur_table.c
index fae7667e44f..76f7fc5865f 100644
--- a/src/cursor/cur_table.c
+++ b/src/cursor/cur_table.c
@@ -951,7 +951,7 @@ __wt_curtable_open(WT_SESSION_IMPL *session,
if (F_ISSET(cursor, WT_CURSTD_DUMP_JSON))
__wt_json_column_init(
- cursor, table->key_format, NULL, &table->colconf);
+ cursor, uri, table->key_format, NULL, &table->colconf);
/*
* Open the colgroup cursors immediately: we're going to need them for
diff --git a/src/docs/Doxyfile b/src/docs/Doxyfile
index 69e9716b425..3d8c46962f1 100644
--- a/src/docs/Doxyfile
+++ b/src/docs/Doxyfile
@@ -216,11 +216,19 @@ ALIASES = "notyet{1}=Note: <b>"\1"</b> not yet supported in Wired
"hrow{3}=<tr><th>\1</th><th>\2</th><th>\3</th></tr>" \
"hrow{4}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th></tr>" \
"hrow{5}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th><th>\5</th></tr>" \
+ "hrow{6}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th><th>\5</th><th>\6</th></tr>" \
+ "hrow{7}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th><th>\5</th><th>\6</th><th>\7</th></tr>" \
+ "hrow{8}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th><th>\5</th><th>\6</th><th>\7</th><th>\8</th></tr>" \
+ "hrow{9}=<tr><th>\1</th><th>\2</th><th>\3</th><th>\4</th><th>\5</th><th>\6</th><th>\7</th><th>\8</th><th>\9</th></tr>" \
"row{1}=<tr><td>\1</td></tr>" \
"row{2}=<tr><td>\1</td><td>\2</td></tr>" \
"row{3}=<tr><td>\1</td><td>\2</td><td>\3</td></tr>" \
"row{4}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td></tr>" \
"row{5}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td><td>\5</td></tr>" \
+ "row{6}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td><td>\5</td><td>\6</td></tr>" \
+ "row{7}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td><td>\5</td><td>\6</td><td>\7</td></tr>" \
+ "row{8}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td><td>\5</td><td>\6</td><td>\7</td><td>\8</td></tr>" \
+ "row{9}=<tr><td>\1</td><td>\2</td><td>\3</td><td>\4</td><td>\5</td><td>\6</td><td>\7</td><td>\8</td><td>\9</td></tr>" \
"configstart{2}=@param config\n Configuration string, see @ref config_strings. Permitted values:\n <table>@hrow{Name,Effect,Values}" \
"config{3}= @row{<tt>\1</tt>,\2,\3}" \
"configend= </table>" \
diff --git a/src/docs/build-pydoc.sh b/src/docs/build-pydoc.sh
index aef88fd4c97..5e6e3635be5 100755
--- a/src/docs/build-pydoc.sh
+++ b/src/docs/build-pydoc.sh
@@ -3,4 +3,4 @@ TOP=$DOCS/..
. $TOP/config.sh
cd python
-PYTHONPATH=../../lang/python/src:$THRIFT_HOME/lib/python2.7/site-packages pydoc -w wiredtiger
+PYTHONPATH=../../lang/python/src:$THRIFT_HOME/lib/python2.6/site-packages pydoc -w wiredtiger
diff --git a/src/docs/command-line.dox b/src/docs/command-line.dox
index 5726a1d19a1..df52324f8f8 100644
--- a/src/docs/command-line.dox
+++ b/src/docs/command-line.dox
@@ -370,6 +370,19 @@ Include only "fast" statistics in the output (equivalent to passing
<code>statistics=(fast)</code>) to WT_SESSION::open_cursor.
<hr>
+@section util_truncate wt truncate
+Truncate a table, removing all data.
+
+The \c truncate command truncates the specified \c uri. It is equivalent to a
+call to WT_SESSION::truncate with no start or stop specified.
+
+@subsection util_truncate_synopsis Synopsis
+<code>wt [-RVv] [-C config] [-E secretkey ] [-h directory] truncate uri</code>
+
+@subsection util_truncate_options Options
+The \c truncate command has no command-specific options.
+
+<hr>
@section util_upgrade wt upgrade
Upgrade a table.
diff --git a/src/docs/file-formats.dox b/src/docs/file-formats.dox
index d8990aca7a6..21dc4580bc2 100644
--- a/src/docs/file-formats.dox
+++ b/src/docs/file-formats.dox
@@ -110,7 +110,7 @@ considered. (See @subpage_single huffman for details.)
compressing blocks of the backing object's file. The cost is additional
CPU and memory use when reading and writing pages to disk. Note the
additional CPU cost of block compression can be high, and should be
-considered. (See @x_ref compression_formats for details.)
+considered. (See @x_ref compression_considerations for details.)
Block compression is disabled by default.
@@ -146,7 +146,7 @@ Huffman encoding can be high, and should be considered.
compressing blocks of the backing object's file. The cost is additional
CPU and memory use when reading and writing pages to disk. Note the
additional CPU cost of block compression can be high, and should be
-considered. (See @x_ref compression_formats for details.)
+considered. (See @x_ref compression_considerations for details.)
Block compression is disabled by default.
@@ -157,7 +157,7 @@ compression: block compression.
compressing blocks of the backing object's file. The cost is additional
CPU and memory use when reading and writing pages to disk. Note the
additional CPU cost of block compression can be high, and should be
-considered. (See @x_ref compression_formats for details.)
+considered. (See @x_ref compression_considerations for details.)
Block compression is disabled by default.
diff --git a/src/docs/programming.dox b/src/docs/programming.dox
index 81e612e8ee8..aa76bef4614 100644
--- a/src/docs/programming.dox
+++ b/src/docs/programming.dox
@@ -66,14 +66,13 @@ each of which is ordered by one or more columns.
- @subpage_single wtstats
<p>
- @subpage_single tune_memory_allocator
-- @subpage_single tune_page_sizes
+- @subpage_single tune_page_size_and_comp
- @subpage_single tune_cache
- @subpage_single tune_bulk_load
- @subpage_single tune_cursor_persist
- @subpage_single tune_read_only
- @subpage_single tune_durability
- @subpage_single tune_checksum
-- @subpage_single tune_compression
- @subpage_single tune_file_alloc
- @subpage_single tune_system_buffer_cache
- @subpage_single tune_transparent_huge_pages
diff --git a/src/docs/spell.ok b/src/docs/spell.ok
index 2413cbc93fb..bc2e16b1122 100644
--- a/src/docs/spell.ok
+++ b/src/docs/spell.ok
@@ -50,6 +50,7 @@ LDFLAGS
LIBS
LLVM
LOGREC
+LRU
LRVv
LSB
LSM
@@ -167,6 +168,7 @@ dNLen
dNOff
dT
dataN
+database's
dataitem
dataset
datasets
diff --git a/src/docs/testing.dox b/src/docs/testing.dox
index cf280e8f3ff..7d454d54212 100644
--- a/src/docs/testing.dox
+++ b/src/docs/testing.dox
@@ -27,7 +27,7 @@ The WiredTiger unit test suite includes tests that cover:
The WiredTiger Python test suite is built using the WiredTiger Python
API and the Python unittest functionality (the test suite requires at
-least Python version 2.7).
+least Python version 2.6).
The WiredTiger test suite automatically runs as part of every commit
into the WiredTiger GitHub source tree.
diff --git a/src/docs/top/main.dox b/src/docs/top/main.dox
index 01acc849d50..84487c13174 100644
--- a/src/docs/top/main.dox
+++ b/src/docs/top/main.dox
@@ -6,12 +6,12 @@ WiredTiger is an high performance, scalable, production quality, NoSQL,
@section releases Releases
<table>
-@row{<b>WiredTiger 2.9.0</b> (current),
+@row{<b>WiredTiger 2.9.1</b> (current),
+ <a href="releases/wiredtiger-2.9.1.tar.bz2"><b>[Release package]</b></a>,
+ <a href="2.9.1/index.html"><b>[Documentation]</b></a>}
+@row{<b>WiredTiger 2.9.0</b> (previous),
<a href="releases/wiredtiger-2.9.0.tar.bz2"><b>[Release package]</b></a>,
<a href="2.9.0/index.html"><b>[Documentation]</b></a>}
-@row{<b>WiredTiger 2.8.0</b> (previous),
- <a href="releases/wiredtiger-2.8.0.tar.bz2"><b>[Release package]</b></a>,
- <a href="2.8.0/index.html"><b>[Documentation]</b></a>}
@row{<b>Development branch</b>,
<a href="https://github.com/wiredtiger/wiredtiger"><b>[Source code]</b></a>,
<a href="develop/index.html"><b>[Documentation]</b></a>}
diff --git a/src/docs/transactions.dox b/src/docs/transactions.dox
index bbbd2d52296..3b438eda366 100644
--- a/src/docs/transactions.dox
+++ b/src/docs/transactions.dox
@@ -141,7 +141,7 @@ as if the transaction started at the time of the WT_SESSION::snapshot
call that created the snapshot.
Named snapshots keep data pinned in cache as if a real transaction were
-running for the time that the named transaction is active. The resources
+running for the time that the named snapshot is active. The resources
associated with named snapshots should be released by calling
WT_SESSION::snapshot with a configuration that includes
<code>"drop="</code>. See WT_SESSION::snapshot documentation for details of
diff --git a/src/docs/tune-compression.dox b/src/docs/tune-compression.dox
deleted file mode 100644
index 8db2151aa76..00000000000
--- a/src/docs/tune-compression.dox
+++ /dev/null
@@ -1,62 +0,0 @@
-/*! @page tune_compression Compression
-
-WiredTiger includes a number of optional compression techniques. Configuring
-compression generally decreases on-disk and in-memory resource requirements
-and the amount of I/O, and increases CPU cost when data are read and written.
-
-Configuring compression may change application throughput. For example,
-in applications using solid-state drives (where I/O is less expensive),
-turning off compression may increase application performance by reducing
-CPU costs; in applications where I/O costs are more expensive, turning on
-compression may increase application performance by reducing the overall
-number of I/O operations.
-
-An example of turning on row-store key prefix compression:
-
-@snippet ex_all.c Configure key prefix compression on
-
-An example of turning on row-store or column-store dictionary compression:
-
-@snippet ex_all.c Configure dictionary compression on
-
-@section compression_formats Block Compression Formats
-WiredTiger provides two methods of compressing your data when using block
-compression: the raw and noraw methods. These methods change how WiredTiger
-works to fit data into the blocks that are stored on disk.
-
-@subsection noraw_compression Noraw Compression
-Noraw compression is the traditional compression model where a fixed
-amount of data is given to the compression system, then turned into a
-compressed block of data. The amount of data chosen to compress is the
-data needed to fill the uncompressed block. Thus when compressed, the block will
-be smaller than the normal data size and the sizes written to disk will often
-vary depending on how compressible the data being stored is. Algorithms
-using noraw compression include zlib-noraw, lz4-noraw and snappy.
-
-@subsection raw_compression Raw Compression
-WiredTiger's raw compression takes advantage of compressors that provide a
-streaming compression API. Using the streaming API WiredTiger will try to fit
-as much data as possible into one block. This means that blocks created
-with raw compression should be of similar size. Using a streaming compression
-method should also make for less overhead in compression, as the setup and
-initial work for compressing is done fewer times compared to the amount of
-data stored. Algorithms using raw compression include zlib, lz4.
-
-@subsection to_raw_or_noraw Choosing between Raw and Noraw Compression
-When looking at which compression method to use the biggest consideration is
-that raw compression will normally provide higher compression levels while
-using more CPU for compression.
-
-An additional consideration is that raw compression may provide a performance
-advantage in workloads where data is accessed sequentially. That is because
-more data is generally packed into each block on disk. Conversely, noraw
-compression may perform better for workloads with random access patterns
-because each block will tend to be smaller and require less work to read and
-decompress.
-
-See @ref file_formats_compression for more information on available
-compression techniques.
-
-See @ref compression for information on how to configure and enable compression.
-
- */
diff --git a/src/docs/tune-page-size-and-comp.dox b/src/docs/tune-page-size-and-comp.dox
new file mode 100644
index 00000000000..96b0fda2333
--- /dev/null
+++ b/src/docs/tune-page-size-and-comp.dox
@@ -0,0 +1,426 @@
+/*! @page tune_page_size_and_comp Tuning page size and compression
+
+This document aims to explain the role played by different page sizes in
+WiredTiger. It also details motivation behind an application wanting to modify
+these page sizes from their default values and the procedure to do so.
+Applications commonly configure page sizes based on their workload's typical key
+and value size. Once a page size has been chosen, appropriate defaults for the
+other configuration values are derived by WiredTiger from the page sizes, and
+relatively few applications will need to modify the other page and key/value
+size configuration options. WiredTiger also offers several compression options
+that have an impact on the size of the data both in-memory and on-disk. Hence
+while selecting page sizes, an application must also look at its desired
+compression needs. Since the data and workload for a table differs from one
+table to another in the database, an application can choose to set page sizes
+and compression options on a per-table basis.
+
+@section data_life_cycle Data life cycle
+Before detailing each page size, here is a review of how data gets stored inside
+WiredTiger:
+ - WiredTiger uses the physical disks to store data durably, creating on-disk
+files for the tables in the database directory. It also caches the portion of
+the table being currently accessed by the application for reading or writing in
+main memory.
+ - WiredTiger maintains a table's data in memory using a data structure called a
+<a href="https://en.wikipedia.org/wiki/B-tree">B-Tree</a> (
+<a href="https://en.wikipedia.org/wiki/B%2B_tree">B+ Tree</a> to be specific),
+referring to the nodes of a B-Tree as pages. Internal pages carry only keys. The
+leaf pages store both keys and values.
+ - The format of the in-memory pages is not the same as the format of the
+on-disk pages. Therefore, the in-memory pages regularly go through a process
+called reconciliation to create data structures appropriate for storage on the
+disk. These data structures are referred to as on-disk pages. An application can
+set a maximum size separately for the internal and leaf on-disk pages otherwise
+WiredTiger uses a default value. If reconciliation of an in-memory page is
+leading to an on-disk page size greater than this maximum, WiredTiger creates
+multiple smaller on-disk pages.
+ - A component of WiredTiger called the Block Manager divides the on-disk pages
+into smaller chunks called blocks, which then get written to the disk. The size
+of these blocks is defined by a parameter called allocation_size, which is the
+underlying unit of allocation for the file the data gets stored in. An
+application might choose to have data compressed before it gets stored to disk
+by enabling block compression.
+ - A database's tables are usually much larger than the main memory available.
+Not all of the data can be kept in memory at any given time. A process called
+eviction takes care of making space for new data by freeing the memory of data
+infrequently accessed. An eviction server regularly finds in-memory pages that
+have not been accessed in a while (following an LRU algorithm). Several
+background eviction threads continuously process these pages, reconcile them to
+disk and remove them from the main memory.
+ - When an application does an insert or an update of a key/value pair, the
+associated key is used to refer to an in-memory page. In the case of this page
+not being in memory, appropriate on-disk page(s) are read and an in-memory page
+constructed (the opposite of reconciliation). A data structure is maintained on
+every in-memory page to store any insertions or modifications to the data done
+on that page. As more and more data gets written to this page, the page's memory
+footprint keeps growing.
+ - An application can choose to set the maximum size a page is allowed to grow
+in-memory. A default size is set by WiredTiger if the application doesn't
+specify one. To keep page management efficient, as a page grows larger in-memory
+and approaches this maximum size, if possible, it is split into smaller
+in-memory pages.
+ - When doing an insert or an update, if a page grows larger than the maximum,
+the application thread is used to forcefully evict this page. This is done to
+split the growing page into smaller in-memory pages and reconcile them into
+on-disk pages. Once written to the disk they are removed from the main memory,
+making space for more data to be written. When an application gets involved in
+forced eviction, it might take longer than usual to do these inserts and
+updates. It is not always possible to (force) evict a page from memory and this
+page can temporarily grow larger in size than the configured maximum. This page
+then remains marked to be evicted and reattempts are made as the application
+puts more data in it.
+
+@section configurable_page_struct Configurable page structures in WiredTiger
+There are three page sizes that the user can configure:
+ 1. The maximum page size of any type of in-memory page in the WiredTiger cache,
+memory_page_max.
+ 2. The maximum size of the on-disk page for an internal page, internal_page_max.
+ 3. The maximum size of the on-disk leaf page, leaf_page_max.
+
+There are additional configuration settings that tune more esoteric and
+specialized data. Those are included for completeness but are rarely changed.
+
+@subsection memory_page_max memory_page_max
+The maximum size a table's page is allowed to grow to in memory before being
+reconciled to disk.
+ - An integer, with acceptable values between 512B and 10TB
+ - Default size: 5 MB
+ - Additionally constrained by the condition:
+ leaf_page_max <= memory_page_max <= cache_size/10
+ - Motivation to tune the value:
+\n memory_page_max is significant for applications wanting to tune for
+consistency in write intensive workloads.
+ - This is the parameter to start with for tuning and trying different values
+to find the correct balance between overall throughput and individual operation
+latency for each table.
+ - Splitting a growing in-memory page into smaller pages and reconciliation
+both require exclusive access to the page which makes an application's write
+operations wait. Having a large memory_page_max means that the pages will need
+to be split and reconciled less often. But when that happens, the duration that
+an exclusive access to the page is required is longer, increasing the latency of
+an application's insert or update operations. Conversely, having a smaller
+memory_page_max reduces the time taken for splitting and reconciling the pages,
+but causes it to happen more frequently, forcing more frequent but shorter
+exclusive accesses to the pages.
+ - Applications should choose the memory_page_max value considering the
+trade-off between frequency of exclusive access to the pages (for reconciliation
+or splitting pages into smaller pages) versus the duration that the exclusive
+access is required.
+ - Configuration:
+\n Specified as memory_page_max configuration option to WT_SESSION::create(). An
+example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,memory_page_max=10MB"
+</pre>
+
+@subsection internal_page_max internal_page_max
+The maximum page size for the reconciled on-disk internal pages of the B-Tree,
+in bytes. When an internal page grows past this size, it splits into multiple
+pages.
+ - An integer, with acceptable values between 512B and 512MB
+ - Default size: 4 KB (*appropriate for applications with relatively small keys)
+ - Additionally constrained by the condition: the size must be a multiple of the
+allocation size
+ - Motivation to tune the value:
+\n internal_page_max is significant for applications wanting to avoid excessive
+L2 cache misses while searching the tree.
+ - Recall that only keys are stored on internal pages, so the type and size of
+the key values for a table help drive the setting for this parameter.
+ - Should be sized to fit into on-chip caches.
+ - Applications doing full-table scans with out-of-memory workloads might
+increase internal_page_max to transfer more data per I/O.
+ - Influences the shape of the B-Tree, i.e. depth and the number of children
+each page in B-Tree has. To iterate to the desired key/value pair in the B-Tree,
+WiredTiger has to binary search the key-range in a page to determine the child
+page to proceed to and continue down the depth until it reaches the correct leaf
+page. Having an unusually deep B-Tree, or having too many children per page can
+negatively impact time taken to iterate the B-Tree, slowing down the application.
+The number of children per page and, hence, the tree depth depends upon the
+number of keys that can be stored in an internal page, which is
+internal_page_max divided by key size. Applications should choose an appropriate
+internal_page_max size that avoids the B-Tree from getting too deep.
+ - Configuration:
+\n Specified as internal_page_max configuration option to WT_SESSION::create().
+An example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,internal_page_max=16KB,leaf_page_max=1MB"
+</pre>
+
+@subsection leaf_page_max leaf_page_max
+The maximum page size for the reconciled on-disk leaf pages of the B-Tree, in
+bytes. When a leaf page grows past this size, it splits into multiple pages.
+ - An integer, with acceptable values between 512B and 512MB
+ - Default size: 32 KB (*appropriate for applications with relatively small keys
+and values)
+ - Additionally constrained by the condition: must be a multiple of the
+allocation size
+ - Motivation to tune the value:
+\n leaf_page_max is significant for applications wanting to maximize sequential
+data transfer from a storage device.
+ - Should be sized to maximize I/O performance (when reading from disk, it is
+usually desirable to read a large amount of data, assuming some locality of
+reference in the application's access pattern).
+ - Applications doing full-table scans through out-of-cache workloads might
+increase leaf_page_max to transfer more data per I/O.
+ - Applications focused on read/write amplification might decrease the page
+size to better match the underlying storage block size.
+ - Configuration:
+\n Specified as leaf_page_max configuration option to WT_SESSION::create(). An
+example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,internal_page_max=16KB,leaf_page_max=1MB"
+</pre>
+
+The following configuration items following are rarely used. They are described
+for completeness:
+
+@subsection allocation_size allocation_size
+This is the underlying unit of allocation for the file. As the unit of file
+allocation, it sets the minimum page size and how much space is wasted when
+storing small amounts of data and overflow items.
+ - an integer between 512B and 128 MB
+ - must a power-of-two
+ - default : 4 KB
+ - Motivation to tune the value:
+\n Most applications should not need to tune the allocation size.
+ - To be compatible with virtual memory page sizes and direct I/O requirements
+on the platform (4KB for most common server platforms)
+ - Smaller values decrease the file space required by overflow items.
+ - For example, if the allocation size is set to 4KB, an overflow item of
+18,000 bytes requires 5 allocation units and wastes about 2KB of space. If the
+allocation size is 16KB, the same overflow item would waste more than 10KB.
+ - Configuration:
+\n Specified as allocation_size configuration option to WT_SESSION::create(). An
+example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,allocation_size=4KB"
+</pre>
+
+@subsection key_val_max internal/leaf key/value max
+ - Overflow items
+\n Overflow items are keys and values too large to easily store on a page. Overflow
+items are stored separately in the file from the page where the item logically
+appears, and so reading or writing an overflow item is more expensive than an
+on-page item, normally requiring additional I/O. Additionally, overflow values
+are not cached in memory. This means overflow items won't affect the caching
+behavior of the application. It also means that each time an overflow value is
+read, it is re-read from disk.
+ - internal_key_max
+\n The largest key stored in an internal page, in bytes. If set, keys larger than
+the specified size are stored as overflow items.
+ - The default and the maximum allowed value are both one-tenth the size of a
+newly split internal page.
+ - leaf_key_max
+\n The largest key stored in a leaf page, in bytes. If set, keys larger than the
+specified size are stored as overflow items.
+ - The default value is one-tenth the size of a newly split leaf page.
+ - leaf_value_max
+\n The largest value stored in a leaf page, in bytes. If set, values larger than
+the specified size are stored as overflow items
+ - The default is one-half the size of a newly split leaf page.
+ - If the size is larger than the maximum leaf page size, the page size is
+temporarily ignored when large values are written.
+ - Motivation to tune the values:
+\n Most applications should not need to tune the maximum key and value sizes.
+Applications requiring a small page size, but also having latency concerns such
+that the additional work to retrieve an overflow item may find modifying these
+values useful.
+\n Since overflow items are separately stored in the on-disk file, aren't cached
+and require additional I/O to access (read or write), applications should avoid
+creating overflow items.
+ - Since page sizes also determine the default size of overflow items, i.e.,
+keys and values too large to easily store on a page, they can be configured to
+avoid performance penalties working with overflow items:
+ - Applications with large keys and values, and concerned with latency,
+might increase the page size to avoid creating overflow items, in order to avoid
+the additional cost of retrieving them.
+ - Applications with large keys and values, doing random searches, might
+decrease the page size to avoid wasting cache space on overflow items that
+aren't likely to be needed.
+ - Applications with large keys and values, doing table scans, might
+increase the page size to avoid creating overflow items, as the overflow items
+must be read into memory in all cases, anyway.
+ - internal_key_max, leaf_key_max and leaf_value_max configuration values
+allow applications to change the size at which a key or value will be treated
+as an overflow item.
+ - Most applications should not need to tune the maximum key and value
+sizes.
+ - The value of internal_key_max is relative to the maximum internal page
+size. Because the number of keys on an internal page determines the depth of the
+tree, the internal_key_max value can only be adjusted within a certain range,
+and the configured value will be automatically adjusted by WiredTiger, if
+necessary, to ensure a reasonable number of keys fit on an internal page.
+ - The values of leaf_key_max and leaf_value_max are not relative to the
+maximum leaf page size. If either is larger than the maximum page size, the page
+size will be ignored when the larger keys and values are being written, and a
+larger page will be created as necessary.
+ - Configuration:
+\n Specified as internal_key_max, leaf_key_max and leaf_value_max configuration
+options to WT_SESSION::create(). An example of configuration string for a large
+leaf overflow value:
+
+<pre>
+ "key_format=S,value_format=S,leaf_page_max=16KB,leaf_value_max=256KB"
+</pre>
+
+@subsection split_pct split_pct (split percentage)
+The size (specified as percentage of internal/leaf page_max) at which the
+reconciled page must be split into multiple smaller pages before being sent for
+compression and then be written to the disk. If the reconciled page can fit into
+a single on-disk page without the page growing beyond it's set max size,
+split_pct is ignored and the page isn't split.
+ - an integer between 25 and 100
+ - default : 75
+ - Motivation to tune the value:
+\n Most applications should not need to tune the split percentage size.
+ - This value should be selected to avoid creating a large number of tiny
+pages or repeatedly splitting whenever new entries are inserted.
+\n For example, if the maximum page size is 1MB, a split_pct value of 10%
+would potentially result in creating a large number of 100KB pages, which may
+not be optimal for future I/O. Or, if the maximum page size is 1MB, a split_pct
+value of 90% would potentially result in repeatedly splitting pages as the split
+pages grow to 1MB over and over. The default value for split_pct is 75%,
+intended to keep large pages relatively large, while still giving split pages
+room to grow.
+ - Configuration:
+\n Specified as split_pct configuration option to WT_SESSION::create(). An
+example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,split_pct=60"
+</pre>
+
+@section compression_considerations Compression considerations
+WiredTiger compresses data at several stages to preserve memory and disk space.
+Applications can configure these different compression algorithms to tailor
+their requirements between memory, disk and CPU consumption. Compression
+algorithms other than block compression work by modifying how the keys and
+values are represented, and hence reduce data size in-memory and on-disk. Block
+compression on the other hand compress the data in its binary representation
+while saving it on the disk.
+
+Configuring compression may change application throughput. For example, in
+applications using solid-state drives (where I/O is less expensive), turning
+off compression may increase application performance by reducing CPU costs; in
+applications where I/O costs are more expensive, turning on compression may
+increase application performance by reducing the overall number of I/O
+operations.
+
+WiredTiger uses some internal algorithms to compress the amount of data stored
+that are not configurable, but always on. For example, run-length reduces the
+size requirement by storing sequential, duplicate values in the store only a
+single time (with an associated count).
+
+Different compression options available with WiredTiger:
+ - Key-prefix
+ - Reduces the size requirement by storing any identical key prefix only once
+per page. The cost is additional CPU and memory when operating on the in-memory
+tree. Specifically, reverse sequential cursor movement (but not forward) through
+a prefix-compressed page or the random lookup of a key/value pair will allocate
+sufficient memory to hold some number of uncompressed keys. So, for example, if
+key prefix compression only saves a small number of bytes per key, the
+additional memory cost of instantiating the uncompressed key may mean prefix
+compression is not worthwhile. Further, in cases where the on-disk cost is the
+primary concern, block compression may mean prefix compression is less useful.
+ - Configuration:
+\n Specified as prefix_compression configuration option to
+WT_SESSION::create(). Applications may limit the use of prefix compression by
+configuring the minimum number of bytes that must be gained before prefix
+compression is used with prefix_compression_min configuration option. An example
+of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,prefix_compression=true,prefix_compression_min=7"
+</pre>
+
+ - Dictionary
+ - Reduces the size requirement by storing any identical value only once per
+page.
+ - Configuration:
+\n Specified as dictionary configuration configuration option to
+WT_SESSION::create(), which specifies the maximum number of unique values
+remembered in the B-Tree row-store leaf page value dictionary. An example of
+such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,dictionary=1000"
+</pre>
+
+ - Huffman
+ - Reduces the size requirement by compressing individual key/value items, and
+can be separately configured either or both keys and values. The additional CPU
+cost of Huffman encoding can be high, and should be considered. (See Huffman
+Encoding for details.)
+ - Configuration:
+\n Specified as huffman_key and/or huffman_value configuration option to
+WT_SESSION::create(). These options can take values of "english" (to use a
+built-in English language frequency table), "utf8<file>" or "utf16<file>" (to
+use a custom utf8 or utf16 symbol frequency table file). An example of such a
+configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,huffman_key=english,huffman_value=english"
+</pre>
+
+ - Block Compression
+ - Reduces the size requirement of on-disk objects by compressing blocks of
+the backing object's file. The additional CPU cost of block compression can be
+high, and should be considered. When block compression has been configured,
+configured page sizes will not match the actual size of the page on disk.
+ - WiredTiger provides two methods of compressing your data when using block
+compression: the raw and noraw methods. These methods change how WiredTiger
+works to fit data into the blocks that are stored on disk. Applications needing
+to write specific sized blocks may want to consider implementing a
+WT_COMPRESSOR::compress_raw function.
+ - Noraw compression:
+\n A fixed amount of data is given to the compression system, then turned into
+a compressed block of data. The amount of data chosen to compress is the data
+needed to fill the uncompressed block. Thus when compressed, the block will be
+smaller than the normal data size and the sizes written to disk will often vary
+depending on how compressible the data being stored is. Algorithms using noraw
+compression include zlib-noraw, lz4-noraw and snappy.
+Noraw compression is better suited for workloads with random access patterns
+because each block will tend to be smaller and require less work to read and
+decompress.
+ - Raw compression:
+\n WiredTiger's raw compression takes advantage of compressors that provide a
+streaming compression API. Using the streaming API WiredTiger will try to fit as
+much data as possible into one block. This means that blocks created with raw
+compression should be of similar size. Using a streaming compression method
+should also make for less overhead in compression, as the setup and initial work
+for compressing is done fewer times compared to the amount of data stored.
+Algorithms using raw compression include zlib, lz4.
+Compared to noraw, raw compression provides more compression while using more
+CPU. Raw compression may provide a performance advantage in workloads where data
+is accessed sequentially. That is because more data is generally packed into
+each block on disk.
+ - Configuration:
+\n Specified as the block_compressor configuration option to
+WT_SESSION::create(). If WiredTiger has builtin support for "lz4", "snappy",
+"zlib" or "zstd" compression, these names are available as the value to the
+option. An example of such a configuration string is as follows:
+
+<pre>
+ "key_format=S,value_format=S,block_compressor=snappy"
+</pre>
+
+See @ref compression for further information on how to configure and enable
+different compression options.
+
+@subsection table_compress Table summarizing compression in WiredTiger
+
+<table>
+@hrow{Compression Type, Supported by row-store, Supported by variable col-store,
+ Supported by fixed col-store, Default config, Reduces in-mem size,
+ Reduces on-disk size, CPU and Memory cost}
+@row{Key-prefix, yes, no, no, disabled, yes, yes, minor}
+@row{Dictionary, yes, yes, no, disabled, yes, yes, minor}
+@row{Huffman, yes, yes, no, disabled, yes, yes, can be high}
+@row{Block, yes, yes, yes, disabled, no, yes, can be high}
+</table>
+
+*/
diff --git a/src/docs/tune-page-sizes.dox b/src/docs/tune-page-sizes.dox
deleted file mode 100644
index 130e047a02d..00000000000
--- a/src/docs/tune-page-sizes.dox
+++ /dev/null
@@ -1,142 +0,0 @@
-/*! @page tune_page_sizes Page and overflow key/value sizes
-
-There are seven page and key/value size configuration strings:
-
-- allocation size (\c allocation_size),
-- page sizes (\c internal_page_max and \c leaf_page_max),
-- key and value sizes (\c internal_key_max, \c leaf_key_max and \c leaf_value_max), and the
-- page-split percentage (\c split_pct).
-
-All seven are specified to the WT_SESSION::create method, in other
-words, they are configurable on a per-file basis.
-
-Applications commonly configure page sizes, based on their workload's
-typical key and value size. Once the correct page size has been chosen,
-appropriate defaults for the other configuration values are derived from
-the page sizes, and relatively few applications will need to modify the
-other page and key/value size configuration options.
-
-An example of configuring page and key/value sizes:
-
-@snippet ex_all.c Create a table and configure the page size
-
-@section tune_page_sizes_sizes Page, key and value sizes
-
-The \c internal_page_max and \c leaf_page_max configuration values
-specify a maximum size for Btree internal and leaf pages. That is, when
-an internal or leaf page grows past that size, it splits into multiple
-pages. Generally, internal pages should be sized to fit into on-chip
-caches in order to minimize cache misses when searching the tree, while
-leaf pages should be sized to maximize I/O performance (if reading from
-disk is necessary, it is usually desirable to read a large amount of
-data, assuming some locality of reference in the application's access
-pattern).
-
-The default page size configurations (2KB for \c internal_page_max, 32KB
-for \c leaf_page_max), are appropriate for applications with relatively
-small keys and values.
-
-- Applications doing full-table scans through out-of-memory workloads
-might increase both internal and leaf page sizes to transfer more data
-per I/O.
-- Applications focused on read/write amplification might decrease the page
-size to better match the underlying storage block size.
-
-When block compression has been configured, configured page sizes will
-not match the actual size of the page on disk. Block compression in
-WiredTiger happens within the I/O subsystem, and so a page might split
-even if subsequent compression would result in a resulting page size
-small enough to leave as a single page. In other words, page sizes are
-based on in-memory sizes, not on-disk sizes. Applications needing to
-write specific sized blocks may want to consider implementing a
-WT_COMPRESSOR::compress_raw function.
-
-The page sizes also determine the default size of overflow items, that
-is, keys and values too large to easily store on a page. Overflow items
-are stored separately in the file from the page where the item logically
-appears, and so reading or writing an overflow item is more expensive
-than an on-page item, normally requiring additional I/O. Additionally,
-overflow values are not cached in memory. This means overflow items
-won't affect the caching behavior of the application, but it also means
-that each time an overflow value is read, it is re-read from disk.
-
-For both of these reasons, applications should avoid creating large
-numbers of commonly referenced overflow items. This is especially
-important for keys, as keys on internal pages are referenced during
-random searches, not just during data retrieval. Generally,
-applications should make every attempt to avoid creating overflow keys.
-
-- Applications with large keys and values, and concerned with latency,
-might increase the page size to avoid creating overflow items, in order
-to avoid the additional cost of retrieving them.
-
-- Applications with large keys and values, doing random searches, might
-decrease the page size to avoid wasting cache space on overflow items
-that aren't likely to be needed.
-
-- Applications with large keys and values, doing table scans, might
-increase the page size to avoid creating overflow items, as the overflow
-items must be read into memory in all cases, anyway.
-
-The \c internal_key_max, \c leaf_key_max and \c leaf_value_max
-configuration values allow applications to change the size at which a
-key or value will be treated as an overflow item.
-
-The value of \c internal_key_max is relative to the maximum internal
-page size. Because the number of keys on an internal page determines
-the depth of the tree, the \c internal_key_max value can only be
-adjusted within a certain range, and the configured value will be
-automatically adjusted by WiredTiger, if necessary to ensure a
-reasonable number of keys fit on an internal page.
-
-The values of \c leaf_key_max and \c leaf_value_max are not relative to
-the maximum leaf page size. If either is larger than the maximum page
-size, the page size will be ignored when the larger keys and values are
-being written, and a larger page will be created as necessary.
-
-Most applications should not need to tune the maximum key and value
-sizes. Applications requiring a small page size, but also having
-latency concerns such that the additional work to retrieve an overflow
-item is an issue, may find them useful.
-
-An example of configuring a large leaf overflow value:
-
-@snippet ex_all.c Create a table and configure a large leaf value max
-
-@section tune_page_sizes_split_percentage Split percentage
-
-The \c split_pct configuration string configures the size of a split
-page. When a page grows sufficiently large that it must be written as
-multiple disk blocks, the newly written block size is \c split_pct
-percent of the maximum page size. This value should be selected to
-avoid creating a large number of tiny pages or repeatedly splitting
-whenever new entries are inserted. For example, if the maximum page
-size is 1MB, a \c split_pct value of 10% would potentially result in
-creating a large number of 100KB pages, which may not be optimal for
-future I/O. Or, if the maximum page size is 1MB, a \c split_pct value
-of 90% would potentially result in repeatedly splitting pages as the
-split pages grow to 1MB over and over. The default value for \c
-split_pct is 75%, intended to keep large pages relatively large, while
-still giving split pages room to grow.
-
-Most applications should not need to tune the split percentage size.
-
-@section tune_page_sizes_allocation_size Allocation size
-
-The \c allocation_size configuration value is the underlying unit of
-allocation for the file. As the unit of file allocation, it sets the
-minimum page size and how much space is wasted when storing small
-amounts of data and overflow items. For example, if the allocation size
-is set to 4KB, an overflow item of 18,000 bytes requires 5 allocation
-units and wastes about 2KB of space. If the allocation size is 16KB,
-the same overflow item would waste more than 10KB.
-
-The default allocation size is 4KB, chosen for compatibility with
-virtual memory page sizes and direct I/O requirements on common server
-platforms.
-
-Most applications should not need to tune the allocation size; it is
-primarily intended for applications coping with the specific
-requirements some file systems make to support features like direct I/O.
-
-*/
diff --git a/src/docs/upgrading.dox b/src/docs/upgrading.dox
index 1e0e2eaf99a..4a356f7da61 100644
--- a/src/docs/upgrading.dox
+++ b/src/docs/upgrading.dox
@@ -1,19 +1,33 @@
/*! @page upgrading Upgrading WiredTiger applications
-@section version_291 Upgrading to Version 2.9.1
+
+@section version_292 Upgrading to Version 2.9.2
<dl>
-<dt>WiredTiger now requires Python 2.7 at minimum</dt>
+<dt>WiredTiger Utility now supports truncate</dt>
<dd>
-The minimum version of Python supported by WiredTiger is now 2.7 up from the
-previous version of 2.6. This is due to extra unit tests added in this release
-that depend on 2.7. This is not due to a change in the Python API.
+The WiredTiger Utility can now \c truncate an object. Removing all contents
+from the specified object.
</dd>
+</dl>
+@section version_291 Upgrading to Version 2.9.1
+
+<dl>
<dt>Changes to hazard pointer configuration</dt>
<dd>
The \c hazard_max parameter to ::wiredtiger_open is now ignored. Memory is
allocated for hazard pointers as required by each session.
</dd>
-</dl><hr>
+
+<dt>Change to the default fadvise behavior for data files</dt>
+<dd>
+The old default behavior was to advise the file system that access would be
+random for data files, and there was no way to alter that. We no longer
+call advise the file system of expected access patterns by default, and
+have added a new \c access_pattern_hint configuration option available for
+WT_SESSION::create that can be used to restore the old default by setting
+the value to "random".
+</dd>
+</dl>
@section version_290 Upgrading to Version 2.9.0
<dl>
@@ -314,7 +328,7 @@ be updated.
The WT_SESSION::create \c internal_item_max and \c leaf_item_max
configuration strings are now deprecated in favor of the
\c internal_key_max, \c leaf_key_max, and \c leaf_value_max
-configuration strings. See @ref tune_page_sizes for more information.
+configuration strings. See @ref tune_page_size_and_comp for more information.
</dd>
</dl><hr>
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index 6fa728916de..9b969de9a9e 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -15,6 +15,7 @@ static int __evict_lru_walk(WT_SESSION_IMPL *);
static int __evict_page(WT_SESSION_IMPL *, bool);
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(
WT_SESSION_IMPL *, WT_EVICT_QUEUE *, u_int, u_int *);
@@ -23,6 +24,59 @@ static int __evict_walk_file(
(S2C(s)->evict_threads.current_threads > 1)
/*
+ * __evict_lock_dhandle --
+ * Try to get the dhandle lock, with yield and sleep back off.
+ * Keep timing statistics overall.
+ */
+static int
+__evict_lock_dhandle(WT_SESSION_IMPL *session)
+{
+ struct timespec enter, leave;
+ WT_CACHE *cache;
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ WT_SPINLOCK *dh_lock;
+ int64_t **stats;
+ u_int spins;
+ bool dh_stats;
+
+ conn = S2C(session);
+ cache = conn->cache;
+ dh_lock = &conn->dhandle_lock;
+ stats = (int64_t **)conn->stats;
+ dh_stats = WT_STAT_ENABLED(session) && dh_lock->stat_count_off != -1;
+
+ /*
+ * Maintain lock acquisition timing statistics as if this were a
+ * regular lock acquisition.
+ */
+ if (dh_stats)
+ __wt_epoch(session, &enter);
+ /*
+ * Use a custom lock acquisition back off loop so the eviction server
+ * notices any interrupt quickly.
+ */
+ for (spins = 0;
+ (ret = __wt_spin_trylock_track(session, dh_lock)) == EBUSY &&
+ cache->pass_intr == 0; spins++) {
+ if (spins < WT_THOUSAND)
+ __wt_yield();
+ else
+ __wt_sleep(0, WT_THOUSAND);
+ }
+ /*
+ * Only record statistics on success.
+ */
+ WT_RET(ret);
+ if (dh_stats) {
+ __wt_epoch(session, &leave);
+ stats[session->stat_bucket][dh_lock->stat_int_usecs_off] +=
+ (int64_t)WT_TIMEDIFF_US(leave, enter);
+ }
+ return (0);
+}
+
+/*
* __evict_entry_priority --
* Get the adjusted read generation for an eviction entry.
*/
@@ -306,7 +360,6 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
struct timespec now;
#endif
uint64_t orig_pages_evicted;
- u_int spins;
conn = S2C(session);
cache = conn->cache;
@@ -325,21 +378,14 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
* otherwise we can block applications evicting large pages.
*/
if (!__wt_cache_stuck(session)) {
- for (spins = 0; (ret = __wt_spin_trylock(
- session, &conn->dhandle_lock)) == EBUSY &&
- cache->pass_intr == 0; spins++) {
- if (spins < WT_THOUSAND)
- __wt_yield();
- else
- __wt_sleep(0, WT_THOUSAND);
- }
+
/*
* If we gave up acquiring the lock, that indicates a
* session is waiting for us to clear walks. Do that
* as part of a normal pass (without the handle list
* lock) to avoid deadlock.
*/
- if (ret == EBUSY)
+ if ((ret = __evict_lock_dhandle(session)) == EBUSY)
return (0);
WT_RET(ret);
ret = __evict_clear_all_walks(session);
@@ -365,7 +411,7 @@ __evict_server(WT_SESSION_IMPL *session, bool *did_work)
ret = ETIMEDOUT;
__wt_err(session, ret,
"Cache stuck for too long, giving up");
- WT_TRET(__wt_cache_dump(session, NULL));
+ WT_TRET(__wt_dump_stuck_info(session, NULL));
return (ret);
}
#endif
@@ -389,11 +435,13 @@ __wt_evict_create(WT_SESSION_IMPL *session)
/* Set first, the thread might run before we finish up. */
F_SET(conn, WT_CONN_EVICTION_RUN);
- /* Create the eviction thread group */
+ /*
+ * Create the eviction thread group.
+ * Set the group size to the maximum allowed sessions.
+ */
WT_RET(__wt_thread_group_create(session, &conn->evict_threads,
- "eviction-server", conn->evict_threads_min,
- conn->evict_threads_max, WT_THREAD_CAN_WAIT | WT_THREAD_PANIC_FAIL,
- __wt_evict_thread_run));
+ "eviction-server", conn->evict_threads_min, conn->evict_threads_max,
+ WT_THREAD_CAN_WAIT | WT_THREAD_PANIC_FAIL, __wt_evict_thread_run));
/*
* Allow queues to be populated now that the eviction threads
@@ -420,7 +468,7 @@ __wt_evict_destroy(WT_SESSION_IMPL *session)
return (0);
/* Wait for any eviction thread group changes to stabilize. */
- __wt_writelock(session, conn->evict_threads.lock);
+ __wt_writelock(session, &conn->evict_threads.lock);
/*
* Signal the threads to finish and stop populating the queue.
@@ -548,6 +596,8 @@ __evict_pass(WT_SESSION_IMPL *session)
if (loop == 0)
prev = now;
+ if (conn->evict_threads.threads[0]->session == session)
+ WT_RET(__evict_tune_workers(session));
/*
* Increment the shared read generation. Do this occasionally
* even if eviction is not currently required, so that pages
@@ -573,14 +623,6 @@ __evict_pass(WT_SESSION_IMPL *session)
if (!__evict_update_work(session))
break;
- /*
- * Try to start a new thread if we have capacity and haven't
- * reached the eviction targets.
- */
- if (F_ISSET(cache, WT_CACHE_EVICT_ALL))
- WT_RET(__wt_thread_group_start_one(
- session, &conn->evict_threads, false));
-
__wt_verbose(session, WT_VERB_EVICTSERVER,
"Eviction pass with: Max: %" PRIu64
" In use: %" PRIu64 " Dirty: %" PRIu64,
@@ -844,6 +886,184 @@ __wt_evict_file_exclusive_off(WT_SESSION_IMPL *session)
__wt_spin_unlock(session, &cache->evict_walk_lock);
}
+#define EVICT_TUNE_BATCH 1 /* Max workers to add each period */
+#define EVICT_TUNE_DATAPT_MIN 3 /* Data points needed before deciding
+ if we should keep adding workers or
+ settle on an earlier value. */
+#define EVICT_TUNE_PERIOD 2 /* Tune period in seconds */
+
+/*
+ * __evict_tune_workers --
+ * Find the right number of eviction workers. Gradually ramp up the number of
+ * workers increasing the number in batches indicated by the setting above.
+ * Store the number of workers that gave us the best throughput so far and
+ * the number of data points we have tried.
+ *
+ * Every once in a while when we have the minimum number of data points
+ * we check whether the eviction throughput achieved with the current number
+ * of workers is the best we have seen so far. If so, we will keep increasing
+ * the number of workers. If not, we are past the infliction point on the
+ * eviction throughput curve. In that case, we will set the number of workers
+ * to the best observed so far and settle into a stable state.
+ */
+static int
+__evict_tune_workers(WT_SESSION_IMPL *session)
+{
+ struct timespec current_time;
+ WT_CACHE *cache;
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ uint64_t cur_threads, delta_msec, delta_pages, i, target_threads;
+ uint64_t pgs_evicted_cur, pgs_evicted_persec_cur;
+ uint32_t thread_surplus;
+
+ conn = S2C(session);
+ cache = conn->cache;
+
+ WT_ASSERT(session, conn->evict_threads.threads[0]->session == session);
+ pgs_evicted_persec_cur = 0;
+
+ if (conn->evict_tune_stable)
+ return (0);
+
+ __wt_epoch(session, &current_time);
+
+ /*
+ * Every EVICT_TUNE_PERIOD seconds record the number of
+ * pages evicted per second observed in the previous period.
+ */
+ if (WT_TIMEDIFF_SEC(
+ current_time, conn->evict_tune_last_time) < EVICT_TUNE_PERIOD)
+ return (0);
+
+ pgs_evicted_cur = cache->pages_evict;
+
+ /*
+ * If we have recorded the number of pages evicted at the end of
+ * the previous measurement interval, we can compute the eviction
+ * rate in evicted pages per second achieved during the current
+ * measurement interval.
+ * Otherwise, we just record the number of evicted pages and return.
+ */
+ if (conn->evict_tune_pgs_last == 0)
+ goto err;
+
+ delta_msec = WT_TIMEDIFF_MS(current_time, conn->evict_tune_last_time);
+ delta_pages = pgs_evicted_cur - conn->evict_tune_pgs_last;
+ pgs_evicted_persec_cur = (delta_pages * WT_THOUSAND) / delta_msec;
+ conn->evict_tune_num_points++;
+
+ /* Keep track of the maximum eviction throughput seen and the number
+ * of workers corresponding to that throughput.
+ */
+ if (pgs_evicted_persec_cur > conn->evict_tune_pg_sec_max) {
+ conn->evict_tune_pg_sec_max = pgs_evicted_persec_cur;
+ conn->evict_tune_workers_best =
+ conn->evict_threads.current_threads;
+ }
+
+ /*
+ * Compare the current number of data points with the number
+ * needed variable. If they are equal, we will check whether
+ * we are still going up on the performance curve, in which
+ * case we will continue increasing the number of workers, or
+ * we are past the inflection point on the curve, in which case
+ * we will go back to the best observed number of workers and
+ * settle into a stable state.
+ */
+ if (conn->evict_tune_num_points >= conn->evict_tune_datapts_needed) {
+ if ((conn->evict_tune_workers_best ==
+ conn->evict_threads.current_threads) &&
+ (conn->evict_threads.current_threads <
+ conn->evict_threads_max)) {
+ /*
+ * Keep adding workers. We will check again
+ * at the next check point.
+ */
+ conn->evict_tune_datapts_needed +=
+ WT_MIN(EVICT_TUNE_DATAPT_MIN,
+ (conn->evict_threads_max
+ - conn->evict_threads.current_threads)/
+ EVICT_TUNE_BATCH);
+ } else {
+ /*
+ * We are past the inflection point. Choose the
+ * best number of eviction workers observed and
+ * settle into a stable state.
+ */
+ thread_surplus =
+ conn->evict_threads.current_threads -
+ conn->evict_tune_workers_best;
+
+ for (i = 0; i < thread_surplus; i++) {
+ /*
+ * If we get an error, it should be because we
+ * were unable to acquire the thread group lock.
+ * Break out of trying.
+ */
+ WT_ERR(__wt_thread_group_stop_one(
+ session, &conn->evict_threads, false));
+ WT_STAT_CONN_INCR(session,
+ cache_eviction_worker_removed);
+ }
+ WT_STAT_CONN_SET(session,
+ cache_eviction_stable_state_workers,
+ conn->evict_tune_workers_best);
+ conn->evict_tune_stable = true;
+ WT_STAT_CONN_SET(session, cache_eviction_active_workers,
+ conn->evict_threads.current_threads);
+ return (0);
+ }
+ }
+
+ /*
+ * If we have not added any worker threads in the past, we set the
+ * number needed equal to the number of data points that we must
+ * accumulate before deciding if we should keep adding workers or settle
+ * on a previously tried value of workers.
+ */
+ if (conn->evict_tune_last_action_time.tv_sec == 0)
+ conn->evict_tune_datapts_needed = WT_MIN(EVICT_TUNE_DATAPT_MIN,
+ (conn->evict_threads_max -
+ conn->evict_threads.current_threads) / EVICT_TUNE_BATCH);
+
+ if (F_ISSET(cache, WT_CACHE_EVICT_ALL)) {
+ cur_threads = conn->evict_threads.current_threads;
+ target_threads = WT_MIN(cur_threads + EVICT_TUNE_BATCH,
+ conn->evict_threads_max);
+ /*
+ * Start the new threads.
+ */
+ for (i = 0; i < (target_threads - cur_threads); ++i) {
+ /*
+ * If we get an error, it should be because we were
+ * unable to acquire the thread group lock. Break out
+ * of trying.
+ */
+ WT_ERR(__wt_thread_group_start_one(session,
+ &conn->evict_threads, false));
+ WT_STAT_CONN_INCR(session,
+ cache_eviction_worker_created);
+ __wt_verbose(session, WT_VERB_EVICTSERVER,
+ "added worker thread");
+ }
+ conn->evict_tune_last_action_time = current_time;
+ }
+
+ WT_STAT_CONN_SET(session, cache_eviction_active_workers,
+ conn->evict_threads.current_threads);
+
+err: conn->evict_tune_last_time = current_time;
+ conn->evict_tune_pgs_last = pgs_evicted_cur;
+ /*
+ * If we got an EBUSY trying to acquire the lock just return.
+ * We can try to tune the workers next time.
+ */
+ if (ret == EBUSY)
+ ret = 0;
+ return (ret);
+}
+
/*
* __evict_lru_pages --
* Get pages from the LRU queue to evict.
@@ -1046,7 +1266,7 @@ __evict_walk(WT_SESSION_IMPL *session, WT_EVICT_QUEUE *queue)
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
- u_int max_entries, retries, slot, spins, start_slot, total_candidates;
+ u_int max_entries, retries, slot, start_slot, total_candidates;
bool dhandle_locked, incr;
conn = S2C(session);
@@ -1084,16 +1304,7 @@ retry: while (slot < max_entries) {
* reference count to keep it alive while we sweep.
*/
if (!dhandle_locked) {
- for (spins = 0; (ret = __wt_spin_trylock(
- session, &conn->dhandle_lock)) == EBUSY &&
- cache->pass_intr == 0;
- spins++) {
- if (spins < WT_THOUSAND)
- __wt_yield();
- else
- __wt_sleep(0, WT_THOUSAND);
- }
- WT_ERR(ret);
+ WT_ERR(__evict_lock_dhandle(session));
dhandle_locked = true;
}
@@ -1282,8 +1493,8 @@ __evict_push_candidate(WT_SESSION_IMPL *session,
* Get a few page eviction candidates from a single underlying file.
*/
static int
-__evict_walk_file(WT_SESSION_IMPL *session, WT_EVICT_QUEUE *queue,
- u_int max_entries, u_int *slotp)
+__evict_walk_file(WT_SESSION_IMPL *session,
+ WT_EVICT_QUEUE *queue, u_int max_entries, u_int *slotp)
{
WT_BTREE *btree;
WT_CACHE *cache;
@@ -1439,7 +1650,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, WT_EVICT_QUEUE *queue,
if (page->read_gen == WT_READGEN_NOTSET)
__wt_cache_read_gen_new(session, page);
- /* Pages we no longer need (clean or dirty), are found money. */
+ /* Pages being forcibly evicted go on the urgent queue. */
if (page->read_gen == WT_READGEN_OLDEST ||
page->memory_footprint >= btree->splitmempage) {
WT_STAT_CONN_INCR(
@@ -1449,7 +1660,7 @@ __evict_walk_file(WT_SESSION_IMPL *session, WT_EVICT_QUEUE *queue,
continue;
}
- /* Pages that are empty or from dead trees are also good. */
+ /* Pages that are empty or from dead trees are fast-tracked. */
if (__wt_page_is_empty(page) ||
F_ISSET(session->dhandle, WT_DHANDLE_DEAD))
goto fast;
@@ -1975,14 +2186,111 @@ __wt_evict_priority_clear(WT_SESSION_IMPL *session)
#ifdef HAVE_DIAGNOSTIC
/*
- * __wt_cache_dump --
- * Dump debugging information to a file (default stderr) about the size of
- * the files in the cache.
+ * __dump_txn_state --
+ * Output debugging information about the global transaction state.
*/
-int
-__wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
+static int
+__dump_txn_state(WT_SESSION_IMPL *session, FILE *fp)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_TXN_GLOBAL *txn_global;
+ WT_TXN *txn;
+ WT_TXN_STATE *s;
+ const char *iso_tag;
+ uint64_t id;
+ uint32_t i, session_cnt;
+
+ conn = S2C(session);
+ txn_global = &conn->txn_global;
+ WT_ORDERED_READ(session_cnt, conn->session_cnt);
+
+ /* Note: odd string concatenation avoids spelling errors. */
+ if (fprintf(fp, "==========\n" "transaction state dump\n") < 0)
+ return (EIO);
+
+ if (fprintf(fp,
+ "current ID: %" PRIu64 "\n"
+ "last running ID: %" PRIu64 "\n"
+ "oldest ID: %" PRIu64 "\n"
+ "oldest named snapshot ID: %" PRIu64 "\n",
+ txn_global->current, txn_global->last_running,
+ txn_global->oldest_id, txn_global->nsnap_oldest_id) < 0)
+ return (EIO);
+
+ if (fprintf(fp,
+ "checkpoint running? %s\n"
+ "checkpoint generation: %" PRIu64 "\n"
+ "checkpoint pinned ID: %" PRIu64 "\n"
+ "checkpoint txn ID: %" PRIu64 "\n"
+ "session count: %" PRIu32 "\n",
+ txn_global->checkpoint_running ? "yes" : "no",
+ txn_global->checkpoint_gen,
+ txn_global->checkpoint_pinned,
+ txn_global->checkpoint_txnid,
+ session_cnt) < 0)
+ return (EIO);
+
+ if (fprintf(fp, "Dumping transaction state of active sessions\n") < 0)
+ return (EIO);
+
+ /*
+ * Walk each session transaction state and dump information. Accessing
+ * the content of session handles is not thread safe, so some
+ * information may change while traversing if other threads are active
+ * at the same time, which is OK since this is diagnostic code.
+ */
+ for (i = 0, s = txn_global->states; i < session_cnt; i++, s++) {
+ /* Skip sessions with no active transaction */
+ if ((id = s->id) == WT_TXN_NONE && s->pinned_id == WT_TXN_NONE)
+ continue;
+
+ txn = &conn->sessions[i].txn;
+ iso_tag = "INVALID";
+ switch (txn->isolation) {
+ case WT_ISO_READ_COMMITTED:
+ iso_tag = "WT_ISO_READ_COMMITTED";
+ break;
+ case WT_ISO_READ_UNCOMMITTED:
+ iso_tag = "WT_ISO_READ_UNCOMMITTED";
+ break;
+ case WT_ISO_SNAPSHOT:
+ iso_tag = "WT_ISO_SNAPSHOT";
+ break;
+ }
+
+ if (fprintf(fp,
+ "ID: %6" PRIu64
+ ", mod count: %u"
+ ", pinned ID: %" PRIu64
+ ", snap min: %" PRIu64
+ ", snap max: %" PRIu64
+ ", metadata pinned ID: %" PRIu64
+ ", flags: 0x%08" PRIx32
+ ", name: %s"
+ ", isolation: %s" "\n",
+ id,
+ txn->mod_count,
+ s->pinned_id,
+ txn->snap_min,
+ txn->snap_max,
+ s->metadata_pinned,
+ txn->flags,
+ conn->sessions[i].name == NULL ?
+ "EMPTY" : conn->sessions[i].name,
+ iso_tag) < 0)
+ return (EIO);
+ }
+
+ return (0);
+}
+
+/*
+ * __dump_cache --
+ * Output debugging information about the size of the files in cache.
+ */
+static int
+__dump_cache(WT_SESSION_IMPL *session, FILE *fp)
{
- FILE *fp;
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle, *saved_dhandle;
WT_PAGE *page;
@@ -1997,13 +2305,9 @@ __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
conn = S2C(session);
total_bytes = total_dirty_bytes = 0;
- if (ofile == NULL)
- fp = stderr;
- else if ((fp = fopen(ofile, "w")) == NULL)
- return (EIO);
-
/* Note: odd string concatenation avoids spelling errors. */
- (void)fprintf(fp, "==========\n" "cache dump\n");
+ if (fprintf(fp, "==========\n" "cache dump\n") < 0)
+ return (EIO);
saved_dhandle = session->dhandle;
TAILQ_FOREACH(dhandle, &conn->dhqh, q) {
@@ -2048,13 +2352,17 @@ __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
}
session->dhandle = NULL;
- if (dhandle->checkpoint == NULL)
- (void)fprintf(fp, "%s(<live>): \n", dhandle->name);
- else
- (void)fprintf(fp, "%s(checkpoint=%s): \n",
- dhandle->name, dhandle->checkpoint);
- if (intl_pages != 0)
- (void)fprintf(fp,
+ if (dhandle->checkpoint == NULL) {
+ if (fprintf(fp,
+ "%s(<live>): \n", dhandle->name) < 0)
+ return (EIO);
+ } else {
+ if (fprintf(fp, "%s(checkpoint=%s): \n",
+ dhandle->name, dhandle->checkpoint) < 0)
+ return (EIO);
+ }
+ if (intl_pages != 0) {
+ if (fprintf(fp,
"\t" "internal: "
"%" PRIu64 " pages, "
"%" PRIu64 "MB, "
@@ -2069,9 +2377,11 @@ __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
(intl_bytes - intl_dirty_bytes) >> 20,
intl_dirty_bytes >> 20,
intl_bytes_max >> 20,
- intl_dirty_bytes_max >> 20);
- if (leaf_pages != 0)
- (void)fprintf(fp,
+ intl_dirty_bytes_max >> 20) < 0)
+ return (EIO);
+ }
+ if (leaf_pages != 0) {
+ if (fprintf(fp,
"\t" "leaf: "
"%" PRIu64 " pages, "
"%" PRIu64 "MB, "
@@ -2086,7 +2396,9 @@ __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
(leaf_bytes - leaf_dirty_bytes) >> 20,
leaf_dirty_bytes >> 20,
leaf_bytes_max >> 20,
- leaf_dirty_bytes_max >> 20);
+ leaf_dirty_bytes_max >> 20) < 0)
+ return (EIO);
+ }
total_bytes += intl_bytes + leaf_bytes;
total_dirty_bytes += intl_dirty_bytes + leaf_dirty_bytes;
@@ -2099,16 +2411,39 @@ __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile)
*/
total_bytes = __wt_cache_bytes_plus_overhead(conn->cache, total_bytes);
- (void)fprintf(fp,
+ if (fprintf(fp,
"cache dump: "
- "total found = %" PRIu64 "MB vs tracked inuse %" PRIu64 "MB\n"
- "total dirty bytes = %" PRIu64 "MB\n",
+ "total found: %" PRIu64 "MB vs tracked inuse %" PRIu64 "MB\n"
+ "total dirty bytes: %" PRIu64 "MB\n",
total_bytes >> 20, __wt_cache_bytes_inuse(conn->cache) >> 20,
- total_dirty_bytes >> 20);
- (void)fprintf(fp, "==========\n");
-
- if (ofile != NULL && fclose(fp) != 0)
+ total_dirty_bytes >> 20) < 0)
return (EIO);
+ if (fprintf(fp, "==========\n") < 0)
+ return (EIO);
+
return (0);
}
+
+/*
+ * __wt_dump_stuck_info --
+ * Dump debugging information to a file (default stderr) about the state
+ * of WiredTiger when we have determined that the cache is stuck full.
+ */
+int
+__wt_dump_stuck_info(WT_SESSION_IMPL *session, const char *ofile)
+{
+ FILE *fp;
+ WT_DECL_RET;
+
+ if (ofile == NULL)
+ fp = stderr;
+ else if ((fp = fopen(ofile, "w")) == NULL)
+ return (EIO);
+
+ WT_ERR(__dump_txn_state(session, fp));
+ WT_ERR(__dump_cache(session, fp));
+err: if (ofile != NULL && fclose(fp) != 0)
+ return (EIO);
+ return (ret);
+}
#endif
diff --git a/src/include/btmem.h b/src/include/btmem.h
index 9bd835f5d09..43c1a309d52 100644
--- a/src/include/btmem.h
+++ b/src/include/btmem.h
@@ -435,6 +435,19 @@ struct __wt_page_modify {
};
/*
+ * WT_COL_RLE --
+ * Variable-length column-store pages have an array of page entries with RLE
+ * counts greater than 1 when reading the page, so it's not necessary to walk
+ * the page counting records to find a specific entry. We can do a binary search
+ * in this array, then an offset calculation to find the cell.
+ */
+WT_PACKED_STRUCT_BEGIN(__wt_col_rle)
+ uint64_t recno; /* Record number of first repeat. */
+ uint64_t rle; /* Repeat count. */
+ uint32_t indx; /* Slot of entry in col_var. */
+WT_PACKED_STRUCT_END
+
+/*
* WT_PAGE --
* The WT_PAGE structure describes the in-memory page information.
*/
@@ -515,53 +528,54 @@ struct __wt_page {
} while (0)
/* Row-store leaf page. */
- struct {
- WT_ROW *d; /* Key/value pairs */
- uint32_t entries; /* Entries */
- } row;
-#undef pg_row_d
-#define pg_row_d u.row.d
-#undef pg_row_entries
-#define pg_row_entries u.row.entries
+ WT_ROW *row; /* Key/value pairs */
+#undef pg_row
+#define pg_row u.row
/* Fixed-length column-store leaf page. */
- struct {
- uint8_t *bitf; /* Values */
- uint32_t entries; /* Entries */
- } col_fix;
+ uint8_t *fix_bitf; /* Values */
#undef pg_fix_bitf
-#define pg_fix_bitf u.col_fix.bitf
-#undef pg_fix_entries
-#define pg_fix_entries u.col_fix.entries
+#define pg_fix_bitf u.fix_bitf
/* Variable-length column-store leaf page. */
struct {
- WT_COL *d; /* Values */
+ WT_COL *col_var; /* Values */
/*
- * Variable-length column-store files maintain a list of
- * RLE entries on the page so it's unnecessary to walk
- * the page counting records to find a specific entry.
+ * Variable-length column-store pages have an array
+ * of page entries with RLE counts greater than 1 when
+ * reading the page, so it's not necessary to walk the
+ * page counting records to find a specific entry. We
+ * can do a binary search in this array, then an offset
+ * calculation to find the cell.
+ *
+ * It's a separate structure to keep the page structure
+ * as small as possible.
*/
- WT_COL_RLE *repeats; /* RLE array for lookups */
- uint32_t nrepeats; /* Number of repeat slots */
-
- uint32_t entries; /* Entries */
+ struct __wt_col_var_repeat {
+ uint32_t nrepeats; /* repeat slots */
+ WT_COL_RLE repeats[0]; /* lookup RLE array */
+ } *repeats;
+#define WT_COL_VAR_REPEAT_SET(page) \
+ ((page)->u.col_var.repeats != NULL)
} col_var;
-#undef pg_var_d
-#define pg_var_d u.col_var.d
+#undef pg_var
+#define pg_var u.col_var.col_var
#undef pg_var_repeats
-#define pg_var_repeats u.col_var.repeats
+#define pg_var_repeats u.col_var.repeats->repeats
#undef pg_var_nrepeats
-#define pg_var_nrepeats u.col_var.nrepeats
-#undef pg_var_entries
-#define pg_var_entries u.col_var.entries
+#define pg_var_nrepeats u.col_var.repeats->nrepeats
} u;
/*
- * The page's type and flags are positioned at the end of the WT_PAGE
- * union, it reduces cache misses in the row-store search function.
+ * Page entries, type and flags are positioned at the end of the WT_PAGE
+ * union to reduce cache misses in the row-store search function.
+ *
+ * The entries field only applies to leaf pages, internal pages use the
+ * page-index entries instead.
*/
+ uint32_t entries; /* Leaf page entries */
+
#define WT_PAGE_IS_INTERNAL(page) \
((page)->type == WT_PAGE_COL_INT || (page)->type == WT_PAGE_ROW_INT)
#define WT_PAGE_INVALID 0 /* Invalid page */
@@ -618,8 +632,8 @@ struct __wt_page {
#define WT_READGEN_START_VALUE 100
#define WT_READGEN_STEP 100
uint64_t read_gen;
- /* The evict pass generation for the page */
- uint64_t evict_pass_gen;
+
+ uint64_t evict_pass_gen; /* Eviction pass generation */
size_t memory_footprint; /* Memory attached to the page */
@@ -792,11 +806,11 @@ struct __wt_row { /* On-page key, on-page cell, or off-page WT_IKEY */
* Walk the entries of an in-memory row-store leaf page.
*/
#define WT_ROW_FOREACH(page, rip, i) \
- for ((i) = (page)->pg_row_entries, \
- (rip) = (page)->pg_row_d; (i) > 0; ++(rip), --(i))
+ for ((i) = (page)->entries, \
+ (rip) = (page)->pg_row; (i) > 0; ++(rip), --(i))
#define WT_ROW_FOREACH_REVERSE(page, rip, i) \
- for ((i) = (page)->pg_row_entries, \
- (rip) = (page)->pg_row_d + ((page)->pg_row_entries - 1); \
+ for ((i) = (page)->entries, \
+ (rip) = (page)->pg_row + ((page)->entries - 1); \
(i) > 0; --(rip), --(i))
/*
@@ -804,7 +818,7 @@ struct __wt_row { /* On-page key, on-page cell, or off-page WT_IKEY */
* Return the 0-based array offset based on a WT_ROW reference.
*/
#define WT_ROW_SLOT(page, rip) \
- ((uint32_t)(((WT_ROW *)(rip)) - (page)->pg_row_d))
+ ((uint32_t)(((WT_ROW *)(rip)) - (page)->pg_row))
/*
* WT_COL --
@@ -829,18 +843,6 @@ struct __wt_col {
};
/*
- * WT_COL_RLE --
- * In variable-length column store leaf pages, we build an array of entries
- * with RLE counts greater than 1 when reading the page. We can do a binary
- * search in this array, then an offset calculation to find the cell.
- */
-WT_PACKED_STRUCT_BEGIN(__wt_col_rle)
- uint64_t recno; /* Record number of first repeat. */
- uint64_t rle; /* Repeat count. */
- uint32_t indx; /* Slot of entry in col_var.d */
-WT_PACKED_STRUCT_END
-
-/*
* WT_COL_PTR, WT_COL_PTR_SET --
* Return/Set a pointer corresponding to the data offset. (If the item does
* not exist on the page, return a NULL.)
@@ -856,15 +858,15 @@ WT_PACKED_STRUCT_END
* Walk the entries of variable-length column-store leaf page.
*/
#define WT_COL_FOREACH(page, cip, i) \
- for ((i) = (page)->pg_var_entries, \
- (cip) = (page)->pg_var_d; (i) > 0; ++(cip), --(i))
+ for ((i) = (page)->entries, \
+ (cip) = (page)->pg_var; (i) > 0; ++(cip), --(i))
/*
* WT_COL_SLOT --
* Return the 0-based array offset based on a WT_COL reference.
*/
#define WT_COL_SLOT(page, cip) \
- ((uint32_t)(((WT_COL *)cip) - (page)->pg_var_d))
+ ((uint32_t)(((WT_COL *)cip) - (page)->pg_var))
/*
* WT_IKEY --
@@ -1041,7 +1043,7 @@ struct __wt_insert_head {
#define WT_ROW_INSERT_SMALLEST(page) \
((page)->modify == NULL || \
(page)->modify->mod_row_insert == NULL ? \
- NULL : (page)->modify->mod_row_insert[(page)->pg_row_entries])
+ NULL : (page)->modify->mod_row_insert[(page)->entries])
/*
* The column-store leaf page update lists are arrays of pointers to structures,
diff --git a/src/include/btree.h b/src/include/btree.h
index 595afc453c8..d742310bf8f 100644
--- a/src/include/btree.h
+++ b/src/include/btree.h
@@ -114,7 +114,7 @@ struct __wt_btree {
int split_pct; /* Split page percent */
WT_COMPRESSOR *compressor; /* Page compressor */
WT_KEYED_ENCRYPTOR *kencryptor; /* Page encryptor */
- WT_RWLOCK *ovfl_lock; /* Overflow lock */
+ WT_RWLOCK ovfl_lock; /* Overflow lock */
uint64_t last_recno; /* Column-store last record number */
@@ -131,6 +131,7 @@ struct __wt_btree {
uint64_t write_gen; /* Write generation */
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. */
WT_REF *evict_ref; /* Eviction thread's location */
diff --git a/src/include/btree.i b/src/include/btree.i
index 4f69c258621..09fa8df8c56 100644
--- a/src/include/btree.i
+++ b/src/include/btree.i
@@ -71,6 +71,23 @@ __wt_btree_bytes_inuse(WT_SESSION_IMPL *session)
}
/*
+ * __wt_btree_dirty_inuse --
+ * Return the number of dirty bytes in use.
+ */
+static inline uint64_t
+__wt_btree_dirty_inuse(WT_SESSION_IMPL *session)
+{
+ WT_BTREE *btree;
+ WT_CACHE *cache;
+
+ btree = S2BT(session);
+ cache = S2C(session)->cache;
+
+ return (__wt_cache_bytes_plus_overhead(cache,
+ btree->bytes_dirty_intl + btree->bytes_dirty_leaf));
+}
+
+/*
* __wt_btree_dirty_leaf_inuse --
* Return the number of bytes in use by dirty leaf pages.
*/
@@ -105,11 +122,12 @@ __wt_cache_page_inmem_incr(WT_SESSION_IMPL *session, WT_PAGE *page, size_t size)
(void)__wt_atomic_addsize(&page->memory_footprint, size);
if (__wt_page_is_modified(page)) {
(void)__wt_atomic_addsize(&page->modify->bytes_dirty, size);
- if (WT_PAGE_IS_INTERNAL(page))
+ if (WT_PAGE_IS_INTERNAL(page)) {
+ (void)__wt_atomic_add64(&btree->bytes_dirty_intl, size);
(void)__wt_atomic_add64(&cache->bytes_dirty_intl, size);
- else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
- (void)__wt_atomic_add64(&cache->bytes_dirty_leaf, size);
+ } else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
(void)__wt_atomic_add64(&btree->bytes_dirty_leaf, size);
+ (void)__wt_atomic_add64(&cache->bytes_dirty_leaf, size);
}
}
/* Track internal size in cache. */
@@ -238,10 +256,12 @@ __wt_cache_page_byte_dirty_decr(
if (i == 5)
return;
- if (WT_PAGE_IS_INTERNAL(page))
+ if (WT_PAGE_IS_INTERNAL(page)) {
+ __wt_cache_decr_check_uint64(session, &btree->bytes_dirty_intl,
+ decr, "WT_BTREE.bytes_dirty_intl");
__wt_cache_decr_check_uint64(session, &cache->bytes_dirty_intl,
decr, "WT_CACHE.bytes_dirty_intl");
- else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
+ } else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
__wt_cache_decr_check_uint64(session, &btree->bytes_dirty_leaf,
decr, "WT_BTREE.bytes_dirty_leaf");
__wt_cache_decr_check_uint64(session, &cache->bytes_dirty_leaf,
@@ -297,6 +317,7 @@ __wt_cache_dirty_incr(WT_SESSION_IMPL *session, WT_PAGE *page)
*/
size = page->memory_footprint;
if (WT_PAGE_IS_INTERNAL(page)) {
+ (void)__wt_atomic_add64(&btree->bytes_dirty_intl, size);
(void)__wt_atomic_add64(&cache->bytes_dirty_intl, size);
(void)__wt_atomic_add64(&cache->pages_dirty_intl, 1);
} else {
@@ -392,17 +413,20 @@ __wt_cache_page_evict(WT_SESSION_IMPL *session, WT_PAGE *page)
/* Update the cache's dirty-byte count. */
if (modify != NULL && modify->bytes_dirty != 0) {
- if (WT_PAGE_IS_INTERNAL(page))
+ if (WT_PAGE_IS_INTERNAL(page)) {
+ __wt_cache_decr_zero_uint64(session,
+ &btree->bytes_dirty_intl,
+ modify->bytes_dirty, "WT_BTREE.bytes_dirty_intl");
__wt_cache_decr_zero_uint64(session,
&cache->bytes_dirty_intl,
modify->bytes_dirty, "WT_CACHE.bytes_dirty_intl");
- else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
- __wt_cache_decr_zero_uint64(session,
- &cache->bytes_dirty_leaf,
- modify->bytes_dirty, "WT_CACHE.bytes_dirty_leaf");
+ } else if (!F_ISSET(btree, WT_BTREE_LSM_PRIMARY)) {
__wt_cache_decr_zero_uint64(session,
&btree->bytes_dirty_leaf,
modify->bytes_dirty, "WT_BTREE.bytes_dirty_leaf");
+ __wt_cache_decr_zero_uint64(session,
+ &cache->bytes_dirty_leaf,
+ modify->bytes_dirty, "WT_CACHE.bytes_dirty_leaf");
}
}
@@ -984,7 +1008,7 @@ __wt_cursor_row_leaf_key(WT_CURSOR_BTREE *cbt, WT_ITEM *key)
if (cbt->ins == NULL) {
session = (WT_SESSION_IMPL *)cbt->iface.session;
page = cbt->ref->page;
- rip = &page->u.row.d[cbt->slot];
+ rip = &page->pg_row[cbt->slot];
WT_RET(__wt_row_leaf_key(session, page, rip, key, false));
} else {
key->data = WT_INSERT_KEY(cbt->ins);
@@ -1183,9 +1207,9 @@ __wt_leaf_page_can_split(WT_SESSION_IMPL *session, WT_PAGE *page)
*/
ins_head = page->type == WT_PAGE_ROW_LEAF ?
- (page->pg_row_entries == 0 ?
+ (page->entries == 0 ?
WT_ROW_INSERT_SMALLEST(page) :
- WT_ROW_INSERT_SLOT(page, page->pg_row_entries - 1)) :
+ WT_ROW_INSERT_SLOT(page, page->entries - 1)) :
WT_COL_APPEND(page);
if (ins_head == NULL)
return (false);
diff --git a/src/include/column.i b/src/include/column.i
index d15f874b281..c1b45a1f4e0 100644
--- a/src/include/column.i
+++ b/src/include/column.i
@@ -221,13 +221,13 @@ __col_var_last_recno(WT_REF *ref)
* This function ignores those records, our callers must handle that
* explicitly, if they care.
*/
- if (page->pg_var_nrepeats == 0)
- return (page->pg_var_entries == 0 ? 0 :
- ref->ref_recno + (page->pg_var_entries - 1));
+ if (!WT_COL_VAR_REPEAT_SET(page))
+ return (page->entries == 0 ? 0 :
+ ref->ref_recno + (page->entries - 1));
repeat = &page->pg_var_repeats[page->pg_var_nrepeats - 1];
return ((repeat->recno + repeat->rle) - 1 +
- (page->pg_var_entries - (repeat->indx + 1)));
+ (page->entries - (repeat->indx + 1)));
}
/*
@@ -246,8 +246,7 @@ __col_fix_last_recno(WT_REF *ref)
* This function ignores those records, our callers must handle that
* explicitly, if they care.
*/
- return (page->pg_fix_entries == 0 ?
- 0 : ref->ref_recno + (page->pg_fix_entries - 1));
+ return (page->entries == 0 ? 0 : ref->ref_recno + (page->entries - 1));
}
/*
@@ -273,7 +272,9 @@ __col_var_search(WT_REF *ref, uint64_t recno, uint64_t *start_recnop)
* slot for this record number, because we know any intervening records
* have repeat counts of 1.
*/
- for (base = 0, limit = page->pg_var_nrepeats; limit != 0; limit >>= 1) {
+ for (base = 0,
+ limit = WT_COL_VAR_REPEAT_SET(page) ? page->pg_var_nrepeats : 0;
+ limit != 0; limit >>= 1) {
indx = base + (limit >> 1);
repeat = page->pg_var_repeats + indx;
@@ -281,7 +282,7 @@ __col_var_search(WT_REF *ref, uint64_t recno, uint64_t *start_recnop)
recno < repeat->recno + repeat->rle) {
if (start_recnop != NULL)
*start_recnop = repeat->recno;
- return (page->pg_var_d + repeat->indx);
+ return (page->pg_var + repeat->indx);
}
if (recno < repeat->recno)
continue;
@@ -306,14 +307,14 @@ __col_var_search(WT_REF *ref, uint64_t recno, uint64_t *start_recnop)
* !!!
* The test could be written more simply as:
*
- * (recno >= start_recno + (page->pg_var_entries - start_indx))
+ * (recno >= start_recno + (page->entries - start_indx))
*
* It's split into two parts because the simpler test will overflow if
* searching for large record numbers.
*/
if (recno >= start_recno &&
- recno - start_recno >= page->pg_var_entries - start_indx)
+ recno - start_recno >= page->entries - start_indx)
return (NULL);
- return (page->pg_var_d + start_indx + (uint32_t)(recno - start_recno));
+ return (page->pg_var + start_indx + (uint32_t)(recno - start_recno));
}
diff --git a/src/include/connection.h b/src/include/connection.h
index 60ce5f55234..64ac4271db1 100644
--- a/src/include/connection.h
+++ b/src/include/connection.h
@@ -107,7 +107,7 @@ struct __wt_named_extractor {
* Allocate some additional slots for internal sessions so the user cannot
* configure too few sessions for us to run.
*/
-#define WT_EXTRA_INTERNAL_SESSIONS 10
+#define WT_EXTRA_INTERNAL_SESSIONS 20
/*
* WT_CONN_CHECK_PANIC --
@@ -262,7 +262,7 @@ struct __wt_connection_impl {
WT_TXN_GLOBAL txn_global; /* Global transaction state */
- WT_RWLOCK *hot_backup_lock; /* Hot backup serialization */
+ WT_RWLOCK hot_backup_lock; /* Hot backup serialization */
bool hot_backup; /* Hot backup in progress */
char **hot_backup_list; /* Hot backup file list */
@@ -301,6 +301,15 @@ struct __wt_connection_impl {
uint32_t evict_threads_max;/* Max eviction threads */
uint32_t evict_threads_min;/* Min eviction threads */
+ uint32_t evict_tune_datapts_needed;/* Data needed to tune */
+ struct timespec evict_tune_last_action_time;/* Time of last action */
+ struct timespec evict_tune_last_time; /* Time of last check */
+ uint32_t evict_tune_num_points; /* Number of values tried */
+ uint64_t evict_tune_pgs_last; /* Number of pages evicted */
+ uint64_t evict_tune_pg_sec_max; /* Max throughput encountered */
+ bool evict_tune_stable; /* Are we stable? */
+ uint32_t evict_tune_workers_best;/* Best performing value */
+
#define WT_STATLOG_FILENAME "WiredTigerStat.%d.%H"
WT_SESSION_IMPL *stat_session; /* Statistics log session */
wt_thread_t stat_tid; /* Statistics log thread */
@@ -326,11 +335,11 @@ struct __wt_connection_impl {
bool log_tid_set; /* Log server thread set */
WT_CONDVAR *log_file_cond; /* Log file thread wait mutex */
WT_SESSION_IMPL *log_file_session;/* Log file thread session */
- wt_thread_t log_file_tid; /* Log file thread thread */
+ wt_thread_t log_file_tid; /* Log file thread */
bool log_file_tid_set;/* Log file thread set */
WT_CONDVAR *log_wrlsn_cond;/* Log write lsn thread wait mutex */
WT_SESSION_IMPL *log_wrlsn_session;/* Log write lsn thread session */
- wt_thread_t log_wrlsn_tid; /* Log write lsn thread thread */
+ wt_thread_t log_wrlsn_tid; /* Log write lsn thread */
bool log_wrlsn_tid_set;/* Log write lsn thread set */
WT_LOG *log; /* Logging structure */
WT_COMPRESSOR *log_compressor;/* Logging compressor */
diff --git a/src/include/cursor.h b/src/include/cursor.h
index d522abc2a56..31c8963a486 100644
--- a/src/include/cursor.h
+++ b/src/include/cursor.h
@@ -52,8 +52,8 @@
{ 0 }, /* recno raw buffer */ \
NULL, /* json_private */ \
NULL, /* lang_private */ \
- { NULL, 0, 0, NULL, 0 }, /* WT_ITEM key */ \
- { NULL, 0, 0, NULL, 0 }, /* WT_ITEM value */ \
+ { NULL, 0, NULL, 0, 0 }, /* WT_ITEM key */ \
+ { NULL, 0, NULL, 0, 0 }, /* WT_ITEM value */ \
0, /* int saved_err */ \
NULL, /* internal_uri */ \
0 /* uint32_t flags */ \
diff --git a/src/include/dhandle.h b/src/include/dhandle.h
index d7802bb319b..dcc788f0839 100644
--- a/src/include/dhandle.h
+++ b/src/include/dhandle.h
@@ -42,7 +42,7 @@
* A handle for a generic named data source.
*/
struct __wt_data_handle {
- WT_RWLOCK *rwlock; /* Lock for shared/exclusive ops */
+ WT_RWLOCK rwlock; /* Lock for shared/exclusive ops */
TAILQ_ENTRY(__wt_data_handle) q;
TAILQ_ENTRY(__wt_data_handle) hashq;
diff --git a/src/include/extern.h b/src/include/extern.h
index be042bcd6cb..566eb386c29 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -294,7 +294,7 @@ extern int __wt_curjoin_join(WT_SESSION_IMPL *session, WT_CURSOR_JOIN *cjoin, WT
extern int __wt_json_alloc_unpack(WT_SESSION_IMPL *session, const void *buffer, size_t size, const char *fmt, WT_CURSOR_JSON *json, bool iskey, va_list ap) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_json_close(WT_SESSION_IMPL *session, WT_CURSOR *cursor) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern size_t __wt_json_unpack_char(u_char ch, u_char *buf, size_t bufsz, bool force_unicode) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
-extern void __wt_json_column_init(WT_CURSOR *cursor, const char *keyformat, const WT_CONFIG_ITEM *idxconf, const WT_CONFIG_ITEM *colconf) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_json_column_init(WT_CURSOR *cursor, const char *uri, const char *keyformat, const WT_CONFIG_ITEM *idxconf, const WT_CONFIG_ITEM *colconf) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_json_token(WT_SESSION *wt_session, const char *src, int *toktype, const char **tokstart, size_t *toklen) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default"))) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result));
extern const char *__wt_json_tokname(int toktype) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("default")));
extern int __wt_json_to_item(WT_SESSION_IMPL *session, const char *jstr, const char *format, WT_CURSOR_JSON *json, bool iskey, WT_ITEM *item) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
@@ -315,7 +315,7 @@ extern int __wt_cursor_equals_notsup(WT_CURSOR *cursor, WT_CURSOR *other, int *e
extern int __wt_cursor_search_near_notsup(WT_CURSOR *cursor, int *exact) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cursor_reconfigure_notsup(WT_CURSOR *cursor, const char *config) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cursor_set_notsup(WT_CURSOR *cursor) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern int __wt_cursor_kv_not_set(WT_CURSOR *cursor, bool key) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern int __wt_cursor_kv_not_set(WT_CURSOR *cursor, bool key) WT_GCC_FUNC_DECL_ATTRIBUTE((cold)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cursor_get_key(WT_CURSOR *cursor, ...) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_cursor_set_key(WT_CURSOR *cursor, ...) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_cursor_get_raw_key(WT_CURSOR *cursor, WT_ITEM *key) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
@@ -352,7 +352,7 @@ extern int __wt_cache_eviction_worker(WT_SESSION_IMPL *session, bool busy, u_int
extern bool __wt_page_evict_urgent(WT_SESSION_IMPL *session, WT_REF *ref) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_evict_priority_set(WT_SESSION_IMPL *session, uint64_t v) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_evict_priority_clear(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern int __wt_cache_dump(WT_SESSION_IMPL *session, const char *ofile) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern int __wt_dump_stuck_info(WT_SESSION_IMPL *session, const char *ofile) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_page_release_evict(WT_SESSION_IMPL *session, WT_REF *ref) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_evict(WT_SESSION_IMPL *session, WT_REF *ref, bool closing) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_curstat_cache_walk(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
@@ -671,16 +671,16 @@ extern void __wt_huffman_close(WT_SESSION_IMPL *session, void *huffman_arg) WT_G
extern void __wt_print_huffman_code(void *huffman_arg, uint16_t symbol) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_huffman_encode(WT_SESSION_IMPL *session, void *huffman_arg, const uint8_t *from_arg, size_t from_len, WT_ITEM *to_buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_huffman_decode(WT_SESSION_IMPL *session, void *huffman_arg, const uint8_t *from_arg, size_t from_len, WT_ITEM *to_buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern int __wt_rwlock_alloc( WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp, const char *name) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern int __wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern int __wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern void __wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
-extern bool __wt_rwlock_islocked(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_rwlock_init(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern int __wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern int __wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern void __wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+extern bool __wt_rwlock_islocked(WT_SESSION_IMPL *session, WT_RWLOCK *l) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern uint32_t __wt_nlpo2_round(uint32_t v) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern uint32_t __wt_nlpo2(uint32_t v) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern uint32_t __wt_log2_int(uint32_t n) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
@@ -728,6 +728,7 @@ extern int __wt_thread_group_resize( WT_SESSION_IMPL *session, WT_THREAD_GROUP *
extern int __wt_thread_group_create( WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, const char *name, uint32_t min, uint32_t max, uint32_t flags, int (*run_func)(WT_SESSION_IMPL *session, WT_THREAD *context)) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_thread_group_destroy(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
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)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
+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)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern void __wt_txn_get_snapshot(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
extern int __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden")));
diff --git a/src/include/flags.h b/src/include/flags.h
index e7a5ba066df..2f0c207078a 100644
--- a/src/include/flags.h
+++ b/src/include/flags.h
@@ -102,15 +102,16 @@
#define WT_VERB_REBALANCE 0x00008000
#define WT_VERB_RECONCILE 0x00010000
#define WT_VERB_RECOVERY 0x00020000
-#define WT_VERB_SALVAGE 0x00040000
-#define WT_VERB_SHARED_CACHE 0x00080000
-#define WT_VERB_SPLIT 0x00100000
-#define WT_VERB_TEMPORARY 0x00200000
-#define WT_VERB_THREAD_GROUP 0x00400000
-#define WT_VERB_TRANSACTION 0x00800000
-#define WT_VERB_VERIFY 0x01000000
-#define WT_VERB_VERSION 0x02000000
-#define WT_VERB_WRITE 0x04000000
+#define WT_VERB_RECOVERY_PROGRESS 0x00040000
+#define WT_VERB_SALVAGE 0x00080000
+#define WT_VERB_SHARED_CACHE 0x00100000
+#define WT_VERB_SPLIT 0x00200000
+#define WT_VERB_TEMPORARY 0x00400000
+#define WT_VERB_THREAD_GROUP 0x00800000
+#define WT_VERB_TRANSACTION 0x01000000
+#define WT_VERB_VERIFY 0x02000000
+#define WT_VERB_VERSION 0x04000000
+#define WT_VERB_WRITE 0x08000000
#define WT_VISIBILITY_ERR 0x00000080
/*
* flags section: END
diff --git a/src/include/log.h b/src/include/log.h
index 3f2cb2ba8e6..d9fea892c68 100644
--- a/src/include/log.h
+++ b/src/include/log.h
@@ -235,7 +235,7 @@ struct __wt_log {
WT_SPINLOCK log_sync_lock; /* Locked: Single-thread fsync */
WT_SPINLOCK log_writelsn_lock; /* Locked: write LSN */
- WT_RWLOCK *log_archive_lock; /* Archive and log cursors */
+ WT_RWLOCK log_archive_lock;/* Archive and log cursors */
/* Notify any waiting threads when sync_lsn is updated. */
WT_CONDVAR *log_sync_cond;
diff --git a/src/include/lsm.h b/src/include/lsm.h
index fefed9daa81..2bbb813bad2 100644
--- a/src/include/lsm.h
+++ b/src/include/lsm.h
@@ -189,7 +189,7 @@ struct __wt_lsm_tree {
#define LSM_TREE_MAX_QUEUE 100
uint32_t queue_ref;
- WT_RWLOCK *rwlock;
+ WT_RWLOCK rwlock;
TAILQ_ENTRY(__wt_lsm_tree) q;
uint64_t dsk_gen;
diff --git a/src/include/mutex.h b/src/include/mutex.h
index 6b81b1a6265..727a690bb1c 100644
--- a/src/include/mutex.h
+++ b/src/include/mutex.h
@@ -30,11 +30,14 @@ struct __wt_condvar {
};
/*
+ * Read/write locks:
+ *
+ * WiredTiger uses read/write locks for shared/exclusive access to resources.
* !!!
* Don't modify this structure without understanding the read/write locking
* functions.
*/
-typedef union { /* Read/write lock */
+union __wt_rwlock { /* Read/write lock */
uint64_t u;
struct {
uint32_t wr; /* Writers and readers */
@@ -45,19 +48,6 @@ typedef union { /* Read/write lock */
uint16_t next; /* Next available ticket number */
uint16_t writers_active;/* Count of active writers */
} s;
-} wt_rwlock_t;
-
-/*
- * Read/write locks:
- *
- * WiredTiger uses read/write locks for shared/exclusive access to resources.
- */
-struct __wt_rwlock {
- WT_CACHE_LINE_PAD_BEGIN
- const char *name; /* Lock name for debugging */
-
- wt_rwlock_t rwlock; /* Read/write lock */
- WT_CACHE_LINE_PAD_END
};
/*
diff --git a/src/include/mutex.i b/src/include/mutex.i
index a6309e0976b..6b83cb280d3 100644
--- a/src/include/mutex.i
+++ b/src/include/mutex.i
@@ -300,3 +300,22 @@ __wt_spin_lock_track(WT_SESSION_IMPL *session, WT_SPINLOCK *t)
} else
__wt_spin_lock(session, t);
}
+
+/*
+ * __wt_spin_trylock_track --
+ * Try to lock a spinlock or fail immediately if it is busy.
+ * Track if successful.
+ */
+static inline int
+__wt_spin_trylock_track(WT_SESSION_IMPL *session, WT_SPINLOCK *t)
+{
+ int64_t **stats;
+
+ if (t->stat_count_off != -1 && WT_STAT_ENABLED(session)) {
+ WT_RET(__wt_spin_trylock(session, t));
+ stats = (int64_t **)S2C(session)->stats;
+ stats[session->stat_bucket][t->stat_count_off]++;
+ return (0);
+ } else
+ return (__wt_spin_trylock(session, t));
+}
diff --git a/src/include/schema.h b/src/include/schema.h
index a17affb7660..bb116e5cf2f 100644
--- a/src/include/schema.h
+++ b/src/include/schema.h
@@ -102,7 +102,7 @@ struct __wt_table {
ret = 0; \
if (F_ISSET(session, (flag))) { \
op; \
- } else if ((ret = __wt_spin_trylock(session, lock)) == 0) { \
+ } else if ((ret = __wt_spin_trylock_track(session, lock)) == 0) {\
F_SET(session, (flag)); \
op; \
F_CLR(session, (flag)); \
diff --git a/src/include/stat.h b/src/include/stat.h
index 0daab83e166..fd3e3290d95 100644
--- a/src/include/stat.h
+++ b/src/include/stat.h
@@ -310,7 +310,11 @@ struct __wt_connection_stats {
int64_t cache_eviction_slow;
int64_t cache_eviction_state;
int64_t cache_eviction_walks_abandoned;
+ int64_t cache_eviction_active_workers;
+ int64_t cache_eviction_worker_created;
int64_t cache_eviction_worker_evicting;
+ int64_t cache_eviction_worker_removed;
+ int64_t cache_eviction_stable_state_workers;
int64_t cache_eviction_force_fail;
int64_t cache_eviction_walks_active;
int64_t cache_eviction_walks_started;
@@ -564,6 +568,7 @@ struct __wt_dsrc_stats {
int64_t cache_pages_requested;
int64_t cache_write;
int64_t cache_write_restore;
+ int64_t cache_bytes_dirty;
int64_t cache_eviction_clean;
int64_t cache_state_gen_avg_gap;
int64_t cache_state_avg_written_size;
diff --git a/src/include/thread_group.h b/src/include/thread_group.h
index 76758a090c4..77cff00dc8d 100644
--- a/src/include/thread_group.h
+++ b/src/include/thread_group.h
@@ -40,7 +40,7 @@ struct __wt_thread_group {
const char *name; /* Name */
- WT_RWLOCK *lock; /* Protects group changes */
+ WT_RWLOCK lock; /* Protects group changes */
/*
* Condition signalled when wanting to wake up threads that are
diff --git a/src/include/txn.h b/src/include/txn.h
index 12fc2a0a5b7..7e802c188ab 100644
--- a/src/include/txn.h
+++ b/src/include/txn.h
@@ -92,7 +92,7 @@ struct __wt_txn_global {
* Prevents the oldest ID moving forwards while threads are scanning
* the global transaction state.
*/
- WT_RWLOCK *scan_rwlock;
+ WT_RWLOCK scan_rwlock;
/*
* Track information about the running checkpoint. The transaction
@@ -114,7 +114,7 @@ struct __wt_txn_global {
volatile uint64_t metadata_pinned; /* Oldest ID for metadata */
/* Named snapshot state. */
- WT_RWLOCK *nsnap_rwlock;
+ WT_RWLOCK nsnap_rwlock;
volatile uint64_t nsnap_oldest_id;
TAILQ_HEAD(__wt_nsnap_qh, __wt_named_snapshot) nsnaph;
diff --git a/src/include/verify_build.h b/src/include/verify_build.h
index 8abc192892e..640f5e4cf5f 100644
--- a/src/include/verify_build.h
+++ b/src/include/verify_build.h
@@ -59,7 +59,6 @@ __wt_verify_build(void)
sizeof(s) > WT_CACHE_LINE_ALIGNMENT || \
sizeof(s) % WT_CACHE_LINE_ALIGNMENT == 0)
WT_PADDING_CHECK(WT_LOGSLOT);
- WT_PADDING_CHECK(WT_RWLOCK);
WT_PADDING_CHECK(WT_SPINLOCK);
WT_PADDING_CHECK(WT_TXN_STATE);
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index a6deed7e14e..90989cc679d 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -114,16 +114,16 @@ struct __wt_item {
size_t size;
#ifndef DOXYGEN
-#define WT_ITEM_ALIGNED 0x00000001
-#define WT_ITEM_INUSE 0x00000002
- /* This appears in the middle of the struct to avoid padding. */
- /*! Object flags (internal use). */
- uint32_t flags;
-
/*! Managed memory chunk (internal use). */
void *mem;
+
/*! Managed memory size (internal use). */
size_t memsize;
+
+#define WT_ITEM_ALIGNED 0x00000001
+#define WT_ITEM_INUSE 0x00000002
+ /*! Object flags (internal use). */
+ uint32_t flags;
#endif
};
@@ -1855,7 +1855,7 @@ struct __wt_connection {
* threads WiredTiger will start to help evict pages from cache. The
* number of threads started will vary depending on the current eviction
* load. Each eviction worker thread uses a session from the configured
- * session_max., an integer between 1 and 20; default \c 1.}
+ * session_max., an integer between 1 and 20; default \c 8.}
* @config{&nbsp;&nbsp;&nbsp;&nbsp;threads_min, minimum number of
* threads WiredTiger will start to help evict pages from cache. The
* number of threads currently running will vary depending on the
@@ -1985,9 +1985,9 @@ struct __wt_connection {
* "evictserver"\, \c "fileops"\, \c "handleops"\, \c "log"\, \c "lsm"\,
* \c "lsm_manager"\, \c "metadata"\, \c "mutex"\, \c "overflow"\, \c
* "read"\, \c "rebalance"\, \c "reconcile"\, \c "recovery"\, \c
- * "salvage"\, \c "shared_cache"\, \c "split"\, \c "temporary"\, \c
- * "thread_group"\, \c "transaction"\, \c "verify"\, \c "version"\, \c
- * "write"; default empty.}
+ * "recovery_progress"\, \c "salvage"\, \c "shared_cache"\, \c "split"\,
+ * \c "temporary"\, \c "thread_group"\, \c "transaction"\, \c "verify"\,
+ * \c "version"\, \c "write"; default empty.}
* @configend
* @errors
*/
@@ -2331,7 +2331,7 @@ struct __wt_connection {
* WiredTiger will start to help evict pages from cache. The number of threads
* started will vary depending on the current eviction load. Each eviction
* worker thread uses a session from the configured session_max., an integer
- * between 1 and 20; default \c 1.}
+ * between 1 and 20; default \c 8.}
* @config{&nbsp;&nbsp;&nbsp;&nbsp;threads_min,
* minimum number of threads WiredTiger will start to help evict pages from
* cache. The number of threads currently running will vary depending on the
@@ -2516,9 +2516,9 @@ struct __wt_connection {
* "checkpoint"\, \c "compact"\, \c "evict"\, \c "evictserver"\, \c "fileops"\,
* \c "handleops"\, \c "log"\, \c "lsm"\, \c "lsm_manager"\, \c "metadata"\, \c
* "mutex"\, \c "overflow"\, \c "read"\, \c "rebalance"\, \c "reconcile"\, \c
- * "recovery"\, \c "salvage"\, \c "shared_cache"\, \c "split"\, \c "temporary"\,
- * \c "thread_group"\, \c "transaction"\, \c "verify"\, \c "version"\, \c
- * "write"; default empty.}
+ * "recovery"\, \c "recovery_progress"\, \c "salvage"\, \c "shared_cache"\, \c
+ * "split"\, \c "temporary"\, \c "thread_group"\, \c "transaction"\, \c
+ * "verify"\, \c "version"\, \c "write"; default empty.}
* @config{write_through, Use \c FILE_FLAG_WRITE_THROUGH on Windows to write to
* files. Ignored on non-Windows systems. Options are given as a list\, such
* as <code>"write_through=[data]"</code>. Configuring \c write_through requires
@@ -4429,396 +4429,404 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection);
#define WT_STAT_CONN_CACHE_EVICTION_STATE 1051
/*! cache: eviction walks abandoned */
#define WT_STAT_CONN_CACHE_EVICTION_WALKS_ABANDONED 1052
+/*! cache: eviction worker thread active */
+#define WT_STAT_CONN_CACHE_EVICTION_ACTIVE_WORKERS 1053
+/*! cache: eviction worker thread created */
+#define WT_STAT_CONN_CACHE_EVICTION_WORKER_CREATED 1054
/*! cache: eviction worker thread evicting pages */
-#define WT_STAT_CONN_CACHE_EVICTION_WORKER_EVICTING 1053
+#define WT_STAT_CONN_CACHE_EVICTION_WORKER_EVICTING 1055
+/*! cache: eviction worker thread removed */
+#define WT_STAT_CONN_CACHE_EVICTION_WORKER_REMOVED 1056
+/*! cache: eviction worker thread stable number */
+#define WT_STAT_CONN_CACHE_EVICTION_STABLE_STATE_WORKERS 1057
/*! cache: failed eviction of pages that exceeded the in-memory maximum */
-#define WT_STAT_CONN_CACHE_EVICTION_FORCE_FAIL 1054
+#define WT_STAT_CONN_CACHE_EVICTION_FORCE_FAIL 1058
/*! cache: files with active eviction walks */
-#define WT_STAT_CONN_CACHE_EVICTION_WALKS_ACTIVE 1055
+#define WT_STAT_CONN_CACHE_EVICTION_WALKS_ACTIVE 1059
/*! cache: files with new eviction walks started */
-#define WT_STAT_CONN_CACHE_EVICTION_WALKS_STARTED 1056
+#define WT_STAT_CONN_CACHE_EVICTION_WALKS_STARTED 1060
/*! cache: hazard pointer blocked page eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_HAZARD 1057
+#define WT_STAT_CONN_CACHE_EVICTION_HAZARD 1061
/*! cache: hazard pointer check calls */
-#define WT_STAT_CONN_CACHE_HAZARD_CHECKS 1058
+#define WT_STAT_CONN_CACHE_HAZARD_CHECKS 1062
/*! cache: hazard pointer check entries walked */
-#define WT_STAT_CONN_CACHE_HAZARD_WALKS 1059
+#define WT_STAT_CONN_CACHE_HAZARD_WALKS 1063
/*! cache: hazard pointer maximum array length */
-#define WT_STAT_CONN_CACHE_HAZARD_MAX 1060
+#define WT_STAT_CONN_CACHE_HAZARD_MAX 1064
/*! cache: in-memory page passed criteria to be split */
-#define WT_STAT_CONN_CACHE_INMEM_SPLITTABLE 1061
+#define WT_STAT_CONN_CACHE_INMEM_SPLITTABLE 1065
/*! cache: in-memory page splits */
-#define WT_STAT_CONN_CACHE_INMEM_SPLIT 1062
+#define WT_STAT_CONN_CACHE_INMEM_SPLIT 1066
/*! cache: internal pages evicted */
-#define WT_STAT_CONN_CACHE_EVICTION_INTERNAL 1063
+#define WT_STAT_CONN_CACHE_EVICTION_INTERNAL 1067
/*! cache: internal pages split during eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_SPLIT_INTERNAL 1064
+#define WT_STAT_CONN_CACHE_EVICTION_SPLIT_INTERNAL 1068
/*! cache: leaf pages split during eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_SPLIT_LEAF 1065
+#define WT_STAT_CONN_CACHE_EVICTION_SPLIT_LEAF 1069
/*! cache: lookaside table insert calls */
-#define WT_STAT_CONN_CACHE_LOOKASIDE_INSERT 1066
+#define WT_STAT_CONN_CACHE_LOOKASIDE_INSERT 1070
/*! cache: lookaside table remove calls */
-#define WT_STAT_CONN_CACHE_LOOKASIDE_REMOVE 1067
+#define WT_STAT_CONN_CACHE_LOOKASIDE_REMOVE 1071
/*! cache: maximum bytes configured */
-#define WT_STAT_CONN_CACHE_BYTES_MAX 1068
+#define WT_STAT_CONN_CACHE_BYTES_MAX 1072
/*! cache: maximum page size at eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_MAXIMUM_PAGE_SIZE 1069
+#define WT_STAT_CONN_CACHE_EVICTION_MAXIMUM_PAGE_SIZE 1073
/*! cache: modified pages evicted */
-#define WT_STAT_CONN_CACHE_EVICTION_DIRTY 1070
+#define WT_STAT_CONN_CACHE_EVICTION_DIRTY 1074
/*! cache: modified pages evicted by application threads */
-#define WT_STAT_CONN_CACHE_EVICTION_APP_DIRTY 1071
+#define WT_STAT_CONN_CACHE_EVICTION_APP_DIRTY 1075
/*! cache: overflow pages read into cache */
-#define WT_STAT_CONN_CACHE_READ_OVERFLOW 1072
+#define WT_STAT_CONN_CACHE_READ_OVERFLOW 1076
/*! cache: overflow values cached in memory */
-#define WT_STAT_CONN_CACHE_OVERFLOW_VALUE 1073
+#define WT_STAT_CONN_CACHE_OVERFLOW_VALUE 1077
/*! cache: page split during eviction deepened the tree */
-#define WT_STAT_CONN_CACHE_EVICTION_DEEPEN 1074
+#define WT_STAT_CONN_CACHE_EVICTION_DEEPEN 1078
/*! cache: page written requiring lookaside records */
-#define WT_STAT_CONN_CACHE_WRITE_LOOKASIDE 1075
+#define WT_STAT_CONN_CACHE_WRITE_LOOKASIDE 1079
/*! cache: pages currently held in the cache */
-#define WT_STAT_CONN_CACHE_PAGES_INUSE 1076
+#define WT_STAT_CONN_CACHE_PAGES_INUSE 1080
/*! cache: pages evicted because they exceeded the in-memory maximum */
-#define WT_STAT_CONN_CACHE_EVICTION_FORCE 1077
+#define WT_STAT_CONN_CACHE_EVICTION_FORCE 1081
/*! cache: pages evicted because they had chains of deleted items */
-#define WT_STAT_CONN_CACHE_EVICTION_FORCE_DELETE 1078
+#define WT_STAT_CONN_CACHE_EVICTION_FORCE_DELETE 1082
/*! cache: pages evicted by application threads */
-#define WT_STAT_CONN_CACHE_EVICTION_APP 1079
+#define WT_STAT_CONN_CACHE_EVICTION_APP 1083
/*! cache: pages queued for eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED 1080
+#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED 1084
/*! cache: pages queued for urgent eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED_URGENT 1081
+#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED_URGENT 1085
/*! cache: pages queued for urgent eviction during walk */
-#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED_OLDEST 1082
+#define WT_STAT_CONN_CACHE_EVICTION_PAGES_QUEUED_OLDEST 1086
/*! cache: pages read into cache */
-#define WT_STAT_CONN_CACHE_READ 1083
+#define WT_STAT_CONN_CACHE_READ 1087
/*! cache: pages read into cache requiring lookaside entries */
-#define WT_STAT_CONN_CACHE_READ_LOOKASIDE 1084
+#define WT_STAT_CONN_CACHE_READ_LOOKASIDE 1088
/*! cache: pages requested from the cache */
-#define WT_STAT_CONN_CACHE_PAGES_REQUESTED 1085
+#define WT_STAT_CONN_CACHE_PAGES_REQUESTED 1089
/*! cache: pages seen by eviction walk */
-#define WT_STAT_CONN_CACHE_EVICTION_PAGES_SEEN 1086
+#define WT_STAT_CONN_CACHE_EVICTION_PAGES_SEEN 1090
/*! cache: pages selected for eviction unable to be evicted */
-#define WT_STAT_CONN_CACHE_EVICTION_FAIL 1087
+#define WT_STAT_CONN_CACHE_EVICTION_FAIL 1091
/*! cache: pages walked for eviction */
-#define WT_STAT_CONN_CACHE_EVICTION_WALK 1088
+#define WT_STAT_CONN_CACHE_EVICTION_WALK 1092
/*! cache: pages written from cache */
-#define WT_STAT_CONN_CACHE_WRITE 1089
+#define WT_STAT_CONN_CACHE_WRITE 1093
/*! cache: pages written requiring in-memory restoration */
-#define WT_STAT_CONN_CACHE_WRITE_RESTORE 1090
+#define WT_STAT_CONN_CACHE_WRITE_RESTORE 1094
/*! cache: percentage overhead */
-#define WT_STAT_CONN_CACHE_OVERHEAD 1091
+#define WT_STAT_CONN_CACHE_OVERHEAD 1095
/*! cache: tracked bytes belonging to internal pages in the cache */
-#define WT_STAT_CONN_CACHE_BYTES_INTERNAL 1092
+#define WT_STAT_CONN_CACHE_BYTES_INTERNAL 1096
/*! cache: tracked bytes belonging to leaf pages in the cache */
-#define WT_STAT_CONN_CACHE_BYTES_LEAF 1093
+#define WT_STAT_CONN_CACHE_BYTES_LEAF 1097
/*! cache: tracked dirty bytes in the cache */
-#define WT_STAT_CONN_CACHE_BYTES_DIRTY 1094
+#define WT_STAT_CONN_CACHE_BYTES_DIRTY 1098
/*! cache: tracked dirty pages in the cache */
-#define WT_STAT_CONN_CACHE_PAGES_DIRTY 1095
+#define WT_STAT_CONN_CACHE_PAGES_DIRTY 1099
/*! cache: unmodified pages evicted */
-#define WT_STAT_CONN_CACHE_EVICTION_CLEAN 1096
+#define WT_STAT_CONN_CACHE_EVICTION_CLEAN 1100
/*! connection: auto adjusting condition resets */
-#define WT_STAT_CONN_COND_AUTO_WAIT_RESET 1097
+#define WT_STAT_CONN_COND_AUTO_WAIT_RESET 1101
/*! connection: auto adjusting condition wait calls */
-#define WT_STAT_CONN_COND_AUTO_WAIT 1098
+#define WT_STAT_CONN_COND_AUTO_WAIT 1102
/*! connection: files currently open */
-#define WT_STAT_CONN_FILE_OPEN 1099
+#define WT_STAT_CONN_FILE_OPEN 1103
/*! connection: memory allocations */
-#define WT_STAT_CONN_MEMORY_ALLOCATION 1100
+#define WT_STAT_CONN_MEMORY_ALLOCATION 1104
/*! connection: memory frees */
-#define WT_STAT_CONN_MEMORY_FREE 1101
+#define WT_STAT_CONN_MEMORY_FREE 1105
/*! connection: memory re-allocations */
-#define WT_STAT_CONN_MEMORY_GROW 1102
+#define WT_STAT_CONN_MEMORY_GROW 1106
/*! connection: pthread mutex condition wait calls */
-#define WT_STAT_CONN_COND_WAIT 1103
+#define WT_STAT_CONN_COND_WAIT 1107
/*! connection: pthread mutex shared lock read-lock calls */
-#define WT_STAT_CONN_RWLOCK_READ 1104
+#define WT_STAT_CONN_RWLOCK_READ 1108
/*! connection: pthread mutex shared lock write-lock calls */
-#define WT_STAT_CONN_RWLOCK_WRITE 1105
+#define WT_STAT_CONN_RWLOCK_WRITE 1109
/*! connection: total fsync I/Os */
-#define WT_STAT_CONN_FSYNC_IO 1106
+#define WT_STAT_CONN_FSYNC_IO 1110
/*! connection: total read I/Os */
-#define WT_STAT_CONN_READ_IO 1107
+#define WT_STAT_CONN_READ_IO 1111
/*! connection: total write I/Os */
-#define WT_STAT_CONN_WRITE_IO 1108
+#define WT_STAT_CONN_WRITE_IO 1112
/*! cursor: cursor create calls */
-#define WT_STAT_CONN_CURSOR_CREATE 1109
+#define WT_STAT_CONN_CURSOR_CREATE 1113
/*! cursor: cursor insert calls */
-#define WT_STAT_CONN_CURSOR_INSERT 1110
+#define WT_STAT_CONN_CURSOR_INSERT 1114
/*! cursor: cursor next calls */
-#define WT_STAT_CONN_CURSOR_NEXT 1111
+#define WT_STAT_CONN_CURSOR_NEXT 1115
/*! cursor: cursor prev calls */
-#define WT_STAT_CONN_CURSOR_PREV 1112
+#define WT_STAT_CONN_CURSOR_PREV 1116
/*! cursor: cursor remove calls */
-#define WT_STAT_CONN_CURSOR_REMOVE 1113
+#define WT_STAT_CONN_CURSOR_REMOVE 1117
/*! cursor: cursor reset calls */
-#define WT_STAT_CONN_CURSOR_RESET 1114
+#define WT_STAT_CONN_CURSOR_RESET 1118
/*! cursor: cursor restarted searches */
-#define WT_STAT_CONN_CURSOR_RESTART 1115
+#define WT_STAT_CONN_CURSOR_RESTART 1119
/*! cursor: cursor search calls */
-#define WT_STAT_CONN_CURSOR_SEARCH 1116
+#define WT_STAT_CONN_CURSOR_SEARCH 1120
/*! cursor: cursor search near calls */
-#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1117
+#define WT_STAT_CONN_CURSOR_SEARCH_NEAR 1121
/*! cursor: cursor update calls */
-#define WT_STAT_CONN_CURSOR_UPDATE 1118
+#define WT_STAT_CONN_CURSOR_UPDATE 1122
/*! cursor: truncate calls */
-#define WT_STAT_CONN_CURSOR_TRUNCATE 1119
+#define WT_STAT_CONN_CURSOR_TRUNCATE 1123
/*! data-handle: connection data handles currently active */
-#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1120
+#define WT_STAT_CONN_DH_CONN_HANDLE_COUNT 1124
/*! data-handle: connection sweep candidate became referenced */
-#define WT_STAT_CONN_DH_SWEEP_REF 1121
+#define WT_STAT_CONN_DH_SWEEP_REF 1125
/*! data-handle: connection sweep dhandles closed */
-#define WT_STAT_CONN_DH_SWEEP_CLOSE 1122
+#define WT_STAT_CONN_DH_SWEEP_CLOSE 1126
/*! data-handle: connection sweep dhandles removed from hash list */
-#define WT_STAT_CONN_DH_SWEEP_REMOVE 1123
+#define WT_STAT_CONN_DH_SWEEP_REMOVE 1127
/*! data-handle: connection sweep time-of-death sets */
-#define WT_STAT_CONN_DH_SWEEP_TOD 1124
+#define WT_STAT_CONN_DH_SWEEP_TOD 1128
/*! data-handle: connection sweeps */
-#define WT_STAT_CONN_DH_SWEEPS 1125
+#define WT_STAT_CONN_DH_SWEEPS 1129
/*! data-handle: session dhandles swept */
-#define WT_STAT_CONN_DH_SESSION_HANDLES 1126
+#define WT_STAT_CONN_DH_SESSION_HANDLES 1130
/*! data-handle: session sweep attempts */
-#define WT_STAT_CONN_DH_SESSION_SWEEPS 1127
+#define WT_STAT_CONN_DH_SESSION_SWEEPS 1131
/*! lock: checkpoint lock acquisitions */
-#define WT_STAT_CONN_LOCK_CHECKPOINT_COUNT 1128
+#define WT_STAT_CONN_LOCK_CHECKPOINT_COUNT 1132
/*! lock: checkpoint lock application thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_APPLICATION 1129
+#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_APPLICATION 1133
/*! lock: checkpoint lock internal thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_INTERNAL 1130
+#define WT_STAT_CONN_LOCK_CHECKPOINT_WAIT_INTERNAL 1134
/*! lock: handle-list lock acquisitions */
-#define WT_STAT_CONN_LOCK_HANDLE_LIST_COUNT 1131
+#define WT_STAT_CONN_LOCK_HANDLE_LIST_COUNT 1135
/*! lock: handle-list lock application thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_APPLICATION 1132
+#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_APPLICATION 1136
/*! lock: handle-list lock internal thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_INTERNAL 1133
+#define WT_STAT_CONN_LOCK_HANDLE_LIST_WAIT_INTERNAL 1137
/*! lock: metadata lock acquisitions */
-#define WT_STAT_CONN_LOCK_METADATA_COUNT 1134
+#define WT_STAT_CONN_LOCK_METADATA_COUNT 1138
/*! lock: metadata lock application thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_METADATA_WAIT_APPLICATION 1135
+#define WT_STAT_CONN_LOCK_METADATA_WAIT_APPLICATION 1139
/*! lock: metadata lock internal thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_METADATA_WAIT_INTERNAL 1136
+#define WT_STAT_CONN_LOCK_METADATA_WAIT_INTERNAL 1140
/*! lock: schema lock acquisitions */
-#define WT_STAT_CONN_LOCK_SCHEMA_COUNT 1137
+#define WT_STAT_CONN_LOCK_SCHEMA_COUNT 1141
/*! lock: schema lock application thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_APPLICATION 1138
+#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_APPLICATION 1142
/*! lock: schema lock internal thread wait time (usecs) */
-#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_INTERNAL 1139
+#define WT_STAT_CONN_LOCK_SCHEMA_WAIT_INTERNAL 1143
/*! lock: table lock acquisitions */
-#define WT_STAT_CONN_LOCK_TABLE_COUNT 1140
+#define WT_STAT_CONN_LOCK_TABLE_COUNT 1144
/*!
* lock: table lock application thread time waiting for the table lock
* (usecs)
*/
-#define WT_STAT_CONN_LOCK_TABLE_WAIT_APPLICATION 1141
+#define WT_STAT_CONN_LOCK_TABLE_WAIT_APPLICATION 1145
/*!
* lock: table lock internal thread time waiting for the table lock
* (usecs)
*/
-#define WT_STAT_CONN_LOCK_TABLE_WAIT_INTERNAL 1142
+#define WT_STAT_CONN_LOCK_TABLE_WAIT_INTERNAL 1146
/*! log: busy returns attempting to switch slots */
-#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1143
+#define WT_STAT_CONN_LOG_SLOT_SWITCH_BUSY 1147
/*! log: consolidated slot closures */
-#define WT_STAT_CONN_LOG_SLOT_CLOSES 1144
+#define WT_STAT_CONN_LOG_SLOT_CLOSES 1148
/*! log: consolidated slot join races */
-#define WT_STAT_CONN_LOG_SLOT_RACES 1145
+#define WT_STAT_CONN_LOG_SLOT_RACES 1149
/*! log: consolidated slot join transitions */
-#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1146
+#define WT_STAT_CONN_LOG_SLOT_TRANSITIONS 1150
/*! log: consolidated slot joins */
-#define WT_STAT_CONN_LOG_SLOT_JOINS 1147
+#define WT_STAT_CONN_LOG_SLOT_JOINS 1151
/*! log: consolidated slot unbuffered writes */
-#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1148
+#define WT_STAT_CONN_LOG_SLOT_UNBUFFERED 1152
/*! log: log bytes of payload data */
-#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1149
+#define WT_STAT_CONN_LOG_BYTES_PAYLOAD 1153
/*! log: log bytes written */
-#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1150
+#define WT_STAT_CONN_LOG_BYTES_WRITTEN 1154
/*! log: log files manually zero-filled */
-#define WT_STAT_CONN_LOG_ZERO_FILLS 1151
+#define WT_STAT_CONN_LOG_ZERO_FILLS 1155
/*! log: log flush operations */
-#define WT_STAT_CONN_LOG_FLUSH 1152
+#define WT_STAT_CONN_LOG_FLUSH 1156
/*! log: log force write operations */
-#define WT_STAT_CONN_LOG_FORCE_WRITE 1153
+#define WT_STAT_CONN_LOG_FORCE_WRITE 1157
/*! log: log force write operations skipped */
-#define WT_STAT_CONN_LOG_FORCE_WRITE_SKIP 1154
+#define WT_STAT_CONN_LOG_FORCE_WRITE_SKIP 1158
/*! log: log records compressed */
-#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1155
+#define WT_STAT_CONN_LOG_COMPRESS_WRITES 1159
/*! log: log records not compressed */
-#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1156
+#define WT_STAT_CONN_LOG_COMPRESS_WRITE_FAILS 1160
/*! log: log records too small to compress */
-#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1157
+#define WT_STAT_CONN_LOG_COMPRESS_SMALL 1161
/*! log: log release advances write LSN */
-#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1158
+#define WT_STAT_CONN_LOG_RELEASE_WRITE_LSN 1162
/*! log: log scan operations */
-#define WT_STAT_CONN_LOG_SCANS 1159
+#define WT_STAT_CONN_LOG_SCANS 1163
/*! log: log scan records requiring two reads */
-#define WT_STAT_CONN_LOG_SCAN_REREADS 1160
+#define WT_STAT_CONN_LOG_SCAN_REREADS 1164
/*! log: log server thread advances write LSN */
-#define WT_STAT_CONN_LOG_WRITE_LSN 1161
+#define WT_STAT_CONN_LOG_WRITE_LSN 1165
/*! log: log server thread write LSN walk skipped */
-#define WT_STAT_CONN_LOG_WRITE_LSN_SKIP 1162
+#define WT_STAT_CONN_LOG_WRITE_LSN_SKIP 1166
/*! log: log sync operations */
-#define WT_STAT_CONN_LOG_SYNC 1163
+#define WT_STAT_CONN_LOG_SYNC 1167
/*! log: log sync time duration (usecs) */
-#define WT_STAT_CONN_LOG_SYNC_DURATION 1164
+#define WT_STAT_CONN_LOG_SYNC_DURATION 1168
/*! log: log sync_dir operations */
-#define WT_STAT_CONN_LOG_SYNC_DIR 1165
+#define WT_STAT_CONN_LOG_SYNC_DIR 1169
/*! log: log sync_dir time duration (usecs) */
-#define WT_STAT_CONN_LOG_SYNC_DIR_DURATION 1166
+#define WT_STAT_CONN_LOG_SYNC_DIR_DURATION 1170
/*! log: log write operations */
-#define WT_STAT_CONN_LOG_WRITES 1167
+#define WT_STAT_CONN_LOG_WRITES 1171
/*! log: logging bytes consolidated */
-#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1168
+#define WT_STAT_CONN_LOG_SLOT_CONSOLIDATED 1172
/*! log: maximum log file size */
-#define WT_STAT_CONN_LOG_MAX_FILESIZE 1169
+#define WT_STAT_CONN_LOG_MAX_FILESIZE 1173
/*! log: number of pre-allocated log files to create */
-#define WT_STAT_CONN_LOG_PREALLOC_MAX 1170
+#define WT_STAT_CONN_LOG_PREALLOC_MAX 1174
/*! log: pre-allocated log files not ready and missed */
-#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1171
+#define WT_STAT_CONN_LOG_PREALLOC_MISSED 1175
/*! log: pre-allocated log files prepared */
-#define WT_STAT_CONN_LOG_PREALLOC_FILES 1172
+#define WT_STAT_CONN_LOG_PREALLOC_FILES 1176
/*! log: pre-allocated log files used */
-#define WT_STAT_CONN_LOG_PREALLOC_USED 1173
+#define WT_STAT_CONN_LOG_PREALLOC_USED 1177
/*! log: records processed by log scan */
-#define WT_STAT_CONN_LOG_SCAN_RECORDS 1174
+#define WT_STAT_CONN_LOG_SCAN_RECORDS 1178
/*! log: total in-memory size of compressed records */
-#define WT_STAT_CONN_LOG_COMPRESS_MEM 1175
+#define WT_STAT_CONN_LOG_COMPRESS_MEM 1179
/*! log: total log buffer size */
-#define WT_STAT_CONN_LOG_BUFFER_SIZE 1176
+#define WT_STAT_CONN_LOG_BUFFER_SIZE 1180
/*! log: total size of compressed records */
-#define WT_STAT_CONN_LOG_COMPRESS_LEN 1177
+#define WT_STAT_CONN_LOG_COMPRESS_LEN 1181
/*! log: written slots coalesced */
-#define WT_STAT_CONN_LOG_SLOT_COALESCED 1178
+#define WT_STAT_CONN_LOG_SLOT_COALESCED 1182
/*! log: yields waiting for previous log file close */
-#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1179
+#define WT_STAT_CONN_LOG_CLOSE_YIELDS 1183
/*! reconciliation: fast-path pages deleted */
-#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1180
+#define WT_STAT_CONN_REC_PAGE_DELETE_FAST 1184
/*! reconciliation: page reconciliation calls */
-#define WT_STAT_CONN_REC_PAGES 1181
+#define WT_STAT_CONN_REC_PAGES 1185
/*! reconciliation: page reconciliation calls for eviction */
-#define WT_STAT_CONN_REC_PAGES_EVICTION 1182
+#define WT_STAT_CONN_REC_PAGES_EVICTION 1186
/*! reconciliation: pages deleted */
-#define WT_STAT_CONN_REC_PAGE_DELETE 1183
+#define WT_STAT_CONN_REC_PAGE_DELETE 1187
/*! reconciliation: split bytes currently awaiting free */
-#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1184
+#define WT_STAT_CONN_REC_SPLIT_STASHED_BYTES 1188
/*! reconciliation: split objects currently awaiting free */
-#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1185
+#define WT_STAT_CONN_REC_SPLIT_STASHED_OBJECTS 1189
/*! session: open cursor count */
-#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1186
+#define WT_STAT_CONN_SESSION_CURSOR_OPEN 1190
/*! session: open session count */
-#define WT_STAT_CONN_SESSION_OPEN 1187
+#define WT_STAT_CONN_SESSION_OPEN 1191
/*! session: table alter failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_ALTER_FAIL 1188
+#define WT_STAT_CONN_SESSION_TABLE_ALTER_FAIL 1192
/*! session: table alter successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_ALTER_SUCCESS 1189
+#define WT_STAT_CONN_SESSION_TABLE_ALTER_SUCCESS 1193
/*! session: table alter unchanged and skipped */
-#define WT_STAT_CONN_SESSION_TABLE_ALTER_SKIP 1190
+#define WT_STAT_CONN_SESSION_TABLE_ALTER_SKIP 1194
/*! session: table compact failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1191
+#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1195
/*! session: table compact successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1192
+#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1196
/*! session: table create failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1193
+#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1197
/*! session: table create successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1194
+#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1198
/*! session: table drop failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1195
+#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1199
/*! session: table drop successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1196
+#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1200
/*! session: table rebalance failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1197
+#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1201
/*! session: table rebalance successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1198
+#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1202
/*! session: table rename failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1199
+#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1203
/*! session: table rename successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1200
+#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1204
/*! session: table salvage failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1201
+#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1205
/*! session: table salvage successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1202
+#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1206
/*! session: table truncate failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1203
+#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1207
/*! session: table truncate successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1204
+#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1208
/*! session: table verify failed calls */
-#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1205
+#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1209
/*! session: table verify successful calls */
-#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1206
+#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1210
/*! thread-state: active filesystem fsync calls */
-#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1207
+#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1211
/*! thread-state: active filesystem read calls */
-#define WT_STAT_CONN_THREAD_READ_ACTIVE 1208
+#define WT_STAT_CONN_THREAD_READ_ACTIVE 1212
/*! thread-state: active filesystem write calls */
-#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1209
+#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1213
/*! thread-yield: application thread time evicting (usecs) */
-#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1210
+#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1214
/*! thread-yield: application thread time waiting for cache (usecs) */
-#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1211
+#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1215
/*! thread-yield: page acquire busy blocked */
-#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1212
+#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1216
/*! thread-yield: page acquire eviction blocked */
-#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1213
+#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1217
/*! thread-yield: page acquire locked blocked */
-#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1214
+#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1218
/*! thread-yield: page acquire read blocked */
-#define WT_STAT_CONN_PAGE_READ_BLOCKED 1215
+#define WT_STAT_CONN_PAGE_READ_BLOCKED 1219
/*! thread-yield: page acquire time sleeping (usecs) */
-#define WT_STAT_CONN_PAGE_SLEEP 1216
+#define WT_STAT_CONN_PAGE_SLEEP 1220
/*! transaction: number of named snapshots created */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1217
+#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1221
/*! transaction: number of named snapshots dropped */
-#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1218
+#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1222
/*! transaction: transaction begins */
-#define WT_STAT_CONN_TXN_BEGIN 1219
+#define WT_STAT_CONN_TXN_BEGIN 1223
/*! transaction: transaction checkpoint currently running */
-#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1220
+#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1224
/*! transaction: transaction checkpoint generation */
-#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1221
+#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1225
/*! transaction: transaction checkpoint max time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1222
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1226
/*! transaction: transaction checkpoint min time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1223
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1227
/*! transaction: transaction checkpoint most recent time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1224
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1228
/*! transaction: transaction checkpoint scrub dirty target */
-#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1225
+#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1229
/*! transaction: transaction checkpoint scrub time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1226
+#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1230
/*! transaction: transaction checkpoint total time (msecs) */
-#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1227
+#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1231
/*! transaction: transaction checkpoints */
-#define WT_STAT_CONN_TXN_CHECKPOINT 1228
+#define WT_STAT_CONN_TXN_CHECKPOINT 1232
/*!
* transaction: transaction checkpoints skipped because database was
* clean
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1229
+#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1233
/*! transaction: transaction failures due to cache overflow */
-#define WT_STAT_CONN_TXN_FAIL_CACHE 1230
+#define WT_STAT_CONN_TXN_FAIL_CACHE 1234
/*!
* transaction: transaction fsync calls for checkpoint after allocating
* the transaction ID
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1231
+#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1235
/*!
* transaction: transaction fsync duration for checkpoint after
* allocating the transaction ID (usecs)
*/
-#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1232
+#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1236
/*! transaction: transaction range of IDs currently pinned */
-#define WT_STAT_CONN_TXN_PINNED_RANGE 1233
+#define WT_STAT_CONN_TXN_PINNED_RANGE 1237
/*! transaction: transaction range of IDs currently pinned by a checkpoint */
-#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1234
+#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1238
/*!
* transaction: transaction range of IDs currently pinned by named
* snapshots
*/
-#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1235
+#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1239
/*! transaction: transaction sync calls */
-#define WT_STAT_CONN_TXN_SYNC 1236
+#define WT_STAT_CONN_TXN_SYNC 1240
/*! transaction: transactions committed */
-#define WT_STAT_CONN_TXN_COMMIT 1237
+#define WT_STAT_CONN_TXN_COMMIT 1241
/*! transaction: transactions rolled back */
-#define WT_STAT_CONN_TXN_ROLLBACK 1238
+#define WT_STAT_CONN_TXN_ROLLBACK 1242
/*!
* @}
@@ -4978,181 +4986,183 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection);
#define WT_STAT_DSRC_CACHE_WRITE 2059
/*! cache: pages written requiring in-memory restoration */
#define WT_STAT_DSRC_CACHE_WRITE_RESTORE 2060
+/*! cache: tracked dirty bytes in the cache */
+#define WT_STAT_DSRC_CACHE_BYTES_DIRTY 2061
/*! cache: unmodified pages evicted */
-#define WT_STAT_DSRC_CACHE_EVICTION_CLEAN 2061
+#define WT_STAT_DSRC_CACHE_EVICTION_CLEAN 2062
/*!
* cache_walk: Average difference between current eviction generation
* when the page was last considered, only reported if cache_walk or all
* statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_GEN_AVG_GAP 2062
+#define WT_STAT_DSRC_CACHE_STATE_GEN_AVG_GAP 2063
/*!
* cache_walk: Average on-disk page image size seen, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_AVG_WRITTEN_SIZE 2063
+#define WT_STAT_DSRC_CACHE_STATE_AVG_WRITTEN_SIZE 2064
/*!
* cache_walk: Clean pages currently in cache, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_PAGES_CLEAN 2064
+#define WT_STAT_DSRC_CACHE_STATE_PAGES_CLEAN 2065
/*!
* cache_walk: Current eviction generation, only reported if cache_walk
* or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_GEN_CURRENT 2065
+#define WT_STAT_DSRC_CACHE_STATE_GEN_CURRENT 2066
/*!
* cache_walk: Dirty pages currently in cache, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_PAGES_DIRTY 2066
+#define WT_STAT_DSRC_CACHE_STATE_PAGES_DIRTY 2067
/*!
* cache_walk: Entries in the root page, only reported if cache_walk or
* all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_ROOT_ENTRIES 2067
+#define WT_STAT_DSRC_CACHE_STATE_ROOT_ENTRIES 2068
/*!
* cache_walk: Internal pages currently in cache, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_PAGES_INTERNAL 2068
+#define WT_STAT_DSRC_CACHE_STATE_PAGES_INTERNAL 2069
/*!
* cache_walk: Leaf pages currently in cache, only reported if cache_walk
* or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_PAGES_LEAF 2069
+#define WT_STAT_DSRC_CACHE_STATE_PAGES_LEAF 2070
/*!
* cache_walk: Maximum difference between current eviction generation
* when the page was last considered, only reported if cache_walk or all
* statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_GEN_MAX_GAP 2070
+#define WT_STAT_DSRC_CACHE_STATE_GEN_MAX_GAP 2071
/*!
* cache_walk: Maximum page size seen, only reported if cache_walk or all
* statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_MAX_PAGESIZE 2071
+#define WT_STAT_DSRC_CACHE_STATE_MAX_PAGESIZE 2072
/*!
* cache_walk: Minimum on-disk page image size seen, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_MIN_WRITTEN_SIZE 2072
+#define WT_STAT_DSRC_CACHE_STATE_MIN_WRITTEN_SIZE 2073
/*!
* cache_walk: On-disk page image sizes smaller than a single allocation
* unit, only reported if cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_SMALLER_ALLOC_SIZE 2073
+#define WT_STAT_DSRC_CACHE_STATE_SMALLER_ALLOC_SIZE 2074
/*!
* cache_walk: Pages created in memory and never written, only reported
* if cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_MEMORY 2074
+#define WT_STAT_DSRC_CACHE_STATE_MEMORY 2075
/*!
* cache_walk: Pages currently queued for eviction, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_QUEUED 2075
+#define WT_STAT_DSRC_CACHE_STATE_QUEUED 2076
/*!
* cache_walk: Pages that could not be queued for eviction, only reported
* if cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_NOT_QUEUEABLE 2076
+#define WT_STAT_DSRC_CACHE_STATE_NOT_QUEUEABLE 2077
/*!
* cache_walk: Refs skipped during cache traversal, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_REFS_SKIPPED 2077
+#define WT_STAT_DSRC_CACHE_STATE_REFS_SKIPPED 2078
/*!
* cache_walk: Size of the root page, only reported if cache_walk or all
* statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_ROOT_SIZE 2078
+#define WT_STAT_DSRC_CACHE_STATE_ROOT_SIZE 2079
/*!
* cache_walk: Total number of pages currently in cache, only reported if
* cache_walk or all statistics are enabled
*/
-#define WT_STAT_DSRC_CACHE_STATE_PAGES 2079
+#define WT_STAT_DSRC_CACHE_STATE_PAGES 2080
/*! compression: compressed pages read */
-#define WT_STAT_DSRC_COMPRESS_READ 2080
+#define WT_STAT_DSRC_COMPRESS_READ 2081
/*! compression: compressed pages written */
-#define WT_STAT_DSRC_COMPRESS_WRITE 2081
+#define WT_STAT_DSRC_COMPRESS_WRITE 2082
/*! compression: page written failed to compress */
-#define WT_STAT_DSRC_COMPRESS_WRITE_FAIL 2082
+#define WT_STAT_DSRC_COMPRESS_WRITE_FAIL 2083
/*! compression: page written was too small to compress */
-#define WT_STAT_DSRC_COMPRESS_WRITE_TOO_SMALL 2083
+#define WT_STAT_DSRC_COMPRESS_WRITE_TOO_SMALL 2084
/*! compression: raw compression call failed, additional data available */
-#define WT_STAT_DSRC_COMPRESS_RAW_FAIL_TEMPORARY 2084
+#define WT_STAT_DSRC_COMPRESS_RAW_FAIL_TEMPORARY 2085
/*! compression: raw compression call failed, no additional data available */
-#define WT_STAT_DSRC_COMPRESS_RAW_FAIL 2085
+#define WT_STAT_DSRC_COMPRESS_RAW_FAIL 2086
/*! compression: raw compression call succeeded */
-#define WT_STAT_DSRC_COMPRESS_RAW_OK 2086
+#define WT_STAT_DSRC_COMPRESS_RAW_OK 2087
/*! cursor: bulk-loaded cursor-insert calls */
-#define WT_STAT_DSRC_CURSOR_INSERT_BULK 2087
+#define WT_STAT_DSRC_CURSOR_INSERT_BULK 2088
/*! cursor: create calls */
-#define WT_STAT_DSRC_CURSOR_CREATE 2088
+#define WT_STAT_DSRC_CURSOR_CREATE 2089
/*! cursor: cursor-insert key and value bytes inserted */
-#define WT_STAT_DSRC_CURSOR_INSERT_BYTES 2089
+#define WT_STAT_DSRC_CURSOR_INSERT_BYTES 2090
/*! cursor: cursor-remove key bytes removed */
-#define WT_STAT_DSRC_CURSOR_REMOVE_BYTES 2090
+#define WT_STAT_DSRC_CURSOR_REMOVE_BYTES 2091
/*! cursor: cursor-update value bytes updated */
-#define WT_STAT_DSRC_CURSOR_UPDATE_BYTES 2091
+#define WT_STAT_DSRC_CURSOR_UPDATE_BYTES 2092
/*! cursor: insert calls */
-#define WT_STAT_DSRC_CURSOR_INSERT 2092
+#define WT_STAT_DSRC_CURSOR_INSERT 2093
/*! cursor: next calls */
-#define WT_STAT_DSRC_CURSOR_NEXT 2093
+#define WT_STAT_DSRC_CURSOR_NEXT 2094
/*! cursor: prev calls */
-#define WT_STAT_DSRC_CURSOR_PREV 2094
+#define WT_STAT_DSRC_CURSOR_PREV 2095
/*! cursor: remove calls */
-#define WT_STAT_DSRC_CURSOR_REMOVE 2095
+#define WT_STAT_DSRC_CURSOR_REMOVE 2096
/*! cursor: reset calls */
-#define WT_STAT_DSRC_CURSOR_RESET 2096
+#define WT_STAT_DSRC_CURSOR_RESET 2097
/*! cursor: restarted searches */
-#define WT_STAT_DSRC_CURSOR_RESTART 2097
+#define WT_STAT_DSRC_CURSOR_RESTART 2098
/*! cursor: search calls */
-#define WT_STAT_DSRC_CURSOR_SEARCH 2098
+#define WT_STAT_DSRC_CURSOR_SEARCH 2099
/*! cursor: search near calls */
-#define WT_STAT_DSRC_CURSOR_SEARCH_NEAR 2099
+#define WT_STAT_DSRC_CURSOR_SEARCH_NEAR 2100
/*! cursor: truncate calls */
-#define WT_STAT_DSRC_CURSOR_TRUNCATE 2100
+#define WT_STAT_DSRC_CURSOR_TRUNCATE 2101
/*! cursor: update calls */
-#define WT_STAT_DSRC_CURSOR_UPDATE 2101
+#define WT_STAT_DSRC_CURSOR_UPDATE 2102
/*! reconciliation: dictionary matches */
-#define WT_STAT_DSRC_REC_DICTIONARY 2102
+#define WT_STAT_DSRC_REC_DICTIONARY 2103
/*! reconciliation: fast-path pages deleted */
-#define WT_STAT_DSRC_REC_PAGE_DELETE_FAST 2103
+#define WT_STAT_DSRC_REC_PAGE_DELETE_FAST 2104
/*!
* reconciliation: internal page key bytes discarded using suffix
* compression
*/
-#define WT_STAT_DSRC_REC_SUFFIX_COMPRESSION 2104
+#define WT_STAT_DSRC_REC_SUFFIX_COMPRESSION 2105
/*! reconciliation: internal page multi-block writes */
-#define WT_STAT_DSRC_REC_MULTIBLOCK_INTERNAL 2105
+#define WT_STAT_DSRC_REC_MULTIBLOCK_INTERNAL 2106
/*! reconciliation: internal-page overflow keys */
-#define WT_STAT_DSRC_REC_OVERFLOW_KEY_INTERNAL 2106
+#define WT_STAT_DSRC_REC_OVERFLOW_KEY_INTERNAL 2107
/*! reconciliation: leaf page key bytes discarded using prefix compression */
-#define WT_STAT_DSRC_REC_PREFIX_COMPRESSION 2107
+#define WT_STAT_DSRC_REC_PREFIX_COMPRESSION 2108
/*! reconciliation: leaf page multi-block writes */
-#define WT_STAT_DSRC_REC_MULTIBLOCK_LEAF 2108
+#define WT_STAT_DSRC_REC_MULTIBLOCK_LEAF 2109
/*! reconciliation: leaf-page overflow keys */
-#define WT_STAT_DSRC_REC_OVERFLOW_KEY_LEAF 2109
+#define WT_STAT_DSRC_REC_OVERFLOW_KEY_LEAF 2110
/*! reconciliation: maximum blocks required for a page */
-#define WT_STAT_DSRC_REC_MULTIBLOCK_MAX 2110
+#define WT_STAT_DSRC_REC_MULTIBLOCK_MAX 2111
/*! reconciliation: overflow values written */
-#define WT_STAT_DSRC_REC_OVERFLOW_VALUE 2111
+#define WT_STAT_DSRC_REC_OVERFLOW_VALUE 2112
/*! reconciliation: page checksum matches */
-#define WT_STAT_DSRC_REC_PAGE_MATCH 2112
+#define WT_STAT_DSRC_REC_PAGE_MATCH 2113
/*! reconciliation: page reconciliation calls */
-#define WT_STAT_DSRC_REC_PAGES 2113
+#define WT_STAT_DSRC_REC_PAGES 2114
/*! reconciliation: page reconciliation calls for eviction */
-#define WT_STAT_DSRC_REC_PAGES_EVICTION 2114
+#define WT_STAT_DSRC_REC_PAGES_EVICTION 2115
/*! reconciliation: pages deleted */
-#define WT_STAT_DSRC_REC_PAGE_DELETE 2115
+#define WT_STAT_DSRC_REC_PAGE_DELETE 2116
/*! session: object compaction */
-#define WT_STAT_DSRC_SESSION_COMPACT 2116
+#define WT_STAT_DSRC_SESSION_COMPACT 2117
/*! session: open cursor count */
-#define WT_STAT_DSRC_SESSION_CURSOR_OPEN 2117
+#define WT_STAT_DSRC_SESSION_CURSOR_OPEN 2118
/*! transaction: update conflicts */
-#define WT_STAT_DSRC_TXN_UPDATE_CONFLICT 2118
+#define WT_STAT_DSRC_TXN_UPDATE_CONFLICT 2119
/*!
* @}
diff --git a/src/include/wt_internal.h b/src/include/wt_internal.h
index e18563dd2d2..da318ad8a86 100644
--- a/src/include/wt_internal.h
+++ b/src/include/wt_internal.h
@@ -106,6 +106,8 @@ struct __wt_col;
typedef struct __wt_col WT_COL;
struct __wt_col_rle;
typedef struct __wt_col_rle WT_COL_RLE;
+struct __wt_col_var_repeat;
+ typedef struct __wt_col_var_repeat WT_COL_VAR_REPEAT;
struct __wt_colgroup;
typedef struct __wt_colgroup WT_COLGROUP;
struct __wt_compact_state;
@@ -266,8 +268,6 @@ struct __wt_ref;
typedef struct __wt_ref WT_REF;
struct __wt_row;
typedef struct __wt_row WT_ROW;
-struct __wt_rwlock;
- typedef struct __wt_rwlock WT_RWLOCK;
struct __wt_salvage_cookie;
typedef struct __wt_salvage_cookie WT_SALVAGE_COOKIE;
struct __wt_save_upd;
@@ -302,6 +302,8 @@ union __wt_lsn;
typedef union __wt_lsn WT_LSN;
union __wt_rand_state;
typedef union __wt_rand_state WT_RAND_STATE;
+union __wt_rwlock;
+ typedef union __wt_rwlock WT_RWLOCK;
/*
* Forward type declarations for internal types: END
* DO NOT EDIT: automatically built by dist/s_typedef.
diff --git a/src/log/log.c b/src/log/log.c
index 413df312a15..da500a74e87 100644
--- a/src/log/log.c
+++ b/src/log/log.c
@@ -895,12 +895,12 @@ __log_newfile(WT_SESSION_IMPL *session, bool conn_open, bool *created)
*/
create_log = true;
if (conn->log_prealloc > 0 && !conn->hot_backup) {
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
if (conn->hot_backup)
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
else {
ret = __log_alloc_prealloc(session, log->fileid);
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
/*
* If ret is 0 it means we found a pre-allocated file.
@@ -1029,12 +1029,12 @@ __log_truncate_file(WT_SESSION_IMPL *session, WT_FH *log_fh, wt_off_t offset)
log = conn->log;
if (!F_ISSET(log, WT_LOG_TRUNCATE_NOTSUP) && !conn->hot_backup) {
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
if (conn->hot_backup)
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
else {
ret = __wt_ftruncate(session, log_fh, offset);
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
if (ret != ENOTSUP)
return (ret);
F_SET(log, WT_LOG_TRUNCATE_NOTSUP);
@@ -1655,10 +1655,7 @@ __wt_log_scan(WT_SESSION_IMPL *session, WT_LSN *lsnp, uint32_t flags,
WT_RET(__log_get_files(session,
WT_LOG_FILENAME, &logfiles, &logcount));
if (logcount == 0)
- /*
- * Return it is not supported if none don't exist.
- */
- return (ENOTSUP);
+ WT_RET_MSG(session, ENOTSUP, "no log files found");
for (i = 0; i < logcount; i++) {
WT_ERR(__wt_log_extract_lognum(session, logfiles[i],
&lognum));
@@ -1674,6 +1671,10 @@ __wt_log_scan(WT_SESSION_IMPL *session, WT_LSN *lsnp, uint32_t flags,
&log_fh, WT_LOG_FILENAME, start_lsn.l.file, WT_LOG_OPEN_VERIFY));
WT_ERR(__wt_filesize(session, log_fh, &log_size));
rd_lsn = start_lsn;
+ if (LF_ISSET(WT_LOGSCAN_RECOVER))
+ __wt_verbose(session, WT_VERB_RECOVERY_PROGRESS,
+ "Recovering log %" PRIu32 " through %" PRIu32,
+ rd_lsn.l.file, end_lsn.l.file);
WT_ERR(__wt_scr_alloc(session, WT_LOG_ALIGN, &buf));
WT_ERR(__wt_scr_alloc(session, 0, &decryptitem));
@@ -1722,6 +1723,11 @@ advance:
WT_ERR(__log_openfile(session,
&log_fh, WT_LOG_FILENAME,
rd_lsn.l.file, WT_LOG_OPEN_VERIFY));
+ if (LF_ISSET(WT_LOGSCAN_RECOVER))
+ __wt_verbose(session, WT_VERB_RECOVERY_PROGRESS,
+ "Recovering log %" PRIu32
+ " through %" PRIu32,
+ rd_lsn.l.file, end_lsn.l.file);
WT_ERR(__wt_filesize(session, log_fh, &log_size));
eol = false;
continue;
diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c
index 839648b97d7..a2511f48e2b 100644
--- a/src/lsm/lsm_cursor.c
+++ b/src/lsm/lsm_cursor.c
@@ -304,7 +304,7 @@ __clsm_leave(WT_CURSOR_LSM *clsm)
* byte, if the application uses two leading DC4 byte for some reason, we'll do
* a wasted data copy each time a new value is inserted into the object.
*/
-static const WT_ITEM __tombstone = { "\x14\x14", 2, 0, NULL, 0 };
+static const WT_ITEM __tombstone = { "\x14\x14", 2, NULL, 0, 0 };
/*
* __clsm_deleted --
diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c
index 38d87dd852b..71a981a6284 100644
--- a/src/lsm/lsm_tree.c
+++ b/src/lsm/lsm_tree.c
@@ -469,7 +469,7 @@ __lsm_tree_open(WT_SESSION_IMPL *session,
/* Try to open the tree. */
WT_RET(__wt_calloc_one(session, &lsm_tree));
- WT_ERR(__wt_rwlock_alloc(session, &lsm_tree->rwlock, "lsm tree"));
+ __wt_rwlock_init(session, &lsm_tree->rwlock);
WT_ERR(__lsm_tree_set_name(session, lsm_tree, uri));
@@ -1082,7 +1082,7 @@ err: if (locked)
void
__wt_lsm_tree_readlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
- __wt_readlock(session, lsm_tree->rwlock);
+ __wt_readlock(session, &lsm_tree->rwlock);
/*
* Diagnostic: avoid deadlocks with the schema lock: if we need it for
@@ -1100,7 +1100,7 @@ __wt_lsm_tree_readunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
F_CLR(session, WT_SESSION_NO_EVICTION | WT_SESSION_NO_SCHEMA_LOCK);
- __wt_readunlock(session, lsm_tree->rwlock);
+ __wt_readunlock(session, &lsm_tree->rwlock);
}
/*
@@ -1110,7 +1110,7 @@ __wt_lsm_tree_readunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
void
__wt_lsm_tree_writelock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
- __wt_writelock(session, lsm_tree->rwlock);
+ __wt_writelock(session, &lsm_tree->rwlock);
/*
* Diagnostic: avoid deadlocks with the schema lock: if we need it for
@@ -1128,7 +1128,7 @@ __wt_lsm_tree_writeunlock(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
{
F_CLR(session, WT_SESSION_NO_EVICTION | WT_SESSION_NO_SCHEMA_LOCK);
- __wt_writeunlock(session, lsm_tree->rwlock);
+ __wt_writeunlock(session, &lsm_tree->rwlock);
}
/*
diff --git a/src/os_posix/os_yield.c b/src/os_posix/os_yield.c
index 37d05bc1854..f7c43aae746 100644
--- a/src/os_posix/os_yield.c
+++ b/src/os_posix/os_yield.c
@@ -16,5 +16,13 @@ void
__wt_yield(void)
WT_GCC_FUNC_ATTRIBUTE((visibility("default")))
{
+ /*
+ * Yielding the processor isn't documented as a memory barrier, and it's
+ * a reasonable expectation to have. There's no reason not to explicitly
+ * include a barrier since we're giving up the CPU, and ensures callers
+ * aren't ever surprised.
+ */
+ WT_FULL_BARRIER();
+
sched_yield();
}
diff --git a/src/os_win/os_yield.c b/src/os_win/os_yield.c
index aab1559e072..038f2efe162 100644
--- a/src/os_win/os_yield.c
+++ b/src/os_win/os_yield.c
@@ -15,5 +15,13 @@
void
__wt_yield(void)
{
+ /*
+ * Yielding the processor isn't documented as a memory barrier, and it's
+ * a reasonable expectation to have. There's no reason not to explicitly
+ * include a barrier since we're giving up the CPU, and ensures callers
+ * aren't ever surprised.
+ */
+ WT_FULL_BARRIER();
+
SwitchToThread();
}
diff --git a/src/reconcile/rec_track.c b/src/reconcile/rec_track.c
index 3795b6e5ae8..5bf425b1b21 100644
--- a/src/reconcile/rec_track.c
+++ b/src/reconcile/rec_track.c
@@ -875,9 +875,9 @@ __wt_ovfl_track_wrapup(WT_SESSION_IMPL *session, WT_PAGE *page)
WT_RET(__ovfl_reuse_wrapup(session, page));
if (track->ovfl_txnc[0] != NULL) {
- __wt_writelock(session, S2BT(session)->ovfl_lock);
+ __wt_writelock(session, &S2BT(session)->ovfl_lock);
ret = __ovfl_txnc_wrapup(session, page);
- __wt_writeunlock(session, S2BT(session)->ovfl_lock);
+ __wt_writeunlock(session, &S2BT(session)->ovfl_lock);
}
return (ret);
}
@@ -903,9 +903,9 @@ __wt_ovfl_track_wrapup_err(WT_SESSION_IMPL *session, WT_PAGE *page)
WT_RET(__ovfl_reuse_wrapup_err(session, page));
if (track->ovfl_txnc[0] != NULL) {
- __wt_writelock(session, S2BT(session)->ovfl_lock);
+ __wt_writelock(session, &S2BT(session)->ovfl_lock);
ret = __ovfl_txnc_wrapup(session, page);
- __wt_writeunlock(session, S2BT(session)->ovfl_lock);
+ __wt_writeunlock(session, &S2BT(session)->ovfl_lock);
}
return (ret);
}
diff --git a/src/reconcile/rec_write.c b/src/reconcile/rec_write.c
index e82f449a50d..a667a288187 100644
--- a/src/reconcile/rec_write.c
+++ b/src/reconcile/rec_write.c
@@ -4069,7 +4069,7 @@ __rec_col_fix(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_REF *pageref)
/* Copy the original, disk-image bytes into place. */
memcpy(r->first_free, page->pg_fix_bitf,
- __bitstr_size((size_t)page->pg_fix_entries * btree->bitcnt));
+ __bitstr_size((size_t)page->entries * btree->bitcnt));
/* Update any changes to the original on-page data items. */
WT_SKIP_FOREACH(ins, WT_COL_UPDATE_SINGLE(page)) {
@@ -4081,9 +4081,8 @@ __rec_col_fix(WT_SESSION_IMPL *session, WT_RECONCILE *r, WT_REF *pageref)
}
/* Calculate the number of entries per page remainder. */
- entry = page->pg_fix_entries;
- nrecs = WT_FIX_BYTES_TO_ENTRIES(
- btree, r->space_avail) - page->pg_fix_entries;
+ entry = page->entries;
+ nrecs = WT_FIX_BYTES_TO_ENTRIES(btree, r->space_avail) - page->entries;
r->recno += entry;
/* Walk any append list. */
@@ -4206,7 +4205,7 @@ __rec_col_fix_slvg(WT_SESSION_IMPL *session,
session, r, page, pageref->ref_recno, btree->maxleafpage));
/* We may not be taking all of the entries on the original page. */
- page_take = salvage->take == 0 ? page->pg_fix_entries : salvage->take;
+ page_take = salvage->take == 0 ? page->entries : salvage->take;
page_start = salvage->skip == 0 ? 0 : salvage->skip;
/* Calculate the number of entries per page. */
diff --git a/src/schema/schema_util.c b/src/schema/schema_util.c
index 433224a868e..9de4b916a79 100644
--- a/src/schema/schema_util.c
+++ b/src/schema/schema_util.c
@@ -26,7 +26,7 @@ __wt_schema_backup_check(WT_SESSION_IMPL *session, const char *name)
conn = S2C(session);
if (!conn->hot_backup)
return (0);
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
/*
* There is a window at the end of a backup where the list has been
* cleared from the connection but the flag is still set. It is safe
@@ -34,7 +34,7 @@ __wt_schema_backup_check(WT_SESSION_IMPL *session, const char *name)
*/
if (!conn->hot_backup ||
(backup_list = conn->hot_backup_list) == NULL) {
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
return (0);
}
for (i = 0; backup_list[i] != NULL; ++i) {
@@ -43,7 +43,7 @@ __wt_schema_backup_check(WT_SESSION_IMPL *session, const char *name)
break;
}
}
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
return (ret);
}
diff --git a/src/session/session_api.c b/src/session/session_api.c
index fe1bf821d3b..fcbfa8809b3 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -1686,7 +1686,7 @@ __session_snapshot(WT_SESSION *wt_session, const char *config)
WT_ERR(__wt_txn_named_snapshot_config(
session, cfg, &has_create, &has_drop));
- __wt_writelock(session, txn_global->nsnap_rwlock);
+ __wt_writelock(session, &txn_global->nsnap_rwlock);
/* Drop any snapshots to be removed first. */
if (has_drop)
@@ -1696,7 +1696,7 @@ __session_snapshot(WT_SESSION *wt_session, const char *config)
if (has_create)
WT_ERR(__wt_txn_named_snapshot_begin(session, cfg));
-err: __wt_writeunlock(session, txn_global->nsnap_rwlock);
+err: __wt_writeunlock(session, &txn_global->nsnap_rwlock);
API_END_RET_NOTFOUND_MAP(session, ret);
}
diff --git a/src/session/session_dhandle.c b/src/session/session_dhandle.c
index 732dc797b6d..f1251794b89 100644
--- a/src/session/session_dhandle.c
+++ b/src/session/session_dhandle.c
@@ -181,17 +181,17 @@ __wt_session_lock_dhandle(
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
(!want_exclusive || lock_busy)) {
- __wt_readlock(session, dhandle->rwlock);
+ __wt_readlock(session, &dhandle->rwlock);
if (F_ISSET(dhandle, WT_DHANDLE_DEAD)) {
*is_deadp = 1;
- __wt_readunlock(session, dhandle->rwlock);
+ __wt_readunlock(session, &dhandle->rwlock);
return (0);
}
is_open = F_ISSET(dhandle, WT_DHANDLE_OPEN);
if (is_open && !want_exclusive)
return (0);
- __wt_readunlock(session, dhandle->rwlock);
+ __wt_readunlock(session, &dhandle->rwlock);
} else
is_open = false;
@@ -201,10 +201,11 @@ __wt_session_lock_dhandle(
* with another thread that successfully opens the file, we
* don't want to block waiting to get exclusive access.
*/
- if ((ret = __wt_try_writelock(session, dhandle->rwlock)) == 0) {
+ if ((ret =
+ __wt_try_writelock(session, &dhandle->rwlock)) == 0) {
if (F_ISSET(dhandle, WT_DHANDLE_DEAD)) {
*is_deadp = 1;
- __wt_writeunlock(session, dhandle->rwlock);
+ __wt_writeunlock(session, &dhandle->rwlock);
return (0);
}
@@ -215,7 +216,7 @@ __wt_session_lock_dhandle(
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
!want_exclusive) {
lock_busy = false;
- __wt_writeunlock(session, dhandle->rwlock);
+ __wt_writeunlock(session, &dhandle->rwlock);
continue;
}
@@ -286,9 +287,9 @@ __wt_session_release_btree(WT_SESSION_IMPL *session)
if (locked) {
if (write_locked) {
F_CLR(dhandle, WT_DHANDLE_EXCLUSIVE);
- __wt_writeunlock(session, dhandle->rwlock);
+ __wt_writeunlock(session, &dhandle->rwlock);
} else
- __wt_readunlock(session, dhandle->rwlock);
+ __wt_readunlock(session, &dhandle->rwlock);
}
session->dhandle = NULL;
@@ -509,7 +510,7 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
dhandle->excl_session = NULL;
dhandle->excl_ref = 0;
F_CLR(dhandle, WT_DHANDLE_EXCLUSIVE);
- __wt_writeunlock(session, dhandle->rwlock);
+ __wt_writeunlock(session, &dhandle->rwlock);
WT_WITH_SCHEMA_LOCK(session,
WT_WITH_HANDLE_LIST_LOCK(session,
@@ -531,7 +532,7 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
dhandle->excl_session = NULL;
dhandle->excl_ref = 0;
F_CLR(dhandle, WT_DHANDLE_EXCLUSIVE);
- __wt_writeunlock(session, dhandle->rwlock);
+ __wt_writeunlock(session, &dhandle->rwlock);
WT_RET(ret);
}
diff --git a/src/support/mtx_rw.c b/src/support/mtx_rw.c
index ea18f556257..35ad5da23f2 100644
--- a/src/support/mtx_rw.c
+++ b/src/support/mtx_rw.c
@@ -115,23 +115,27 @@
#include "wt_internal.h"
/*
- * __wt_rwlock_alloc --
- * Allocate and initialize a read/write lock.
+ * __wt_rwlock_init --
+ * Initialize a read/write lock.
*/
-int
-__wt_rwlock_alloc(
- WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp, const char *name)
+void
+__wt_rwlock_init(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- WT_RWLOCK *rwlock;
-
- __wt_verbose(session, WT_VERB_MUTEX, "rwlock: alloc %s", name);
+ WT_UNUSED(session);
- WT_RET(__wt_calloc_one(session, &rwlock));
+ l->u = 0;
+}
- rwlock->name = name;
+/*
+ * __wt_rwlock_destroy --
+ * Destroy a read/write lock.
+ */
+void
+__wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK *l)
+{
+ WT_UNUSED(session);
- *rwlockp = rwlock;
- return (0);
+ l->u = 0;
}
/*
@@ -139,13 +143,12 @@ __wt_rwlock_alloc(
* Try to get a shared lock, fail immediately if unavailable.
*/
int
-__wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l, new, old;
+ WT_RWLOCK new, old;
WT_STAT_CONN_INCR(session, rwlock_read);
- l = &rwlock->rwlock;
new = old = *l;
/*
@@ -172,19 +175,15 @@ __wt_try_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* exclusive.
*/
void
-__wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l;
-
- l = &rwlock->rwlock;
-
/*
* Try to get the lock in a single operation if it is available to
* readers. This avoids the situation where multiple readers arrive
* concurrently and have to line up in order to enter the lock. For
* read-heavy workloads it can make a significant difference.
*/
- while (__wt_try_readlock(session, rwlock) != 0) {
+ while (__wt_try_readlock(session, l) != 0) {
if (l->s.writers_active > 0)
__wt_yield();
else
@@ -197,9 +196,8 @@ __wt_readlock_spin(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* Get a shared lock.
*/
void
-__wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l;
uint16_t ticket;
int pause_cnt;
@@ -207,8 +205,6 @@ __wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
WT_DIAGNOSTIC_YIELD;
- l = &rwlock->rwlock;
-
/*
* Possibly wrap: if we have more than 64K lockers waiting, the ticket
* value will wrap and two lockers will simultaneously be granted the
@@ -246,14 +242,10 @@ __wt_readlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* Release a shared lock.
*/
void
-__wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l;
-
WT_UNUSED(session);
- l = &rwlock->rwlock;
-
/*
* Increment the writers value (other readers are doing the same, make
* sure we don't race).
@@ -266,13 +258,12 @@ __wt_readunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* Try to get an exclusive lock, fail immediately if unavailable.
*/
int
-__wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l, new, old;
+ WT_RWLOCK new, old;
WT_STAT_CONN_INCR(session, rwlock_write);
- l = &rwlock->rwlock;
old = new = *l;
/*
@@ -296,16 +287,13 @@ __wt_try_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* Wait to get an exclusive lock.
*/
void
-__wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l;
uint16_t ticket;
int pause_cnt;
WT_STAT_CONN_INCR(session, rwlock_write);
- l = &rwlock->rwlock;
-
/*
* Possibly wrap: if we have more than 64K lockers waiting, the ticket
* value will wrap and two lockers will simultaneously be granted the
@@ -338,13 +326,12 @@ __wt_writelock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
* Release an exclusive lock.
*/
void
-__wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l, new;
+ WT_RWLOCK new;
WT_UNUSED(session);
- l = &rwlock->rwlock;
(void)__wt_atomic_sub16(&l->s.writers_active, 1);
/*
@@ -368,40 +355,16 @@ __wt_writeunlock(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
WT_DIAGNOSTIC_YIELD;
}
-/*
- * __wt_rwlock_destroy --
- * Destroy a read/write lock.
- */
-void
-__wt_rwlock_destroy(WT_SESSION_IMPL *session, WT_RWLOCK **rwlockp)
-{
- WT_RWLOCK *rwlock;
-
- rwlock = *rwlockp; /* Clear our caller's reference. */
- if (rwlock == NULL)
- return;
- *rwlockp = NULL;
-
- __wt_verbose(
- session, WT_VERB_MUTEX, "rwlock: destroy %s", rwlock->name);
-
- __wt_free(session, rwlock);
-}
-
#ifdef HAVE_DIAGNOSTIC
/*
* __wt_rwlock_islocked --
* Return if a read/write lock is currently locked for reading or writing.
*/
bool
-__wt_rwlock_islocked(WT_SESSION_IMPL *session, WT_RWLOCK *rwlock)
+__wt_rwlock_islocked(WT_SESSION_IMPL *session, WT_RWLOCK *l)
{
- wt_rwlock_t *l;
-
WT_UNUSED(session);
- l = &rwlock->rwlock;
-
return (l->s.writers != l->s.next || l->s.readers != l->s.next);
}
#endif
diff --git a/src/support/stat.c b/src/support/stat.c
index a9c0b24ef29..167d17137ce 100644
--- a/src/support/stat.c
+++ b/src/support/stat.c
@@ -64,6 +64,7 @@ static const char * const __stats_dsrc_desc[] = {
"cache: pages requested from the cache",
"cache: pages written from cache",
"cache: pages written requiring in-memory restoration",
+ "cache: tracked dirty bytes in the cache",
"cache: unmodified pages evicted",
"cache_walk: Average difference between current eviction generation when the page was last considered",
"cache_walk: Average on-disk page image size seen",
@@ -225,6 +226,7 @@ __wt_stat_dsrc_clear_single(WT_DSRC_STATS *stats)
stats->cache_pages_requested = 0;
stats->cache_write = 0;
stats->cache_write_restore = 0;
+ /* not clearing cache_bytes_dirty */
stats->cache_eviction_clean = 0;
/* not clearing cache_state_gen_avg_gap */
/* not clearing cache_state_avg_written_size */
@@ -372,6 +374,7 @@ __wt_stat_dsrc_aggregate_single(
to->cache_pages_requested += from->cache_pages_requested;
to->cache_write += from->cache_write;
to->cache_write_restore += from->cache_write_restore;
+ to->cache_bytes_dirty += from->cache_bytes_dirty;
to->cache_eviction_clean += from->cache_eviction_clean;
to->cache_state_gen_avg_gap += from->cache_state_gen_avg_gap;
to->cache_state_avg_written_size +=
@@ -535,6 +538,7 @@ __wt_stat_dsrc_aggregate(
WT_STAT_READ(from, cache_pages_requested);
to->cache_write += WT_STAT_READ(from, cache_write);
to->cache_write_restore += WT_STAT_READ(from, cache_write_restore);
+ to->cache_bytes_dirty += WT_STAT_READ(from, cache_bytes_dirty);
to->cache_eviction_clean += WT_STAT_READ(from, cache_eviction_clean);
to->cache_state_gen_avg_gap +=
WT_STAT_READ(from, cache_state_gen_avg_gap);
@@ -673,7 +677,11 @@ static const char * const __stats_connection_desc[] = {
"cache: eviction server unable to reach eviction goal",
"cache: eviction state",
"cache: eviction walks abandoned",
+ "cache: eviction worker thread active",
+ "cache: eviction worker thread created",
"cache: eviction worker thread evicting pages",
+ "cache: eviction worker thread removed",
+ "cache: eviction worker thread stable number",
"cache: failed eviction of pages that exceeded the in-memory maximum",
"cache: files with active eviction walks",
"cache: files with new eviction walks started",
@@ -954,7 +962,11 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats)
stats->cache_eviction_slow = 0;
/* not clearing cache_eviction_state */
stats->cache_eviction_walks_abandoned = 0;
+ /* not clearing cache_eviction_active_workers */
+ stats->cache_eviction_worker_created = 0;
stats->cache_eviction_worker_evicting = 0;
+ stats->cache_eviction_worker_removed = 0;
+ /* not clearing cache_eviction_stable_state_workers */
stats->cache_eviction_force_fail = 0;
/* not clearing cache_eviction_walks_active */
stats->cache_eviction_walks_started = 0;
@@ -1228,8 +1240,16 @@ __wt_stat_connection_aggregate(
to->cache_eviction_state += WT_STAT_READ(from, cache_eviction_state);
to->cache_eviction_walks_abandoned +=
WT_STAT_READ(from, cache_eviction_walks_abandoned);
+ to->cache_eviction_active_workers +=
+ WT_STAT_READ(from, cache_eviction_active_workers);
+ to->cache_eviction_worker_created +=
+ WT_STAT_READ(from, cache_eviction_worker_created);
to->cache_eviction_worker_evicting +=
WT_STAT_READ(from, cache_eviction_worker_evicting);
+ to->cache_eviction_worker_removed +=
+ WT_STAT_READ(from, cache_eviction_worker_removed);
+ to->cache_eviction_stable_state_workers +=
+ WT_STAT_READ(from, cache_eviction_stable_state_workers);
to->cache_eviction_force_fail +=
WT_STAT_READ(from, cache_eviction_force_fail);
to->cache_eviction_walks_active +=
diff --git a/src/support/thread_group.c b/src/support/thread_group.c
index a866d2d01c5..beb143e63e2 100644
--- a/src/support/thread_group.c
+++ b/src/support/thread_group.c
@@ -50,8 +50,7 @@ __thread_group_grow(
{
WT_THREAD *thread;
- WT_ASSERT(session,
- __wt_rwlock_islocked(session, group->lock));
+ WT_ASSERT(session, __wt_rwlock_islocked(session, &group->lock));
/*
* Any bounds checking is done by the caller so we know that
@@ -72,20 +71,19 @@ __thread_group_grow(
/*
* __thread_group_shrink --
- * Decrease the number of running threads in the group, and free any
+ * Decrease the number of running threads in the group. Optionally free any
* memory associated with slots larger than the new count.
*/
static int
__thread_group_shrink(WT_SESSION_IMPL *session,
- WT_THREAD_GROUP *group, uint32_t new_count)
+ WT_THREAD_GROUP *group, uint32_t new_count, bool free_thread)
{
WT_DECL_RET;
WT_SESSION *wt_session;
WT_THREAD *thread;
uint32_t current_slot;
- WT_ASSERT(session,
- __wt_rwlock_islocked(session, group->lock));
+ WT_ASSERT(session, __wt_rwlock_islocked(session, &group->lock));
for (current_slot = group->alloc; current_slot > new_count; ) {
/*
@@ -107,14 +105,15 @@ __thread_group_shrink(WT_SESSION_IMPL *session,
WT_TRET(__wt_thread_join(session, thread->tid));
thread->tid = 0;
}
-
- if (thread->session != NULL) {
- wt_session = (WT_SESSION *)thread->session;
- WT_TRET(wt_session->close(wt_session, NULL));
- thread->session = NULL;
+ if (free_thread) {
+ if (thread->session != NULL) {
+ wt_session = (WT_SESSION *)thread->session;
+ WT_TRET(wt_session->close(wt_session, NULL));
+ thread->session = NULL;
+ }
+ __wt_free(session, thread);
+ group->threads[current_slot] = NULL;
}
- __wt_free(session, thread);
- group->threads[current_slot] = NULL;
}
/* Update the thread group state to match our changes */
@@ -142,16 +141,19 @@ __thread_group_resize(
WT_ASSERT(session,
group->current_threads <= group->alloc &&
- __wt_rwlock_islocked(session, group->lock));
+ __wt_rwlock_islocked(session, &group->lock));
if (new_min == group->min && new_max == group->max)
return (0);
+ if (new_min > new_max)
+ return (EINVAL);
+
/*
- * Coll shrink to reduce the number of thread structures and running
+ * Call shrink to reduce the number of thread structures and running
* threads if required by the change in group size.
*/
- WT_RET(__thread_group_shrink(session, group, new_max));
+ WT_RET(__thread_group_shrink(session, group, new_max, true));
/*
* Only reallocate the thread array if it is the largest ever, since
@@ -227,9 +229,9 @@ __wt_thread_group_resize(
" from max: %" PRIu32 " -> %" PRIu32,
(void *)group, group->min, new_min, group->max, new_max);
- __wt_writelock(session, group->lock);
+ __wt_writelock(session, &group->lock);
WT_TRET(__thread_group_resize(session, group, new_min, new_max, flags));
- __wt_writeunlock(session, group->lock);
+ __wt_writeunlock(session, &group->lock);
return (ret);
}
@@ -255,17 +257,17 @@ __wt_thread_group_create(
__wt_verbose(session, WT_VERB_THREAD_GROUP,
"Creating thread group: %p", (void *)group);
- WT_RET(__wt_rwlock_alloc(session, &group->lock, "Thread group"));
+ __wt_rwlock_init(session, &group->lock);
WT_ERR(__wt_cond_alloc(
session, "Thread group cond", false, &group->wait_cond));
cond_alloced = true;
- __wt_writelock(session, group->lock);
+ __wt_writelock(session, &group->lock);
group->run_func = run_func;
group->name = name;
WT_TRET(__thread_group_resize(session, group, min, max, flags));
- __wt_writeunlock(session, group->lock);
+ __wt_writeunlock(session, &group->lock);
/* Cleanup on error to avoid leaking resources */
err: if (ret != 0) {
@@ -288,10 +290,10 @@ __wt_thread_group_destroy(WT_SESSION_IMPL *session, WT_THREAD_GROUP *group)
__wt_verbose(session, WT_VERB_THREAD_GROUP,
"Destroying thread group: %p", (void *)group);
- WT_ASSERT(session, __wt_rwlock_islocked(session, group->lock));
+ WT_ASSERT(session, __wt_rwlock_islocked(session, &group->lock));
/* Shut down all threads and free associated resources. */
- WT_TRET(__thread_group_shrink(session, group, 0));
+ WT_TRET(__thread_group_shrink(session, group, 0, true));
__wt_free(session, group->threads);
@@ -322,15 +324,42 @@ __wt_thread_group_start_one(
return (0);
if (wait)
- __wt_writelock(session, group->lock);
- else if (__wt_try_writelock(session, group->lock) != 0)
- return (0);
+ __wt_writelock(session, &group->lock);
+ else
+ WT_RET(__wt_try_writelock(session, &group->lock));
/* Recheck the bounds now that we hold the lock */
if (group->current_threads < group->max)
WT_TRET(__thread_group_grow(
session, group, group->current_threads + 1));
- __wt_writeunlock(session, group->lock);
+ __wt_writeunlock(session, &group->lock);
+
+ return (ret);
+}
+
+/*
+ * __wt_thread_group_stop_one --
+ * Stop one thread if possible.
+ */
+int
+__wt_thread_group_stop_one(
+ WT_SESSION_IMPL *session, WT_THREAD_GROUP *group, bool wait)
+{
+ WT_DECL_RET;
+
+ if (group->current_threads <= group->min)
+ return (0);
+
+ if (wait)
+ __wt_writelock(session, &group->lock);
+ else
+ WT_RET(__wt_try_writelock(session, &group->lock));
+
+ /* Recheck the bounds now that we hold the lock */
+ if (group->current_threads > group->min)
+ WT_TRET(__thread_group_shrink(
+ session, group, group->current_threads - 1, false));
+ __wt_writeunlock(session, &group->lock);
return (ret);
}
diff --git a/src/txn/txn.c b/src/txn/txn.c
index 26a0ed679e2..660d37b17d5 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -126,7 +126,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
n = 0;
/* We're going to scan the table: wait for the lock. */
- __wt_readlock_spin(session, txn_global->scan_rwlock);
+ __wt_readlock_spin(session, &txn_global->scan_rwlock);
current_id = pinned_id = txn_global->current;
prev_oldest_id = txn_global->oldest_id;
@@ -180,7 +180,7 @@ __wt_txn_get_snapshot(WT_SESSION_IMPL *session)
WT_ASSERT(session, prev_oldest_id == txn_global->oldest_id);
txn_state->pinned_id = pinned_id;
-done: __wt_readunlock(session, txn_global->scan_rwlock);
+done: __wt_readunlock(session, &txn_global->scan_rwlock);
__txn_sort_snapshot(session, n, current_id);
}
@@ -293,13 +293,13 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
/* First do a read-only scan. */
if (wait)
- __wt_readlock_spin(session, txn_global->scan_rwlock);
+ __wt_readlock_spin(session, &txn_global->scan_rwlock);
else if ((ret =
- __wt_try_readlock(session, txn_global->scan_rwlock)) != 0)
+ __wt_try_readlock(session, &txn_global->scan_rwlock)) != 0)
return (ret == EBUSY ? 0 : ret);
__txn_oldest_scan(session,
&oldest_id, &last_running, &metadata_pinned, &oldest_session);
- __wt_readunlock(session, txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->scan_rwlock);
/*
* If the state hasn't changed (or hasn't moved far enough for
@@ -314,9 +314,9 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
/* It looks like an update is necessary, wait for exclusive access. */
if (wait)
- __wt_writelock(session, txn_global->scan_rwlock);
+ __wt_writelock(session, &txn_global->scan_rwlock);
else if ((ret =
- __wt_try_writelock(session, txn_global->scan_rwlock)) != 0)
+ __wt_try_writelock(session, &txn_global->scan_rwlock)) != 0)
return (ret == EBUSY ? 0 : ret);
/*
@@ -375,7 +375,7 @@ __wt_txn_update_oldest(WT_SESSION_IMPL *session, uint32_t flags)
#endif
}
-done: __wt_writeunlock(session, txn_global->scan_rwlock);
+done: __wt_writeunlock(session, &txn_global->scan_rwlock);
return (ret);
}
@@ -768,10 +768,8 @@ __wt_txn_global_init(WT_SESSION_IMPL *session, const char *cfg[])
WT_RET(__wt_spin_init(session,
&txn_global->id_lock, "transaction id lock"));
- WT_RET(__wt_rwlock_alloc(session,
- &txn_global->scan_rwlock, "transaction scan lock"));
- WT_RET(__wt_rwlock_alloc(session,
- &txn_global->nsnap_rwlock, "named snapshot lock"));
+ __wt_rwlock_init(session, &txn_global->scan_rwlock);
+ __wt_rwlock_init(session, &txn_global->nsnap_rwlock);
txn_global->nsnap_oldest_id = WT_TXN_NONE;
TAILQ_INIT(&txn_global->nsnaph);
diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c
index 399d9187d82..3b19162fd3d 100644
--- a/src/txn/txn_ckpt.c
+++ b/src/txn/txn_ckpt.c
@@ -679,7 +679,7 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
* This allows ordinary visibility checks to move forward because
* checkpoints often take a long time and only write to the metadata.
*/
- __wt_writelock(session, txn_global->scan_rwlock);
+ __wt_writelock(session, &txn_global->scan_rwlock);
txn_global->checkpoint_txnid = txn->id;
txn_global->checkpoint_pinned = WT_MIN(txn->id, txn->snap_min);
@@ -700,7 +700,7 @@ __txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
*/
txn_state->id = txn_state->pinned_id =
txn_state->metadata_pinned = WT_TXN_NONE;
- __wt_writeunlock(session, txn_global->scan_rwlock);
+ __wt_writeunlock(session, &txn_global->scan_rwlock);
/*
* Unblock updates -- we can figure out that any updates to clean pages
@@ -1159,7 +1159,7 @@ __checkpoint_lock_tree(WT_SESSION_IMPL *session,
* Hold the lock until we're done (blocking hot backups from starting),
* we don't want to race with a future hot backup.
*/
- __wt_readlock(session, conn->hot_backup_lock);
+ __wt_readlock(session, &conn->hot_backup_lock);
hot_backup_locked = true;
if (conn->hot_backup)
WT_CKPT_FOREACH(ckptbase, ckpt) {
@@ -1233,7 +1233,7 @@ __checkpoint_lock_tree(WT_SESSION_IMPL *session,
WT_ASSERT(session,
!is_checkpoint || !F_ISSET(btree, WT_BTREE_SPECIAL_FLAGS));
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
WT_ASSERT(session, btree->ckpt == NULL);
btree->ckpt = ckptbase;
@@ -1241,7 +1241,7 @@ __checkpoint_lock_tree(WT_SESSION_IMPL *session,
return (0);
err: if (hot_backup_locked)
- __wt_readunlock(session, conn->hot_backup_lock);
+ __wt_readunlock(session, &conn->hot_backup_lock);
__wt_meta_ckptlist_free(session, ckptbase);
__wt_free(session, name_alloc);
diff --git a/src/txn/txn_log.c b/src/txn/txn_log.c
index 5f4704b40c4..7ad295f421b 100644
--- a/src/txn/txn_log.c
+++ b/src/txn/txn_log.c
@@ -368,14 +368,16 @@ __wt_txn_checkpoint_log(
/*
* If this full checkpoint completed successfully and there is
- * no hot backup in progress, 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 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 && txn->full_ckpt)
+ if (!S2C(session)->hot_backup &&
+ !F_ISSET(S2C(session), WT_CONN_RECOVERING) &&
+ txn->full_ckpt)
__wt_log_ckpt(session, ckpt_lsn);
/* FALLTHROUGH */
diff --git a/src/txn/txn_nsnap.c b/src/txn/txn_nsnap.c
index 65ec1a6662f..659570dbcd9 100644
--- a/src/txn/txn_nsnap.c
+++ b/src/txn/txn_nsnap.c
@@ -211,9 +211,9 @@ __wt_txn_named_snapshot_begin(WT_SESSION_IMPL *session, const char *cfg[])
if (TAILQ_EMPTY(&txn_global->nsnaph)) {
WT_ASSERT(session, txn_global->nsnap_oldest_id == WT_TXN_NONE &&
!__wt_txn_visible_all(session, nsnap_new->pinned_id));
- __wt_readlock(session, txn_global->scan_rwlock);
+ __wt_readlock(session, &txn_global->scan_rwlock);
txn_global->nsnap_oldest_id = nsnap_new->pinned_id;
- __wt_readunlock(session, txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->scan_rwlock);
}
TAILQ_INSERT_TAIL(&txn_global->nsnaph, nsnap_new, q);
WT_STAT_CONN_INCR(session, txn_snapshots_created);
@@ -297,16 +297,16 @@ __wt_txn_named_snapshot_get(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *nameval)
if (session->ncursors > 0)
WT_RET(__wt_session_copy_values(session));
- __wt_readlock(session, txn_global->nsnap_rwlock);
+ __wt_readlock(session, &txn_global->nsnap_rwlock);
TAILQ_FOREACH(nsnap, &txn_global->nsnaph, q)
if (WT_STRING_MATCH(nsnap->name, nameval->str, nameval->len)) {
/*
* Acquire the scan lock so the oldest ID can't move
* forward without seeing our pinned ID.
*/
- __wt_readlock(session, txn_global->scan_rwlock);
+ __wt_readlock(session, &txn_global->scan_rwlock);
txn_state->pinned_id = nsnap->pinned_id;
- __wt_readunlock(session, txn_global->scan_rwlock);
+ __wt_readunlock(session, &txn_global->scan_rwlock);
WT_ASSERT(session, !__wt_txn_visible_all(
session, txn_state->pinned_id) &&
@@ -327,7 +327,7 @@ __wt_txn_named_snapshot_get(WT_SESSION_IMPL *session, WT_CONFIG_ITEM *nameval)
F_SET(txn, WT_TXN_HAS_SNAPSHOT);
break;
}
- __wt_readunlock(session, txn_global->nsnap_rwlock);
+ __wt_readunlock(session, &txn_global->nsnap_rwlock);
if (nsnap == NULL)
WT_RET_MSG(session, EINVAL,
diff --git a/src/txn/txn_recover.c b/src/txn/txn_recover.c
index a6390dcbd06..2d8a77a69e6 100644
--- a/src/txn/txn_recover.c
+++ b/src/txn/txn_recover.c
@@ -501,7 +501,7 @@ __wt_txn_recover(WT_SESSION_IMPL *session)
* Pass WT_LOGSCAN_RECOVER so that old logs get truncated.
*/
r.metadata_only = false;
- __wt_verbose(session, WT_VERB_RECOVERY,
+ __wt_verbose(session, WT_VERB_RECOVERY | WT_VERB_RECOVERY_PROGRESS,
"Main recovery loop: starting at %" PRIu32 "/%" PRIu32,
r.ckpt_lsn.l.file, r.ckpt_lsn.l.offset);
WT_ERR(__wt_log_needs_recovery(session, &r.ckpt_lsn, &needs_rec));
diff --git a/src/utilities/util.h b/src/utilities/util.h
index 2658d877b63..cf12d7d4aa6 100644
--- a/src/utilities/util.h
+++ b/src/utilities/util.h
@@ -49,6 +49,7 @@ int util_rename(WT_SESSION *, int, char *[]);
int util_salvage(WT_SESSION *, int, char *[]);
int util_stat(WT_SESSION *, int, char *[]);
int util_str2recno(WT_SESSION *, const char *p, uint64_t *recnop);
+int util_truncate(WT_SESSION *, int, char *[]);
int util_upgrade(WT_SESSION *, int, char *[]);
int util_verify(WT_SESSION *, int, char *[]);
int util_write(WT_SESSION *, int, char *[]);
diff --git a/src/utilities/util_dump.c b/src/utilities/util_dump.c
index 7dde13ee837..3f8b4a49dfe 100644
--- a/src/utilities/util_dump.c
+++ b/src/utilities/util_dump.c
@@ -6,10 +6,14 @@
* See the file LICENSE for redistribution information.
*/
+#include <assert.h>
#include "util.h"
#include "util_dump.h"
-static int dump_config(WT_SESSION *, const char *, bool, bool);
+#define STRING_MATCH_CONFIG(s, item) \
+ (strncmp(s, (item).str, (item).len) == 0 && (s)[(item).len] == '\0')
+
+static int dump_config(WT_SESSION *, const char *, WT_CURSOR *, bool, bool);
static int dump_json_begin(WT_SESSION *);
static int dump_json_end(WT_SESSION *);
static int dump_json_separator(WT_SESSION *);
@@ -17,7 +21,8 @@ static int dump_json_table_end(WT_SESSION *);
static int dump_prefix(WT_SESSION *, bool, bool);
static int dump_record(WT_CURSOR *, bool, bool);
static int dump_suffix(WT_SESSION *, bool);
-static int dump_table_config(WT_SESSION *, WT_CURSOR *, const char *, bool);
+static int dump_table_config(
+ WT_SESSION *, WT_CURSOR *, WT_CURSOR *, const char *, bool);
static int dump_table_parts_config(
WT_SESSION *, WT_CURSOR *, const char *, const char *, bool);
static int dup_json_string(const char *, char **);
@@ -32,10 +37,11 @@ util_dump(WT_SESSION *session, int argc, char *argv[])
size_t len;
int ch, i;
bool hex, json, reverse;
- char *checkpoint, *config, *name;
+ char *checkpoint, *config, *name, *p, *simplename;
hex = json = reverse = false;
- checkpoint = config = name = NULL;
+ checkpoint = config = name = simplename = NULL;
+ cursor = NULL;
while ((ch = __wt_getopt(progname, argc, argv, "c:f:jrx")) != EOF)
switch (ch) {
case 'c':
@@ -75,23 +81,21 @@ util_dump(WT_SESSION *session, int argc, char *argv[])
return (usage());
if (json &&
- ((ret = dump_json_begin(session)) != 0 ||
- (ret = dump_prefix(session, hex, json)) != 0))
+ (dump_json_begin(session) != 0 ||
+ dump_prefix(session, hex, json) != 0))
goto err;
for (i = 0; i < argc; i++) {
if (json && i > 0)
- if ((ret = dump_json_separator(session)) != 0)
+ if (dump_json_separator(session) != 0)
goto err;
free(name);
- name = NULL;
+ free(simplename);
+ name = simplename = NULL;
if ((name = util_name(session, argv[i], "table")) == NULL)
goto err;
- if (dump_config(session, name, hex, json) != 0)
- goto err;
-
len =
checkpoint == NULL ? 0 : strlen("checkpoint=") +
strlen(checkpoint) + 1;
@@ -115,12 +119,28 @@ util_dump(WT_SESSION *session, int argc, char *argv[])
goto err;
}
- if ((ret = dump_record(cursor, reverse, json)) != 0)
+ if ((simplename = strdup(name)) == NULL) {
+ (void)util_err(session, errno, NULL);
+ goto err;
+ }
+ if ((p = strchr(simplename, '(')) != NULL)
+ *p = '\0';
+ if (dump_config(session, simplename, cursor, hex, json) != 0)
+ goto err;
+
+ if (dump_record(cursor, reverse, json) != 0)
goto err;
- if (json && (ret = dump_json_table_end(session)) != 0)
+ if (json && dump_json_table_end(session) != 0)
goto err;
+
+ ret = cursor->close(cursor);
+ cursor = NULL;
+ if (ret != 0) {
+ (void)util_err(session, ret, NULL);
+ goto err;
+ }
}
- if (json && ((ret = dump_json_end(session)) != 0))
+ if (json && dump_json_end(session) != 0)
goto err;
if (0) {
@@ -129,7 +149,11 @@ err: ret = 1;
free(config);
free(name);
-
+ free(simplename);
+ if (cursor != NULL && (ret = cursor->close(cursor)) != 0) {
+ (void)util_err(session, ret, NULL);
+ ret = 1;
+ }
return (ret);
}
@@ -138,15 +162,16 @@ err: ret = 1;
* Dump the config for the uri.
*/
static int
-dump_config(WT_SESSION *session, const char *uri, bool hex, bool json)
+dump_config(WT_SESSION *session, const char *uri, WT_CURSOR *cursor, bool hex,
+ bool json)
{
- WT_CURSOR *cursor;
+ WT_CURSOR *mcursor;
WT_DECL_RET;
int tret;
/* Open a metadata cursor. */
if ((ret = session->open_cursor(
- session, "metadata:create", NULL, NULL, &cursor)) != 0) {
+ session, "metadata:create", NULL, NULL, &mcursor)) != 0) {
fprintf(stderr, "%s: %s: session.open_cursor: %s\n", progname,
"metadata:create", session->strerror(session, ret));
return (1);
@@ -156,10 +181,11 @@ dump_config(WT_SESSION *session, const char *uri, bool hex, bool json)
* want to output a header if the user entered the wrong name. This is
* where we find out a table doesn't exist, use a simple error message.
*/
- cursor->set_key(cursor, uri);
- if ((ret = cursor->search(cursor)) == 0) {
+ mcursor->set_key(mcursor, uri);
+ if ((ret = mcursor->search(mcursor)) == 0) {
if ((!json && dump_prefix(session, hex, json) != 0) ||
- dump_table_config(session, cursor, uri, json) != 0 ||
+ dump_table_config(session, mcursor, cursor,
+ uri, json) != 0 ||
dump_suffix(session, json) != 0)
ret = 1;
} else if (ret == WT_NOTFOUND)
@@ -167,8 +193,8 @@ dump_config(WT_SESSION *session, const char *uri, bool hex, bool json)
else
ret = util_err(session, ret, "%s", uri);
- if ((tret = cursor->close(cursor)) != 0) {
- tret = util_cerr(cursor, "close", tret);
+ if ((tret = mcursor->close(mcursor)) != 0) {
+ tret = util_cerr(mcursor, "close", tret);
if (ret == 0)
ret = tret;
}
@@ -225,16 +251,125 @@ dump_json_table_end(WT_SESSION *session)
}
/*
+ * dump_add_config
+ * Add a formatted config string to an output buffer.
+ */
+static int
+dump_add_config(WT_SESSION *session, char **bufp, size_t *leftp,
+ const char *fmt, ...)
+ WT_GCC_FUNC_ATTRIBUTE((format (printf, 4, 5)))
+{
+ int n;
+ va_list ap;
+
+ va_start(ap, fmt);
+ n = vsnprintf(*bufp, *leftp, fmt, ap);
+ va_end(ap);
+ if (n < 0)
+ return (util_err(session, EINVAL, NULL));
+ *bufp += n;
+ *leftp -= (size_t)n;
+ return (0);
+}
+
+/*
+ * dump_projection --
+ * Create a new config containing projection information.
+ */
+static int
+dump_projection(WT_SESSION *session, const char *config, WT_CURSOR *cursor,
+ char **newconfigp)
+{
+ WT_DECL_RET;
+ WT_CONFIG_ITEM key, value;
+ WT_CONFIG_PARSER *parser;
+ WT_EXTENSION_API *wt_api;
+ size_t len, vallen;
+ int nkeys;
+ char *newconfig;
+ const char *keyformat, *p;
+
+ len = strlen(config) + strlen(cursor->value_format) +
+ strlen(cursor->uri) + 20;
+ if ((newconfig = malloc(len)) == NULL)
+ return util_err(session, errno, NULL);
+ *newconfigp = newconfig;
+ wt_api = session->connection->get_extension_api(session->connection);
+ if ((ret = wt_api->config_parser_open(wt_api, session, config,
+ strlen(config), &parser)) != 0)
+ return (util_err(
+ session, ret, "WT_EXTENSION_API.config_parser_open"));
+ keyformat = cursor->key_format;
+ for (nkeys = 0; *keyformat; keyformat++)
+ if (!__wt_isdigit((u_char)*keyformat))
+ nkeys++;
+
+ /*
+ * Copy the configuration, replacing some fields to match the
+ * projection.
+ */
+ while ((ret = parser->next(parser, &key, &value)) == 0) {
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "%.*s=", (int)key.len, key.str));
+ if (STRING_MATCH_CONFIG("value_format", key))
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "%s", cursor->value_format));
+ else if (STRING_MATCH_CONFIG("columns", key)) {
+ /* copy names of keys */
+ p = value.str;
+ vallen = value.len;
+ while (vallen > 0) {
+ if ((*p == ',' || *p == ')') && --nkeys == 0)
+ break;
+ p++;
+ vallen--;
+ }
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "%.*s", (int)(p - value.str), value.str));
+
+ /* copy names of projected values */
+ p = strchr(cursor->uri, '(');
+ assert(p != NULL);
+ assert(p[strlen(p) - 1] == ')');
+ p++;
+ if (*p != ')')
+ WT_RET(dump_add_config(session, &newconfig,
+ &len, "%s", ","));
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "%.*s),", (int)(strlen(p) - 1), p));
+ } else if (value.type == WT_CONFIG_ITEM_STRING &&
+ value.len != 0)
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "\"%.*s\",", (int)value.len, value.str));
+ else
+ WT_RET(dump_add_config(session, &newconfig, &len,
+ "%.*s,", (int)value.len, value.str));
+ }
+ if (ret != WT_NOTFOUND)
+ return (util_err(session, ret, "WT_CONFIG_PARSER.next"));
+
+ assert(len > 0);
+ if ((ret = parser->close(parser)) != 0)
+ return (util_err(
+ session, ret, "WT_CONFIG_PARSER.close"));
+
+ return (0);
+}
+
+/*
* dump_table_config --
* Dump the config for a table.
*/
static int
dump_table_config(
- WT_SESSION *session, WT_CURSOR *cursor, const char *uri, bool json)
+ WT_SESSION *session, WT_CURSOR *mcursor, WT_CURSOR *cursor,
+ const char *uri, bool json)
{
WT_DECL_RET;
+ char *proj_config;
const char *name, *v;
+ proj_config = NULL;
/* Get the table name. */
if ((name = strchr(uri, ':')) == NULL) {
fprintf(stderr, "%s: %s: corrupted uri\n", progname, uri);
@@ -246,20 +381,25 @@ dump_table_config(
* Dump out the config information: first, dump the uri entry itself,
* it overrides all subsequent configurations.
*/
- cursor->set_key(cursor, uri);
- if ((ret = cursor->search(cursor)) != 0)
- return (util_cerr(cursor, "search", ret));
- if ((ret = cursor->get_value(cursor, &v)) != 0)
- return (util_cerr(cursor, "get_value", ret));
-
- WT_RET(print_config(session, uri, v, json, true));
+ mcursor->set_key(mcursor, uri);
+ if ((ret = mcursor->search(mcursor)) != 0)
+ return (util_cerr(mcursor, "search", ret));
+ if ((ret = mcursor->get_value(mcursor, &v)) != 0)
+ return (util_cerr(mcursor, "get_value", ret));
+
+ if (strchr(cursor->uri, '(') != NULL) {
+ WT_ERR(dump_projection(session, v, cursor, &proj_config));
+ v = proj_config;
+ }
+ WT_ERR(print_config(session, uri, v, json, true));
- WT_RET(dump_table_parts_config(
- session, cursor, name, "colgroup:", json));
- WT_RET(dump_table_parts_config(
- session, cursor, name, "index:", json));
+ WT_ERR(dump_table_parts_config(
+ session, mcursor, name, "colgroup:", json));
+ WT_ERR(dump_table_parts_config(
+ session, mcursor, name, "index:", json));
- return (0);
+err: free(proj_config);
+ return (ret);
}
/*
diff --git a/src/utilities/util_main.c b/src/utilities/util_main.c
index 1da56adf137..001a66d6d9e 100644
--- a/src/utilities/util_main.c
+++ b/src/utilities/util_main.c
@@ -175,6 +175,10 @@ main(int argc, char *argv[])
config = "statistics=(all)";
}
break;
+ case 't' :
+ if (strcmp(command, "truncate") == 0)
+ func = util_truncate;
+ break;
case 'u':
if (strcmp(command, "upgrade") == 0)
func = util_upgrade;
@@ -272,6 +276,7 @@ usage(void)
"\t" "rename\t rename an object\n"
"\t" "salvage\t salvage a file\n"
"\t" "stat\t display statistics for an object\n"
+ "\t" "truncate truncate an object, removing all content\n"
"\t" "upgrade\t upgrade an object\n"
"\t" "verify\t verify an object\n"
"\t" "write\t write values to an object\n");
diff --git a/src/utilities/util_truncate.c b/src/utilities/util_truncate.c
new file mode 100644
index 00000000000..9325c0d7e84
--- /dev/null
+++ b/src/utilities/util_truncate.c
@@ -0,0 +1,51 @@
+/*-
+ * Copyright (c) 2014-2016 MongoDB, Inc.
+ * Copyright (c) 2008-2014 WiredTiger, Inc.
+ * All rights reserved.
+ *
+ * See the file LICENSE for redistribution information.
+ */
+
+#include "util.h"
+
+static int usage(void);
+
+int
+util_truncate(WT_SESSION *session, int argc, char *argv[])
+{
+ WT_DECL_RET;
+ int ch;
+ char *name;
+
+ while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF)
+ switch (ch) {
+ case '?':
+ default:
+ return (usage());
+ }
+
+ argc -= __wt_optind;
+ argv += __wt_optind;
+
+ /* The remaining argument is the uri. */
+ if (argc != 1)
+ return (usage());
+ if ((name = util_name(session, *argv, "table")) == NULL)
+ return (1);
+
+ if ((ret = session->truncate(session, name, NULL, NULL, NULL)) != 0)
+ return (util_err(session, ret, "%s: session.truncate", name));
+
+ free(name);
+ return (ret);
+}
+
+static int
+usage(void)
+{
+ (void)fprintf(stderr,
+ "usage: %s %s "
+ "truncate uri\n",
+ progname, usage_prefix);
+ return (1);
+}
diff --git a/test/format/config.c b/test/format/config.c
index cf922b5db04..50430fe073e 100644
--- a/test/format/config.c
+++ b/test/format/config.c
@@ -44,6 +44,7 @@ static void config_map_compression(const char *, u_int *);
static void config_map_encryption(const char *, u_int *);
static void config_map_file_type(const char *, u_int *);
static void config_map_isolation(const char *, u_int *);
+static void config_pct(void);
static void config_reset(void);
/*
@@ -159,31 +160,19 @@ config_setup(void)
config_encryption();
config_isolation();
config_lrt();
+ config_pct();
/*
- * Periodically, set the delete percentage to 0 so salvage gets run,
- * as long as the delete percentage isn't nailed down.
- * Don't do it on the first run, all our smoke tests would hit it.
- */
- if (!g.replay && g.run_cnt % 10 == 9 && !config_is_perm("delete_pct"))
- config_single("delete_pct=0", 0);
-
- /*
- * If this is an LSM run, set the cache size and crank up the insert
- * percentage.
+ * If this is an LSM run, ensure cache size sanity.
+ * Ensure there is at least 1MB of cache per thread.
*/
- if (DATASOURCE("lsm")) {
- if (!config_is_perm("cache"))
+ if (!config_is_perm("cache")) {
+ if (DATASOURCE("lsm"))
g.c_cache = 30 * g.c_chunk_size;
-
- if (!config_is_perm("insert_pct"))
- g.c_insert_pct = mmrand(NULL, 50, 85);
+ if (g.c_cache < g.c_threads)
+ g.c_cache = g.c_threads;
}
- /* Ensure there is at least 1MB of cache per thread. */
- if (!config_is_perm("cache") && g.c_cache < g.c_threads)
- g.c_cache = g.c_threads;
-
/* Give in-memory configuration a final review. */
config_in_memory_check();
@@ -482,6 +471,83 @@ config_lrt(void)
}
/*
+ * config_pct --
+ * Configure operation percentages.
+ */
+static void
+config_pct(void)
+{
+ static struct {
+ const char *name; /* Operation */
+ uint32_t *vp; /* Value store */
+ u_int order; /* Order of assignment */
+ } list[] = {
+#define CONFIG_DELETE_ENTRY 0
+ { "delete_pct", &g.c_delete_pct, 0 },
+ { "insert_pct", &g.c_insert_pct, 0 },
+ { "read_pct", &g.c_read_pct, 0 },
+ { "write_pct", &g.c_write_pct, 0 },
+ };
+ u_int i, max_order, max_slot, n, pct;
+
+ /*
+ * Walk the list of operations, checking for an illegal configuration
+ * and creating a random order in the list.
+ */
+ pct = 0;
+ for (i = 0; i < WT_ELEMENTS(list); ++i)
+ if (config_is_perm(list[i].name))
+ pct += *list[i].vp;
+ else
+ list[i].order = mmrand(NULL, 1, 1000);
+ if (pct > 100)
+ testutil_die(EINVAL,
+ "operation percentages total to more than 100%%");
+
+ /*
+ * If the delete percentage isn't nailed down, periodically set it to
+ * 0 so salvage gets run. Don't do it on the first run, all our smoke
+ * tests would hit it.
+ */
+ if (!config_is_perm("delete_pct") && !g.replay && g.run_cnt % 10 == 9) {
+ list[CONFIG_DELETE_ENTRY].order = 0;
+ *list[CONFIG_DELETE_ENTRY].vp = 0;
+ }
+
+ /*
+ * Walk the list, allocating random numbers of operations in a random
+ * order.
+ *
+ * If the "order" field is non-zero, we need to create a value for this
+ * operation. Find the largest order field in the array; if one non-zero
+ * order field is found, it's the last entry and gets the remainder of
+ * the operations.
+ */
+ for (pct = 100 - pct;;) {
+ for (i = n =
+ max_order = max_slot = 0; i < WT_ELEMENTS(list); ++i) {
+ if (list[i].order != 0)
+ ++n;
+ if (list[i].order > max_order) {
+ max_order = list[i].order;
+ max_slot = i;
+ }
+ }
+ if (n == 0)
+ break;
+ if (n == 1) {
+ *list[max_slot].vp = pct;
+ break;
+ }
+ *list[max_slot].vp = mmrand(NULL, 0, pct);
+ list[max_slot].order = 0;
+ pct -= *list[max_slot].vp;
+ }
+ testutil_assert(g.c_delete_pct +
+ g.c_insert_pct + g.c_read_pct + g.c_write_pct == 100);
+}
+
+/*
* config_error --
* Display configuration information on error.
*/
diff --git a/test/format/config.h b/test/format/config.h
index e4f7af2e1b2..e3e1e73a786 100644
--- a/test/format/config.h
+++ b/test/format/config.h
@@ -131,7 +131,7 @@ static CONFIG c[] = {
{ "delete_pct",
"percent operations that are deletes",
- 0x0, 0, 45, 90, &g.c_delete_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_delete_pct, NULL },
{ "dictionary",
"if values are dictionary compressed", /* 20% */
@@ -171,7 +171,7 @@ static CONFIG c[] = {
{ "insert_pct",
"percent operations that are inserts",
- 0x0, 0, 45, 90, &g.c_insert_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_insert_pct, NULL },
{ "internal_key_truncation",
"if internal keys are truncated", /* 95% */
@@ -254,6 +254,14 @@ static CONFIG c[] = {
"quiet run (same as -q)",
C_IGNORE|C_BOOL, 0, 0, 0, &g.c_quiet, NULL },
+ { "read_pct",
+ "percent operations that are reads",
+ C_IGNORE, 0, 0, 100, &g.c_read_pct, NULL },
+
+ { "rebalance",
+ "rebalance testing", /* 100% */
+ C_BOOL, 100, 1, 0, &g.c_rebalance, NULL },
+
{ "repeat_data_pct",
"percent duplicate values in row- or var-length column-stores",
0x0, 0, 90, 90, &g.c_repeat_data_pct, NULL },
@@ -270,10 +278,6 @@ static CONFIG c[] = {
"the number of runs",
C_IGNORE, 0, UINT_MAX, UINT_MAX, &g.c_runs, NULL },
- { "rebalance",
- "rebalance testing", /* 100% */
- C_BOOL, 100, 1, 0, &g.c_rebalance, NULL },
-
{ "salvage",
"salvage testing", /* 100% */
C_BOOL, 100, 1, 0, &g.c_salvage, NULL },
@@ -320,7 +324,7 @@ static CONFIG c[] = {
{ "write_pct",
"percent operations that are writes",
- 0x0, 0, 90, 90, &g.c_write_pct, NULL },
+ C_IGNORE, 0, 0, 100, &g.c_write_pct, NULL },
{ NULL, NULL, 0x0, 0, 0, 0, NULL, NULL }
};
diff --git a/test/format/format.h b/test/format/format.h
index c1f4875dbb2..6bb44410acc 100644
--- a/test/format/format.h
+++ b/test/format/format.h
@@ -192,6 +192,7 @@ typedef struct {
uint32_t c_reverse;
uint32_t c_rows;
uint32_t c_runs;
+ uint32_t c_read_pct;
uint32_t c_rebalance;
uint32_t c_salvage;
uint32_t c_split_pct;
diff --git a/test/recovery/random-abort.c b/test/recovery/random-abort.c
index c407361c7eb..660ef0cca67 100644
--- a/test/recovery/random-abort.c
+++ b/test/recovery/random-abort.c
@@ -31,9 +31,13 @@
#include <sys/wait.h>
#include <signal.h>
-static char home[512]; /* Program working dir */
+static char home[1024]; /* Program working dir */
static const char *progname; /* Program name */
+/*
+ * These two names for the URI and file system must be maintained in tandem.
+ */
static const char * const uri = "table:main";
+static const char * const fs_main = "main.wt";
static bool inmem;
#define MAX_TH 12
@@ -211,6 +215,7 @@ extern char *__wt_optarg;
int
main(int argc, char *argv[])
{
+ struct stat sb;
FILE *fp;
WT_CONNECTION *conn;
WT_CURSOR *cursor;
@@ -222,7 +227,7 @@ main(int argc, char *argv[])
pid_t pid;
bool fatal, rand_th, rand_time, verify_only;
const char *working_dir;
- char fname[64], kname[64];
+ char fname[64], kname[64], statname[1024];
if ((progname = strrchr(argv[0], DIR_DELIM)) == NULL)
progname = argv[0];
@@ -263,7 +268,7 @@ main(int argc, char *argv[])
if (argc != 0)
usage();
- testutil_work_dir_from_path(home, 512, working_dir);
+ testutil_work_dir_from_path(home, sizeof(home), working_dir);
/*
* If the user wants to verify they need to tell us how many threads
* there were so we can find the old record files.
@@ -305,8 +310,15 @@ main(int argc, char *argv[])
/* parent */
/*
* Sleep for the configured amount of time before killing
- * the child.
+ * the child. Start the timeout from the time we notice that
+ * the table has been created. That allows the test to run
+ * correctly on really slow machines. Verify the process ID
+ * still exists in case the child aborts for some reason we
+ * don't stay in this loop forever.
*/
+ snprintf(statname, sizeof(statname), "%s/%s", home, fs_main);
+ while (stat(statname, &sb) != 0 && kill(pid, 0) == 0)
+ sleep(1);
sleep(timeout);
/*
@@ -340,11 +352,8 @@ main(int argc, char *argv[])
for (i = 0; i < nth; ++i) {
middle = 0;
snprintf(fname, sizeof(fname), RECORDS_FILE, i);
- if ((fp = fopen(fname, "r")) == NULL) {
- fprintf(stderr,
- "Failed to open %s. i %" PRIu32 "\n", fname, i);
- testutil_die(errno, "fopen");
- }
+ if ((fp = fopen(fname, "r")) == NULL)
+ testutil_die(errno, "fopen: %s", fname);
/*
* For every key in the saved file, verify that the key exists
diff --git a/test/recovery/truncated-log.c b/test/recovery/truncated-log.c
index c265263d44c..6a142b8e710 100644
--- a/test/recovery/truncated-log.c
+++ b/test/recovery/truncated-log.c
@@ -35,7 +35,7 @@
#define snprintf _snprintf
#endif
-static char home[512]; /* Program working dir */
+static char home[1024]; /* Program working dir */
static const char *progname; /* Program name */
static const char * const uri = "table:main";
@@ -290,7 +290,7 @@ main(int argc, char *argv[])
if (argc != 0)
usage();
- testutil_work_dir_from_path(home, 512, working_dir);
+ testutil_work_dir_from_path(home, sizeof(home), working_dir);
testutil_make_work_dir(home);
/*
diff --git a/test/suite/run.py b/test/suite/run.py
index ba6d9f78503..97c58bfdccf 100644
--- a/test/suite/run.py
+++ b/test/suite/run.py
@@ -324,7 +324,8 @@ if __name__ == '__main__':
# All global variables should be set before any test classes are loaded.
# That way, verbose printing can be done at the class definition level.
wttest.WiredTigerTestCase.globalSetup(preserve, timestamp, gdbSub,
- verbose, dirarg, longtest)
+ verbose, wt_builddir, dirarg,
+ longtest)
# Without any tests listed as arguments, do discovery
if len(testargs) == 0:
diff --git a/test/suite/test_async01.py b/test/suite/test_async01.py
index cbb3dad8de6..158c16a9381 100644
--- a/test/suite/test_async01.py
+++ b/test/suite/test_async01.py
@@ -132,7 +132,7 @@ class test_async01(wttest.WiredTigerTestCase, suite_subprocess):
])
# Enable async for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'async=(enabled=true,ops_max=%s,' % self.async_ops + \
'threads=%s)' % self.async_threads
diff --git a/test/suite/test_async02.py b/test/suite/test_async02.py
index 50652da6dfd..28435fe85b2 100644
--- a/test/suite/test_async02.py
+++ b/test/suite/test_async02.py
@@ -129,7 +129,7 @@ class test_async02(wttest.WiredTigerTestCase, suite_subprocess):
])
# Enable async for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'async=(enabled=true,ops_max=%s,' % self.async_ops + \
'threads=%s)' % self.async_threads
diff --git a/test/suite/test_backup03.py b/test/suite/test_backup03.py
index 73d05f0b0a1..c1ed3cc9e1a 100644
--- a/test/suite/test_backup03.py
+++ b/test/suite/test_backup03.py
@@ -74,7 +74,7 @@ class test_backup_target(wttest.WiredTigerTestCase, suite_subprocess):
('backup_9', dict(big=3,list=[])), # Backup everything
]
- scenarios = make_scenarios(list)
+ scenarios = make_scenarios(list, prune=3, prunelong=1000)
# Create a large cache, otherwise this test runs quite slowly.
conn_config = 'cache_size=1G'
diff --git a/test/suite/test_backup04.py b/test/suite/test_backup04.py
index 919649fed57..be52a5e1e97 100644
--- a/test/suite/test_backup04.py
+++ b/test/suite/test_backup04.py
@@ -60,7 +60,7 @@ class test_backup_target(wttest.WiredTigerTestCase, suite_subprocess):
])
# Create a large cache, otherwise this test runs quite slowly.
- def conn_config(self, dir):
+ def conn_config(self):
return 'cache_size=1G,log=(archive=false,enabled,file_max=%s)' % \
self.logmax
diff --git a/test/suite/test_bug011.py b/test/suite/test_bug011.py
index 969aaeb5b39..5e0721b93f1 100644
--- a/test/suite/test_bug011.py
+++ b/test/suite/test_bug011.py
@@ -43,7 +43,7 @@ class test_bug011(wttest.WiredTigerTestCase):
nrows = 10000
nops = 10000
# Add connection configuration for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'cache_size=1GB'
@wttest.longtest("Eviction copes with lots of files")
diff --git a/test/suite/test_collator.py b/test/suite/test_collator.py
index 3fae4ff47cb..7ce135c8976 100644
--- a/test/suite/test_collator.py
+++ b/test/suite/test_collator.py
@@ -48,34 +48,10 @@ class test_collator(wttest.WiredTigerTestCase):
nentries = 100
nindices = 4
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, libname) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + libname + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- extarg = self.extensionArg([('extractors', 'csv', 'csv_extractor'),
- ('collators', 'revint', 'revint_collator')])
- connarg = 'create,error_prefix="{0}: ",{1}'.format(
- self.shortid(), extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('extractors', 'csv')
+ extlist.extension('collators', 'revint')
def create_indices(self):
# Create self.nindices index files, each with a column from the CSV
diff --git a/test/suite/test_compress01.py b/test/suite/test_compress01.py
index 606f7b63235..ef1064d294e 100644
--- a/test/suite/test_compress01.py
+++ b/test/suite/test_compress01.py
@@ -51,22 +51,10 @@ class test_compress01(wttest.WiredTigerTestCase):
nrecords = 10000
bigvalue = "abcdefghij" * 1000
- # Load the compression extension, compression is enabled elsewhere.
- def conn_config(self, dir):
- return self.extensionArg(self.compress)
-
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, name):
- if name == None:
- return ''
-
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext/compressors')
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('compression extension "' + extfile + '" not built')
- return ',extensions=["' + extfile + '"]'
+ # Load the compression extension, skip the test if missing
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('compressors', self.compress)
# Create a table, add keys with both big and small values, then verify them.
def test_compress(self):
diff --git a/test/suite/test_config03.py b/test/suite/test_config03.py
index 6699f7d2650..89038d71319 100644
--- a/test/suite/test_config03.py
+++ b/test/suite/test_config03.py
@@ -71,7 +71,7 @@ class test_config03(test_base03.test_base03):
cache_size_scenarios, create_scenarios, error_prefix_scenarios,
eviction_target_scenarios, eviction_trigger_scenarios,
multiprocess_scenarios, session_max_scenarios,
- transactional_scenarios, verbose_scenarios, prune=1000)
+ transactional_scenarios, verbose_scenarios, prune=100, prunelong=1000)
#wttest.WiredTigerTestCase.printVerbose(2, 'test_config03: running ' + \
# str(len(scenarios)) + ' of ' + \
diff --git a/test/suite/test_cursor07.py b/test/suite/test_cursor07.py
index d6078183fc1..19db718fd11 100644
--- a/test/suite/test_cursor07.py
+++ b/test/suite/test_cursor07.py
@@ -49,7 +49,7 @@ class test_cursor07(wttest.WiredTigerTestCase, suite_subprocess):
('reopen', dict(reopen=True))
])
# Enable logging for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
'transaction_sync="(method=dsync,enabled)"'
diff --git a/test/suite/test_cursor08.py b/test/suite/test_cursor08.py
index 3f8f50defa7..cc76f528aa9 100644
--- a/test/suite/test_cursor08.py
+++ b/test/suite/test_cursor08.py
@@ -54,24 +54,14 @@ class test_cursor08(wttest.WiredTigerTestCase, suite_subprocess):
]
scenarios = make_scenarios(reopens, compress)
# Load the compression extension, and enable it for logging.
- def conn_config(self, dir):
+ def conn_config(self):
return 'log=(archive=false,enabled,file_max=%s,' % self.logmax + \
'compressor=%s),' % self.compress + \
- 'transaction_sync="(method=dsync,enabled)",' + \
- self.extensionArg(self.compress)
+ 'transaction_sync="(method=dsync,enabled)"'
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, name):
- if name == None or name == 'none':
- return ''
-
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext/compressors')
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('compression extension "' + extfile + '" not built')
- return ',extensions=["' + extfile + '"]'
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('compressors', self.compress)
def test_log_cursor(self):
# print "Creating %s with config '%s'" % (self.uri, self.create_params)
diff --git a/test/suite/test_dump.py b/test/suite/test_dump.py
index f6a83c32489..3127c7aef00 100644
--- a/test/suite/test_dump.py
+++ b/test/suite/test_dump.py
@@ -32,7 +32,7 @@ import wiredtiger, wttest
from suite_subprocess import suite_subprocess
from wtscenario import make_scenarios
from wtdataset import SimpleDataSet, SimpleIndexDataSet, SimpleLSMDataSet, \
- ComplexDataSet, ComplexLSMDataSet
+ ComplexDataSet, ComplexLSMDataSet, ProjectionDataSet, ProjectionIndexDataSet
# test_dump.py
# Utilities: wt dump
@@ -62,6 +62,10 @@ class test_dump(wttest.WiredTigerTestCase, suite_subprocess):
('table-simple-lsm', dict(uri='table:', dataset=SimpleLSMDataSet)),
('table-complex', dict(uri='table:', dataset=ComplexDataSet)),
('table-complex-lsm', dict(uri='table:', dataset=ComplexLSMDataSet)),
+ ('table-simple-proj', dict(uri='table:',
+ dataset=ProjectionDataSet, projection=True)),
+ ('table-index-proj', dict(uri='table:',
+ dataset=ProjectionIndexDataSet, projection=True)),
]
scenarios = make_scenarios(types, keyfmt, dumpfmt)
@@ -158,5 +162,53 @@ class test_dump(wttest.WiredTigerTestCase, suite_subprocess):
pop = self.dataset(self, uri2, self.nentries, key_format=self.keyfmt)
pop.check()
+# test_dump_projection
+# Utilities: wt dump
+# Test the dump utility with projections
+class test_dump_projection(wttest.WiredTigerTestCase, suite_subprocess):
+ dir = 'dump.dir' # Backup directory name
+
+ name = 'test_dump'
+ nentries = 2500
+ uri = 'table:'
+
+ # Dump, re-load and do a content comparison.
+ def test_dump(self):
+
+ # Create the object.
+ uri = self.uri + self.name
+ pop = ProjectionDataSet(self, uri, self.nentries, key_format='S')
+ pop.populate()
+
+ # Check some cases with invalid projections.
+ self.runWt(['dump', '-x', uri + '('], \
+ outfilename='bad1.out', errfilename='err1.out', failure=True)
+ self.check_non_empty_file('err1.out')
+ self.runWt(['dump', '-x', uri + '(xx)'], \
+ outfilename='bad2.out', errfilename='err2.out', failure=True)
+ self.check_non_empty_file('err2.out')
+ self.runWt(['dump', '-x', uri + pop.projection[:-1]], \
+ outfilename='bad3.out', errfilename='err3.out', failure=True)
+ self.check_non_empty_file('err3.out')
+
+ # Dump the object with a valid projection.
+ self.runWt(['dump', '-x', uri + pop.projection], outfilename='dump.out')
+
+ # Re-load the object in a new home.
+ os.mkdir(self.dir)
+ self.runWt(['-h', self.dir, 'load', '-f', 'dump.out'])
+
+ # Check the database contents.
+ self.runWt(['list'], outfilename='list.out')
+ self.runWt(['-h', self.dir, 'list'], outfilename='list.out.new')
+ s1 = set(open('list.out').read().split())
+ s2 = set(open('list.out.new').read().split())
+ self.assertEqual(not s1.symmetric_difference(s2), True)
+
+ # Check the object's contents.
+ self.reopen_conn(self.dir)
+ pop_reload = ProjectionDataSet(self, uri, self.nentries, key_format='S')
+ pop_reload.check()
+
if __name__ == '__main__':
wttest.run()
diff --git a/test/suite/test_encrypt01.py b/test/suite/test_encrypt01.py
index 746c9d13e96..317bed93246 100644
--- a/test/suite/test_encrypt01.py
+++ b/test/suite/test_encrypt01.py
@@ -66,41 +66,20 @@ class test_encrypt01(wttest.WiredTigerTestCase):
nrecords = 5000
bigvalue = "abcdefghij" * 1001 # len(bigvalue) = 10010
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.sys_encrypt)
+ extlist.extension('encryptors', self.file_encrypt)
+ extlist.extension('compressors', self.block_compress)
+ extlist.extension('compressors', self.log_compress)
+
+ def conn_config(self):
encarg = 'encryption=(name={0}{1}),'.format(
self.sys_encrypt, self.sys_encrypt_args)
comparg = ''
if self.log_compress != None:
comparg='log=(compressor={0}),'.format(self.log_compress)
- extarg = self.extensionArg([('encryptors', self.sys_encrypt),
- ('encryptors', self.file_encrypt),
- ('compressors', self.block_compress),
- ('compressors', self.log_compress)])
- conn = self.wiredtiger_open(dir,
- 'create,error_prefix="{0}: ",{1}{2}{3}'.format(
- self.shortid(), encarg, comparg, extarg))
- self.pr(`conn`)
- return conn
-
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
+ return encarg + comparg
# Create a table, add keys with both big and small values, then verify them.
def test_encrypt(self):
diff --git a/test/suite/test_encrypt02.py b/test/suite/test_encrypt02.py
index 648686274c4..d950be067e2 100644
--- a/test/suite/test_encrypt02.py
+++ b/test/suite/test_encrypt02.py
@@ -39,51 +39,27 @@ from wtscenario import make_scenarios
class test_encrypt02(wttest.WiredTigerTestCase, suite_subprocess):
uri = 'file:test_encrypt02'
encrypt_type = [
- ('noarg', dict( encrypt='rotn', encrypt_args='name=rotn',
- secret_arg=None)),
- ('keyid', dict( encrypt='rotn', encrypt_args='name=rotn,keyid=11',
- secret_arg=None)),
- ('pass', dict( encrypt='rotn', encrypt_args='name=rotn',
- secret_arg='ABC')),
- ('keyid-pass', dict( encrypt='rotn', encrypt_args='name=rotn,keyid=11',
- secret_arg='ABC')),
+ ('noarg', dict( encrypt_args='name=rotn', secret_arg=None)),
+ ('keyid', dict( encrypt_args='name=rotn,keyid=11', secret_arg=None)),
+ ('pass', dict( encrypt_args='name=rotn', secret_arg='ABC')),
+ ('keyid-pass', dict(
+ encrypt_args='name=rotn,keyid=11', secret_arg='ABC')),
]
scenarios = make_scenarios(encrypt_type)
+ def conn_extensions(self, extlist):
+ # Load the compression extension, skip the test if missing
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', 'rotn')
+
nrecords = 5000
bigvalue = "abcdefghij" * 1001 # len(bigvalue) = 10010
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
+ def conn_config(self):
secretarg = ''
if self.secret_arg != None:
secretarg = ',secretkey=' + self.secret_arg
- encarg = 'encryption=({0}{1})'.format(self.encrypt_args, secretarg)
- extarg = self.extensionArg([('encryptors', self.encrypt)])
- connarg = 'create,error_prefix="{0}: ",{1},{2}'.format(
- self.shortid(), encarg, extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ return 'encryption=({0}{1})'.format(self.encrypt_args, secretarg)
# Create a table, add keys with both big and small values, then verify them.
def test_pass(self):
diff --git a/test/suite/test_encrypt03.py b/test/suite/test_encrypt03.py
index cf459190637..302572bd044 100644
--- a/test/suite/test_encrypt03.py
+++ b/test/suite/test_encrypt03.py
@@ -50,37 +50,14 @@ class test_encrypt03(wttest.WiredTigerTestCase):
]
scenarios = make_scenarios(types, encrypt)
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- encarg = 'encryption=(name={0}{1}),'.format(
- self.sys_encrypt, self.sys_encrypt_args)
- extarg = self.extensionArg([('encryptors', self.sys_encrypt),
- ('encryptors', self.file_encrypt)])
- self.pr('encarg = ' + encarg + ' extarg = ' + extarg)
- conn = self.wiredtiger_open(dir,
- 'create,error_prefix="{0}: ",{1}{2}'.format(
- self.shortid(), encarg, extarg))
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.sys_encrypt)
+ extlist.extension('encryptors', self.file_encrypt)
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
+ def conn_config(self):
+ return 'encryption=(name={0}{1}),'.format(
+ self.sys_encrypt, self.sys_encrypt_args)
# Create a table with encryption values that are in error.
def test_encrypt(self):
diff --git a/test/suite/test_encrypt04.py b/test/suite/test_encrypt04.py
index a244cf97961..17777fc9564 100644
--- a/test/suite/test_encrypt04.py
+++ b/test/suite/test_encrypt04.py
@@ -77,9 +77,16 @@ class test_encrypt04(wttest.WiredTigerTestCase, suite_subprocess):
wttest.WiredTigerTestCase.__init__(self, *args, **kwargs)
self.part = 1
+ def conn_extensions(self, extlist):
+ extarg = None
+ if self.expect_forceerror:
+ extarg='(config=\"rotn_force_error=true\")'
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.name, extarg)
+
# Override WiredTigerTestCase, we have extensions.
def setUpConnectionOpen(self, dir):
- forceerror = None
+ self.expect_forceerror = False
if self.part == 1:
self.name = self.name1
self.keyid = self.keyid1
@@ -93,16 +100,15 @@ class test_encrypt04(wttest.WiredTigerTestCase, suite_subprocess):
self.fileinclear = self.fileinclear2 if \
hasattr(self, 'fileinclear2') else False
if hasattr(self, 'forceerror1') and hasattr(self, 'forceerror2'):
- forceerror = "rotn_force_error=true"
- self.expect_forceerror = forceerror != None
+ self.expect_forceerror = True
self.got_forceerror = False
encarg = 'encryption=(name={0},keyid={1},secretkey={2}),'.format(
self.name, self.keyid, self.secretkey)
- # If forceerror is set for this test, add a config arg to
- # the extension string. That signals rotn to return a (-1000)
- # error code, which we'll detect here.
- extarg = self.extensionArg([('encryptors', self.name, forceerror)])
+ # If forceerror is set for this test, conn_extensions adds a
+ # config arg to the extension string. That signals rotn to
+ # return a (-1000) error code, which we'll detect here.
+ extarg = self.extensionsConfig()
self.pr('encarg = ' + encarg + ' extarg = ' + extarg)
completed = False
try:
@@ -135,29 +141,6 @@ class test_encrypt04(wttest.WiredTigerTestCase, suite_subprocess):
self.assertEqual(cursor.search(), 0)
self.assertEquals(cursor.get_value(), val)
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, extarg) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- extfile = '"' + extfile + '"'
- if not extfile in extfiles:
- s = extfile
- if extarg != None:
- s += "=(config=\"" + extarg + "\")"
- extfiles.append(s)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=[' + ','.join(extfiles) + ']'
-
# Evaluate expression, which either must succeed (if expect_okay)
# or must fail (if !expect_okay).
def check_okay(self, expect_okay, expr):
diff --git a/test/suite/test_encrypt05.py b/test/suite/test_encrypt05.py
index 19a3522b3d5..d8862321821 100644
--- a/test/suite/test_encrypt05.py
+++ b/test/suite/test_encrypt05.py
@@ -49,41 +49,20 @@ class test_encrypt05(wttest.WiredTigerTestCase):
nrecords = 500
bigvalue = 'a' * 500 # we use values that will definitely give compression
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.sys_encrypt)
+ extlist.extension('encryptors', self.file_encrypt)
+ extlist.extension('compressors', self.block_compress)
+ extlist.extension('compressors', self.log_compress)
+
+ def conn_config(self):
encarg = 'encryption=(name={0}{1}),'.format(
self.sys_encrypt, self.sys_encrypt_args)
comparg = ''
if self.log_compress != None:
comparg='log=(compressor={0}),'.format(self.log_compress)
- extarg = self.extensionArg([('encryptors', self.sys_encrypt),
- ('encryptors', self.file_encrypt),
- ('compressors', self.block_compress),
- ('compressors', self.log_compress)])
- conn = self.wiredtiger_open(dir,
- 'create,error_prefix="{0}: ",{1}{2}{3}'.format(
- self.shortid(), encarg, comparg, extarg))
- self.pr(`conn`)
- return conn
-
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
+ return encarg + comparg
def getvalue(self, r, n):
if n < len(self.bigvalue):
diff --git a/test/suite/test_encrypt06.py b/test/suite/test_encrypt06.py
index 893c4ba3095..72718e53b2b 100644
--- a/test/suite/test_encrypt06.py
+++ b/test/suite/test_encrypt06.py
@@ -89,38 +89,15 @@ class test_encrypt06(wttest.WiredTigerTestCase):
scenarios = make_scenarios(encrypt, storagetype)
nrecords = 1000
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- encarg = 'encryption=(name={0}{1}),'.format(
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.sys_encrypt)
+ extlist.extension('encryptors', self.file0_encrypt)
+ extlist.extension('encryptors', self.file1_encrypt)
+
+ def conn_config(self):
+ return 'encryption=(name={0}{1}),'.format(
self.sys_encrypt, self.sys_encrypt_args)
- comparg = ''
- extarg = self.extensionArg([('encryptors', self.sys_encrypt),
- ('encryptors', self.file0_encrypt),
- ('encryptors', self.file1_encrypt)])
- self.open_params = 'create,error_prefix="{0}: ",{1}{2}{3}'.format(
- self.shortid(), encarg, comparg, extarg)
- conn = self.wiredtiger_open(dir, self.open_params)
- self.pr(`conn`)
- return conn
-
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
def encrypt_file_params(self, name, args):
if name == None:
diff --git a/test/suite/test_encrypt07.py b/test/suite/test_encrypt07.py
index 97ab1987d4f..81c9f1a49ea 100644
--- a/test/suite/test_encrypt07.py
+++ b/test/suite/test_encrypt07.py
@@ -44,35 +44,14 @@ class test_encrypt07(test_salvage.test_salvage):
nrecords = 5000
bigvalue = "abcdefghij" * 1007 # len(bigvalue) = 10070
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- encarg = 'encryption=(name={0}{1}),'.format(
- self.sys_encrypt, self.sys_encrypt_args)
- extarg = self.extensionArg([('encryptors', self.sys_encrypt)])
- conn = self.wiredtiger_open(dir,
- 'create,error_prefix="{0}: ",{1}{2}'.format(
- self.shortid(), encarg, extarg))
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ # Load the compression extension, skip the test if missing
+ extlist.skip_if_missing = True
+ extlist.extension('encryptors', self.sys_encrypt)
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
+ def conn_config(self):
+ return 'encryption=(name={0}{1}),'.format(
+ self.sys_encrypt, self.sys_encrypt_args)
def rot13(self, s):
return codecs.encode(s, 'rot_13')
diff --git a/test/suite/test_intpack.py b/test/suite/test_intpack.py
index b0cece09494..ae391e68fca 100644
--- a/test/suite/test_intpack.py
+++ b/test/suite/test_intpack.py
@@ -126,8 +126,8 @@ class PackTester:
class test_intpack(wttest.WiredTigerTestCase):
name = 'test_intpack'
- # We have to be a bit verbose here with naming, as there can be problems with
- # case insensitive test names:w
+ # We have to be a bit verbose here with naming, scenario names are
+ # case insensitive and must be unique.
scenarios = make_scenarios([
('int8_t_b', dict(formatcode='b', low=-128, high=127, nbits=8)),
diff --git a/test/suite/test_join01.py b/test/suite/test_join01.py
index 2c4328dc7d3..bdd86a06d4f 100644
--- a/test/suite/test_join01.py
+++ b/test/suite/test_join01.py
@@ -69,7 +69,7 @@ class test_join01(wttest.WiredTigerTestCase):
]
scenarios = make_scenarios(type_scen, bloom0_scen, bloom1_scen,
projection_scen, nested_scen, stats_scen,
- order_scen)
+ order_scen, prune=50, prunelong=1000)
# We need statistics for these tests.
conn_config = 'statistics=(all)'
diff --git a/test/suite/test_join03.py b/test/suite/test_join03.py
index edab7146a6b..dd8111f6ead 100644
--- a/test/suite/test_join03.py
+++ b/test/suite/test_join03.py
@@ -36,33 +36,9 @@ class test_join03(wttest.WiredTigerTestCase):
table_name1 = 'test_join03'
nentries = 100
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, libname) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + libname + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- extarg = self.extensionArg([('extractors', 'csv', 'csv_extractor')])
- connarg = 'create,error_prefix="{0}: ",{1}'.format(
- self.shortid(), extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('extractors', 'csv')
def gen_key(self, i):
return [ i + 1 ]
diff --git a/test/suite/test_join04.py b/test/suite/test_join04.py
index a71418d9f05..e65b8b53333 100644
--- a/test/suite/test_join04.py
+++ b/test/suite/test_join04.py
@@ -36,33 +36,9 @@ class test_join04(wttest.WiredTigerTestCase):
table_name1 = 'test_join04'
nentries = 100
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, libname) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + libname + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- extarg = self.extensionArg([('extractors', 'csv', 'csv_extractor')])
- connarg = 'create,error_prefix="{0}: ",{1}'.format(
- self.shortid(), extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('extractors', 'csv')
# JIRA WT-2308:
# Test extractors with equality joins
diff --git a/test/suite/test_join07.py b/test/suite/test_join07.py
index 2a32e678d72..8fae3539246 100644
--- a/test/suite/test_join07.py
+++ b/test/suite/test_join07.py
@@ -200,33 +200,9 @@ class test_join07(wttest.WiredTigerTestCase):
scenarios = make_scenarios(extractscen)
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, libname) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + libname + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- extarg = self.extensionArg([('extractors', 'csv', 'csv_extractor')])
- connarg = 'create,error_prefix="{0}: ",{1}'.format(
- self.shortid(), extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('extractors', 'csv')
def expect(self, token, expected):
if token == None or token.kind not in expected:
diff --git a/test/suite/test_jsondump02.py b/test/suite/test_jsondump02.py
index 8482851fb94..60863c4aa97 100644
--- a/test/suite/test_jsondump02.py
+++ b/test/suite/test_jsondump02.py
@@ -234,6 +234,24 @@ class test_jsondump02(wttest.WiredTigerTestCase, suite_subprocess):
('"ikey" : 4,\n"Skey" : "key4"',
'"S1" : "val16",\n"i2" : 16,\n"S3" : "val64",\n"i4" : 64'))
self.check_json(self.table_uri4, table4_json)
+ # This projection has 3 value fields reversed with a key at the end.
+ table4_json_projection = (
+ ('"ikey" : 1,\n"Skey" : "key1"',
+ '"i4" : 1,\n"S3" : "val1",\n"i2" : 1,\n"ikey" : 1'),
+ ('"ikey" : 2,\n"Skey" : "key2"',
+ '"i4" : 8,\n"S3" : "val8",\n"i2" : 4,\n"ikey" : 2'),
+ ('"ikey" : 3,\n"Skey" : "key3"',
+ '"i4" : 27,\n"S3" : "val27",\n"i2" : 9,\n"ikey" : 3'),
+ ('"ikey" : 4,\n"Skey" : "key4"',
+ '"i4" : 64,\n"S3" : "val64",\n"i2" : 16,\n"ikey" : 4'))
+ # bad projection URI
+ self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
+ lambda: self.check_json(self.table_uri4 + '(i4,S3,i2,ikey',
+ table4_json_projection),
+ '/Unbalanced brackets/')
+ # This projection should work.
+ self.check_json(self.table_uri4 + '(i4,S3,i2,ikey)',
+ table4_json_projection)
# The dump config currently is not supported for the index type.
self.check_json(uri4index1, (
('"Skey" : "key1"',
diff --git a/test/suite/test_lsm01.py b/test/suite/test_lsm01.py
index b44df4bae14..f705b09b0a4 100644
--- a/test/suite/test_lsm01.py
+++ b/test/suite/test_lsm01.py
@@ -57,7 +57,7 @@ class test_lsm01(wttest.WiredTigerTestCase):
scenarios = wtscenario.make_scenarios(
chunk_size_scenarios, merge_max_scenarios, bloom_scenarios,
bloom_bit_scenarios, bloom_hash_scenarios, record_count_scenarios,
- prune=500)
+ prune=100, prunelong=500)
# Test drop of an object.
def test_lsm(self):
diff --git a/test/suite/test_perf001.py b/test/suite/test_perf001.py
index b22ed2baeb0..6331a3f64d6 100644
--- a/test/suite/test_perf001.py
+++ b/test/suite/test_perf001.py
@@ -40,7 +40,8 @@ class test_perf001(wttest.WiredTigerTestCase):
scenarios = make_scenarios([
#('file-file', dict(tabletype='file',indextype='file')),
- ('file-lsm', dict(tabletype='file',indextype='lsm')),
+ ('file-lsm', dict(tabletype='file',indextype='lsm', cfg='',
+ conn_config="statistics=(fast),statistics_log=(wait=1)")),
#('lsm-file', dict(tabletype='lsm',indextype='file')),
#('lsm-lsm', dict(tabletype='lsm',indextype='lsm')),
])
diff --git a/test/suite/test_readonly01.py b/test/suite/test_readonly01.py
index e4b431ca1da..f41280a3283 100644
--- a/test/suite/test_readonly01.py
+++ b/test/suite/test_readonly01.py
@@ -75,8 +75,7 @@ class test_readonly01(wttest.WiredTigerTestCase, suite_subprocess):
scenarios = make_scenarios(basecfg_list, dir_list, log_list, types)
- def conn_config(self, dir):
- self.home = dir
+ def conn_config(self):
params = \
'error_prefix="%s",' % self.shortid() + \
'%s' % self.logcfg + \
diff --git a/test/suite/test_reconfig01.py b/test/suite/test_reconfig01.py
index e76becac76a..cbc8bca5740 100644
--- a/test/suite/test_reconfig01.py
+++ b/test/suite/test_reconfig01.py
@@ -64,6 +64,18 @@ class test_reconfig01(wttest.WiredTigerTestCase):
# same ops_max of 512 and thread of 8.
self.conn.reconfigure("async=(enabled=true)")
+ def test_reconfig_eviction(self):
+ # Increase the max number of running threads (default 8).
+ self.conn.reconfigure("eviction=(threads_max=10)")
+ # Increase the min number of running threads (default 1).
+ self.conn.reconfigure("eviction=(threads_min=5)")
+ # Decrease the max number of running threads.
+ self.conn.reconfigure("eviction=(threads_max=7)")
+ # Decrease the min number of running threads.
+ self.conn.reconfigure("eviction=(threads_min=2)")
+ # Set min and max the same.
+ self.conn.reconfigure("eviction=(threads_min=6,threads_max=6)")
+
def test_reconfig_lsm_manager(self):
# We create and populate a tiny LSM so that we can start off with
# the LSM threads running and change the numbers of threads.
diff --git a/test/suite/test_reconfig02.py b/test/suite/test_reconfig02.py
index 36a78a1805f..8054b2a6ab5 100644
--- a/test/suite/test_reconfig02.py
+++ b/test/suite/test_reconfig02.py
@@ -109,6 +109,7 @@ class test_reconfig02(wttest.WiredTigerTestCase):
# Now turn on archive, sleep a bit to allow the archive thread
# to run and then confirm that all original logs are gone.
self.conn.reconfigure("log=(archive=true)")
+ self.session.checkpoint("force")
time.sleep(2)
cur_logs = fnmatch.filter(os.listdir('.'), "*Log*")
for o in orig_logs:
diff --git a/test/suite/test_schema05.py b/test/suite/test_schema05.py
index 28ad51b3c92..d536a629373 100644
--- a/test/suite/test_schema05.py
+++ b/test/suite/test_schema05.py
@@ -57,33 +57,9 @@ class test_schema05(wttest.WiredTigerTestCase):
('index-after', { 'create_index' : 2 }),
])
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, exts):
- extfiles = []
- for ext in exts:
- (dirname, name, libname) = ext
- if name != None and name != 'none':
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext', dirname)
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + libname + '.so')
- if not os.path.exists(extfile):
- self.skipTest('extension "' + extfile + '" not built')
- if not extfile in extfiles:
- extfiles.append(extfile)
- if len(extfiles) == 0:
- return ''
- else:
- return ',extensions=["' + '","'.join(extfiles) + '"]'
-
- # Override WiredTigerTestCase, we have extensions.
- def setUpConnectionOpen(self, dir):
- extarg = self.extensionArg([('extractors', 'csv', 'csv_extractor')])
- connarg = 'create,error_prefix="{0}: ",{1}'.format(
- self.shortid(), extarg)
- conn = self.wiredtiger_open(dir, connarg)
- self.pr(`conn`)
- return conn
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('extractors', 'csv')
def create_indices(self):
# Create self.nindices index files, each with a column from the CSV
diff --git a/test/suite/test_schema07.py b/test/suite/test_schema07.py
index ac397c6e1a1..3e4b1d28a4d 100644
--- a/test/suite/test_schema07.py
+++ b/test/suite/test_schema07.py
@@ -33,8 +33,7 @@ import wiredtiger, wttest
class test_schema07(wttest.WiredTigerTestCase):
tablename = 'table:test_schema07'
- def conn_config(self, dir):
- return 'cache_size=10MB'
+ conn_config = 'cache_size=10MB'
@wttest.longtest("Creating many tables shouldn't fill the cache")
def test_many_tables(self):
diff --git a/test/suite/test_stat02.py b/test/suite/test_stat02.py
index cecda7f1ddc..45af283ed02 100644
--- a/test/suite/test_stat02.py
+++ b/test/suite/test_stat02.py
@@ -59,7 +59,7 @@ class test_stat_cursor_config(wttest.WiredTigerTestCase):
scenarios = make_scenarios(uri, data_config, cursor_config)
# Turn on statistics for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'statistics=(%s)' % self.data_config
# For each database/cursor configuration, confirm the right combinations
diff --git a/test/suite/test_truncate01.py b/test/suite/test_truncate01.py
index 2319eeddbef..7d2b3862568 100644
--- a/test/suite/test_truncate01.py
+++ b/test/suite/test_truncate01.py
@@ -183,11 +183,11 @@ class test_truncate_cursor(wttest.WiredTigerTestCase):
# those tests to file objects.
types = [
('file', dict(type='file:', valuefmt='S',
- config='allocation_size=512,leaf_page_max=512')),
+ config='allocation_size=512,leaf_page_max=512', P=0.25)),
('file8t', dict(type='file:', valuefmt='8t',
- config='allocation_size=512,leaf_page_max=512')),
+ config='allocation_size=512,leaf_page_max=512', P=0.25)),
('table', dict(type='table:', valuefmt='S',
- config='allocation_size=512,leaf_page_max=512')),
+ config='allocation_size=512,leaf_page_max=512', P=0.5)),
]
keyfmt = [
('integer', dict(keyfmt='i')),
@@ -203,7 +203,8 @@ class test_truncate_cursor(wttest.WiredTigerTestCase):
('big', dict(nentries=1000,skip=37)),
]
- scenarios = make_scenarios(types, keyfmt, size, reopen)
+ scenarios = make_scenarios(types, keyfmt, size, reopen,
+ prune=10, prunelong=1000)
# Set a cursor key.
def cursorKey(self, ds, uri, key):
diff --git a/test/suite/test_truncate02.py b/test/suite/test_truncate02.py
index 73fed362354..729825b26d4 100644
--- a/test/suite/test_truncate02.py
+++ b/test/suite/test_truncate02.py
@@ -85,7 +85,8 @@ class test_truncate_fast_delete(wttest.WiredTigerTestCase):
('txn2', dict(commit=False)),
]
- scenarios = make_scenarios(types, keyfmt, overflow, reads, writes, txn)
+ scenarios = make_scenarios(types, keyfmt, overflow, reads, writes, txn,
+ prune=20, prunelong=1000)
# Return the number of records visible to the cursor; test both forward
# and backward iteration, they are different code paths in this case.
diff --git a/test/suite/test_txn02.py b/test/suite/test_txn02.py
index a0c2c12a47c..01626057b9e 100644
--- a/test/suite/test_txn02.py
+++ b/test/suite/test_txn02.py
@@ -93,11 +93,10 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
checklog_calls = 100 if wttest.islongtest() else 2
checklog_mod = (len(scenarios) / checklog_calls + 1)
- def setUpConnectionOpen(self, dir):
- self.home = dir
+ def conn_config(self):
# Cycle through the different transaction_sync values in a
# deterministic manner.
- self.txn_sync = self.sync_list[
+ txn_sync = self.sync_list[
self.scenario_number % len(self.sync_list)]
#
# We don't want to run zero fill with only the same settings, such
@@ -107,17 +106,9 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
zerofill = 'false'
if self.scenario_number % freq == 0:
zerofill = 'true'
- self.backup_dir = os.path.join(self.home, "WT_BACKUP")
- conn_params = \
- 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
- 'log=(zero_fill=%s),' % zerofill + \
- 'create,error_prefix="%s: ",' % self.shortid() + \
- 'transaction_sync="%s",' % self.txn_sync
- # print "Creating conn at '%s' with config '%s'" % (dir, conn_params)
- conn = self.wiredtiger_open(dir, conn_params)
- self.pr(`conn`)
- self.session2 = conn.open_session()
- return conn
+ return 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
+ 'log=(zero_fill=%s),' % zerofill + \
+ 'transaction_sync="%s",' % txn_sync
# Check that a cursor (optionally started in a new transaction), sees the
# expected values.
@@ -176,8 +167,10 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
backup_conn = self.wiredtiger_open(self.backup_dir,
backup_conn_params)
try:
- self.check(backup_conn.open_session(), None, committed)
+ 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.
time.sleep(1.0)
@@ -204,6 +197,8 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
self.assertEqual(cur_logs, pr_logs)
def test_ops(self):
+ self.backup_dir = os.path.join(self.home, "WT_BACKUP")
+ self.session2 = self.conn.open_session()
# print "Creating %s with config '%s'" % (self.uri, self.create_params)
self.session.create(self.uri, self.create_params)
# Set up the table with entries for 1, 2, 10 and 11.
@@ -226,6 +221,7 @@ class test_txn02(wttest.WiredTigerTestCase, suite_subprocess):
# Close and reopen the connection and cursor.
if reopen == 'reopen':
self.reopen_conn()
+ self.session2 = self.conn.open_session()
c = self.session.open_cursor(self.uri, None, 'overwrite')
self.session.begin_transaction(
diff --git a/test/suite/test_txn04.py b/test/suite/test_txn04.py
index ade39272f84..d8f6774ded1 100644
--- a/test/suite/test_txn04.py
+++ b/test/suite/test_txn04.py
@@ -63,24 +63,15 @@ class test_txn04(wttest.WiredTigerTestCase, suite_subprocess):
txn1s = [('t1c', dict(txn1='commit')), ('t1r', dict(txn1='rollback'))]
scenarios = make_scenarios(types, op1s, txn1s)
- # Overrides WiredTigerTestCase
- def setUpConnectionOpen(self, dir):
- self.home = dir
+
+ def conn_config(self):
# Cycle through the different transaction_sync values in a
# deterministic manner.
- self.txn_sync = self.sync_list[
+ txn_sync = self.sync_list[
self.scenario_number % len(self.sync_list)]
- self.backup_dir = os.path.join(self.home, "WT_BACKUP")
# Set archive false on the home directory.
- conn_params = \
- 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
- 'create,error_prefix="%s: ",' % self.shortid() + \
- 'transaction_sync="%s",' % self.txn_sync
- # print "Creating conn at '%s' with config '%s'" % (dir, conn_params)
- conn = self.wiredtiger_open(dir, conn_params)
- self.pr(`conn`)
- self.session2 = conn.open_session()
- return conn
+ return 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
+ 'transaction_sync="%s",' % txn_sync
# Check that a cursor (optionally started in a new transaction), sees the
# expected values.
@@ -146,6 +137,7 @@ class test_txn04(wttest.WiredTigerTestCase, suite_subprocess):
# The runWt command closes our connection and sessions so
# we need to reopen them here.
self.hot_backup(None, committed)
+ self.session2 = self.conn.open_session()
c = self.session.open_cursor(self.uri, None, 'overwrite')
c.set_value(1)
# Then do the given modification.
@@ -193,6 +185,8 @@ class test_txn04(wttest.WiredTigerTestCase, suite_subprocess):
self.hot_backup(self.uri, committed)
def test_ops(self):
+ self.backup_dir = os.path.join(self.home, "WT_BACKUP")
+ self.session2 = self.conn.open_session()
with self.expectedStdoutPattern('recreating metadata'):
self.ops()
diff --git a/test/suite/test_txn05.py b/test/suite/test_txn05.py
index 9e84fe7d3fe..7aaff221ba4 100644
--- a/test/suite/test_txn05.py
+++ b/test/suite/test_txn05.py
@@ -64,23 +64,15 @@ class test_txn05(wttest.WiredTigerTestCase, suite_subprocess):
txn1s = [('t1c', dict(txn1='commit')), ('t1r', dict(txn1='rollback'))]
scenarios = make_scenarios(types, op1s, txn1s)
- # Overrides WiredTigerTestCase
- def setUpConnectionOpen(self, dir):
- self.home = dir
+
+ def conn_config(self):
# Cycle through the different transaction_sync values in a
# deterministic manner.
- self.txn_sync = self.sync_list[
+ txn_sync = self.sync_list[
self.scenario_number % len(self.sync_list)]
- self.backup_dir = os.path.join(self.home, "WT_BACKUP")
- conn_params = \
- 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
- 'create,error_prefix="%s: ",' % self.shortid() + \
- 'transaction_sync="%s",' % self.txn_sync
- # print "Creating conn at '%s' with config '%s'" % (dir, conn_params)
- conn = self.wiredtiger_open(dir, conn_params)
- self.pr(`conn`)
- self.session2 = conn.open_session()
- return conn
+ # Set archive false on the home directory.
+ return 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
+ 'transaction_sync="%s",' % txn_sync
# Check that a cursor (optionally started in a new transaction), sees the
# expected values.
@@ -139,8 +131,12 @@ class test_txn05(wttest.WiredTigerTestCase, suite_subprocess):
backup_conn = self.wiredtiger_open(self.backup_dir,
backup_conn_params)
try:
- self.check(backup_conn.open_session(), None, committed)
+ 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)
@@ -163,6 +159,8 @@ class test_txn05(wttest.WiredTigerTestCase, suite_subprocess):
self.runWt(['-h', self.backup_dir, 'printlog'], outfilename='printlog.out')
def test_ops(self):
+ self.backup_dir = os.path.join(self.home, "WT_BACKUP")
+ self.session2 = self.conn.open_session()
# print "Creating %s with config '%s'" % (self.uri, self.create_params)
self.session.create(self.uri, self.create_params)
# Set up the table with entries for 1-5.
diff --git a/test/suite/test_txn06.py b/test/suite/test_txn06.py
index 2bff97f6aac..c91dc6a623b 100644
--- a/test/suite/test_txn06.py
+++ b/test/suite/test_txn06.py
@@ -40,10 +40,10 @@ class test_txn06(wttest.WiredTigerTestCase, suite_subprocess):
source_uri = 'table:' + tablename + "_src"
nrows = 100000
- def setUpConnectionOpen(self, *args):
+ def conn_config(self):
if not wiredtiger.verbose_build():
self.skipTest('requires a verbose build')
- return super(test_txn06, self).setUpConnectionOpen(*args)
+ return ''
def test_long_running(self):
# Populate a table
diff --git a/test/suite/test_txn07.py b/test/suite/test_txn07.py
index f9577bad7f2..e2986fb999a 100644
--- a/test/suite/test_txn07.py
+++ b/test/suite/test_txn07.py
@@ -70,43 +70,20 @@ class test_txn07(wttest.WiredTigerTestCase, suite_subprocess):
('none', dict(compress='')),
]
- scenarios = make_scenarios(types, op1s, txn1s, compress)
- # Overrides WiredTigerTestCase
- def setUpConnectionOpen(self, dir):
- self.home = dir
- # Cycle through the different transaction_sync values in a
- # deterministic manner.
- self.txn_sync = self.sync_list[
- self.scenario_number % len(self.sync_list)]
- self.backup_dir = os.path.join(self.home, "WT_BACKUP")
- conn_params = \
- 'log=(archive=false,enabled,file_max=%s,' % self.logmax + \
- 'compressor=%s)' % self.compress + \
- self.extensionArg(self.compress) + \
- ',create,error_prefix="%s: ",' % self.shortid() + \
- "statistics=(fast)," + \
- 'transaction_sync="%s",' % self.txn_sync
- # print "Creating conn at '%s' with config '%s'" % (dir, conn_params)
- try:
- conn = self.wiredtiger_open(dir, conn_params)
- except wiredtiger.WiredTigerError as e:
- print "Failed conn at '%s' with config '%s'" % (dir, conn_params)
- self.pr(`conn`)
- self.session2 = conn.open_session()
- return conn
-
- # Return the wiredtiger_open extension argument for a shared library.
- def extensionArg(self, name):
- if name == None or name == '':
- return ''
-
- testdir = os.path.dirname(__file__)
- extdir = os.path.join(run.wt_builddir, 'ext/compressors')
- extfile = os.path.join(
- extdir, name, '.libs', 'libwiredtiger_' + name + '.so')
- if not os.path.exists(extfile):
- self.skipTest('compression extension "' + extfile + '" not built')
- return ',extensions=["' + extfile + '"]'
+ scenarios = make_scenarios(types, op1s, txn1s, compress,
+ prune=30, prunelong=1000)
+
+ def conn_config(self):
+ return 'log=(archive=false,enabled,file_max=%s,' % self.logmax + \
+ 'compressor=%s)' % self.compress + \
+ ',create,error_prefix="%s: ",' % self.shortid() + \
+ "statistics=(fast)," + \
+ 'transaction_sync="%s",' % \
+ self.sync_list[self.scenario_number % len(self.sync_list)]
+
+ def conn_extensions(self, extlist):
+ extlist.skip_if_missing = True
+ extlist.extension('compressors', self.compress)
# Check that a cursor (optionally started in a new transaction), sees the
# expected values.
@@ -139,7 +116,7 @@ class test_txn07(wttest.WiredTigerTestCase, suite_subprocess):
self.backup(self.backup_dir)
backup_conn_params = 'log=(enabled,file_max=%s,' % self.logmax + \
'compressor=%s)' % self.compress + \
- self.extensionArg(self.compress)
+ self.extensionsConfig()
backup_conn = self.wiredtiger_open(self.backup_dir, backup_conn_params)
try:
self.check(backup_conn.open_session(), None, committed)
@@ -147,6 +124,9 @@ class test_txn07(wttest.WiredTigerTestCase, suite_subprocess):
backup_conn.close()
def test_ops(self):
+ self.backup_dir = os.path.join(self.home, "WT_BACKUP")
+ self.session2 = self.conn.open_session()
+
# print "Creating %s with config '%s'" % (self.uri, self.create_params)
self.session.create(self.uri, self.create_params)
# Set up the table with entries for 1-5.
diff --git a/test/suite/test_txn08.py b/test/suite/test_txn08.py
index f0cdf08df07..04faed9d45a 100644
--- a/test/suite/test_txn08.py
+++ b/test/suite/test_txn08.py
@@ -41,7 +41,7 @@ class test_txn08(wttest.WiredTigerTestCase, suite_subprocess):
uri = 'table:' + tablename
# Turn on logging for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'log=(archive=false,enabled,file_max=%s),' % self.logmax + \
'transaction_sync="(method=dsync,enabled)"'
diff --git a/test/suite/test_txn09.py b/test/suite/test_txn09.py
index cfad8270ab1..768d714e248 100644
--- a/test/suite/test_txn09.py
+++ b/test/suite/test_txn09.py
@@ -80,19 +80,9 @@ class test_txn09(wttest.WiredTigerTestCase, suite_subprocess):
op1s, txn1s, op2s, txn2s, op3s, txn3s, op4s, txn4s,
prune=20, prunelong=5000)
- # Overrides WiredTigerTestCase
- def setUpConnectionOpen(self, dir):
- self.home = dir
- conn_params = \
- 'create,error_prefix="%s: ",' % self.shortid() + \
- 'log=(archive=false,enabled=%s),' % int(self.log_enabled) + \
- 'transaction_sync=(enabled=false),'
-
- # print "Opening conn at '%s' with config '%s'" % (dir, conn_params)
- conn = self.wiredtiger_open(dir, conn_params)
- self.pr(`conn`)
- self.session2 = conn.open_session()
- return conn
+ def conn_config(self):
+ return 'log=(archive=false,enabled=%s),' % int(self.log_enabled) + \
+ 'transaction_sync=(enabled=false)'
# Check that a cursor (optionally started in a new transaction), sees the
# expected values.
@@ -141,6 +131,7 @@ class test_txn09(wttest.WiredTigerTestCase, suite_subprocess):
# Close and reopen the connection and cursor, toggling the log
self.log_enabled = not self.log_enabled
self.reopen_conn()
+ self.session2 = self.conn.open_session()
c = self.session.open_cursor(self.uri, None, 'overwrite')
self.session.begin_transaction(
diff --git a/test/suite/test_txn11.py b/test/suite/test_txn11.py
index 147bf3a76c0..3c02b1e86e3 100644
--- a/test/suite/test_txn11.py
+++ b/test/suite/test_txn11.py
@@ -44,7 +44,7 @@ class test_txn11(wttest.WiredTigerTestCase, suite_subprocess):
uri = 'table:' + tablename
# Turn on logging for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'log=(archive=%s,' % self.archive + \
'enabled,file_max=%s,prealloc=false),' % self.logmax + \
'transaction_sync=(enabled=false),'
diff --git a/test/suite/test_txn13.py b/test/suite/test_txn13.py
index ae0250c06e8..2bf49486b3a 100644
--- a/test/suite/test_txn13.py
+++ b/test/suite/test_txn13.py
@@ -50,7 +50,7 @@ class test_txn13(wttest.WiredTigerTestCase, suite_subprocess):
])
# Turn on logging for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'log=(archive=false,enabled,file_max=%s)' % self.logmax + \
',cache_size=8G'
diff --git a/test/suite/test_txn15.py b/test/suite/test_txn15.py
index c061c093b02..a2bfb626338 100644
--- a/test/suite/test_txn15.py
+++ b/test/suite/test_txn15.py
@@ -41,7 +41,7 @@ class test_txn15(wttest.WiredTigerTestCase, suite_subprocess):
create_params = 'key_format=i,value_format=i'
entries = 100
# Turn on logging for this test.
- def conn_config(self, dir):
+ def conn_config(self):
return 'statistics=(fast),' + \
'log=(archive=false,enabled,file_max=100K),' + \
'use_environment=false,' + \
diff --git a/test/suite/test_util14.py b/test/suite/test_util14.py
new file mode 100644
index 00000000000..e2a9f41f0d4
--- /dev/null
+++ b/test/suite/test_util14.py
@@ -0,0 +1,92 @@
+#!/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 os
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+
+# test_util14.py
+# Utilities: wt truncate
+class test_util14(wttest.WiredTigerTestCase, suite_subprocess):
+ tablename = 'test_util14.a'
+ nentries = 1000
+
+ def test_truncate_process(self):
+ """
+ Test truncate in a 'wt' process
+ """
+ params = 'key_format=S,value_format=S'
+ self.session.create('table:' + self.tablename, params)
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+ cursor = self.session.open_cursor('table:' + self.tablename, None, None)
+ for i in range(0, self.nentries):
+ cursor[str(i)] = str(i)
+ cursor.close()
+
+ self.runWt(["truncate", "table:" + self.tablename])
+
+ """
+ Test to confirm table exists and is empty
+ """
+ outfile="outfile.txt"
+ errfile="errfile.txt"
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+ self.runWt(["read", 'table:' + self.tablename, 'NoMatch'],
+ outfilename=outfile, errfilename=errfile, failure=True)
+ self.check_empty_file(outfile)
+ self.check_file_contains(errfile, 'NoMatch: not found\n')
+
+ """
+ Tests for error cases
+ 1. Missing URI
+ 2. Invalid URI
+ 3. Valid but incorrect URI
+ 4. Double URI
+ """
+ self.runWt(["truncate"],
+ outfilename=outfile, errfilename=errfile, failure=True)
+ self.check_empty_file(outfile)
+ self.check_file_contains(errfile, 'usage:')
+
+ self.runWt(["truncate", "foobar"],
+ outfilename=outfile, errfilename=errfile, failure=True)
+ self.check_empty_file(outfile)
+ self.check_file_contains(errfile, 'No such file or directory')
+
+ self.runWt(["truncate", 'table:xx' + self.tablename],
+ outfilename=outfile, errfilename=errfile, failure=True)
+ self.check_empty_file(outfile)
+ self.check_file_contains(errfile, 'No such file or directory')
+
+ self.runWt(["truncate", 'table:' + self.tablename, 'table:' + self.tablename],
+ outfilename=outfile, errfilename=errfile, failure=True)
+ self.check_empty_file(outfile)
+ self.check_file_contains(errfile, 'usage:')
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/test/suite/test_util15.py b/test/suite/test_util15.py
new file mode 100644
index 00000000000..33096e71bee
--- /dev/null
+++ b/test/suite/test_util15.py
@@ -0,0 +1,71 @@
+#!/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 os
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+
+# test_util15.py
+# Utilities: wt alter
+class test_util15(wttest.WiredTigerTestCase, suite_subprocess):
+ tablename = 'test_util15.a'
+
+ def test_alter_process(self):
+ """
+ Test alter in a 'wt' process
+ """
+ params = 'key_format=S,value_format=S'
+ self.session.create('table:' + self.tablename, params)
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+
+ """
+ Alter access pattern and confirm
+ """
+ acc_pat_seq="access_pattern_hint=sequential"
+ self.runWt(["alter", "table:" + self.tablename, acc_pat_seq])
+ cursor = self.session.open_cursor("metadata:create", None, None)
+ cursor.set_key("table:" + self.tablename)
+ self.assertEqual(cursor.search(),0)
+ string = cursor.get_value()
+ cursor.close()
+ self.assertTrue(acc_pat_seq in string)
+
+ """
+ Alter access pattern again and confirm
+ """
+ acc_pat_rand="access_pattern_hint=random"
+ self.runWt(["alter", "table:" + self.tablename, acc_pat_rand])
+ cursor = self.session.open_cursor("metadata:create", None, None)
+ cursor.set_key("table:" + self.tablename)
+ self.assertEqual(cursor.search(),0)
+ string = cursor.get_value()
+ cursor.close()
+ self.assertTrue(acc_pat_rand in string)
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/test/suite/test_util16.py b/test/suite/test_util16.py
new file mode 100644
index 00000000000..00e68c1017a
--- /dev/null
+++ b/test/suite/test_util16.py
@@ -0,0 +1,71 @@
+#!/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 os
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+
+# test_util16.py
+# Utilities: wt rename
+class test_util16(wttest.WiredTigerTestCase, suite_subprocess):
+ tablename = 'test_util16.a'
+ tablename2 = 'test_util16.b'
+ nentries = 1000
+
+ def test_rename_process(self):
+ """
+ Test alter in a 'wt' process
+ """
+ params = 'key_format=S,value_format=S'
+ self.session.create('table:' + self.tablename, params)
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+ cursor = self.session.open_cursor('table:' + self.tablename, None, None)
+ for i in range(0, self.nentries):
+ cursor[str(i)] = str(i)
+ cursor.close()
+
+ self.runWt(["rename", "table:" + self.tablename, "table:" + self.tablename2])
+ self.assertTrue(os.path.exists(self.tablename2 + ".wt"))
+ cursor = self.session.open_cursor('table:' + self.tablename2, None, None)
+ count = 0
+ while cursor.next() == 0:
+ count +=1
+ cursor.close()
+ self.assertEquals(self.nentries, count)
+
+ self.runWt(["rename", "table:" + self.tablename2, "table:" + self.tablename])
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+ cursor = self.session.open_cursor('table:' + self.tablename, None, None)
+ count = 0
+ while cursor.next() == 0:
+ count +=1
+ cursor.close()
+ self.assertEquals(self.nentries, count)
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/test/suite/test_util17.py b/test/suite/test_util17.py
new file mode 100644
index 00000000000..decc1fabf1d
--- /dev/null
+++ b/test/suite/test_util17.py
@@ -0,0 +1,57 @@
+#!/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 os
+from suite_subprocess import suite_subprocess
+import wiredtiger, wttest
+
+# test_util17.py
+# Utilities: wt stat
+class test_util17(wttest.WiredTigerTestCase, suite_subprocess):
+ tablename = 'test_util17.a'
+
+ def test_stat_process(self):
+ """
+ Test stat in a 'wt' process
+ This test is just here to confirm that stat produces a correct looking
+ output, it isn't here to do statistics validation.
+ """
+ params = 'key_format=S,value_format=S'
+ outfile = "wt-stat.out"
+ expected_string = "cursor: cursor create calls="
+ self.session.create('table:' + self.tablename, params)
+ self.assertTrue(os.path.exists(self.tablename + ".wt"))
+ self.runWt(["stat"], outfilename=outfile)
+ self.check_file_contains(outfile, expected_string)
+
+ expected_string = "cache_walk: Entries in the root page=1"
+ self.runWt(["stat", "table:" + self.tablename ], outfilename=outfile)
+ self.check_file_contains(outfile, expected_string)
+
+if __name__ == '__main__':
+ wttest.run()
diff --git a/test/suite/wtdataset.py b/test/suite/wtdataset.py
index 74e07e24e93..946b97d995f 100644
--- a/test/suite/wtdataset.py
+++ b/test/suite/wtdataset.py
@@ -41,6 +41,7 @@ class BaseDataSet(object):
self.key_format = kwargs.get('key_format', 'S')
self.value_format = kwargs.get('value_format', 'S')
self.config = kwargs.get('config', '')
+ self.projection = kwargs.get('projection', '')
def create(self):
self.testcase.session.create(self.uri, 'key_format=' + self.key_format
@@ -103,7 +104,8 @@ class BaseDataSet(object):
def check(self):
self.testcase.pr('check: ' + self.uri)
- cursor = self.testcase.session.open_cursor(self.uri, None)
+ cursor = self.testcase.session.open_cursor(
+ self.uri + self.projection, None, None)
self.check_cursor(cursor)
cursor.close()
@@ -289,6 +291,94 @@ class ComplexLSMDataSet(ComplexDataSet):
def is_lsm(cls):
return True
+class ProjectionDataSet(SimpleDataSet):
+ """
+ ProjectionDataSet creates a table with predefined data identical to
+ SimpleDataSet (single key and value), but when checking it, uses
+ a cursor with a projection.
+ """
+ def __init__(self, testcase, uri, rows, **kwargs):
+ kwargs['config'] = kwargs.get('config', '') + ',columns=(k,v0)'
+ kwargs['projection'] = '(v0,v0,v0)'
+ super(ProjectionDataSet, self).__init__(testcase, uri, rows, **kwargs)
+
+ # A value suitable for checking the value returned by a cursor.
+ def comparable_value(self, i):
+ v0 = self.value(i)
+ return [v0, v0, v0]
+
+ def check_cursor(self, cursor):
+ i = 0
+ for key, got0, got1, got2 in cursor:
+ i += 1
+ self.testcase.assertEqual(key, self.key(i))
+ if cursor.value_format == '8t' and got0 == 0: # deleted
+ continue
+ self.testcase.assertEqual([got0, got1, got2],
+ self.comparable_value(i))
+ self.testcase.assertEqual(i, self.rows)
+
+class ProjectionIndexDataSet(BaseDataSet):
+ """
+ ProjectionIndexDataSet creates a table with three values and
+ an index. Checks are made against a projection of the main table
+ and a projection of the index.
+ """
+ def __init__(self, testcase, uri, rows, **kwargs):
+ self.origconfig = kwargs.get('config', '')
+ self.indexname = 'index:' + uri.split(":")[1] + ':index0'
+ kwargs['config'] = self.origconfig + ',columns=(k,v0,v1,v2)'
+ kwargs['value_format'] = kwargs.get('value_format', 'SiS')
+ kwargs['projection'] = '(v1,v2,v0)'
+ super(ProjectionIndexDataSet, self).__init__(
+ testcase, uri, rows, **kwargs)
+
+ def value(self, i):
+ return ('v0:' + str(i), i*i, 'v2:' + str(i))
+
+ # Suitable for checking the value returned by a cursor using a projection.
+ def comparable_value(self, i):
+ return [i*i, 'v2:' + str(i), 'v0:' + str(i)]
+
+ def create(self):
+ super(ProjectionIndexDataSet, self).create()
+ self.testcase.session.create(self.indexname, 'columns=(v2,v1),' +
+ self.origconfig)
+
+ def check_cursor(self, cursor):
+ i = 0
+ for key, got0, got1, got2 in cursor:
+ i += 1
+ self.testcase.assertEqual(key, self.key(i))
+ if cursor.value_format == '8t' and got0 == 0: # deleted
+ continue
+ self.testcase.assertEqual([got0, got1, got2],
+ self.comparable_value(i))
+ self.testcase.assertEqual(i, self.rows)
+
+ def check_index_cursor(self, cursor):
+ for i in xrange(1, self.rows + 1):
+ k = self.key(i)
+ v = self.value(i)
+ ik = (v[2], v[1]) # The index key is (v2,v2)
+ expect = [v[1],k,v[2],v[0]]
+ self.testcase.assertEqual(expect, cursor[ik])
+
+ def check(self):
+ BaseDataSet.check(self)
+
+ # Check values in the index.
+ idxcursor = self.testcase.session.open_cursor(
+ self.indexname + '(v1,k,v2,v0)')
+ self.check_index_cursor(idxcursor)
+ idxcursor.close()
+
+ def index_count(self):
+ return 1
+
+ def index_name(self, i):
+ return self.indexname
+
# create a key based on a cursor as a shortcut to creating a SimpleDataSet
def simple_key(cursor, i):
return BaseDataSet.key_by_format(i, cursor.key_format)
diff --git a/test/suite/wttest.py b/test/suite/wttest.py
index 4d6df0bc8bd..0dce51f07d5 100644
--- a/test/suite/wttest.py
+++ b/test/suite/wttest.py
@@ -37,9 +37,8 @@ except ImportError:
import unittest
from contextlib import contextmanager
-import os, re, shutil, sys, time, traceback
-import wtscenario
-import wiredtiger
+import glob, os, re, shutil, sys, time, traceback
+import wiredtiger, wtscenario
def shortenWithEllipsis(s, maxlen):
if len(s) > maxlen:
@@ -152,6 +151,14 @@ class TestSuiteConnection(object):
else:
return getattr(self._conn, attr)
+# Just like a list of strings, but with a convenience function
+class ExtensionList(list):
+ skipIfMissing = False
+ def extension(self, dirname, name, extarg=None):
+ if name != None and name != 'none':
+ ext = '' if extarg == None else '=' + extarg
+ self.append(dirname + '/' + name + ext)
+
class WiredTigerTestCase(unittest.TestCase):
_globalSetup = False
_printOnceSeen = {}
@@ -160,9 +167,16 @@ class WiredTigerTestCase(unittest.TestCase):
# Can be a string or a callable function or lambda expression.
conn_config = ''
+ # conn_extensions can be overridden to add a list of extensions to load.
+ # Each entry is a string (directory and extension name) and optional config.
+ # Example:
+ # conn_extensions = ('extractors/csv_extractor',
+ # 'test/fail_fs={allow_writes=100}')
+ conn_extensions = ()
+
@staticmethod
def globalSetup(preserveFiles = False, useTimestamp = False,
- gdbSub = False, verbose = 1, dirarg = None,
+ gdbSub = False, verbose = 1, builddir = None, dirarg = None,
longtest = False):
WiredTigerTestCase._preserveFiles = preserveFiles
d = 'WT_TEST' if dirarg == None else dirarg
@@ -172,6 +186,7 @@ class WiredTigerTestCase(unittest.TestCase):
os.makedirs(d)
wtscenario.set_long_run(longtest)
WiredTigerTestCase._parentTestdir = d
+ WiredTigerTestCase._builddir = builddir
WiredTigerTestCase._origcwd = os.getcwd()
WiredTigerTestCase._resultfile = open(os.path.join(d, 'results.txt'), "w", 0) # unbuffered
WiredTigerTestCase._gdbSubprocess = gdbSub
@@ -224,12 +239,66 @@ class WiredTigerTestCase(unittest.TestCase):
return "%s.%s.%s" % (self.__module__,
self.className(), self._testMethodName)
- # Can be overridden, but first consider setting self.conn_config .
+ # Return the wiredtiger_open extension argument for
+ # any needed shared library.
+ def extensionsConfig(self):
+ exts = self.conn_extensions
+ if hasattr(exts, '__call__'):
+ exts = ExtensionList()
+ self.conn_extensions(exts)
+ result = ''
+ extfiles = {}
+ skipIfMissing = False
+ if hasattr(exts, 'skip_if_missing'):
+ skipIfMissing = exts.skip_if_missing
+ for ext in exts:
+ extconf = ''
+ if '=' in ext:
+ splits = ext.split('=', 1)
+ ext = splits[0]
+ extconf = '=' + splits[1]
+ splits = ext.split('/')
+ if len(splits) != 2:
+ raise Exception(self.shortid() +
+ ": " + ext +
+ ": extension is not named <dir>/<name>")
+ libname = splits[1]
+ dirname = splits[0]
+ pat = os.path.join(WiredTigerTestCase._builddir, 'ext',
+ dirname, libname, '.libs', 'libwiredtiger_*.so')
+ filenames = glob.glob(pat)
+ if len(filenames) == 0:
+ if skipIfMissing:
+ self.skipTest('extension "' + ext + '" not built')
+ continue
+ else:
+ raise Exception(self.shortid() +
+ ": " + ext +
+ ": no extensions library found matching: " + pat)
+ elif len(filenames) > 1:
+ raise Exception(self.shortid() +
+ ": " + ext +
+ ": multiple extensions libraries found matching: " + pat)
+ complete = '"' + filenames[0] + '"' + extconf
+ if ext in extfiles:
+ if extfiles[ext] != complete:
+ raise Exception(self.shortid() +
+ ": non-matching extension arguments in " +
+ str(exts))
+ else:
+ extfiles[ext] = complete
+ if len(extfiles) != 0:
+ result = ',extensions=[' + ','.join(extfiles.values()) + ']'
+ return result
+
+ # Can be overridden, but first consider setting self.conn_config
+ # or self.conn_extensions
def setUpConnectionOpen(self, home):
self.home = home
config = self.conn_config
if hasattr(config, '__call__'):
- config = config(home)
+ config = self.conn_config()
+ config += self.extensionsConfig()
# In case the open starts additional threads, flush first to
# avoid confusion.
sys.stdout.flush()
@@ -287,6 +356,7 @@ class WiredTigerTestCase(unittest.TestCase):
self.testsubdir = self.className() + '.' + str(self.__class__.wt_ntests)
self.testdir = os.path.join(WiredTigerTestCase._parentTestdir, self.testsubdir)
self.__class__.wt_ntests += 1
+ self.starttime = time.time()
if WiredTigerTestCase._verbose > 2:
self.prhead('started in ' + self.testdir, True)
# tearDown needs connections list, set it here in case the open fails.
@@ -355,6 +425,9 @@ class WiredTigerTestCase(unittest.TestCase):
else:
self.pr('preserving directory ' + self.testdir)
+ elapsed = time.time() - self.starttime
+ if elapsed > 0.001 and WiredTigerTestCase._verbose >= 2:
+ print "%s: %.2f seconds" % (str(self), elapsed)
if not passed and not skipped:
print "ERROR in " + str(self)
self.pr('FAIL')
diff --git a/test/wtperf/test_conf_dump.py b/test/wtperf/test_conf_dump.py
new file mode 100644
index 00000000000..ef7f276a1d0
--- /dev/null
+++ b/test/wtperf/test_conf_dump.py
@@ -0,0 +1,296 @@
+# Usage: python test_conf_dump.py <optional-wtperf-config>
+#
+# This script tests if the config file dumped in the test directory corresponds
+# correctly to the wtperf config file used. Command line options to wtperf are
+# also taken into account.
+#
+# Following expectations are checked for:
+# 1. If provided through multiple sources, "conn_config" and "table_config"
+# configuration options are appended to each other. All other options get
+# replaced by a higher precedent source.
+# 2. The precedence order for the options in an increasing order is as follows:
+# default option,
+# provided through config file,
+# provided through option -o
+# provided through option -C (for conn_config) or -T (for table_config)
+#
+# Test fails if any config option is missing or has a wrong value. Test also
+# fails if the value for the option is not replaced/appended in the correct
+# order of precedence as stated above.
+
+import os, re, subprocess, sys
+
+OP_FILE = "WT_TEST/CONFIG.wtperf"
+TMP_CONF = "__tmp.wtperf"
+WTPERF_BIN = "./wtperf"
+WTPERF_DIR = "../../build_posix/bench/wtperf/"
+
+CONF_NOT_PROVIDED = -2
+
+# Generate a wtperf conf file to use
+def generate_conf_file(file_name):
+ f = open(file_name, 'w')
+ f.write(
+'''conn_config="cache_size=16GB,eviction=(threads_max=4),log=(enabled=false),session_max=33"
+table_config="leaf_page_max=32k,internal_page_max=16k,allocation_size=4k,split_pct=90,type=file"
+close_conn=false
+icount=1500
+create=true
+compression="snappy"
+checkpoint_interval=5
+checkpoint_threads=1
+populate_threads=1
+report_interval=5
+session_count_idle=50
+session_count_idle=60
+session_count_idle=70
+session_count_idle=80
+run_time=5
+sample_interval=5
+sample_rate=1
+table_count=2
+threads=((count=6,updates=1))
+value_sz=1000
+warmup=2
+''')
+ f.close()
+
+# Build a command from the given options and execute wtperf
+def execute_wtperf(conf_file, option_C = "", option_T = "", option_o = ""):
+ # Generate the command to run, execute wtperf
+ cmd = WTPERF_BIN + " -O " + conf_file
+ if option_C:
+ cmd += " -C " + option_C
+ if option_T:
+ cmd += " -T " + option_T
+ if option_o:
+ # Any quotes in option_o need to be escaped before providing it as part
+ # of the command
+ option_o_cmd_str = option_o.replace('"', '\\"')
+ cmd += " -o " + option_o_cmd_str
+
+ print "Running: ", cmd
+ subprocess.check_call(cmd, shell=True)
+ print "=========================\n"
+
+# Build a dictionary of config key and it's value from the given config file.
+# Optionally take -C, -T and -o and overwrite/append values as per correct
+# precedence
+def build_dict_from_conf(
+ conf_file, option_C = "", option_T = "", option_o = ""):
+ # Open given conf file and make a dictionary of passed arguments and values
+ with open(conf_file) as f:
+ lines = f.read().splitlines()
+
+ # Maintain precedence order of config file, -o, -C/-T
+ # Build a dict of config options, appending values for table_config and
+ # conn_config, if specified multiple times. Replace with the latest in
+ # case of all other configuration keys.
+ key_val_dict = {}
+ for line in lines:
+ if re.match('^\s*#', line) is None:
+ key_val_pair = line.split('=', 1)
+ if ((key_val_pair[0] == 'table_config' or
+ key_val_pair[0] == 'conn_config') and
+ key_val_pair[0] in key_val_dict):
+ tmp_val = key_val_dict[key_val_pair[0]][:-1]
+ tmp_val += ","
+ tmp_val += key_val_pair[1][1:]
+ key_val_dict[key_val_pair[0]] = tmp_val
+ else:
+ key_val_dict[key_val_pair[0]] = key_val_pair[1]
+
+ # If provided, put option o in the dict
+ if option_o:
+ opt_o_key_val_list = option_o.split(',')
+ for op_o_key_val in opt_o_key_val_list:
+ key_val_pair = op_o_key_val.split('=', 1)
+ if ((key_val_pair[0] == 'table_config' or
+ key_val_pair[0] == 'conn_config') and
+ key_val_pair[0] in key_val_dict):
+ tmp_val = key_val_dict[key_val_pair[0]][:-1]
+ tmp_val += ","
+ tmp_val += key_val_pair[1][1:]
+ key_val_dict[key_val_pair[0]] = tmp_val
+ else:
+ key_val_dict[key_val_pair[0]] = key_val_pair[1]
+
+ # If provided, put option C in the dict
+ if option_C:
+ tmp_val = key_val_dict["conn_config"][:-1]
+ tmp_val += ","
+ tmp_val += option_C[1:]
+ key_val_dict["conn_config"] = tmp_val
+
+ # If provided, put option T in the dict
+ if option_T:
+ tmp_val = key_val_dict["table_config"][:-1]
+ tmp_val += ","
+ tmp_val += option_T[1:]
+ key_val_dict["table_config"] = tmp_val
+
+ return key_val_dict
+
+# Extract configuration value for the given key from the given config file
+def extract_config_from_file(conf_file, key):
+ ret_val = ""
+ with open(conf_file) as f:
+ lines = f.read().splitlines()
+ for line in lines:
+ if re.match('^\s*#', line) is None:
+ key_val_pair = line.split('=', 1)
+ if key_val_pair[0] == key:
+ ret_val = key_val_pair[1]
+ return ret_val
+
+# Extract configuration value for the given key from the given "-o" string
+def extract_config_from_opt_o(option_o, key):
+ ret_val = ""
+ opt_o_key_val_list = option_o.split(',')
+ for op_o_key_val in opt_o_key_val_list:
+ key_val_pair = op_o_key_val.split('=', 1)
+ if key_val_pair[0] == key:
+ ret_val = key_val_pair[1]
+ return ret_val
+
+# Execute test:
+# Run wtperf with given config and check if the dumped config file matches the
+# given inputs
+def run_test(conf_file, option_C = "", option_T = "", option_o = ""):
+ # Run wtperf
+ execute_wtperf(conf_file, option_C, option_T, option_o)
+
+ key_val_dict_ip = build_dict_from_conf(
+ conf_file, option_C, option_T, option_o)
+ key_val_dict_op = build_dict_from_conf(OP_FILE)
+
+ conn_config_from_file = extract_config_from_file(conf_file, "conn_config")
+ table_config_from_file = extract_config_from_file(conf_file, "table_config")
+ conn_config_from_opt_o = ""
+ table_config_from_opt_o = ""
+ if option_o:
+ conn_config_from_opt_o = extract_config_from_opt_o(
+ option_o, "conn_config")
+ table_config_from_opt_o = extract_config_from_opt_o(
+ option_o, "table_config")
+
+ # Check if dumped output conf matches with input file and options
+ match = True
+ for key in key_val_dict_ip:
+ match_itr = True
+
+ # Check if we see this config key in the dumped file
+ if not key in key_val_dict_op:
+ print "Key '", key, "' not found in dumped file ", OP_FILE
+ match = match_itr = False
+ continue
+
+ # Check if values from all sources of conn_config are presented in the
+ # conn_config in dumped file. Also check of their relative ordering as
+ # per precedence rules defined.
+ if (key == 'conn_config' and
+ (conn_config_from_file or conn_config_from_opt_o or option_C)):
+ # Should find these config in order: file < option o < option C
+ file_loc = CONF_NOT_PROVIDED
+ option_o_loc = CONF_NOT_PROVIDED
+ option_C_loc = CONF_NOT_PROVIDED
+ op_conn_config = key_val_dict_op['conn_config']
+
+ if conn_config_from_file:
+ file_loc = op_conn_config.find(conn_config_from_file[1:-1])
+ if conn_config_from_opt_o:
+ option_o_loc = op_conn_config.find(conn_config_from_opt_o[1:-1])
+ if option_C:
+ option_C_loc = op_conn_config.find(option_C[1:-1])
+
+ # Check if value from any of the sources is missing
+ if ((conn_config_from_file and file_loc == -1) or
+ (conn_config_from_opt_o and option_o_loc == -1) or
+ (option_C and option_C_loc == -1)):
+ print "Part of conn_config missing in dumped file ", OP_FILE
+ match_itr = False
+
+ # Check if the values got appended in the correct order
+ if match_itr:
+ if ((option_o_loc != CONF_NOT_PROVIDED and
+ option_o_loc < file_loc) or
+ (option_C_loc != CONF_NOT_PROVIDED and
+ (option_C_loc < file_loc or option_C_loc < option_o_loc))):
+ print "Detected incorrect config append order:"
+ match_itr = False
+
+ # Check if values from all sources of table_config are presented in the
+ # table_config in dumped file. Also check of their relative ordering as
+ # per precedence rules defined.
+ if (key == 'table_config' and
+ (table_config_from_file or table_config_from_opt_o or option_T)):
+ # Should find these config in order: file < option o < option T
+ file_loc = CONF_NOT_PROVIDED
+ option_o_loc = CONF_NOT_PROVIDED
+ option_T_loc = CONF_NOT_PROVIDED
+ op_table_config = key_val_dict_op['table_config']
+
+ if table_config_from_file:
+ file_loc = op_table_config.find(table_config_from_file[1:-1])
+ if table_config_from_opt_o:
+ option_o_loc = op_table_config.find(
+ table_config_from_opt_o[1:-1])
+ if option_T:
+ option_T_loc = op_table_config.find(option_T[1:-1])
+
+ # Check if value from any of the sources is missing
+ if ((table_config_from_file and file_loc == -1) or
+ (table_config_from_opt_o and option_o_loc == -1) or
+ (option_T and option_T_loc == -1)):
+ print "Part of table_config missing in dumped file ", OP_FILE
+ match_itr = False
+
+ # Check if the values got appended in the correct order
+ if match_itr:
+ if ((option_o_loc != CONF_NOT_PROVIDED and
+ option_o_loc < file_loc) or
+ (option_T_loc != CONF_NOT_PROVIDED and
+ (option_T_loc < file_loc or option_T_loc < option_o_loc))):
+ print "Detected incorrect config append order:"
+ match_itr = False
+
+ if (key != 'table_config' and key != 'conn_config' and
+ key_val_dict_ip[key] != key_val_dict_op[key]):
+ print "Config mismatch between:"
+ match_itr = False
+
+ if match_itr is False:
+ print "Input Config:", key, '=', key_val_dict_ip[key]
+ print "Dumped Config:", key, '=', key_val_dict_op[key]
+ print "\n"
+
+ match = match and match_itr
+
+ return match
+
+# ----------------- Execute Test --------------
+# If a wtperf conf file is provided use it, else generate a temp conf file
+os.chdir(WTPERF_DIR)
+if len(sys.argv) == 2:
+ conf_file = sys.argv[1]
+else:
+ conf_file = TMP_CONF
+ generate_conf_file(conf_file)
+
+# Run a test with no options
+if not run_test(conf_file):
+ exit(-1)
+
+# Run a test with -C, -T, -o provided
+option_o = "verbose=2,conn_config=\"session_max=135\",table_config=\"type=lsm\",sample_interval=2,run_time=0,sample_rate=2,readonly=false"
+option_C = "\"cache_size=10GB,session_max=115\""
+option_T = "\"allocation_size=8k,split_pct=92\""
+if not run_test(conf_file, option_C, option_T, option_o):
+ exit(-1)
+
+# Cleanup generated temp files
+subprocess.check_call("rm -rf WT_TEST/", shell=True)
+if len(sys.argv) == 1 and conf_file == TMP_CONF:
+ subprocess.check_call("rm " + TMP_CONF, shell=True)
+
+print "All tests succeeded"
diff --git a/tools/wtstats/stat_data.py b/tools/wtstats/stat_data.py
index d925dd67b80..a94ce524ae3 100644
--- a/tools/wtstats/stat_data.py
+++ b/tools/wtstats/stat_data.py
@@ -94,6 +94,7 @@ no_scale_per_second_list = [
'btree: row-store leaf pages',
'cache: bytes currently in the cache',
'cache: overflow values cached in memory',
+ 'cache: tracked dirty bytes in the cache',
'cache_walk: Average difference between current eviction generation when the page was last considered',
'cache_walk: Average on-disk page image size seen',
'cache_walk: Clean pages currently in cache',
@@ -127,6 +128,8 @@ no_clear_list = [
'cache: eviction currently operating in aggressive mode',
'cache: eviction empty score',
'cache: eviction state',
+ 'cache: eviction worker thread active',
+ 'cache: eviction worker thread stable number',
'cache: files with active eviction walks',
'cache: maximum bytes configured',
'cache: maximum page size at eviction',
@@ -186,6 +189,7 @@ no_clear_list = [
'transaction: transaction range of IDs currently pinned by named snapshots',
'btree: btree checkpoint generation',
'cache: bytes currently in the cache',
+ 'cache: tracked dirty bytes in the cache',
'cache_walk: Average difference between current eviction generation when the page was last considered',
'cache_walk: Average on-disk page image size seen',
'cache_walk: Clean pages currently in cache',