summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--SConstruct14
-rw-r--r--build_posix/aclocal/options.m419
-rw-r--r--build_posix/configure.ac.in2
-rw-r--r--build_win/filelist.win1
-rw-r--r--build_win/wiredtiger.def1
-rw-r--r--build_win/wiredtiger_config.h3
-rw-r--r--dist/api_config.py18
-rw-r--r--dist/api_data.py58
-rw-r--r--dist/filelist1
-rw-r--r--dist/s_export.list1
-rw-r--r--dist/s_funcs.list1
-rw-r--r--dist/s_string.ok4
-rw-r--r--examples/c/ex_all.c21
-rw-r--r--examples/c/ex_data_source.c15
-rw-r--r--ext/datasources/helium/helium.c2
-rw-r--r--lang/python/wiredtiger.i14
-rw-r--r--src/bloom/bloom.c2
-rw-r--r--src/btree/bt_cursor.c2
-rw-r--r--src/btree/bt_debug.c2
-rw-r--r--src/btree/bt_handle.c13
-rw-r--r--src/btree/bt_page.c40
-rw-r--r--src/config/config_api.c280
-rw-r--r--src/config/config_check.c207
-rw-r--r--src/config/config_concat.c72
-rw-r--r--src/config/config_def.c378
-rw-r--r--src/conn/conn_dhandle.c81
-rw-r--r--src/conn/conn_log.c26
-rw-r--r--src/conn/conn_stat.c2
-rw-r--r--src/conn/conn_sweep.c228
-rw-r--r--src/cursor/cur_dump.c2
-rw-r--r--src/cursor/cur_log.c2
-rw-r--r--src/docs/command-line.dox30
-rw-r--r--src/docs/custom-data-sources.dox5
-rw-r--r--src/evict/evict_lru.c13
-rw-r--r--src/include/api.h14
-rw-r--r--src/include/btree.h4
-rw-r--r--src/include/btree.i13
-rw-r--r--src/include/config.h64
-rw-r--r--src/include/dhandle.h13
-rw-r--r--src/include/extern.h11
-rw-r--r--src/include/log.h2
-rw-r--r--src/include/misc.h27
-rw-r--r--src/include/txn.i28
-rw-r--r--src/include/wiredtiger.in77
-rw-r--r--src/log/log.c10
-rw-r--r--src/lsm/lsm_cursor.c2
-rw-r--r--src/lsm/lsm_manager.c3
-rw-r--r--src/lsm/lsm_merge.c4
-rw-r--r--src/lsm/lsm_stat.c4
-rw-r--r--src/lsm/lsm_tree.c11
-rw-r--r--src/lsm/lsm_work_unit.c9
-rw-r--r--src/meta/meta_table.c4
-rw-r--r--src/meta/meta_track.c29
-rw-r--r--src/os_posix/os_alloc.c15
-rw-r--r--src/os_win/os_fallocate.c17
-rw-r--r--src/schema/schema_create.c20
-rw-r--r--src/schema/schema_truncate.c2
-rw-r--r--src/session/session_api.c2
-rw-r--r--src/session/session_dhandle.c85
-rw-r--r--src/support/err.c8
-rw-r--r--src/support/hazard.c4
-rw-r--r--src/txn/txn.c22
-rw-r--r--src/txn/txn_ckpt.c11
-rw-r--r--src/txn/txn_recover.c6
-rw-r--r--src/utilities/util_load.c105
-rw-r--r--test/suite/test_bug007.py2
-rw-r--r--test/suite/test_util02.py68
-rw-r--r--test/suite/test_verify.py2
68 files changed, 1355 insertions, 903 deletions
diff --git a/SConstruct b/SConstruct
index 9d9a3918a2e..1d32cf05a6c 100644
--- a/SConstruct
+++ b/SConstruct
@@ -34,6 +34,9 @@ AddOption("--enable-python", dest="lang-python", type="string", nargs=1, action=
AddOption("--enable-snappy", dest="snappy", type="string", nargs=1, action="store",
help="Use snappy compression")
+AddOption("--enable-tcmalloc", dest="tcmalloc", type="string", nargs=1, action="store",
+ help="Use TCMalloc for memory allocation")
+
AddOption("--enable-verbose", dest="verbose", action="store_true", default=False,
help="Configure WiredTiger to support the verbose configuration string to wiredtiger_open")
@@ -113,6 +116,7 @@ useZlib = GetOption("zlib")
useSnappy = GetOption("snappy")
useLz4 = GetOption("lz4")
useBdb = GetOption("bdb")
+useTcmalloc = GetOption("tcmalloc")
wtlibs = []
conf = Configure(env)
@@ -157,6 +161,16 @@ if useBdb:
print 'db.h must be installed!'
Exit(1)
+if useTcmalloc:
+ conf.env.Append(CPPPATH=[useTcmalloc + "/include"])
+ conf.env.Append(LIBPATH=[useTcmalloc + "/lib"])
+ if conf.CheckCHeader('gperftools/tcmalloc.h'):
+ wtlibs.append("libtcmalloc_minimal")
+ conf.env.Append(CPPDEFINES=['HAVE_LIBTCMALLOC'])
+ else:
+ print 'tcmalloc.h must be installed!'
+ Exit(1)
+
env = conf.Finish()
# Configure build environment variables
diff --git a/build_posix/aclocal/options.m4 b/build_posix/aclocal/options.m4
index 4e14df0a468..d2cdbf65dce 100644
--- a/build_posix/aclocal/options.m4
+++ b/build_posix/aclocal/options.m4
@@ -202,6 +202,25 @@ if test "$wt_cv_enable_lz4" = "yes"; then
fi
AM_CONDITIONAL([LZ4], [test "$wt_cv_enable_lz4" = "yes"])
+AC_MSG_CHECKING(if --enable-tcmalloc option specified)
+AC_ARG_ENABLE(tcmalloc,
+ [AS_HELP_STRING([--enable-tcmalloc],
+ [Build WiredTiger with tcmalloc.])], r=$enableval, r=no)
+case "$r" in
+no) wt_cv_enable_tcmalloc=no;;
+*) wt_cv_enable_tcmalloc=yes;;
+esac
+AC_MSG_RESULT($wt_cv_enable_tcmalloc)
+if test "$wt_cv_enable_tcmalloc" = "yes"; then
+ AC_LANG_PUSH([C++])
+ AC_CHECK_HEADER(gperftools/tcmalloc.h,,
+ [AC_MSG_ERROR([--enable-tcmalloc requires gperftools/tcmalloc.h])])
+ AC_LANG_POP([C++])
+ AC_CHECK_LIB(tcmalloc, tc_calloc,,
+ [AC_MSG_ERROR([--enable-tcmalloc requires tcmalloc library])])
+fi
+AM_CONDITIONAL([TCMalloc], [test "$wt_cv_enable_tcmalloc" = "yes"])
+
AH_TEMPLATE(SPINLOCK_TYPE, [Spinlock type from mutex.h.])
AC_MSG_CHECKING(if --with-spinlock option specified)
AC_ARG_WITH(spinlock,
diff --git a/build_posix/configure.ac.in b/build_posix/configure.ac.in
index fdd5903c0f1..d93793a997b 100644
--- a/build_posix/configure.ac.in
+++ b/build_posix/configure.ac.in
@@ -19,7 +19,7 @@ m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([no])])
# Configure options. The AM_OPTIONS and the libtool configuration
# need to stay here. Moving them below the compiler and other
# configurations causes -Wcast_align warnings and other warnings
-# on MacOS.
+# on OS X.
AM_OPTIONS
define([AC_LIBTOOL_LANG_CXX_CONFIG], [:])dnl
diff --git a/build_win/filelist.win b/build_win/filelist.win
index 270cd96ac86..d1b43bd8348 100644
--- a/build_win/filelist.win
+++ b/build_win/filelist.win
@@ -49,7 +49,6 @@ src/config/config.c
src/config/config_api.c
src/config/config_check.c
src/config/config_collapse.c
-src/config/config_concat.c
src/config/config_def.c
src/config/config_ext.c
src/config/config_upgrade.c
diff --git a/build_win/wiredtiger.def b/build_win/wiredtiger.def
index 86096fb778d..25e7a01e0d9 100644
--- a/build_win/wiredtiger.def
+++ b/build_win/wiredtiger.def
@@ -1,6 +1,7 @@
LIBRARY WIREDTIGER
EXPORTS
wiredtiger_config_parser_open
+ wiredtiger_config_validate
wiredtiger_open
wiredtiger_pack_close
wiredtiger_pack_int
diff --git a/build_win/wiredtiger_config.h b/build_win/wiredtiger_config.h
index 80dc11d7671..d1ed307cb85 100644
--- a/build_win/wiredtiger_config.h
+++ b/build_win/wiredtiger_config.h
@@ -70,6 +70,9 @@
/* Define to 1 if you have the `snappy' library (-lsnappy). */
/* #undef HAVE_LIBSNAPPY */
+/* Define to 1 if you have the `tcmalloc' library (-ltcmalloc). */
+/* #undef HAVE_LIBTCMALLOC */
+
/* Define to 1 if you have the `z' library (-lz). */
/* #undef HAVE_LIBZ */
diff --git a/dist/api_config.py b/dist/api_config.py
index 020acb993e9..b451e939ef3 100644
--- a/dist/api_config.py
+++ b/dist/api_config.py
@@ -306,8 +306,7 @@ __wt_conn_config_init(WT_SESSION_IMPL *session)
\tconn = S2C(session);
\t/* Build a list of pointers to the configuration information. */
-\tWT_RET(__wt_calloc_def(session,
-\t sizeof(config_entries) / sizeof(config_entries[0]), &epp));
+\tWT_RET(__wt_calloc_def(session, WT_ELEMENTS(config_entries), &epp));
\tconn->config_entries = epp;
\t/* Fill in the list to reference the default information. */
@@ -328,6 +327,21 @@ __wt_conn_config_discard(WT_SESSION_IMPL *session)
\t__wt_free(session, conn->config_entries);
}
+
+/*
+ * __wt_conn_config_match --
+ * Return the static configuration entry for a method.
+ */
+const WT_CONFIG_ENTRY *
+__wt_conn_config_match(const char *method)
+{
+\tconst WT_CONFIG_ENTRY *ep;
+
+\tfor (ep = config_entries; ep->method != NULL; ++ep)
+\t\tif (strcmp(method, ep->method) == 0)
+\t\t\treturn (ep);
+\treturn (NULL);
+}
''')
tfile.close()
diff --git a/dist/api_data.py b/dist/api_data.py
index 81a34910325..b82d47711a5 100644
--- a/dist/api_data.py
+++ b/dist/api_data.py
@@ -674,13 +674,13 @@ methods = {
'table.meta' : Method(table_meta),
-'cursor.close' : Method([]),
+'WT_CURSOR.close' : Method([]),
-'cursor.reconfigure' : Method(cursor_runtime_config),
+'WT_CURSOR.reconfigure' : Method(cursor_runtime_config),
-'session.close' : Method([]),
+'WT_SESSION.close' : Method([]),
-'session.compact' : Method([
+'WT_SESSION.compact' : Method([
Config('timeout', '1200', r'''
maximum amount of time to allow for compact in seconds. The
actual amount of time spent in compact may exceed the configured
@@ -688,7 +688,7 @@ methods = {
type='int'),
]),
-'session.create' : Method(file_config + lsm_config + source_meta +
+'WT_SESSION.create' : Method(file_config + lsm_config + source_meta +
index_only_config + table_only_config + [
Config('exclusive', 'false', r'''
fail if the object exists. When false (the default), if the
@@ -697,7 +697,7 @@ methods = {
type='boolean'),
]),
-'session.drop' : Method([
+'WT_SESSION.drop' : Method([
Config('force', 'false', r'''
return success if the object does not exist''',
type='boolean'),
@@ -706,9 +706,9 @@ methods = {
type='boolean'),
]),
-'session.log_printf' : Method([]),
+'WT_SESSION.log_printf' : Method([]),
-'session.open_cursor' : Method(cursor_runtime_config + [
+'WT_SESSION.open_cursor' : Method(cursor_runtime_config + [
Config('bulk', 'false', r'''
configure the cursor for bulk-loading, a fast, initial load
path (see @ref tune_bulk_load for more information). Bulk-load
@@ -782,17 +782,17 @@ methods = {
type='list'),
]),
-'session.rename' : Method([]),
-'session.salvage' : Method([
+'WT_SESSION.rename' : Method([]),
+'WT_SESSION.salvage' : Method([
Config('force', 'false', r'''
force salvage even of files that do not appear to be WiredTiger
files''',
type='boolean'),
]),
-'session.strerror' : Method([]),
-'session.truncate' : Method([]),
-'session.upgrade' : Method([]),
-'session.verify' : Method([
+'WT_SESSION.strerror' : Method([]),
+'WT_SESSION.truncate' : Method([]),
+'WT_SESSION.upgrade' : Method([]),
+'WT_SESSION.verify' : Method([
Config('dump_address', 'false', r'''
Display addresses and page types as pages are verified,
using the application's message handler, intended for debugging''',
@@ -815,7 +815,7 @@ methods = {
type='boolean')
]),
-'session.begin_transaction' : Method([
+'WT_SESSION.begin_transaction' : Method([
Config('isolation', '', r'''
the isolation level for this transaction; defaults to the
session's isolation level''',
@@ -832,10 +832,10 @@ methods = {
type='boolean'),
]),
-'session.commit_transaction' : Method([]),
-'session.rollback_transaction' : Method([]),
+'WT_SESSION.commit_transaction' : Method([]),
+'WT_SESSION.rollback_transaction' : Method([]),
-'session.checkpoint' : Method([
+'WT_SESSION.checkpoint' : Method([
Config('drop', '', r'''
specify a list of checkpoints to drop.
The list may additionally contain one of the following keys:
@@ -857,12 +857,12 @@ methods = {
if non-empty, checkpoint the list of objects''', type='list'),
]),
-'connection.add_collator' : Method([]),
-'connection.add_compressor' : Method([]),
-'connection.add_data_source' : Method([]),
-'connection.add_encryptor' : Method([]),
-'connection.add_extractor' : Method([]),
-'connection.async_new_op' : Method([
+'WT_CONNECTION.add_collator' : Method([]),
+'WT_CONNECTION.add_compressor' : Method([]),
+'WT_CONNECTION.add_data_source' : Method([]),
+'WT_CONNECTION.add_encryptor' : Method([]),
+'WT_CONNECTION.add_extractor' : Method([]),
+'WT_CONNECTION.async_new_op' : Method([
Config('append', 'false', r'''
append the value as a new record, creating a new record
number key; valid only for operations with record number keys''',
@@ -884,14 +884,14 @@ methods = {
value. A value of zero disables the timeout''',
type='int'),
]),
-'connection.close' : Method([
+'WT_CONNECTION.close' : Method([
Config('leak_memory', 'false', r'''
don't free memory during close''',
type='boolean'),
]),
-'connection.reconfigure' : Method(connection_runtime_config),
+'WT_CONNECTION.reconfigure' : Method(connection_runtime_config),
-'connection.load_extension' : Method([
+'WT_CONNECTION.load_extension' : Method([
Config('config', '', r'''
configuration string passed to the entry point of the
extension as its WT_CONFIG_ARG argument'''),
@@ -906,9 +906,9 @@ methods = {
::wiredtiger_extension_terminate'''),
]),
-'connection.open_session' : Method(session_config),
+'WT_CONNECTION.open_session' : Method(session_config),
-'session.reconfigure' : Method(session_config),
+'WT_SESSION.reconfigure' : Method(session_config),
# There are 4 variants of the wiredtiger_open configurations.
# wiredtiger_open:
diff --git a/dist/filelist b/dist/filelist
index ac3f29ad7ab..7d57864a788 100644
--- a/dist/filelist
+++ b/dist/filelist
@@ -49,7 +49,6 @@ src/config/config.c
src/config/config_api.c
src/config/config_check.c
src/config/config_collapse.c
-src/config/config_concat.c
src/config/config_def.c
src/config/config_ext.c
src/config/config_upgrade.c
diff --git a/dist/s_export.list b/dist/s_export.list
index d3803bc3afa..c7f088bc2d5 100644
--- a/dist/s_export.list
+++ b/dist/s_export.list
@@ -1,5 +1,6 @@
# List of OK external symbols.
wiredtiger_config_parser_open
+wiredtiger_config_validate
wiredtiger_open
wiredtiger_pack_close
wiredtiger_pack_int
diff --git a/dist/s_funcs.list b/dist/s_funcs.list
index 4bb9796c11f..9b343e21507 100644
--- a/dist/s_funcs.list
+++ b/dist/s_funcs.list
@@ -30,6 +30,7 @@ __wt_nlpo2_round
__wt_print_huffman_code
__wt_try_readlock
wiredtiger_config_parser_open
+wiredtiger_config_validate
wiredtiger_pack_int
wiredtiger_pack_item
wiredtiger_pack_str
diff --git a/dist/s_string.ok b/dist/s_string.ok
index a8ba82e6c0a..c02f601701e 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -45,6 +45,7 @@ CELL's
CELLs
CHECKKEY
CKPT
+CMP
CONCAT
CONFIG
CPUs
@@ -168,6 +169,7 @@ LockFile
Lookup
MALLOC
MEM
+MEMALIGN
MERCHANTABILITY
MSVC
MUTEX
@@ -251,6 +253,7 @@ Spinlocks
Split's
Stoica
TAILQ
+TCMalloc
TODO
TORTIOUS
TXN
@@ -283,6 +286,7 @@ Vo
Vv
VxWorks
WIREDTIGER
+WRLSN
WakeAllConditionVariable
Wconditional
WeakHashLen
diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c
index 00aee5ba57d..e562af73fc3 100644
--- a/examples/c/ex_all.c
+++ b/examples/c/ex_all.c
@@ -892,6 +892,20 @@ connection_ops(WT_CONNECTION *conn)
}
/*! [Check if the database is newly created] */
+ /*! [Validate a configuration string] */
+ /*
+ * Validate a configuration string for a WiredTiger function or method.
+ *
+ * Functions are specified by name (for example, "wiredtiger_open").
+ *
+ * Methods are specified using a concatenation of the handle name, a
+ * period and the method name (for example, session create would be
+ * "WT_SESSION.create" and cursor close would be WT_CURSOR.close").
+ */
+ ret = wiredtiger_config_validate(
+ NULL, NULL, "WT_SESSION.create", "allocation_size=32KB");
+ /*! [Validate a configuration string] */
+
{
/*! [Open a session] */
WT_SESSION *session;
@@ -906,9 +920,12 @@ connection_ops(WT_CONNECTION *conn)
* Applications opening a cursor for the data-source object "my_data"
* have an additional configuration option "entries", which is an
* integer type, defaults to 5, and must be an integer between 1 and 10.
+ *
+ * The method being configured is specified using a concatenation of the
+ * handle name, a period and the method name.
*/
ret = conn->configure_method(conn,
- "session.open_cursor",
+ "WT_SESSION.open_cursor",
"my_data:", "entries=5", "int", "min=1,max=10");
/*
@@ -917,7 +934,7 @@ connection_ops(WT_CONNECTION *conn)
* of strings.
*/
ret = conn->configure_method(conn,
- "session.open_cursor", "my_data:", "devices", "list", NULL);
+ "WT_SESSION.open_cursor", "my_data:", "devices", "list", NULL);
/*! [Configure method configuration] */
/*! [Close a connection] */
diff --git a/examples/c/ex_data_source.c b/examples/c/ex_data_source.c
index 4d0e4275b79..3cd44257d39 100644
--- a/examples/c/ex_data_source.c
+++ b/examples/c/ex_data_source.c
@@ -612,25 +612,25 @@ main(void)
/*! [WT_DATA_SOURCE configure boolean] */
/* my_boolean defaults to true. */
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "my_boolean=true", "boolean", NULL);
+ "WT_SESSION.open_cursor", NULL, "my_boolean=true", "boolean", NULL);
/*! [WT_DATA_SOURCE configure boolean] */
/*! [WT_DATA_SOURCE configure integer] */
/* my_integer defaults to 5. */
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "my_integer=5", "int", NULL);
+ "WT_SESSION.open_cursor", NULL, "my_integer=5", "int", NULL);
/*! [WT_DATA_SOURCE configure integer] */
/*! [WT_DATA_SOURCE configure string] */
/* my_string defaults to "name". */
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "my_string=name", "string", NULL);
+ "WT_SESSION.open_cursor", NULL, "my_string=name", "string", NULL);
/*! [WT_DATA_SOURCE configure string] */
/*! [WT_DATA_SOURCE configure list] */
/* my_list defaults to "first" and "second". */
ret = conn->configure_method(conn,
- "session.open_cursor",
+ "WT_SESSION.open_cursor",
NULL, "my_list=[first, second]", "list", NULL);
/*! [WT_DATA_SOURCE configure list] */
@@ -639,7 +639,8 @@ main(void)
* Limit the number of devices to between 1 and 30; the default is 5.
*/
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "devices=5", "int", "min=1, max=30");
+ "WT_SESSION.open_cursor",
+ NULL, "devices=5", "int", "min=1, max=30");
/*! [WT_DATA_SOURCE configure integer with checking] */
/*! [WT_DATA_SOURCE configure string with checking] */
@@ -648,7 +649,7 @@ main(void)
* to /home.
*/
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "target=/home", "string",
+ "WT_SESSION.open_cursor", NULL, "target=/home", "string",
"choices=[/device, /home, /target]");
/*! [WT_DATA_SOURCE configure string with checking] */
@@ -658,7 +659,7 @@ main(void)
* /target; default to /mnt.
*/
ret = conn->configure_method(conn,
- "session.open_cursor", NULL, "paths=[/mnt]", "list",
+ "WT_SESSION.open_cursor", NULL, "paths=[/mnt]", "list",
"choices=[/device, /home, /mnt, /target]");
/*! [WT_DATA_SOURCE configure list with checking] */
diff --git a/ext/datasources/helium/helium.c b/ext/datasources/helium/helium.c
index 3fc521d93b2..2b7cb5f7d4c 100644
--- a/ext/datasources/helium/helium.c
+++ b/ext/datasources/helium/helium.c
@@ -3427,7 +3427,7 @@ wiredtiger_extension_init(WT_CONNECTION *connection, WT_CONFIG_ARG *config)
/* Add Helium-specific WT_SESSION.create configuration options. */
for (p = session_create_opts; *p != NULL; ++p)
if ((ret = connection->configure_method(connection,
- "session.create", "helium:", *p, "boolean", NULL)) != 0)
+ "WT_SESSION.create", "helium:", *p, "boolean", NULL)) != 0)
EMSG_ERR(wtext, NULL, ret,
"WT_CONNECTION.configure_method: session.create: "
"%s: %s",
diff --git a/lang/python/wiredtiger.i b/lang/python/wiredtiger.i
index fb5b9ac5c55..3f297ca25a0 100644
--- a/lang/python/wiredtiger.i
+++ b/lang/python/wiredtiger.i
@@ -31,10 +31,16 @@
* The SWIG interface file defining the wiredtiger python API.
*/
%define DOCSTRING
-"@defgroup wt_python WiredTiger Python API
-Python wrappers aroung the WiredTiger C API.
-@{
-@cond IGNORE"
+"Python wrappers around the WiredTiger C API
+
+This provides an API similar to the C API, with the following modifications:
+ - Many C functions are exposed as OO methods. See the Python examples and test suite
+ - Errors are handled in a Pythonic way; wrap calls in try/except blocks
+ - Cursors have extra accessor methods and iterators that are higher-level than the C API
+ - Statistics cursors behave a little differently and are best handled using the C-like functions
+ - C Constants starting with WT_STAT_DSRC are instead exposed under wiredtiger.stat.dsrc
+ - C Constants starting with WT_STAT_CONN are instead exposed under wiredtiger.stat.conn
+"
%enddef
%module(docstring=DOCSTRING) wiredtiger
diff --git a/src/bloom/bloom.c b/src/bloom/bloom.c
index 06d0b7478dd..9225b9fe3b5 100644
--- a/src/bloom/bloom.c
+++ b/src/bloom/bloom.c
@@ -124,7 +124,7 @@ __bloom_open_cursor(WT_BLOOM *bloom, WT_CURSOR *owner)
return (0);
session = bloom->session;
- cfg[0] = WT_CONFIG_BASE(session, session_open_cursor);
+ cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_open_cursor);
cfg[1] = bloom->config;
cfg[2] = NULL;
c = NULL;
diff --git a/src/btree/bt_cursor.c b/src/btree/bt_cursor.c
index 5c15ff79afc..7c894effacd 100644
--- a/src/btree/bt_cursor.c
+++ b/src/btree/bt_cursor.c
@@ -842,7 +842,7 @@ __wt_btcur_next_random(WT_CURSOR_BTREE *cbt)
if (__cursor_valid(cbt, &upd))
WT_ERR(__wt_kv_return(session, cbt, upd));
else
- WT_ERR(__wt_btcur_search_near(cbt, 0));
+ WT_ERR(__wt_btcur_search_near(cbt, NULL));
err: if (ret != 0)
WT_TRET(__cursor_reset(cbt));
diff --git a/src/btree/bt_debug.c b/src/btree/bt_debug.c
index e8e802ea74c..9cc7cd2a824 100644
--- a/src/btree/bt_debug.c
+++ b/src/btree/bt_debug.c
@@ -797,7 +797,7 @@ __debug_page_row_int(WT_DBG *ds, WT_PAGE *page, uint32_t flags)
WT_REF *ref;
WT_SESSION_IMPL *session;
size_t len;
- uint8_t *p;
+ void *p;
session = ds->session;
diff --git a/src/btree/bt_handle.c b/src/btree/bt_handle.c
index 93453efaf43..09e38fa7fd5 100644
--- a/src/btree/bt_handle.c
+++ b/src/btree/bt_handle.c
@@ -259,13 +259,13 @@ __btree_conf(WT_SESSION_IMPL *session, WT_CKPT *ckpt)
/* Eviction; the metadata file is never evicted. */
if (WT_IS_METADATA(btree->dhandle))
- F_SET(btree, WT_BTREE_NO_EVICTION | WT_BTREE_NO_HAZARD);
+ F_SET(btree, WT_BTREE_IN_MEMORY | WT_BTREE_NO_EVICTION);
else {
WT_RET(__wt_config_gets(session, cfg, "cache_resident", &cval));
if (cval.val)
- F_SET(btree, WT_BTREE_NO_EVICTION | WT_BTREE_NO_HAZARD);
+ F_SET(btree, WT_BTREE_IN_MEMORY | WT_BTREE_NO_EVICTION);
else
- F_CLR(btree, WT_BTREE_NO_EVICTION);
+ F_CLR(btree, WT_BTREE_IN_MEMORY | WT_BTREE_NO_EVICTION);
}
/* Checksums */
@@ -529,8 +529,11 @@ __wt_btree_evictable(WT_SESSION_IMPL *session, int on)
btree = S2BT(session);
- /* The metadata file is never evicted. */
- if (on && !WT_IS_METADATA(btree->dhandle))
+ /* Permanently cache-resident files can never be evicted. */
+ if (F_ISSET(btree, WT_BTREE_IN_MEMORY))
+ return;
+
+ if (on)
F_CLR(btree, WT_BTREE_NO_EVICTION);
else
F_SET(btree, WT_BTREE_NO_EVICTION);
diff --git a/src/btree/bt_page.c b/src/btree/bt_page.c
index dd7a29347df..8086806b3a4 100644
--- a/src/btree/bt_page.c
+++ b/src/btree/bt_page.c
@@ -102,10 +102,18 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags
return (WT_RESTART);
case WT_REF_MEM:
/*
- * The page is in memory: get a hazard pointer, update
- * the page's LRU and return. The expected reason we
- * can't get a hazard pointer is because the page is
- * being evicted; yield and try again.
+ * The page is in memory.
+ *
+ * Get a hazard pointer if one is required. We cannot
+ * be evicting if no hazard pointer is required, we're
+ * done.
+ */
+ if (F_ISSET(S2BT(session), WT_BTREE_IN_MEMORY))
+ goto skip_evict;
+
+ /*
+ * The expected reason we can't get a hazard pointer is
+ * because the page is being evicted, yield, try again.
*/
#ifdef HAVE_DIAGNOSTIC
WT_RET(
@@ -119,12 +127,19 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags
break;
}
- page = ref->page;
- WT_ASSERT(session, page != NULL);
+ /*
+ * If eviction is configured for this file, check to see
+ * if the page qualifies for forced eviction and update
+ * the page's generation number. If eviction isn't being
+ * done on this file, we're done.
+ */
+ if (F_ISSET(S2BT(session), WT_BTREE_NO_EVICTION))
+ goto skip_evict;
/*
* Forcibly evict pages that are too big.
*/
+ page = ref->page;
if (force_attempts < 10 &&
__evict_force_check(session, page, flags)) {
++force_attempts;
@@ -149,12 +164,6 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags
continue;
}
- /* Check if we need an autocommit transaction. */
- if ((ret = __wt_txn_autocommit_check(session)) != 0) {
- WT_TRET(__wt_hazard_clear(session, page));
- return (ret);
- }
-
/*
* If we read the page and we are configured to not
* trash the cache, set the oldest read generation so
@@ -169,8 +178,11 @@ __wt_page_in_func(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags
page->read_gen < __wt_cache_read_gen(session))
page->read_gen =
__wt_cache_read_gen_set(session);
-
- return (0);
+skip_evict:
+ /*
+ * Check if we need an autocommit transaction.
+ */
+ return (__wt_txn_autocommit_check(session));
WT_ILLEGAL_VALUE(session);
}
diff --git a/src/config/config_api.c b/src/config/config_api.c
index d956b2d677d..deff33a10bd 100644
--- a/src/config/config_api.c
+++ b/src/config/config_api.c
@@ -94,8 +94,7 @@ wiredtiger_config_parser_open(WT_SESSION *wt_session,
* structure for iterations through the configuration string.
*/
memcpy(&config_parser->config_item, &config_item, sizeof(config_item));
- WT_ERR(__wt_config_initn(
- session, &config_parser->config, config, len));
+ WT_ERR(__wt_config_initn(session, &config_parser->config, config, len));
if (ret == 0)
*config_parserp = (WT_CONFIG_PARSER *)config_parser;
@@ -104,3 +103,280 @@ err: __wt_free(session, config_parser);
return (ret);
}
+
+/*
+ * wiredtiger_config_validate --
+ * Validate a configuration string.
+ */
+int
+wiredtiger_config_validate(WT_SESSION *wt_session,
+ WT_EVENT_HANDLER *handler, const char *name, const char *config)
+{
+ WT_CONNECTION_IMPL *conn, dummy_conn;
+ WT_SESSION_IMPL *session;
+ const WT_CONFIG_ENTRY *ep, **epp;
+
+ session = (WT_SESSION_IMPL *)wt_session;
+
+ /*
+ * It's a logic error to specify both a session and an event handler.
+ */
+ if (session != NULL && handler != NULL)
+ WT_RET_MSG(session, EINVAL,
+ "wiredtiger_config_validate error handler ignored when "
+ "a session also specified");
+
+ /*
+ * If we're not given a session, but we do have an event handler, build
+ * a fake session/connection pair and configure the event handler.
+ */
+ conn = NULL;
+ if (session == NULL && handler != NULL) {
+ WT_CLEAR(dummy_conn);
+ conn = &dummy_conn;
+ session = conn->default_session = &conn->dummy_session;
+ session->iface.connection = &conn->iface;
+ session->name = "wiredtiger_config_validate";
+ __wt_event_handler_set(session, handler);
+ }
+ if (session != NULL)
+ conn = S2C(session);
+
+ if (name == NULL)
+ WT_RET_MSG(session, EINVAL, "no name specified");
+ if (config == NULL)
+ WT_RET_MSG(session, EINVAL, "no configuration specified");
+
+ /*
+ * If we don't have a real connection, look for a matching name in the
+ * static list, otherwise look in the configuration list (which has any
+ * configuration information the application has added).
+ */
+ if (session == NULL || conn == NULL || conn->config_entries == NULL)
+ ep = __wt_conn_config_match(name);
+ else {
+ ep = NULL;
+ for (epp = conn->config_entries;
+ *epp != NULL && (*epp)->method != NULL; ++epp)
+ if (strcmp((*epp)->method, name) == 0) {
+ ep = *epp;
+ break;
+ }
+ }
+ if (ep == NULL)
+ WT_RET_MSG(session, EINVAL,
+ "unknown or unsupported configuration API: %s",
+ name);
+
+ return (__wt_config_check(session, ep, config, 0));
+}
+
+/*
+ * __conn_foc_add --
+ * Add a new entry into the connection's free-on-close list.
+ */
+static int
+__conn_foc_add(WT_SESSION_IMPL *session, const void *p)
+{
+ WT_CONNECTION_IMPL *conn;
+
+ conn = S2C(session);
+
+ /*
+ * Our caller is expected to be holding any locks we need.
+ */
+ WT_RET(__wt_realloc_def(
+ session, &conn->foc_size, conn->foc_cnt + 1, &conn->foc));
+
+ conn->foc[conn->foc_cnt++] = (void *)p;
+ return (0);
+}
+
+/*
+ * __wt_conn_foc_discard --
+ * Discard any memory the connection accumulated.
+ */
+void
+__wt_conn_foc_discard(WT_SESSION_IMPL *session)
+{
+ WT_CONNECTION_IMPL *conn;
+ size_t i;
+
+ conn = S2C(session);
+
+ /*
+ * If we have a list of chunks to free, run through the list, then
+ * free the list itself.
+ */
+ for (i = 0; i < conn->foc_cnt; ++i)
+ __wt_free(session, conn->foc[i]);
+ __wt_free(session, conn->foc);
+}
+
+/*
+ * __wt_configure_method --
+ * WT_CONNECTION.configure_method.
+ */
+int
+__wt_configure_method(WT_SESSION_IMPL *session,
+ const char *method, const char *uri,
+ const char *config, const char *type, const char *check)
+{
+ const WT_CONFIG_CHECK *cp;
+ WT_CONFIG_CHECK *checks, *newcheck;
+ const WT_CONFIG_ENTRY **epp;
+ WT_CONFIG_ENTRY *entry;
+ WT_CONNECTION_IMPL *conn;
+ WT_DECL_RET;
+ size_t cnt;
+ char *newcheck_name, *p;
+
+ /*
+ * !!!
+ * We ignore the specified uri, that is, all new configuration options
+ * will be valid for all data sources. That shouldn't be too bad
+ * as the worst that can happen is an application might specify some
+ * configuration option and not get an error -- the option should be
+ * ignored by the underlying implementation since it's unexpected, so
+ * there shouldn't be any real problems. Eventually I expect we will
+ * get the whole data-source thing sorted, at which time there may be
+ * configuration arrays for each data source, and that's when the uri
+ * will matter.
+ */
+ WT_UNUSED(uri);
+
+ conn = S2C(session);
+ checks = newcheck = NULL;
+ entry = NULL;
+ newcheck_name = NULL;
+
+ /* Argument checking; we only support a limited number of types. */
+ if (config == NULL)
+ WT_RET_MSG(session, EINVAL, "no configuration specified");
+ if (type == NULL)
+ WT_RET_MSG(session, EINVAL, "no configuration type specified");
+ if (strcmp(type, "boolean") != 0 && strcmp(type, "int") != 0 &&
+ strcmp(type, "list") != 0 && strcmp(type, "string") != 0)
+ WT_RET_MSG(session, EINVAL,
+ "type must be one of \"boolean\", \"int\", \"list\" or "
+ "\"string\"");
+
+ /*
+ * Translate the method name to our configuration names, then find a
+ * match.
+ */
+ for (epp = conn->config_entries;
+ *epp != NULL && (*epp)->method != NULL; ++epp)
+ if (strcmp((*epp)->method, method) == 0)
+ break;
+ if (*epp == NULL || (*epp)->method == NULL)
+ WT_RET_MSG(session,
+ WT_NOTFOUND, "no method matching %s found", method);
+
+ /*
+ * Technically possible for threads to race, lock the connection while
+ * adding the new configuration information. We're holding the lock
+ * for an extended period of time, but configuration changes should be
+ * rare and only happen during startup.
+ */
+ __wt_spin_lock(session, &conn->api_lock);
+
+ /*
+ * Allocate new configuration entry and fill it in.
+ *
+ * The new base value is the previous base value, a separator and the
+ * new configuration string.
+ */
+ WT_ERR(__wt_calloc_one(session, &entry));
+ entry->method = (*epp)->method;
+ WT_ERR(__wt_calloc_def(session,
+ strlen((*epp)->base) + strlen(",") + strlen(config) + 1, &p));
+ (void)strcpy(p, (*epp)->base);
+ (void)strcat(p, ",");
+ (void)strcat(p, config);
+ entry->base = p;
+
+ /*
+ * There may be a default value in the config argument passed in (for
+ * example, (kvs_parallelism=64"). The default value isn't part of the
+ * name, build a new one.
+ */
+ WT_ERR(__wt_strdup(session, config, &newcheck_name));
+ if ((p = strchr(newcheck_name, '=')) != NULL)
+ *p = '\0';
+
+ /*
+ * The new configuration name may replace an existing check with new
+ * information, in that case skip the old version.
+ */
+ cnt = 0;
+ if ((*epp)->checks != NULL)
+ for (cp = (*epp)->checks; cp->name != NULL; ++cp)
+ ++cnt;
+ WT_ERR(__wt_calloc_def(session, cnt + 2, &checks));
+ cnt = 0;
+ if ((*epp)->checks != NULL)
+ for (cp = (*epp)->checks; cp->name != NULL; ++cp)
+ if (strcmp(newcheck_name, cp->name) != 0)
+ checks[cnt++] = *cp;
+ newcheck = &checks[cnt];
+ newcheck->name = newcheck_name;
+ WT_ERR(__wt_strdup(session, type, &newcheck->type));
+ if (check != NULL)
+ WT_ERR(__wt_strdup(session, check, &newcheck->checks));
+ entry->checks = checks;
+ entry->checks_entries = 0;
+
+ /*
+ * Confirm the configuration string passes the new set of
+ * checks.
+ */
+ WT_ERR(__wt_config_check(session, entry, config, 0));
+
+ /*
+ * The next time this configuration is updated, we don't want to figure
+ * out which of these pieces of memory were allocated and will need to
+ * be free'd on close (this isn't a heavily used API and it's too much
+ * work); add them all to the free-on-close list now. We don't check
+ * for errors deliberately, we'd have to figure out which elements have
+ * already been added to the free-on-close array and which have not in
+ * order to avoid freeing chunks of memory twice. Again, this isn't a
+ * commonly used API and it shouldn't ever happen, just leak it.
+ */
+ (void)__conn_foc_add(session, entry->base);
+ (void)__conn_foc_add(session, entry);
+ (void)__conn_foc_add(session, checks);
+ (void)__conn_foc_add(session, newcheck->type);
+ (void)__conn_foc_add(session, newcheck->checks);
+ (void)__conn_foc_add(session, newcheck_name);
+
+ /*
+ * Instead of using locks to protect configuration information, assume
+ * we can atomically update a pointer to a chunk of memory, and because
+ * a pointer is never partially written, readers will correctly see the
+ * original or new versions of the memory. Readers might be using the
+ * old version as it's being updated, though, which means we cannot free
+ * the old chunk of memory until all possible readers have finished.
+ * Currently, that's on connection close: in other words, we can use
+ * this because it's small amounts of memory, and we really, really do
+ * not want to acquire locks every time we access configuration strings,
+ * since that's done on every API call.
+ */
+ WT_PUBLISH(*epp, entry);
+
+ if (0) {
+err: if (entry != NULL) {
+ __wt_free(session, entry->base);
+ __wt_free(session, entry);
+ }
+ __wt_free(session, checks);
+ if (newcheck != NULL) {
+ __wt_free(session, newcheck->type);
+ __wt_free(session, newcheck->checks);
+ }
+ __wt_free(session, newcheck_name);
+ }
+
+ __wt_spin_unlock(session, &conn->api_lock);
+ return (ret);
+}
diff --git a/src/config/config_check.c b/src/config/config_check.c
index c1f7801c13b..b09a1a10a85 100644
--- a/src/config/config_check.c
+++ b/src/config/config_check.c
@@ -12,213 +12,6 @@ static int config_check(
WT_SESSION_IMPL *, const WT_CONFIG_CHECK *, u_int, const char *, size_t);
/*
- * __conn_foc_add --
- * Add a new entry into the connection's free-on-close list.
- */
-static int
-__conn_foc_add(WT_SESSION_IMPL *session, const void *p)
-{
- WT_CONNECTION_IMPL *conn;
-
- conn = S2C(session);
-
- /*
- * Our caller is expected to be holding any locks we need.
- */
- WT_RET(__wt_realloc_def(
- session, &conn->foc_size, conn->foc_cnt + 1, &conn->foc));
-
- conn->foc[conn->foc_cnt++] = (void *)p;
- return (0);
-}
-
-/*
- * __wt_conn_foc_discard --
- * Discard any memory the connection accumulated.
- */
-void
-__wt_conn_foc_discard(WT_SESSION_IMPL *session)
-{
- WT_CONNECTION_IMPL *conn;
- size_t i;
-
- conn = S2C(session);
-
- /*
- * If we have a list of chunks to free, run through the list, then
- * free the list itself.
- */
- for (i = 0; i < conn->foc_cnt; ++i)
- __wt_free(session, conn->foc[i]);
- __wt_free(session, conn->foc);
-}
-
-/*
- * __wt_configure_method --
- * WT_CONNECTION.configure_method.
- */
-int
-__wt_configure_method(WT_SESSION_IMPL *session,
- const char *method, const char *uri,
- const char *config, const char *type, const char *check)
-{
- const WT_CONFIG_CHECK *cp;
- WT_CONFIG_CHECK *checks, *newcheck;
- const WT_CONFIG_ENTRY **epp;
- WT_CONFIG_ENTRY *entry;
- WT_CONNECTION_IMPL *conn;
- WT_DECL_RET;
- size_t cnt;
- char *newcheck_name, *p;
-
- /*
- * !!!
- * We ignore the specified uri, that is, all new configuration options
- * will be valid for all data sources. That shouldn't be too bad
- * as the worst that can happen is an application might specify some
- * configuration option and not get an error -- the option should be
- * ignored by the underlying implementation since it's unexpected, so
- * there shouldn't be any real problems. Eventually I expect we will
- * get the whole data-source thing sorted, at which time there may be
- * configuration arrays for each data source, and that's when the uri
- * will matter.
- */
- WT_UNUSED(uri);
-
- conn = S2C(session);
- checks = newcheck = NULL;
- entry = NULL;
- newcheck_name = NULL;
-
- /* Argument checking; we only support a limited number of types. */
- if (config == NULL)
- WT_RET_MSG(session, EINVAL, "no configuration specified");
- if (type == NULL)
- WT_RET_MSG(session, EINVAL, "no configuration type specified");
- if (strcmp(type, "boolean") != 0 && strcmp(type, "int") != 0 &&
- strcmp(type, "list") != 0 && strcmp(type, "string") != 0)
- WT_RET_MSG(session, EINVAL,
- "type must be one of \"boolean\", \"int\", \"list\" or "
- "\"string\"");
-
- /* Find a match for the method name. */
- for (epp = conn->config_entries; (*epp)->method != NULL; ++epp)
- if (strcmp((*epp)->method, method) == 0)
- break;
- if ((*epp)->method == NULL)
- WT_RET_MSG(session,
- WT_NOTFOUND, "no method matching %s found", method);
-
- /*
- * Technically possible for threads to race, lock the connection while
- * adding the new configuration information. We're holding the lock
- * for an extended period of time, but configuration changes should be
- * rare and only happen during startup.
- */
- __wt_spin_lock(session, &conn->api_lock);
-
- /*
- * Allocate new configuration entry and fill it in.
- *
- * The new base value is the previous base value, a separator and the
- * new configuration string.
- */
- WT_ERR(__wt_calloc_one(session, &entry));
- entry->method = (*epp)->method;
- WT_ERR(__wt_calloc_def(session,
- strlen((*epp)->base) + strlen(",") + strlen(config) + 1, &p));
- (void)strcpy(p, (*epp)->base);
- (void)strcat(p, ",");
- (void)strcat(p, config);
- entry->base = p;
-
- /*
- * There may be a default value in the config argument passed in (for
- * example, (kvs_parallelism=64"). The default value isn't part of the
- * name, build a new one.
- */
- WT_ERR(__wt_strdup(session, config, &newcheck_name));
- if ((p = strchr(newcheck_name, '=')) != NULL)
- *p = '\0';
-
- /*
- * The new configuration name may replace an existing check with new
- * information, in that case skip the old version.
- */
- cnt = 0;
- if ((*epp)->checks != NULL)
- for (cp = (*epp)->checks; cp->name != NULL; ++cp)
- ++cnt;
- WT_ERR(__wt_calloc_def(session, cnt + 2, &checks));
- cnt = 0;
- if ((*epp)->checks != NULL)
- for (cp = (*epp)->checks; cp->name != NULL; ++cp)
- if (strcmp(newcheck_name, cp->name) != 0)
- checks[cnt++] = *cp;
- newcheck = &checks[cnt];
- newcheck->name = newcheck_name;
- WT_ERR(__wt_strdup(session, type, &newcheck->type));
- if (check != NULL)
- WT_ERR(__wt_strdup(session, check, &newcheck->checks));
- entry->checks = checks;
- entry->checks_entries = 0;
-
- /*
- * Confirm the configuration string passes the new set of
- * checks.
- */
- WT_ERR(config_check(
- session, entry->checks, entry->checks_entries, config, 0));
-
- /*
- * The next time this configuration is updated, we don't want to figure
- * out which of these pieces of memory were allocated and will need to
- * be free'd on close (this isn't a heavily used API and it's too much
- * work); add them all to the free-on-close list now. We don't check
- * for errors deliberately, we'd have to figure out which elements have
- * already been added to the free-on-close array and which have not in
- * order to avoid freeing chunks of memory twice. Again, this isn't a
- * commonly used API and it shouldn't ever happen, just leak it.
- */
- (void)__conn_foc_add(session, entry->base);
- (void)__conn_foc_add(session, entry);
- (void)__conn_foc_add(session, checks);
- (void)__conn_foc_add(session, newcheck->type);
- (void)__conn_foc_add(session, newcheck->checks);
- (void)__conn_foc_add(session, newcheck_name);
-
- /*
- * Instead of using locks to protect configuration information, assume
- * we can atomically update a pointer to a chunk of memory, and because
- * a pointer is never partially written, readers will correctly see the
- * original or new versions of the memory. Readers might be using the
- * old version as it's being updated, though, which means we cannot free
- * the old chunk of memory until all possible readers have finished.
- * Currently, that's on connection close: in other words, we can use
- * this because it's small amounts of memory, and we really, really do
- * not want to acquire locks every time we access configuration strings,
- * since that's done on every API call.
- */
- WT_PUBLISH(*epp, entry);
-
- if (0) {
-err: if (entry != NULL) {
- __wt_free(session, entry->base);
- __wt_free(session, entry);
- }
- __wt_free(session, checks);
- if (newcheck != NULL) {
- __wt_free(session, newcheck->type);
- __wt_free(session, newcheck->checks);
- }
- __wt_free(session, newcheck_name);
- }
-
- __wt_spin_unlock(session, &conn->api_lock);
- return (ret);
-}
-
-/*
* __wt_config_check --
* Check the keys in an application-supplied config string match what is
* specified in an array of check strings.
diff --git a/src/config/config_concat.c b/src/config/config_concat.c
deleted file mode 100644
index e872722a272..00000000000
--- a/src/config/config_concat.c
+++ /dev/null
@@ -1,72 +0,0 @@
-/*-
- * Copyright (c) 2014-2015 MongoDB, Inc.
- * Copyright (c) 2008-2014 WiredTiger, Inc.
- * All rights reserved.
- *
- * See the file LICENSE for redistribution information.
- */
-
-#include "wt_internal.h"
-
-/*
- * __wt_config_concat --
- * Given a NULL-terminated list of configuration strings, concatenate them
- * into newly allocated memory. Nothing special is assumed about any of
- * the config strings, they are simply combined in order.
- *
- * This code deals with the case where some of the config strings are
- * wrapped in brackets but others aren't: the resulting string does not
- * have brackets.
- */
-int
-__wt_config_concat(
- WT_SESSION_IMPL *session, const char **cfg, char **config_ret)
-{
- WT_CONFIG cparser;
- WT_CONFIG_ITEM k, v;
- WT_DECL_ITEM(tmp);
- WT_DECL_RET;
- const char **cp;
-
- WT_RET(__wt_scr_alloc(session, 0, &tmp));
-
- for (cp = cfg; *cp != NULL; ++cp) {
- WT_ERR(__wt_config_init(session, &cparser, *cp));
- while ((ret = __wt_config_next(&cparser, &k, &v)) == 0) {
- if (k.type != WT_CONFIG_ITEM_STRING &&
- k.type != WT_CONFIG_ITEM_ID)
- WT_ERR_MSG(session, EINVAL,
- "Invalid configuration key found: '%s'\n",
- k.str);
- /* Include the quotes around string keys/values. */
- if (k.type == WT_CONFIG_ITEM_STRING) {
- --k.str;
- k.len += 2;
- }
- if (v.type == WT_CONFIG_ITEM_STRING) {
- --v.str;
- v.len += 2;
- }
- WT_ERR(__wt_buf_catfmt(session, tmp, "%.*s%s%.*s,",
- (int)k.len, k.str,
- (v.len > 0) ? "=" : "",
- (int)v.len, v.str));
- }
- if (ret != WT_NOTFOUND)
- goto err;
- }
-
- /*
- * If the caller passes us no valid configuration strings, we get here
- * with no bytes to copy -- that's OK, the underlying string copy can
- * handle empty strings.
- *
- * Strip any trailing comma.
- */
- if (tmp->size != 0)
- --tmp->size;
- ret = __wt_strndup(session, tmp->data, tmp->size, config_ret);
-
-err: __wt_scr_free(session, &tmp);
- return (ret);
-}
diff --git a/src/config/config_def.c b/src/config/config_def.c
index 9be99e6219c..b3286d4e990 100644
--- a/src/config/config_def.c
+++ b/src/config/config_def.c
@@ -2,16 +2,7 @@
#include "wt_internal.h"
-static const WT_CONFIG_CHECK confchk_colgroup_meta[] = {
- { "app_metadata", "string", NULL, NULL, NULL, 0 },
- { "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
- { "columns", "list", NULL, NULL, NULL, 0 },
- { "source", "string", NULL, NULL, NULL, 0 },
- { "type", "string", NULL, NULL, NULL, 0 },
- { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const WT_CONFIG_CHECK confchk_connection_async_new_op[] = {
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_async_new_op[] = {
{ "append", "boolean", NULL, NULL, NULL, 0 },
{ "overwrite", "boolean", NULL, NULL, NULL, 0 },
{ "raw", "boolean", NULL, NULL, NULL, 0 },
@@ -19,19 +10,19 @@ static const WT_CONFIG_CHECK confchk_connection_async_new_op[] = {
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_connection_close[] = {
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_close[] = {
{ "leak_memory", "boolean", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_connection_load_extension[] = {
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_load_extension[] = {
{ "config", "string", NULL, NULL, NULL, 0 },
{ "entry", "string", NULL, NULL, NULL, 0 },
{ "terminate", "string", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_connection_open_session[] = {
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_open_session[] = {
{ "isolation", "string",
NULL, "choices=[\"read-uncommitted\",\"read-committed\","
"\"snapshot\"]",
@@ -100,7 +91,7 @@ static const WT_CONFIG_CHECK
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_connection_reconfigure[] = {
+static const WT_CONFIG_CHECK confchk_WT_CONNECTION_reconfigure[] = {
{ "async", "category",
NULL, NULL,
confchk_wiredtiger_open_async_subconfigs, 3 },
@@ -144,20 +135,60 @@ static const WT_CONFIG_CHECK confchk_connection_reconfigure[] = {
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_cursor_reconfigure[] = {
+static const WT_CONFIG_CHECK confchk_WT_CURSOR_reconfigure[] = {
{ "append", "boolean", NULL, NULL, NULL, 0 },
{ "overwrite", "boolean", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
+static const WT_CONFIG_CHECK confchk_WT_SESSION_begin_transaction[] = {
+ { "isolation", "string",
+ NULL, "choices=[\"read-uncommitted\",\"read-committed\","
+ "\"snapshot\"]",
+ NULL, 0 },
+ { "name", "string", NULL, NULL, NULL, 0 },
+ { "priority", "int", NULL, "min=-100,max=100", NULL, 0 },
+ { "sync", "boolean", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const WT_CONFIG_CHECK confchk_WT_SESSION_checkpoint[] = {
+ { "drop", "list", NULL, NULL, NULL, 0 },
+ { "force", "boolean", NULL, NULL, NULL, 0 },
+ { "name", "string", NULL, NULL, NULL, 0 },
+ { "target", "list", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const WT_CONFIG_CHECK confchk_WT_SESSION_compact[] = {
+ { "timeout", "int", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
static const WT_CONFIG_CHECK
- confchk_session_create_encryption_subconfigs[] = {
+ confchk_WT_SESSION_create_encryption_subconfigs[] = {
{ "keyid", "string", NULL, NULL, NULL, 0 },
{ "name", "string", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_file_meta[] = {
+static const WT_CONFIG_CHECK
+ confchk_WT_SESSION_create_lsm_subconfigs[] = {
+ { "auto_throttle", "boolean", NULL, NULL, NULL, 0 },
+ { "bloom", "boolean", NULL, NULL, NULL, 0 },
+ { "bloom_bit_count", "int", NULL, "min=2,max=1000", NULL, 0 },
+ { "bloom_config", "string", NULL, NULL, NULL, 0 },
+ { "bloom_hash_count", "int", NULL, "min=2,max=100", NULL, 0 },
+ { "bloom_oldest", "boolean", NULL, NULL, NULL, 0 },
+ { "chunk_count_limit", "int", NULL, NULL, NULL, 0 },
+ { "chunk_max", "int", NULL, "min=100MB,max=10TB", NULL, 0 },
+ { "chunk_size", "int", NULL, "min=512K,max=500MB", NULL, 0 },
+ { "merge_max", "int", NULL, "min=2,max=100", NULL, 0 },
+ { "merge_min", "int", NULL, "max=100", NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const WT_CONFIG_CHECK confchk_WT_SESSION_create[] = {
{ "allocation_size", "int",
NULL, "min=512B,max=128MB",
NULL, 0 },
@@ -169,17 +200,20 @@ static const WT_CONFIG_CHECK confchk_file_meta[] = {
__wt_compressor_confchk, NULL,
NULL, 0 },
{ "cache_resident", "boolean", NULL, NULL, NULL, 0 },
- { "checkpoint", "string", NULL, NULL, NULL, 0 },
- { "checkpoint_lsn", "string", NULL, NULL, NULL, 0 },
{ "checksum", "string",
NULL, "choices=[\"on\",\"off\",\"uncompressed\"]",
NULL, 0 },
+ { "colgroups", "list", NULL, NULL, NULL, 0 },
{ "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
{ "columns", "list", NULL, NULL, NULL, 0 },
{ "dictionary", "int", NULL, "min=0", NULL, 0 },
{ "encryption", "category",
NULL, NULL,
- confchk_session_create_encryption_subconfigs, 2 },
+ confchk_WT_SESSION_create_encryption_subconfigs, 2 },
+ { "exclusive", "boolean", NULL, NULL, NULL, 0 },
+ { "extractor", "string",
+ __wt_extractor_confchk, NULL,
+ NULL, 0 },
{ "format", "string", NULL, "choices=[\"btree\"]", NULL, 0 },
{ "huffman_key", "string",
__wt_huffman_confchk, NULL,
@@ -187,7 +221,7 @@ static const WT_CONFIG_CHECK confchk_file_meta[] = {
{ "huffman_value", "string",
__wt_huffman_confchk, NULL,
NULL, 0 },
- { "id", "string", NULL, NULL, NULL, 0 },
+ { "immutable", "boolean", NULL, NULL, NULL, 0 },
{ "internal_item_max", "int", NULL, "min=0", NULL, 0 },
{ "internal_key_max", "int", NULL, "min=0", NULL, 0 },
{ "internal_key_truncate", "boolean", NULL, NULL, NULL, 0 },
@@ -202,6 +236,9 @@ static const WT_CONFIG_CHECK confchk_file_meta[] = {
NULL, "min=512B,max=512MB",
NULL, 0 },
{ "leaf_value_max", "int", NULL, "min=0", NULL, 0 },
+ { "lsm", "category",
+ NULL, NULL,
+ confchk_WT_SESSION_create_lsm_subconfigs, 11 },
{ "memory_page_max", "int",
NULL, "min=512B,max=10TB",
NULL, 0 },
@@ -209,75 +246,74 @@ static const WT_CONFIG_CHECK confchk_file_meta[] = {
{ "os_cache_max", "int", NULL, "min=0", NULL, 0 },
{ "prefix_compression", "boolean", NULL, NULL, NULL, 0 },
{ "prefix_compression_min", "int", NULL, "min=0", NULL, 0 },
+ { "source", "string", NULL, NULL, NULL, 0 },
{ "split_deepen_min_child", "int", NULL, NULL, NULL, 0 },
{ "split_deepen_per_child", "int", NULL, NULL, NULL, 0 },
{ "split_pct", "int", NULL, "min=25,max=100", NULL, 0 },
+ { "type", "string", NULL, NULL, NULL, 0 },
{ "value_format", "format",
__wt_struct_confchk, NULL,
NULL, 0 },
- { "version", "string", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_index_meta[] = {
- { "app_metadata", "string", NULL, NULL, NULL, 0 },
- { "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
- { "columns", "list", NULL, NULL, NULL, 0 },
- { "extractor", "string",
- __wt_extractor_confchk, NULL,
+static const WT_CONFIG_CHECK confchk_WT_SESSION_drop[] = {
+ { "force", "boolean", NULL, NULL, NULL, 0 },
+ { "remove_files", "boolean", NULL, NULL, NULL, 0 },
+ { NULL, NULL, NULL, NULL, NULL, 0 }
+};
+
+static const WT_CONFIG_CHECK confchk_WT_SESSION_open_cursor[] = {
+ { "append", "boolean", NULL, NULL, NULL, 0 },
+ { "bulk", "string", NULL, NULL, NULL, 0 },
+ { "checkpoint", "string", NULL, NULL, NULL, 0 },
+ { "dump", "string",
+ NULL, "choices=[\"hex\",\"json\",\"print\"]",
NULL, 0 },
- { "immutable", "boolean", NULL, NULL, NULL, 0 },
- { "index_key_columns", "int", NULL, NULL, NULL, 0 },
- { "key_format", "format", __wt_struct_confchk, NULL, NULL, 0 },
- { "source", "string", NULL, NULL, NULL, 0 },
- { "type", "string", NULL, NULL, NULL, 0 },
- { "value_format", "format",
- __wt_struct_confchk, NULL,
+ { "next_random", "boolean", NULL, NULL, NULL, 0 },
+ { "overwrite", "boolean", NULL, NULL, NULL, 0 },
+ { "raw", "boolean", NULL, NULL, NULL, 0 },
+ { "readonly", "boolean", NULL, NULL, NULL, 0 },
+ { "skip_sort_check", "boolean", NULL, NULL, NULL, 0 },
+ { "statistics", "list",
+ NULL, "choices=[\"all\",\"fast\",\"clear\"]",
NULL, 0 },
+ { "target", "list", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_begin_transaction[] = {
+static const WT_CONFIG_CHECK confchk_WT_SESSION_reconfigure[] = {
{ "isolation", "string",
NULL, "choices=[\"read-uncommitted\",\"read-committed\","
"\"snapshot\"]",
NULL, 0 },
- { "name", "string", NULL, NULL, NULL, 0 },
- { "priority", "int", NULL, "min=-100,max=100", NULL, 0 },
- { "sync", "boolean", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_checkpoint[] = {
- { "drop", "list", NULL, NULL, NULL, 0 },
+static const WT_CONFIG_CHECK confchk_WT_SESSION_salvage[] = {
{ "force", "boolean", NULL, NULL, NULL, 0 },
- { "name", "string", NULL, NULL, NULL, 0 },
- { "target", "list", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_compact[] = {
- { "timeout", "int", NULL, NULL, NULL, 0 },
+static const WT_CONFIG_CHECK confchk_WT_SESSION_verify[] = {
+ { "dump_address", "boolean", NULL, NULL, NULL, 0 },
+ { "dump_blocks", "boolean", NULL, NULL, NULL, 0 },
+ { "dump_offsets", "list", NULL, NULL, NULL, 0 },
+ { "dump_pages", "boolean", NULL, NULL, NULL, 0 },
+ { "dump_shape", "boolean", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK
- confchk_session_create_lsm_subconfigs[] = {
- { "auto_throttle", "boolean", NULL, NULL, NULL, 0 },
- { "bloom", "boolean", NULL, NULL, NULL, 0 },
- { "bloom_bit_count", "int", NULL, "min=2,max=1000", NULL, 0 },
- { "bloom_config", "string", NULL, NULL, NULL, 0 },
- { "bloom_hash_count", "int", NULL, "min=2,max=100", NULL, 0 },
- { "bloom_oldest", "boolean", NULL, NULL, NULL, 0 },
- { "chunk_count_limit", "int", NULL, NULL, NULL, 0 },
- { "chunk_max", "int", NULL, "min=100MB,max=10TB", NULL, 0 },
- { "chunk_size", "int", NULL, "min=512K,max=500MB", NULL, 0 },
- { "merge_max", "int", NULL, "min=2,max=100", NULL, 0 },
- { "merge_min", "int", NULL, "max=100", NULL, 0 },
+static const WT_CONFIG_CHECK confchk_colgroup_meta[] = {
+ { "app_metadata", "string", NULL, NULL, NULL, 0 },
+ { "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
+ { "columns", "list", NULL, NULL, NULL, 0 },
+ { "source", "string", NULL, NULL, NULL, 0 },
+ { "type", "string", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_create[] = {
+static const WT_CONFIG_CHECK confchk_file_meta[] = {
{ "allocation_size", "int",
NULL, "min=512B,max=128MB",
NULL, 0 },
@@ -289,20 +325,17 @@ static const WT_CONFIG_CHECK confchk_session_create[] = {
__wt_compressor_confchk, NULL,
NULL, 0 },
{ "cache_resident", "boolean", NULL, NULL, NULL, 0 },
+ { "checkpoint", "string", NULL, NULL, NULL, 0 },
+ { "checkpoint_lsn", "string", NULL, NULL, NULL, 0 },
{ "checksum", "string",
NULL, "choices=[\"on\",\"off\",\"uncompressed\"]",
NULL, 0 },
- { "colgroups", "list", NULL, NULL, NULL, 0 },
{ "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
{ "columns", "list", NULL, NULL, NULL, 0 },
{ "dictionary", "int", NULL, "min=0", NULL, 0 },
{ "encryption", "category",
NULL, NULL,
- confchk_session_create_encryption_subconfigs, 2 },
- { "exclusive", "boolean", NULL, NULL, NULL, 0 },
- { "extractor", "string",
- __wt_extractor_confchk, NULL,
- NULL, 0 },
+ confchk_WT_SESSION_create_encryption_subconfigs, 2 },
{ "format", "string", NULL, "choices=[\"btree\"]", NULL, 0 },
{ "huffman_key", "string",
__wt_huffman_confchk, NULL,
@@ -310,7 +343,7 @@ static const WT_CONFIG_CHECK confchk_session_create[] = {
{ "huffman_value", "string",
__wt_huffman_confchk, NULL,
NULL, 0 },
- { "immutable", "boolean", NULL, NULL, NULL, 0 },
+ { "id", "string", NULL, NULL, NULL, 0 },
{ "internal_item_max", "int", NULL, "min=0", NULL, 0 },
{ "internal_key_max", "int", NULL, "min=0", NULL, 0 },
{ "internal_key_truncate", "boolean", NULL, NULL, NULL, 0 },
@@ -325,9 +358,6 @@ static const WT_CONFIG_CHECK confchk_session_create[] = {
NULL, "min=512B,max=512MB",
NULL, 0 },
{ "leaf_value_max", "int", NULL, "min=0", NULL, 0 },
- { "lsm", "category",
- NULL, NULL,
- confchk_session_create_lsm_subconfigs, 11 },
{ "memory_page_max", "int",
NULL, "min=512B,max=10TB",
NULL, 0 },
@@ -335,64 +365,34 @@ static const WT_CONFIG_CHECK confchk_session_create[] = {
{ "os_cache_max", "int", NULL, "min=0", NULL, 0 },
{ "prefix_compression", "boolean", NULL, NULL, NULL, 0 },
{ "prefix_compression_min", "int", NULL, "min=0", NULL, 0 },
- { "source", "string", NULL, NULL, NULL, 0 },
{ "split_deepen_min_child", "int", NULL, NULL, NULL, 0 },
{ "split_deepen_per_child", "int", NULL, NULL, NULL, 0 },
{ "split_pct", "int", NULL, "min=25,max=100", NULL, 0 },
- { "type", "string", NULL, NULL, NULL, 0 },
{ "value_format", "format",
__wt_struct_confchk, NULL,
NULL, 0 },
+ { "version", "string", NULL, NULL, NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_drop[] = {
- { "force", "boolean", NULL, NULL, NULL, 0 },
- { "remove_files", "boolean", NULL, NULL, NULL, 0 },
- { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const WT_CONFIG_CHECK confchk_session_open_cursor[] = {
- { "append", "boolean", NULL, NULL, NULL, 0 },
- { "bulk", "string", NULL, NULL, NULL, 0 },
- { "checkpoint", "string", NULL, NULL, NULL, 0 },
- { "dump", "string",
- NULL, "choices=[\"hex\",\"json\",\"print\"]",
- NULL, 0 },
- { "next_random", "boolean", NULL, NULL, NULL, 0 },
- { "overwrite", "boolean", NULL, NULL, NULL, 0 },
- { "raw", "boolean", NULL, NULL, NULL, 0 },
- { "readonly", "boolean", NULL, NULL, NULL, 0 },
- { "skip_sort_check", "boolean", NULL, NULL, NULL, 0 },
- { "statistics", "list",
- NULL, "choices=[\"all\",\"fast\",\"clear\"]",
+static const WT_CONFIG_CHECK confchk_index_meta[] = {
+ { "app_metadata", "string", NULL, NULL, NULL, 0 },
+ { "collator", "string", __wt_collator_confchk, NULL, NULL, 0 },
+ { "columns", "list", NULL, NULL, NULL, 0 },
+ { "extractor", "string",
+ __wt_extractor_confchk, NULL,
NULL, 0 },
- { "target", "list", NULL, NULL, NULL, 0 },
- { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const WT_CONFIG_CHECK confchk_session_reconfigure[] = {
- { "isolation", "string",
- NULL, "choices=[\"read-uncommitted\",\"read-committed\","
- "\"snapshot\"]",
+ { "immutable", "boolean", NULL, NULL, NULL, 0 },
+ { "index_key_columns", "int", NULL, NULL, NULL, 0 },
+ { "key_format", "format", __wt_struct_confchk, NULL, NULL, 0 },
+ { "source", "string", NULL, NULL, NULL, 0 },
+ { "type", "string", NULL, NULL, NULL, 0 },
+ { "value_format", "format",
+ __wt_struct_confchk, NULL,
NULL, 0 },
{ NULL, NULL, NULL, NULL, NULL, 0 }
};
-static const WT_CONFIG_CHECK confchk_session_salvage[] = {
- { "force", "boolean", NULL, NULL, NULL, 0 },
- { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
-static const WT_CONFIG_CHECK confchk_session_verify[] = {
- { "dump_address", "boolean", NULL, NULL, NULL, 0 },
- { "dump_blocks", "boolean", NULL, NULL, NULL, 0 },
- { "dump_offsets", "list", NULL, NULL, NULL, 0 },
- { "dump_pages", "boolean", NULL, NULL, NULL, 0 },
- { "dump_shape", "boolean", NULL, NULL, NULL, 0 },
- { NULL, NULL, NULL, NULL, NULL, 0 }
-};
-
static const WT_CONFIG_CHECK confchk_table_meta[] = {
{ "app_metadata", "string", NULL, NULL, NULL, 0 },
{ "colgroups", "list", NULL, NULL, NULL, 0 },
@@ -715,48 +715,44 @@ static const WT_CONFIG_CHECK confchk_wiredtiger_open_usercfg[] = {
};
static const WT_CONFIG_ENTRY config_entries[] = {
- { "colgroup.meta",
- "app_metadata=,collator=,columns=,source=,type=file",
- confchk_colgroup_meta, 5
- },
- { "connection.add_collator",
+ { "WT_CONNECTION.add_collator",
"",
NULL, 0
},
- { "connection.add_compressor",
+ { "WT_CONNECTION.add_compressor",
"",
NULL, 0
},
- { "connection.add_data_source",
+ { "WT_CONNECTION.add_data_source",
"",
NULL, 0
},
- { "connection.add_encryptor",
+ { "WT_CONNECTION.add_encryptor",
"",
NULL, 0
},
- { "connection.add_extractor",
+ { "WT_CONNECTION.add_extractor",
"",
NULL, 0
},
- { "connection.async_new_op",
+ { "WT_CONNECTION.async_new_op",
"append=0,overwrite=,raw=0,timeout=1200",
- confchk_connection_async_new_op, 4
+ confchk_WT_CONNECTION_async_new_op, 4
},
- { "connection.close",
+ { "WT_CONNECTION.close",
"leak_memory=0",
- confchk_connection_close, 1
+ confchk_WT_CONNECTION_close, 1
},
- { "connection.load_extension",
+ { "WT_CONNECTION.load_extension",
"config=,entry=wiredtiger_extension_init,"
"terminate=wiredtiger_extension_terminate",
- confchk_connection_load_extension, 3
+ confchk_WT_CONNECTION_load_extension, 3
},
- { "connection.open_session",
+ { "WT_CONNECTION.open_session",
"isolation=read-committed",
- confchk_connection_open_session, 1
+ confchk_WT_CONNECTION_open_session, 1
},
- { "connection.reconfigure",
+ { "WT_CONNECTION.reconfigure",
"async=(enabled=0,ops_max=1024,threads=2),cache_overhead=8,"
"cache_size=100MB,checkpoint=(log_size=0,"
"name=\"WiredTigerCheckpoint\",wait=0),error_prefix=,"
@@ -768,56 +764,37 @@ static const WT_CONFIG_ENTRY config_entries[] = {
",statistics=none,statistics_log=(on_close=0,"
"path=\"WiredTigerStat.%d.%H\",sources=,"
"timestamp=\"%b %d %H:%M:%S\",wait=0),verbose=",
- confchk_connection_reconfigure, 16
+ confchk_WT_CONNECTION_reconfigure, 16
},
- { "cursor.close",
+ { "WT_CURSOR.close",
"",
NULL, 0
},
- { "cursor.reconfigure",
+ { "WT_CURSOR.reconfigure",
"append=0,overwrite=",
- confchk_cursor_reconfigure, 2
- },
- { "file.meta",
- "allocation_size=4KB,app_metadata=,block_allocation=best,"
- "block_compressor=,cache_resident=0,checkpoint=,checkpoint_lsn=,"
- "checksum=uncompressed,collator=,columns=,dictionary=0,"
- "encryption=(keyid=,name=),format=btree,huffman_key=,"
- "huffman_value=,id=,internal_item_max=0,internal_key_max=0,"
- "internal_key_truncate=,internal_page_max=4KB,key_format=u,"
- "key_gap=10,leaf_item_max=0,leaf_key_max=0,leaf_page_max=32KB,"
- "leaf_value_max=0,memory_page_max=5MB,os_cache_dirty_max=0,"
- "os_cache_max=0,prefix_compression=0,prefix_compression_min=4,"
- "split_deepen_min_child=0,split_deepen_per_child=0,split_pct=75,"
- "value_format=u,version=(major=0,minor=0)",
- confchk_file_meta, 36
+ confchk_WT_CURSOR_reconfigure, 2
},
- { "index.meta",
- "app_metadata=,collator=,columns=,extractor=,immutable=0,"
- "index_key_columns=,key_format=u,source=,type=file,value_format=u",
- confchk_index_meta, 10
- },
- { "session.begin_transaction",
+ { "WT_SESSION.begin_transaction",
"isolation=,name=,priority=0,sync=",
- confchk_session_begin_transaction, 4
+ confchk_WT_SESSION_begin_transaction, 4
},
- { "session.checkpoint",
+ { "WT_SESSION.checkpoint",
"drop=,force=0,name=,target=",
- confchk_session_checkpoint, 4
+ confchk_WT_SESSION_checkpoint, 4
},
- { "session.close",
+ { "WT_SESSION.close",
"",
NULL, 0
},
- { "session.commit_transaction",
+ { "WT_SESSION.commit_transaction",
"",
NULL, 0
},
- { "session.compact",
+ { "WT_SESSION.compact",
"timeout=1200",
- confchk_session_compact, 1
+ confchk_WT_SESSION_compact, 1
},
- { "session.create",
+ { "WT_SESSION.create",
"allocation_size=4KB,app_metadata=,block_allocation=best,"
"block_compressor=,cache_resident=0,checksum=uncompressed,"
"colgroups=,collator=,columns=,dictionary=0,encryption=(keyid=,"
@@ -832,53 +809,76 @@ static const WT_CONFIG_ENTRY config_entries[] = {
"os_cache_dirty_max=0,os_cache_max=0,prefix_compression=0,"
"prefix_compression_min=4,source=,split_deepen_min_child=0,"
"split_deepen_per_child=0,split_pct=75,type=file,value_format=u",
- confchk_session_create, 39
+ confchk_WT_SESSION_create, 39
},
- { "session.drop",
+ { "WT_SESSION.drop",
"force=0,remove_files=",
- confchk_session_drop, 2
+ confchk_WT_SESSION_drop, 2
},
- { "session.log_printf",
+ { "WT_SESSION.log_printf",
"",
NULL, 0
},
- { "session.open_cursor",
+ { "WT_SESSION.open_cursor",
"append=0,bulk=0,checkpoint=,dump=,next_random=0,overwrite=,raw=0"
",readonly=0,skip_sort_check=0,statistics=,target=",
- confchk_session_open_cursor, 11
+ confchk_WT_SESSION_open_cursor, 11
},
- { "session.reconfigure",
+ { "WT_SESSION.reconfigure",
"isolation=read-committed",
- confchk_session_reconfigure, 1
+ confchk_WT_SESSION_reconfigure, 1
},
- { "session.rename",
+ { "WT_SESSION.rename",
"",
NULL, 0
},
- { "session.rollback_transaction",
+ { "WT_SESSION.rollback_transaction",
"",
NULL, 0
},
- { "session.salvage",
+ { "WT_SESSION.salvage",
"force=0",
- confchk_session_salvage, 1
+ confchk_WT_SESSION_salvage, 1
},
- { "session.strerror",
+ { "WT_SESSION.strerror",
"",
NULL, 0
},
- { "session.truncate",
+ { "WT_SESSION.truncate",
"",
NULL, 0
},
- { "session.upgrade",
+ { "WT_SESSION.upgrade",
"",
NULL, 0
},
- { "session.verify",
+ { "WT_SESSION.verify",
"dump_address=0,dump_blocks=0,dump_offsets=,dump_pages=0,"
"dump_shape=0",
- confchk_session_verify, 5
+ confchk_WT_SESSION_verify, 5
+ },
+ { "colgroup.meta",
+ "app_metadata=,collator=,columns=,source=,type=file",
+ confchk_colgroup_meta, 5
+ },
+ { "file.meta",
+ "allocation_size=4KB,app_metadata=,block_allocation=best,"
+ "block_compressor=,cache_resident=0,checkpoint=,checkpoint_lsn=,"
+ "checksum=uncompressed,collator=,columns=,dictionary=0,"
+ "encryption=(keyid=,name=),format=btree,huffman_key=,"
+ "huffman_value=,id=,internal_item_max=0,internal_key_max=0,"
+ "internal_key_truncate=,internal_page_max=4KB,key_format=u,"
+ "key_gap=10,leaf_item_max=0,leaf_key_max=0,leaf_page_max=32KB,"
+ "leaf_value_max=0,memory_page_max=5MB,os_cache_dirty_max=0,"
+ "os_cache_max=0,prefix_compression=0,prefix_compression_min=4,"
+ "split_deepen_min_child=0,split_deepen_per_child=0,split_pct=75,"
+ "value_format=u,version=(major=0,minor=0)",
+ confchk_file_meta, 36
+ },
+ { "index.meta",
+ "app_metadata=,collator=,columns=,extractor=,immutable=0,"
+ "index_key_columns=,key_format=u,source=,type=file,value_format=u",
+ confchk_index_meta, 10
},
{ "table.meta",
"app_metadata=,colgroups=,collator=,columns=,key_format=u,"
@@ -976,8 +976,7 @@ __wt_conn_config_init(WT_SESSION_IMPL *session)
conn = S2C(session);
/* Build a list of pointers to the configuration information. */
- WT_RET(__wt_calloc_def(session,
- sizeof(config_entries) / sizeof(config_entries[0]), &epp));
+ WT_RET(__wt_calloc_def(session, WT_ELEMENTS(config_entries), &epp));
conn->config_entries = epp;
/* Fill in the list to reference the default information. */
@@ -998,3 +997,18 @@ __wt_conn_config_discard(WT_SESSION_IMPL *session)
__wt_free(session, conn->config_entries);
}
+
+/*
+ * __wt_conn_config_match --
+ * Return the static configuration entry for a method.
+ */
+const WT_CONFIG_ENTRY *
+__wt_conn_config_match(const char *method)
+{
+ const WT_CONFIG_ENTRY *ep;
+
+ for (ep = config_entries; ep->method != NULL; ++ep)
+ if (strcmp(method, ep->method) == 0)
+ return (ep);
+ return (NULL);
+}
diff --git a/src/conn/conn_dhandle.c b/src/conn/conn_dhandle.c
index 6c03bdb20ae..60e7c41f76d 100644
--- a/src/conn/conn_dhandle.c
+++ b/src/conn/conn_dhandle.c
@@ -74,16 +74,19 @@ __conn_dhandle_open_lock(
*
* Wait for a read lock if we want exclusive access and failed
* to get it: the sweep server may be closing this handle, and
- * we need to wait for it to complete. If we want exclusive
- * access and find the handle open once we get the read lock,
- * give up: some other thread has it locked for real.
+ * we need to wait for it to release its lock. If we want
+ * exclusive access and find the handle open once we get the
+ * read lock, give up: some other thread has it locked for real.
*/
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
(!want_exclusive || lock_busy)) {
WT_RET(__wt_readlock(session, dhandle->rwlock));
is_open = F_ISSET(dhandle, WT_DHANDLE_OPEN) ? 1 : 0;
- if (is_open && !want_exclusive)
+ if (is_open && !want_exclusive) {
+ WT_ASSERT(session,
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
+ }
WT_RET(__wt_readunlock(session, dhandle->rwlock));
} else
is_open = 0;
@@ -109,6 +112,7 @@ __conn_dhandle_open_lock(
/* We have an exclusive lock, we're done. */
F_SET(dhandle, WT_DHANDLE_EXCLUSIVE);
+ WT_ASSERT(session, !F_ISSET(dhandle, WT_DHANDLE_DEAD));
return (0);
} else if (ret != EBUSY || (is_open && want_exclusive))
return (ret);
@@ -143,20 +147,26 @@ __wt_conn_dhandle_find(WT_SESSION_IMPL *session,
bucket = __wt_hash_city64(name, strlen(name)) % WT_HASH_ARRAY_SIZE;
if (ckpt == NULL) {
- SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl)
+ SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD))
+ continue;
if (dhandle->checkpoint == NULL &&
strcmp(name, dhandle->name) == 0) {
session->dhandle = dhandle;
return (0);
}
+ }
} else
- SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl)
+ SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD))
+ continue;
if (dhandle->checkpoint != NULL &&
strcmp(name, dhandle->name) == 0 &&
strcmp(ckpt, dhandle->checkpoint) == 0) {
session->dhandle = dhandle;
return (0);
}
+ }
return (WT_NOTFOUND);
}
@@ -238,6 +248,30 @@ err: WT_TRET(__wt_rwlock_destroy(session, &dhandle->rwlock));
}
/*
+ * __conn_dhandle_mark_dead --
+ * Mark a data handle dead.
+ */
+static int
+__conn_dhandle_mark_dead(WT_SESSION_IMPL *session)
+{
+ int evict_reset;
+
+ WT_ASSERT(session, F_ISSET(session, WT_SESSION_HANDLE_LIST_LOCKED));
+
+ /*
+ * Handle forced discard (e.g., when dropping a file).
+ *
+ * We need exclusive access to the file -- disable ordinary
+ * eviction and drain any blocks already queued.
+ */
+ WT_RET(__wt_evict_file_exclusive_on(session, &evict_reset));
+ F_SET(session->dhandle, WT_DHANDLE_DEAD);
+ if (evict_reset)
+ __wt_evict_file_exclusive_off(session);
+ return (0);
+}
+
+/*
* __wt_conn_btree_sync_and_close --
* Sync and close the underlying btree handle.
*/
@@ -278,16 +312,25 @@ __wt_conn_btree_sync_and_close(WT_SESSION_IMPL *session, int final, int force)
/*
* The close can fail if an update cannot be written, return the EBUSY
* error to our caller for eventual retry.
+ *
+ * If we are forcing the close, just mark the handle dead and the tree
+ * will be discarded later. Don't do this for memory-mapped trees: we
+ * have to close the file handle to allow the file to be removed, but
+ * memory mapped trees contain pointers into memory that will become
+ * invalid if the mapping is closed.
*/
if (!F_ISSET(btree,
WT_BTREE_SALVAGE | WT_BTREE_UPGRADE | WT_BTREE_VERIFY))
- WT_ERR(__wt_checkpoint_close(session, final, force));
-
- if (dhandle->checkpoint == NULL)
- --S2C(session)->open_btree_count;
+ WT_ERR(force && (btree->bm == NULL || btree->bm->map == NULL) ?
+ __conn_dhandle_mark_dead(session) :
+ __wt_checkpoint_close(session, final));
WT_TRET(__wt_btree_close(session));
- F_CLR(dhandle, WT_DHANDLE_OPEN);
+ if (!force || final) {
+ F_CLR(dhandle, WT_DHANDLE_OPEN);
+ if (dhandle->checkpoint == NULL)
+ --S2C(session)->open_btree_count;
+ }
F_CLR(btree, WT_BTREE_SPECIAL_FLAGS);
err: __wt_spin_unlock(session, &dhandle->close_lock);
@@ -529,6 +572,7 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session,
__wt_hash_city64(uri, strlen(uri)) % WT_HASH_ARRAY_SIZE;
SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl)
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD) &&
strcmp(uri, dhandle->name) == 0 &&
(apply_checkpoints || dhandle->checkpoint == NULL))
WT_RET(__conn_btree_apply_internal(
@@ -536,6 +580,7 @@ __wt_conn_btree_apply(WT_SESSION_IMPL *session,
} else {
SLIST_FOREACH(dhandle, &conn->dhlh, l)
if (F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD) &&
(apply_checkpoints ||
dhandle->checkpoint == NULL) &&
WT_PREFIX_MATCH(dhandle->name, "file:") &&
@@ -658,7 +703,8 @@ __wt_conn_dhandle_close_all(
bucket = __wt_hash_city64(name, strlen(name)) % WT_HASH_ARRAY_SIZE;
SLIST_FOREACH(dhandle, &conn->dhhash[bucket], hashl) {
- if (strcmp(dhandle->name, name) != 0)
+ if (strcmp(dhandle->name, name) != 0 ||
+ F_ISSET(dhandle, WT_DHANDLE_DEAD))
continue;
session->dhandle = dhandle;
@@ -730,7 +776,7 @@ __conn_dhandle_remove(WT_SESSION_IMPL *session, int final)
* Close/discard a single data handle.
*/
int
-__wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)
+__wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final, int force)
{
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
@@ -738,8 +784,9 @@ __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final)
dhandle = session->dhandle;
- if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
- tret = __wt_conn_btree_sync_and_close(session, final, 0);
+ if (F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ (final && F_ISSET(dhandle, WT_DHANDLE_DEAD))) {
+ tret = __wt_conn_btree_sync_and_close(session, final, force);
if (final && tret != 0) {
__wt_err(session, tret,
"Final close of %s failed", dhandle->name);
@@ -803,7 +850,7 @@ restart:
continue;
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(session, 1)));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, 1, 0)));
goto restart;
}
@@ -819,7 +866,7 @@ restart:
/* Close the metadata file handle. */
while ((dhandle = SLIST_FIRST(&conn->dhlh)) != NULL)
WT_WITH_DHANDLE(session, dhandle,
- WT_TRET(__wt_conn_dhandle_discard_single(session, 1)));
+ WT_TRET(__wt_conn_dhandle_discard_single(session, 1, 0)));
return (ret);
}
diff --git a/src/conn/conn_log.c b/src/conn/conn_log.c
index 82acc4a99d2..7b78cb16f51 100644
--- a/src/conn/conn_log.c
+++ b/src/conn/conn_log.c
@@ -344,18 +344,13 @@ typedef struct {
} WT_LOG_WRLSN_ENTRY;
/*
- * __log_wrlsn_cmp --
- * The log wrlsn comparison function for qsort.
+ * WT_WRLSN_ENTRY_CMP_LT --
+ * Return comparison of a written slot pair by LSN.
*/
-static int WT_CDECL
-__log_wrlsn_cmp(const void *a, const void *b)
-{
- WT_LOG_WRLSN_ENTRY *ae, *be;
-
- ae = (WT_LOG_WRLSN_ENTRY *)a;
- be = (WT_LOG_WRLSN_ENTRY *)b;
- return (LOG_CMP(&ae->lsn, &be->lsn));
-}
+#define WT_WRLSN_ENTRY_CMP_LT(entry1, entry2) \
+ ((entry1).lsn.file < (entry2).lsn.file || \
+ ((entry1).lsn.file == (entry2).lsn.file && \
+ (entry1).lsn.offset < (entry2).lsn.offset))
/*
* __log_wrlsn_server --
@@ -404,15 +399,16 @@ __log_wrlsn_server(void *arg)
*/
if (written_i > 0) {
yield = 0;
- qsort(written, written_i, sizeof(WT_LOG_WRLSN_ENTRY),
- __log_wrlsn_cmp);
+ WT_INSERTION_SORT(written, written_i,
+ WT_LOG_WRLSN_ENTRY, WT_WRLSN_ENTRY_CMP_LT);
+
/*
* We know the written array is sorted by LSN. Go
* through them either advancing write_lsn or stop
* as soon as one is not in order.
*/
for (i = 0; i < written_i; i++) {
- if (LOG_CMP(&log->write_lsn,
+ if (WT_LOG_CMP(&log->write_lsn,
&written[i].lsn) != 0)
break;
/*
@@ -420,7 +416,7 @@ __log_wrlsn_server(void *arg)
* Advance the LSN and process the slot.
*/
slot = &log->slot_pool[written[i].slot_index];
- WT_ASSERT(session, LOG_CMP(&written[i].lsn,
+ WT_ASSERT(session, WT_LOG_CMP(&written[i].lsn,
&slot->slot_release_lsn) == 0);
log->write_start_lsn = slot->slot_start_lsn;
log->write_lsn = slot->slot_end_lsn;
diff --git a/src/conn/conn_stat.c b/src/conn/conn_stat.c
index 823f7626e09..647e4b02abb 100644
--- a/src/conn/conn_stat.c
+++ b/src/conn/conn_stat.c
@@ -142,7 +142,7 @@ __statlog_dump(WT_SESSION_IMPL *session, const char *name, int conn_stats)
uint64_t max;
const char *uri;
const char *cfg[] = {
- WT_CONFIG_BASE(session, session_open_cursor), NULL };
+ WT_CONFIG_BASE(session, WT_SESSION_open_cursor), NULL };
conn = S2C(session);
diff --git a/src/conn/conn_sweep.c b/src/conn/conn_sweep.c
index 46f40a6fefd..fc29e0b2e15 100644
--- a/src/conn/conn_sweep.c
+++ b/src/conn/conn_sweep.c
@@ -9,104 +9,87 @@
#include "wt_internal.h"
/*
- * __sweep_remove_handles --
- * Remove closed dhandles from the connection list.
+ * __sweep_mark --
+ * Mark idle handles with a time of death, and note if we see dead
+ * handles.
*/
static int
-__sweep_remove_handles(WT_SESSION_IMPL *session)
+__sweep_mark(WT_SESSION_IMPL *session, int *dead_handlesp)
{
WT_CONNECTION_IMPL *conn;
- WT_DATA_HANDLE *dhandle, *dhandle_next;
- WT_DECL_RET;
+ WT_DATA_HANDLE *dhandle;
+ time_t now;
conn = S2C(session);
- dhandle = SLIST_FIRST(&conn->dhlh);
+ *dead_handlesp = 0;
- for (; dhandle != NULL; dhandle = dhandle_next) {
- dhandle_next = SLIST_NEXT(dhandle, l);
+ /* Don't discard handles that have been open recently. */
+ WT_RET(__wt_seconds(session, &now));
+
+ WT_STAT_FAST_CONN_INCR(session, dh_conn_sweeps);
+ SLIST_FOREACH(dhandle, &conn->dhlh, l) {
if (WT_IS_METADATA(dhandle))
continue;
- if (F_ISSET(dhandle, WT_DHANDLE_OPEN))
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD)) {
+ ++*dead_handlesp;
continue;
-
- /* Make sure we get exclusive access. */
- if ((ret =
- __wt_try_writelock(session, dhandle->rwlock)) == EBUSY)
+ }
+ if (dhandle->session_inuse != 0 ||
+ now <= dhandle->timeofdeath + conn->sweep_idle_time)
continue;
- WT_RET(ret);
-
- /*
- * If there are no longer any references to the handle in any
- * sessions, attempt to discard it.
- */
- if (F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
- dhandle->session_inuse != 0 || dhandle->session_ref != 0) {
- WT_RET(__wt_writeunlock(session, dhandle->rwlock));
+ if (dhandle->timeofdeath == 0) {
+ dhandle->timeofdeath = now;
+ WT_STAT_FAST_CONN_INCR(session, dh_conn_tod);
continue;
}
- WT_WITH_DHANDLE(session, dhandle,
- ret = __wt_conn_dhandle_discard_single(session, 0));
-
- /* If the handle was not successfully discarded, unlock it. */
- if (ret != 0)
- WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
- WT_RET_BUSY_OK(ret);
- WT_STAT_FAST_CONN_INCR(session, dh_conn_ref);
+ /* We now have a candidate to close. */
+ ++*dead_handlesp;
}
- return (ret == EBUSY ? 0 : ret);
+ return (0);
}
/*
- * __sweep --
- * Close unused dhandles on the connection dhandle list.
+ * __sweep_expire --
+ * Mark trees dead if they are clean and haven't been accessed recently,
+ * until we have reached the configured minimum number of handles.
*/
static int
-__sweep(WT_SESSION_IMPL *session)
+__sweep_expire(WT_SESSION_IMPL *session)
{
WT_BTREE *btree;
WT_CONNECTION_IMPL *conn;
WT_DATA_HANDLE *dhandle;
WT_DECL_RET;
time_t now;
- int closed_handles;
conn = S2C(session);
- closed_handles = 0;
/* Don't discard handles that have been open recently. */
WT_RET(__wt_seconds(session, &now));
WT_STAT_FAST_CONN_INCR(session, dh_conn_sweeps);
SLIST_FOREACH(dhandle, &conn->dhlh, l) {
+ /*
+ * Ignore open files once the open file count reaches the
+ * minimum number of handles.
+ */
+ if (conn->open_file_count < conn->sweep_handles_min)
+ break;
+
if (WT_IS_METADATA(dhandle))
continue;
-
- if (!F_ISSET(dhandle, WT_DHANDLE_OPEN) &&
- dhandle->session_inuse == 0 && dhandle->session_ref == 0) {
- ++closed_handles;
+ if (!F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ F_ISSET(dhandle, WT_DHANDLE_DEAD))
continue;
- }
if (dhandle->session_inuse != 0 ||
now <= dhandle->timeofdeath + conn->sweep_idle_time)
continue;
- if (dhandle->timeofdeath == 0) {
- dhandle->timeofdeath = now;
- WT_STAT_FAST_CONN_INCR(session, dh_conn_tod);
- continue;
- }
-
- /*
- * Ignore in-use files once the open file count reaches the
- * minimum number of handles.
- */
- if (conn->open_file_count < conn->sweep_handles_min)
- continue;
/*
* We have a candidate for closing; if it's open, acquire an
- * exclusive lock on the handle and close it.
+ * exclusive lock on the handle and mark it dead.
*
* The close would require I/O if an update cannot be written
* (updates in a no-longer-referenced file might not yet be
@@ -115,8 +98,10 @@ __sweep(WT_SESSION_IMPL *session)
* next time, after the transaction state has progressed.
*
* We don't set WT_DHANDLE_EXCLUSIVE deliberately, we want
- * opens to block on us rather than returning an EBUSY error to
- * the application.
+ * opens to block on us and then retry rather than returning an
+ * EBUSY error to the application. This is done holding the
+ * handle list lock so that connection-level handle searches
+ * never need to retry.
*/
if ((ret =
__wt_try_writelock(session, dhandle->rwlock)) == EBUSY)
@@ -129,31 +114,103 @@ __sweep(WT_SESSION_IMPL *session)
!__wt_txn_visible_all(session, btree->rec_max_txn))
goto unlock;
- /* If the handle is open, try to close it. */
- if (F_ISSET(dhandle, WT_DHANDLE_OPEN)) {
- WT_WITH_DHANDLE(session, dhandle, ret =
- __wt_conn_btree_sync_and_close(session, 0, 0));
+ /*
+ * Mark the handle as dead and close the underlying file
+ * handle. Closing the handle decrements the open file count,
+ * meaning the close loop won't overrun the configured minimum.
+ */
+ WT_WITH_DHANDLE(session, dhandle, ret =
+ __wt_conn_btree_sync_and_close(session, 0, 1));
- /* We closed the btree handle, bump the statistic. */
- if (ret == 0)
- WT_STAT_FAST_CONN_INCR(
- session, dh_conn_handles);
- }
+unlock: WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
+ WT_RET_BUSY_OK(ret);
+ }
- if (dhandle->session_inuse == 0 && dhandle->session_ref == 0)
- ++closed_handles;
+ return (0);
+}
+/*
+ * __sweep_flush --
+ * Flush pages from dead trees.
+ */
+static int
+__sweep_flush(WT_SESSION_IMPL *session)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DATA_HANDLE *dhandle;
+ WT_DECL_RET;
+
+ conn = S2C(session);
+
+ WT_STAT_FAST_CONN_INCR(session, dh_conn_sweeps);
+ SLIST_FOREACH(dhandle, &conn->dhlh, l) {
+ if (!F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ !F_ISSET(dhandle, WT_DHANDLE_DEAD))
+ continue;
+
+ /* If the handle is marked "dead", flush it from cache. */
+ WT_WITH_DHANDLE(session, dhandle, ret =
+ __wt_conn_btree_sync_and_close(session, 0, 0));
+
+ /* We closed the btree handle, bump the statistic. */
+ if (ret == 0)
+ WT_STAT_FAST_CONN_INCR(session, dh_conn_handles);
-unlock: WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
WT_RET_BUSY_OK(ret);
}
- if (closed_handles) {
- WT_WITH_DHANDLE_LOCK(session,
- ret = __sweep_remove_handles(session));
+ return (0);
+}
+
+/*
+ * __sweep_remove_handles --
+ * Remove closed dhandles from the connection list.
+ */
+static int
+__sweep_remove_handles(WT_SESSION_IMPL *session)
+{
+ WT_CONNECTION_IMPL *conn;
+ WT_DATA_HANDLE *dhandle, *dhandle_next;
+ WT_DECL_RET;
+
+ conn = S2C(session);
+ dhandle = SLIST_FIRST(&conn->dhlh);
+
+ for (; dhandle != NULL; dhandle = dhandle_next) {
+ dhandle_next = SLIST_NEXT(dhandle, l);
+ if (WT_IS_METADATA(dhandle))
+ continue;
+ if (F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ dhandle->session_inuse != 0 ||
+ dhandle->session_ref != 0)
+ continue;
+
+ /* Make sure we get exclusive access. */
+ if ((ret =
+ __wt_try_writelock(session, dhandle->rwlock)) == EBUSY)
+ continue;
WT_RET(ret);
+
+ /*
+ * If there are no longer any references to the handle in any
+ * sessions, attempt to discard it.
+ */
+ if (F_ISSET(dhandle, WT_DHANDLE_OPEN) ||
+ dhandle->session_inuse != 0 || dhandle->session_ref != 0) {
+ WT_RET(__wt_writeunlock(session, dhandle->rwlock));
+ continue;
+ }
+
+ WT_WITH_DHANDLE(session, dhandle,
+ ret = __wt_conn_dhandle_discard_single(session, 0, 1));
+
+ /* If the handle was not successfully discarded, unlock it. */
+ if (ret != 0)
+ WT_TRET(__wt_writeunlock(session, dhandle->rwlock));
+ WT_RET_BUSY_OK(ret);
+ WT_STAT_FAST_CONN_INCR(session, dh_conn_ref);
}
- return (0);
+ return (ret == EBUSY ? 0 : ret);
}
/*
@@ -166,12 +223,13 @@ __sweep_server(void *arg)
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
WT_SESSION_IMPL *session;
+ int dead_handles;
session = arg;
conn = S2C(session);
/*
- * Sweep for dead handles.
+ * Sweep for dead and excess handles.
*/
while (F_ISSET(conn, WT_CONN_SERVER_RUN) &&
F_ISSET(conn, WT_CONN_SERVER_SWEEP)) {
@@ -179,8 +237,28 @@ __sweep_server(void *arg)
WT_ERR(__wt_cond_wait(session, conn->sweep_cond,
(uint64_t)conn->sweep_interval * WT_MILLION));
- /* Sweep the handles. */
- WT_ERR(__sweep(session));
+ /*
+ * Mark handles with a time of death, and report whether any
+ * handles are marked dead.
+ */
+ WT_ERR(__sweep_mark(session, &dead_handles));
+
+ if (dead_handles == 0 &&
+ conn->open_file_count < conn->sweep_handles_min)
+ continue;
+
+ /* Close handles if we have reached the configured limit */
+ if (conn->open_file_count >= conn->sweep_handles_min) {
+ WT_WITH_DHANDLE_LOCK(session,
+ ret = __sweep_expire(session));
+ WT_ERR(ret);
+ }
+
+ WT_ERR(__sweep_flush(session));
+
+ WT_WITH_DHANDLE_LOCK(session,
+ ret = __sweep_remove_handles(session));
+ WT_ERR(ret);
}
if (0) {
diff --git a/src/cursor/cur_dump.c b/src/cursor/cur_dump.c
index 00281054d22..ae608959f15 100644
--- a/src/cursor/cur_dump.c
+++ b/src/cursor/cur_dump.c
@@ -392,7 +392,7 @@ __wt_curdump_create(WT_CURSOR *child, WT_CURSOR *owner, WT_CURSOR **cursorp)
}
/* __wt_cursor_init is last so we don't have to clean up on error. */
- cfg[0] = WT_CONFIG_BASE(session, session_open_cursor);
+ cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_open_cursor);
cfg[1] = NULL;
WT_ERR(__wt_cursor_init(cursor, NULL, owner, cfg, cursorp));
diff --git a/src/cursor/cur_log.c b/src/cursor/cur_log.c
index 7249167009f..090910ca38a 100644
--- a/src/cursor/cur_log.c
+++ b/src/cursor/cur_log.c
@@ -74,7 +74,7 @@ __curlog_compare(WT_CURSOR *a, WT_CURSOR *b, int *cmpp)
acl = (WT_CURSOR_LOG *)a;
bcl = (WT_CURSOR_LOG *)b;
WT_ASSERT(session, cmpp != NULL);
- *cmpp = LOG_CMP(acl->cur_lsn, bcl->cur_lsn);
+ *cmpp = WT_LOG_CMP(acl->cur_lsn, bcl->cur_lsn);
/*
* If both are on the same LSN, compare step counter.
*/
diff --git a/src/docs/command-line.dox b/src/docs/command-line.dox
index 50850d5297b..af0ea3c5bb9 100644
--- a/src/docs/command-line.dox
+++ b/src/docs/command-line.dox
@@ -194,12 +194,34 @@ load command to fail if there's an attempt to overwrite already existing
data.
@par <code>-r</code>
-By default, the \c load command uses the table or file name taken from
-the input; the \c -r option renames the data source.
+By default, the \c load command uses the table or file name taken from the
+input; the \c -r option renames the data source.
Additionally, \c uri and \c configuration pairs may be specified to the
-\c load command. Each of these pairs will be appended to the configuration
-string from the dump header passed to the WT_SESSION::create call.
+\c load command. These configuration pairs can be used to modify the
+configuration values from the dump header passed to the WT_SESSION::create
+call.
+
+The \c uri part of the configuration pair should match only one of the
+objects being loaded, but may be a prefix of the object being matched.
+For example, the following two sets of configuration pairs are
+equivalent in the case of loading a single table named \c xxx.
+
+@code
+table block_allocation=first
+table:xxx block_allocation=first
+@endcode
+
+It's an error, however, to specify a matching prefix that matches more
+than a single object being loaded.
+
+Multiple \c configuration arguments may be specified. For example, the
+following two sets of configuration pairs are equivalent:
+
+@code
+table:xxx block_allocation=first,prefix_compress=false
+table:xxx block_allocation=first table:xxx prefix_compress=false
+@endcode
<hr>
@section util_loadtext wt loadtext
diff --git a/src/docs/custom-data-sources.dox b/src/docs/custom-data-sources.dox
index 382b5ca7494..9082ee95dea 100644
--- a/src/docs/custom-data-sources.dox
+++ b/src/docs/custom-data-sources.dox
@@ -172,9 +172,10 @@ methods using WT_CONNECTION::configure_method.
WT_CONNECTION::configure_method takes the following arguments:
-- the name of the method being extended. For example, \c "session.create"
+- the method being extended, where the name is the concatenation of the handle
+name, a period and the method name. For example, \c "WT_SESSION.create"
would add new configuration strings to the WT_SESSION::create method,
-and \c "session.open_cursor" would add the configuration string to the
+and \c "WT_SESSION.open_cursor" would add the configuration string to the
WT_SESSION::open_cursor method.
- the object type of the data source being extended. For example, \c "table:"
diff --git a/src/evict/evict_lru.c b/src/evict/evict_lru.c
index 584bb107706..a22531277dd 100644
--- a/src/evict/evict_lru.c
+++ b/src/evict/evict_lru.c
@@ -1424,6 +1424,19 @@ __wt_evict_lru_page(WT_SESSION_IMPL *session, int is_server)
if (page->read_gen != WT_READGEN_OLDEST)
page->read_gen = __wt_cache_read_gen_set(session);
+ /*
+ * If we are evicting in a dead tree, don't write dirty pages.
+ *
+ * Force pages clean to keep statistics correct and to let the
+ * page-discard function assert that no dirty pages are ever
+ * discarded.
+ */
+ if (F_ISSET(btree->dhandle, WT_DHANDLE_DEAD) &&
+ __wt_page_is_modified(page)) {
+ page->modify->write_gen = 0;
+ __wt_cache_dirty_decr(session, page);
+ }
+
WT_WITH_BTREE(session, btree, ret = __wt_evict_page(session, ref));
(void)WT_ATOMIC_SUB4(btree->evict_busy, 1);
diff --git a/src/include/api.h b/src/include/api.h
index 8e0d47f42b1..8f8fd8e98b1 100644
--- a/src/include/api.h
+++ b/src/include/api.h
@@ -96,29 +96,29 @@
#define CONNECTION_API_CALL(conn, s, n, config, cfg) \
s = (conn)->default_session; \
- API_CALL(s, connection, n, NULL, NULL, config, cfg)
+ API_CALL(s, WT_CONNECTION, n, NULL, NULL, config, cfg)
#define CONNECTION_API_CALL_NOCONF(conn, s, n) \
s = (conn)->default_session; \
- API_CALL_NOCONF(s, connection, n, NULL, NULL)
+ API_CALL_NOCONF(s, WT_CONNECTION, n, NULL, NULL)
#define SESSION_API_CALL(s, n, config, cfg) \
- API_CALL(s, session, n, NULL, NULL, config, cfg)
+ API_CALL(s, WT_SESSION, n, NULL, NULL, config, cfg)
#define SESSION_API_CALL_NOCONF(s, n) \
- API_CALL_NOCONF(s, session, n, NULL, NULL)
+ API_CALL_NOCONF(s, WT_SESSION, n, NULL, NULL)
#define SESSION_TXN_API_CALL(s, n, config, cfg) \
- TXN_API_CALL(s, session, n, NULL, NULL, config, cfg)
+ TXN_API_CALL(s, WT_SESSION, n, NULL, NULL, config, cfg)
#define CURSOR_API_CALL(cur, s, n, bt) \
(s) = (WT_SESSION_IMPL *)(cur)->session; \
- API_CALL_NOCONF(s, cursor, n, cur, \
+ API_CALL_NOCONF(s, WT_CURSOR, n, cur, \
((bt) == NULL) ? NULL : ((WT_BTREE *)(bt))->dhandle)
#define CURSOR_UPDATE_API_CALL(cur, s, n, bt) \
(s) = (WT_SESSION_IMPL *)(cur)->session; \
- TXN_API_CALL_NOCONF(s, cursor, n, cur, \
+ TXN_API_CALL_NOCONF(s, WT_CURSOR, n, cur, \
((bt) == NULL) ? NULL : ((WT_BTREE *)(bt))->dhandle)
#define CURSOR_UPDATE_API_END(s, ret) \
diff --git a/src/include/btree.h b/src/include/btree.h
index c8038abf1ed..2db14e293ed 100644
--- a/src/include/btree.h
+++ b/src/include/btree.h
@@ -145,8 +145,8 @@ struct __wt_btree {
/* Flags values up to 0xff are reserved for WT_DHANDLE_* */
#define WT_BTREE_BULK 0x00100 /* Bulk-load handle */
-#define WT_BTREE_NO_EVICTION 0x00200 /* Disable eviction */
-#define WT_BTREE_NO_HAZARD 0x00400 /* Disable hazard pointers */
+#define WT_BTREE_IN_MEMORY 0x00200 /* Cache-resident object */
+#define WT_BTREE_NO_EVICTION 0x00400 /* Disable eviction */
#define WT_BTREE_SALVAGE 0x00800 /* Handle is for salvage */
#define WT_BTREE_UPGRADE 0x01000 /* Handle is for upgrade */
#define WT_BTREE_VERIFY 0x02000 /* Handle is for verify */
diff --git a/src/include/btree.i b/src/include/btree.i
index b3d2c10a5a0..9038dab2b34 100644
--- a/src/include/btree.i
+++ b/src/include/btree.i
@@ -1092,7 +1092,13 @@ __wt_page_release(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags)
*/
if (ref == NULL || __wt_ref_is_root(ref))
return (0);
- page = ref->page;
+
+ /*
+ * If hazard pointers aren't necessary for this file, we can't be
+ * evicting, we're done.
+ */
+ if (F_ISSET(btree, WT_BTREE_IN_MEMORY))
+ return (0);
/*
* Attempt to evict pages with the special "oldest" read generation.
@@ -1106,9 +1112,10 @@ __wt_page_release(WT_SESSION_IMPL *session, WT_REF *ref, uint32_t flags)
* it contains an update that isn't stable. Also skip forced eviction
* if we just did an in-memory split.
*/
- if (page->read_gen != WT_READGEN_OLDEST ||
+ page = ref->page;
+ if (F_ISSET(btree, WT_BTREE_NO_EVICTION) ||
LF_ISSET(WT_READ_NO_EVICT) ||
- F_ISSET(btree, WT_BTREE_NO_EVICTION) ||
+ page->read_gen != WT_READGEN_OLDEST ||
!__wt_page_can_evict(session, page, 1))
return (__wt_hazard_clear(session, page));
diff --git a/src/include/config.h b/src/include/config.h
index e6b8f4a0bb8..8ec9048e861 100644
--- a/src/include/config.h
+++ b/src/include/config.h
@@ -49,38 +49,38 @@ struct __wt_config_parser_impl {
* DO NOT EDIT: automatically built by dist/api_config.py.
* configuration section: BEGIN
*/
-#define WT_CONFIG_ENTRY_colgroup_meta 0
-#define WT_CONFIG_ENTRY_connection_add_collator 1
-#define WT_CONFIG_ENTRY_connection_add_compressor 2
-#define WT_CONFIG_ENTRY_connection_add_data_source 3
-#define WT_CONFIG_ENTRY_connection_add_encryptor 4
-#define WT_CONFIG_ENTRY_connection_add_extractor 5
-#define WT_CONFIG_ENTRY_connection_async_new_op 6
-#define WT_CONFIG_ENTRY_connection_close 7
-#define WT_CONFIG_ENTRY_connection_load_extension 8
-#define WT_CONFIG_ENTRY_connection_open_session 9
-#define WT_CONFIG_ENTRY_connection_reconfigure 10
-#define WT_CONFIG_ENTRY_cursor_close 11
-#define WT_CONFIG_ENTRY_cursor_reconfigure 12
-#define WT_CONFIG_ENTRY_file_meta 13
-#define WT_CONFIG_ENTRY_index_meta 14
-#define WT_CONFIG_ENTRY_session_begin_transaction 15
-#define WT_CONFIG_ENTRY_session_checkpoint 16
-#define WT_CONFIG_ENTRY_session_close 17
-#define WT_CONFIG_ENTRY_session_commit_transaction 18
-#define WT_CONFIG_ENTRY_session_compact 19
-#define WT_CONFIG_ENTRY_session_create 20
-#define WT_CONFIG_ENTRY_session_drop 21
-#define WT_CONFIG_ENTRY_session_log_printf 22
-#define WT_CONFIG_ENTRY_session_open_cursor 23
-#define WT_CONFIG_ENTRY_session_reconfigure 24
-#define WT_CONFIG_ENTRY_session_rename 25
-#define WT_CONFIG_ENTRY_session_rollback_transaction 26
-#define WT_CONFIG_ENTRY_session_salvage 27
-#define WT_CONFIG_ENTRY_session_strerror 28
-#define WT_CONFIG_ENTRY_session_truncate 29
-#define WT_CONFIG_ENTRY_session_upgrade 30
-#define WT_CONFIG_ENTRY_session_verify 31
+#define WT_CONFIG_ENTRY_WT_CONNECTION_add_collator 0
+#define WT_CONFIG_ENTRY_WT_CONNECTION_add_compressor 1
+#define WT_CONFIG_ENTRY_WT_CONNECTION_add_data_source 2
+#define WT_CONFIG_ENTRY_WT_CONNECTION_add_encryptor 3
+#define WT_CONFIG_ENTRY_WT_CONNECTION_add_extractor 4
+#define WT_CONFIG_ENTRY_WT_CONNECTION_async_new_op 5
+#define WT_CONFIG_ENTRY_WT_CONNECTION_close 6
+#define WT_CONFIG_ENTRY_WT_CONNECTION_load_extension 7
+#define WT_CONFIG_ENTRY_WT_CONNECTION_open_session 8
+#define WT_CONFIG_ENTRY_WT_CONNECTION_reconfigure 9
+#define WT_CONFIG_ENTRY_WT_CURSOR_close 10
+#define WT_CONFIG_ENTRY_WT_CURSOR_reconfigure 11
+#define WT_CONFIG_ENTRY_WT_SESSION_begin_transaction 12
+#define WT_CONFIG_ENTRY_WT_SESSION_checkpoint 13
+#define WT_CONFIG_ENTRY_WT_SESSION_close 14
+#define WT_CONFIG_ENTRY_WT_SESSION_commit_transaction 15
+#define WT_CONFIG_ENTRY_WT_SESSION_compact 16
+#define WT_CONFIG_ENTRY_WT_SESSION_create 17
+#define WT_CONFIG_ENTRY_WT_SESSION_drop 18
+#define WT_CONFIG_ENTRY_WT_SESSION_log_printf 19
+#define WT_CONFIG_ENTRY_WT_SESSION_open_cursor 20
+#define WT_CONFIG_ENTRY_WT_SESSION_reconfigure 21
+#define WT_CONFIG_ENTRY_WT_SESSION_rename 22
+#define WT_CONFIG_ENTRY_WT_SESSION_rollback_transaction 23
+#define WT_CONFIG_ENTRY_WT_SESSION_salvage 24
+#define WT_CONFIG_ENTRY_WT_SESSION_strerror 25
+#define WT_CONFIG_ENTRY_WT_SESSION_truncate 26
+#define WT_CONFIG_ENTRY_WT_SESSION_upgrade 27
+#define WT_CONFIG_ENTRY_WT_SESSION_verify 28
+#define WT_CONFIG_ENTRY_colgroup_meta 29
+#define WT_CONFIG_ENTRY_file_meta 30
+#define WT_CONFIG_ENTRY_index_meta 31
#define WT_CONFIG_ENTRY_table_meta 32
#define WT_CONFIG_ENTRY_wiredtiger_open 33
#define WT_CONFIG_ENTRY_wiredtiger_open_all 34
diff --git a/src/include/dhandle.h b/src/include/dhandle.h
index 300e8e735b9..034db30a0a2 100644
--- a/src/include/dhandle.h
+++ b/src/include/dhandle.h
@@ -65,11 +65,12 @@ struct __wt_data_handle {
WT_DSRC_STATS stats; /* Data-source statistics */
/* Flags values over 0xff are reserved for WT_BTREE_* */
-#define WT_DHANDLE_DISCARD 0x01 /* Discard on release */
-#define WT_DHANDLE_DISCARD_CLOSE 0x02 /* Close on release */
-#define WT_DHANDLE_EXCLUSIVE 0x04 /* Need exclusive access */
-#define WT_DHANDLE_HAVE_REF 0x08 /* Already have ref */
-#define WT_DHANDLE_LOCK_ONLY 0x10 /* Handle only used as a lock */
-#define WT_DHANDLE_OPEN 0x20 /* Handle is open */
+#define WT_DHANDLE_DEAD 0x01 /* Dead, awaiting discard */
+#define WT_DHANDLE_DISCARD 0x02 /* Discard on release */
+#define WT_DHANDLE_DISCARD_FORCE 0x04 /* Force discard on release */
+#define WT_DHANDLE_EXCLUSIVE 0x08 /* Need exclusive access */
+#define WT_DHANDLE_HAVE_REF 0x10 /* Already have ref */
+#define WT_DHANDLE_LOCK_ONLY 0x20 /* Handle only used as a lock */
+#define WT_DHANDLE_OPEN 0x40 /* Handle is open */
uint32_t flags;
};
diff --git a/src/include/extern.h b/src/include/extern.h
index d9a3ea2b71a..0885d776e50 100644
--- a/src/include/extern.h
+++ b/src/include/extern.h
@@ -197,9 +197,9 @@ extern int __wt_configure_method(WT_SESSION_IMPL *session, const char *method, c
extern int __wt_config_check(WT_SESSION_IMPL *session, const WT_CONFIG_ENTRY *entry, const char *config, size_t config_len);
extern int __wt_config_collapse( WT_SESSION_IMPL *session, const char **cfg, char **config_ret);
extern int __wt_config_merge(WT_SESSION_IMPL *session, const char **cfg, const char *cfg_strip, const char **config_ret);
-extern int __wt_config_concat( WT_SESSION_IMPL *session, const char **cfg, char **config_ret);
extern int __wt_conn_config_init(WT_SESSION_IMPL *session);
extern void __wt_conn_config_discard(WT_SESSION_IMPL *session);
+extern const WT_CONFIG_ENTRY *__wt_conn_config_match(const char *method);
extern int __wt_ext_config_parser_open(WT_EXTENSION_API *wt_ext, WT_SESSION *wt_session, const char *config, size_t len, WT_CONFIG_PARSER **config_parserp);
extern int __wt_ext_config_get(WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, WT_CONFIG_ARG *cfg_arg, const char *key, WT_CONFIG_ITEM *cval);
extern int __wt_config_upgrade(WT_SESSION_IMPL *session, WT_ITEM *buf);
@@ -235,7 +235,7 @@ extern int __wt_conn_btree_apply(WT_SESSION_IMPL *session, int apply_checkpoints
extern int __wt_conn_btree_apply_single_ckpt(WT_SESSION_IMPL *session, const char *uri, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]);
extern int __wt_conn_btree_apply_single(WT_SESSION_IMPL *session, const char *uri, const char *checkpoint, int (*func)(WT_SESSION_IMPL *, const char *[]), const char *cfg[]);
extern int __wt_conn_dhandle_close_all( WT_SESSION_IMPL *session, const char *name, int force);
-extern int __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final);
+extern int __wt_conn_dhandle_discard_single(WT_SESSION_IMPL *session, int final, int force);
extern int __wt_conn_dhandle_discard(WT_SESSION_IMPL *session);
extern int __wt_connection_init(WT_CONNECTION_IMPL *conn);
extern int __wt_connection_destroy(WT_CONNECTION_IMPL *conn);
@@ -429,6 +429,7 @@ extern int __wt_metadata_remove(WT_SESSION_IMPL *session, const char *key);
extern int __wt_metadata_search( WT_SESSION_IMPL *session, const char *key, char **valuep);
extern void __wt_meta_track_discard(WT_SESSION_IMPL *session);
extern int __wt_meta_track_on(WT_SESSION_IMPL *session);
+extern int __wt_meta_track_find_handle( WT_SESSION_IMPL *session, const char *name, const char *checkpoint);
extern int __wt_meta_track_off(WT_SESSION_IMPL *session, int need_sync, int unroll);
extern int __wt_meta_track_sub_on(WT_SESSION_IMPL *session);
extern int __wt_meta_track_sub_off(WT_SESSION_IMPL *session);
@@ -578,7 +579,7 @@ extern int __wt_open_internal_session(WT_CONNECTION_IMPL *conn, const char *name
extern int __wt_open_session(WT_CONNECTION_IMPL *conn, WT_EVENT_HANDLER *event_handler, const char *config, WT_SESSION_IMPL **sessionp);
extern int __wt_compact_uri_analyze(WT_SESSION_IMPL *session, const char *uri, int *skip);
extern int __wt_session_compact( WT_SESSION *wt_session, const char *uri, const char *config);
-extern int __wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags);
+extern int __wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags, int *deadp);
extern int __wt_session_release_btree(WT_SESSION_IMPL *session);
extern int __wt_session_get_btree_ckpt(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], uint32_t flags);
extern void __wt_session_close_cache(WT_SESSION_IMPL *session);
@@ -658,7 +659,7 @@ extern int WT_CDECL __wt_txnid_cmp(const void *v1, const void *v2);
extern void __wt_txn_release_snapshot(WT_SESSION_IMPL *session);
extern void __wt_txn_update_oldest(WT_SESSION_IMPL *session);
extern void __wt_txn_refresh(WT_SESSION_IMPL *session, int get_snapshot);
-extern int __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[]);
+extern int __wt_txn_config(WT_SESSION_IMPL *session, const char *cfg[]);
extern void __wt_txn_release(WT_SESSION_IMPL *session);
extern int __wt_txn_commit(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_txn_rollback(WT_SESSION_IMPL *session, const char *cfg[]);
@@ -672,7 +673,7 @@ extern int __wt_checkpoint_list(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_checkpoint(WT_SESSION_IMPL *session, const char *cfg[]);
extern int __wt_checkpoint_sync(WT_SESSION_IMPL *session, const char *cfg[]);
-extern int __wt_checkpoint_close(WT_SESSION_IMPL *session, int final, int force);
+extern int __wt_checkpoint_close(WT_SESSION_IMPL *session, int final);
extern uint64_t __wt_ext_transaction_id(WT_EXTENSION_API *wt_api, WT_SESSION *wt_session);
extern int __wt_ext_transaction_isolation_level( WT_EXTENSION_API *wt_api, WT_SESSION *wt_session);
extern int __wt_ext_transaction_notify( WT_EXTENSION_API *wt_api, WT_SESSION *wt_session, WT_TXN_NOTIFY *notify);
diff --git a/src/include/log.h b/src/include/log.h
index 68b0b941986..ef5c3ce1b31 100644
--- a/src/include/log.h
+++ b/src/include/log.h
@@ -51,7 +51,7 @@
* Compare 2 LSNs, return -1 if lsn0 < lsn1, 0 if lsn0 == lsn1
* and 1 if lsn0 > lsn1.
*/
-#define LOG_CMP(lsn1, lsn2) \
+#define WT_LOG_CMP(lsn1, lsn2) \
((lsn1)->file != (lsn2)->file ? \
((lsn1)->file < (lsn2)->file ? -1 : 1) : \
((lsn1)->offset != (lsn2)->offset ? \
diff --git a/src/include/misc.h b/src/include/misc.h
index f6fe42248c1..cf546e4fa99 100644
--- a/src/include/misc.h
+++ b/src/include/misc.h
@@ -134,6 +134,33 @@
#define FLD_ISSET(field, mask) ((field) & ((uint32_t)(mask)))
#define FLD_SET(field, mask) ((field) |= ((uint32_t)(mask)))
+/*
+ * Insertion sort, for sorting small sets of values.
+ *
+ * The "compare_lt" argument is a function or macro that returns true when
+ * its first argument is less than its second argument.
+ */
+#define WT_INSERTION_SORT(arrayp, n, value_type, compare_lt) do { \
+ value_type __v; \
+ int __i, __j, __n = (int)(n); \
+ if (__n == 2) { \
+ __v = (arrayp)[1]; \
+ if (compare_lt(__v, (arrayp)[0])) { \
+ (arrayp)[1] = (arrayp)[0]; \
+ (arrayp)[0] = __v; \
+ } \
+ } \
+ if (__n > 2) { \
+ for (__i = 1; __i < __n; ++__i) { \
+ __v = (arrayp)[__i]; \
+ for (__j = __i - 1; __j >= 0 && \
+ compare_lt(__v, (arrayp)[__j]); --__j) \
+ (arrayp)[__j + 1] = (arrayp)[__j]; \
+ (arrayp)[__j + 1] = __v; \
+ } \
+ } \
+} while (0)
+
/* Verbose messages. */
#ifdef HAVE_VERBOSE
#define WT_VERBOSE_ISSET(session, f) \
diff --git a/src/include/txn.i b/src/include/txn.i
index 3a3bdde2b73..4141d829f1d 100644
--- a/src/include/txn.i
+++ b/src/include/txn.i
@@ -204,9 +204,35 @@ __wt_txn_read(WT_SESSION_IMPL *session, WT_UPDATE *upd)
}
/*
+ * __wt_txn_begin --
+ * Begin a transaction.
+ */
+static inline int
+__wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
+{
+ WT_TXN *txn;
+
+ txn = &session->txn;
+ txn->isolation = session->isolation;
+ txn->txn_logsync = S2C(session)->txn_logsync;
+
+ if (cfg != NULL)
+ WT_RET(__wt_txn_config(session, cfg));
+
+ if (txn->isolation == TXN_ISO_SNAPSHOT) {
+ if (session->ncursors > 0)
+ WT_RET(__wt_session_copy_values(session));
+ __wt_txn_refresh(session, 1);
+ }
+
+ F_SET(txn, TXN_RUNNING);
+ return (0);
+}
+
+/*
* __wt_txn_autocommit_check --
* If an auto-commit transaction is required, start one.
-*/
+ */
static inline int
__wt_txn_autocommit_check(WT_SESSION_IMPL *session)
{
diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in
index c6d41ad0e9c..2f497a89daf 100644
--- a/src/include/wiredtiger.in
+++ b/src/include/wiredtiger.in
@@ -523,7 +523,7 @@ struct __wt_cursor {
* @snippet ex_all.c Reconfigure a cursor
*
* @param cursor the cursor handle
- * @configstart{cursor.reconfigure, see dist/api_data.py}
+ * @configstart{WT_CURSOR.reconfigure, see dist/api_data.py}
* @config{append, append the value as a new record\, creating a new
* record number key; valid only for cursors with record number keys., a
* boolean flag; default \c false.}
@@ -810,7 +810,7 @@ struct __wt_session {
* @snippet ex_all.c Close a session
*
* @param session the session handle
- * @configempty{session.close, see dist/api_data.py}
+ * @configempty{WT_SESSION.close, see dist/api_data.py}
* @errors
*/
int __F(close)(WT_HANDLE_CLOSED(WT_SESSION) *session,
@@ -827,7 +827,7 @@ struct __wt_session {
* All cursors are reset.
*
* @param session the session handle
- * @configstart{session.reconfigure, see dist/api_data.py}
+ * @configstart{WT_SESSION.reconfigure, see dist/api_data.py}
* @config{isolation, the default isolation level for operations in this
* session., a string\, chosen from the following options: \c
* "read-uncommitted"\, \c "read-committed"\, \c "snapshot"; default \c
@@ -889,7 +889,7 @@ struct __wt_session {
* <br>
* @copydoc doc_cursor_types
* @param to_dup a cursor to duplicate
- * @configstart{session.open_cursor, see dist/api_data.py}
+ * @configstart{WT_SESSION.open_cursor, see dist/api_data.py}
* @config{append, append the value as a new record\, creating a new
* record number key; valid only for cursors with record number keys., a
* boolean flag; default \c false.}
@@ -978,7 +978,7 @@ struct __wt_session {
* @param name the URI of the object to create, such as
* \c "table:stock". For a description of URI formats
* see @ref data_sources.
- * @configstart{session.create, see dist/api_data.py}
+ * @configstart{WT_SESSION.create, see dist/api_data.py}
* @config{allocation_size, the file unit allocation size\, in bytes\,
* must a power-of-two; smaller values decrease the file space required
* by overflow items\, and the default value of 4KB is a good choice
@@ -1195,7 +1195,7 @@ struct __wt_session {
* @param session the session handle
* @param name the URI of the object to compact, such as
* \c "table:stock"
- * @configstart{session.compact, see dist/api_data.py}
+ * @configstart{WT_SESSION.compact, see dist/api_data.py}
* @config{timeout, maximum amount of time to allow for compact in
* seconds. The actual amount of time spent in compact may exceed the
* configured value. A value of zero disables the timeout., an integer;
@@ -1213,7 +1213,7 @@ struct __wt_session {
*
* @param session the session handle
* @param name the URI of the object to drop, such as \c "table:stock"
- * @configstart{session.drop, see dist/api_data.py}
+ * @configstart{WT_SESSION.drop, see dist/api_data.py}
* @config{force, return success if the object does not exist., a
* boolean flag; default \c false.}
* @config{remove_files, should the underlying files be removed?., a
@@ -1243,7 +1243,7 @@ struct __wt_session {
* @param session the session handle
* @param uri the current URI of the object, such as \c "table:old"
* @param newuri the new URI of the object, such as \c "table:new"
- * @configempty{session.rename, see dist/api_data.py}
+ * @configempty{WT_SESSION.rename, see dist/api_data.py}
* @ebusy_errors
*/
int __F(rename)(WT_SESSION *session,
@@ -1268,7 +1268,7 @@ struct __wt_session {
*
* @param session the session handle
* @param name the URI of the file or table to salvage
- * @configstart{session.salvage, see dist/api_data.py}
+ * @configstart{WT_SESSION.salvage, see dist/api_data.py}
* @config{force, force salvage even of files that do not appear to be
* WiredTiger files., a boolean flag; default \c false.}
* @configend
@@ -1298,7 +1298,7 @@ struct __wt_session {
* @param stop optional cursor marking the last record discarded;
* if <code>NULL</code>, the truncate continues to the end of the
* object
- * @configempty{session.truncate, see dist/api_data.py}
+ * @configempty{WT_SESSION.truncate, see dist/api_data.py}
* @ebusy_errors
*/
int __F(truncate)(WT_SESSION *session,
@@ -1316,7 +1316,7 @@ struct __wt_session {
*
* @param session the session handle
* @param name the URI of the file or table to upgrade
- * @configempty{session.upgrade, see dist/api_data.py}
+ * @configempty{WT_SESSION.upgrade, see dist/api_data.py}
* @ebusy_errors
*/
int __F(upgrade)(WT_SESSION *session,
@@ -1333,7 +1333,7 @@ struct __wt_session {
*
* @param session the session handle
* @param name the URI of the file or table to verify
- * @configstart{session.verify, see dist/api_data.py}
+ * @configstart{WT_SESSION.verify, see dist/api_data.py}
* @config{dump_address, Display addresses and page types as pages are
* verified\, using the application's message handler\, intended for
* debugging., a boolean flag; default \c false.}
@@ -1376,7 +1376,7 @@ struct __wt_session {
* @snippet ex_all.c transaction commit/rollback
*
* @param session the session handle
- * @configstart{session.begin_transaction, see dist/api_data.py}
+ * @configstart{WT_SESSION.begin_transaction, see dist/api_data.py}
* @config{isolation, the isolation level for this transaction; defaults
* to the session's isolation level., a string\, chosen from the
* following options: \c "read-uncommitted"\, \c "read-committed"\, \c
@@ -1405,7 +1405,7 @@ struct __wt_session {
* @snippet ex_all.c transaction commit/rollback
*
* @param session the session handle
- * @configempty{session.commit_transaction, see dist/api_data.py}
+ * @configempty{WT_SESSION.commit_transaction, see dist/api_data.py}
* @errors
*/
int __F(commit_transaction)(WT_SESSION *session, const char *config);
@@ -1420,7 +1420,7 @@ struct __wt_session {
* @snippet ex_all.c transaction commit/rollback
*
* @param session the session handle
- * @configempty{session.rollback_transaction, see dist/api_data.py}
+ * @configempty{WT_SESSION.rollback_transaction, see dist/api_data.py}
* @errors
*/
int __F(rollback_transaction)(WT_SESSION *session, const char *config);
@@ -1434,7 +1434,7 @@ struct __wt_session {
* @snippet ex_all.c Checkpoint examples
*
* @param session the session handle
- * @configstart{session.checkpoint, see dist/api_data.py}
+ * @configstart{WT_SESSION.checkpoint, see dist/api_data.py}
* @config{drop, specify a list of checkpoints to drop. The list may
* additionally contain one of the following keys: \c "from=all" to drop
* all checkpoints\, \c "from=<checkpoint>" to drop all checkpoints
@@ -1509,7 +1509,7 @@ struct __wt_connection {
*
* @param connection the connection handle
* @param uri the connection handle
- * @configstart{connection.async_new_op, see dist/api_data.py}
+ * @configstart{WT_CONNECTION.async_new_op, see dist/api_data.py}
* @config{append, append the value as a new record\, creating a new
* record number key; valid only for operations with record number
* keys., a boolean flag; default \c false.}
@@ -1545,7 +1545,7 @@ struct __wt_connection {
* @snippet ex_all.c Close a connection
*
* @param connection the connection handle
- * @configstart{connection.close, see dist/api_data.py}
+ * @configstart{WT_CONNECTION.close, see dist/api_data.py}
* @config{leak_memory, don't free memory during close., a boolean flag;
* default \c false.}
* @configend
@@ -1560,7 +1560,7 @@ struct __wt_connection {
* @snippet ex_all.c Reconfigure a connection
*
* @param connection the connection handle
- * @configstart{connection.reconfigure, see dist/api_data.py}
+ * @configstart{WT_CONNECTION.reconfigure, see dist/api_data.py}
* @config{async = (, asynchronous operations configuration options., a
* set of related configuration options defined below.}
* @config{&nbsp;&nbsp;&nbsp;&nbsp;enabled, enable asynchronous
@@ -1737,7 +1737,7 @@ struct __wt_connection {
* @snippet ex_all.c Configure method configuration
*
* @param connection the connection handle
- * @param method the name of the method
+ * @param method the method being configured
* @param uri the object type or NULL for all object types
* @param config the additional configuration's name and default value
* @param type the additional configuration's type (must be one of
@@ -1774,7 +1774,7 @@ struct __wt_connection {
* @param connection the connection handle
* @param errhandler An error handler. If <code>NULL</code>, the
* connection's error handler is used
- * @configstart{connection.open_session, see dist/api_data.py}
+ * @configstart{WT_CONNECTION.open_session, see dist/api_data.py}
* @config{isolation, the default isolation level for operations in this
* session., a string\, chosen from the following options: \c
* "read-uncommitted"\, \c "read-committed"\, \c "snapshot"; default \c
@@ -1801,7 +1801,7 @@ struct __wt_connection {
* @param path the filename of the extension module, or \c "local" to
* search the current application binary for the initialization
* function, see @ref extensions for more details.
- * @configstart{connection.load_extension, see dist/api_data.py}
+ * @configstart{WT_CONNECTION.load_extension, see dist/api_data.py}
* @config{config, configuration string passed to the entry point of the
* extension as its WT_CONFIG_ARG argument., a string; default empty.}
* @config{entry, the entry point of the extension\, called to
@@ -1832,7 +1832,7 @@ struct __wt_connection {
* @param prefix the URI prefix for this data source, e.g., "file:"
* @param data_source the application-supplied implementation of
* WT_DATA_SOURCE to manage this data source.
- * @configempty{connection.add_data_source, see dist/api_data.py}
+ * @configempty{WT_CONNECTION.add_data_source, see dist/api_data.py}
* @errors
*/
int __F(add_data_source)(WT_CONNECTION *connection, const char *prefix,
@@ -1850,7 +1850,7 @@ struct __wt_connection {
* @param name the name of the collation to be used in calls to
* WT_SESSION::create, may not be \c "none"
* @param collator the application-supplied collation handler
- * @configempty{connection.add_collator, see dist/api_data.py}
+ * @configempty{WT_CONNECTION.add_collator, see dist/api_data.py}
* @errors
*/
int __F(add_collator)(WT_CONNECTION *connection,
@@ -1870,7 +1870,7 @@ struct __wt_connection {
* @param name the name of the compression function to be used in calls
* to WT_SESSION::create, may not be \c "none"
* @param compressor the application-supplied compression handler
- * @configempty{connection.add_compressor, see dist/api_data.py}
+ * @configempty{WT_CONNECTION.add_compressor, see dist/api_data.py}
* @errors
*/
int __F(add_compressor)(WT_CONNECTION *connection,
@@ -1908,7 +1908,7 @@ struct __wt_connection {
* @param name the name of the extractor to be used in calls to
* WT_SESSION::create, may not be \c "none"
* @param extractor the application-supplied extractor
- * @configempty{connection.add_extractor, see dist/api_data.py}
+ * @configempty{WT_CONNECTION.add_extractor, see dist/api_data.py}
* @errors
*/
int __F(add_extractor)(WT_CONNECTION *connection, const char *name,
@@ -2498,7 +2498,7 @@ int wiredtiger_unpack_uint(WT_PACK_STREAM *ps, uint64_t *up);
/*! @} */
/*!
- * @name Configuration string parsing
+ * @name Configuration strings
* @{
*/
@@ -2554,6 +2554,27 @@ struct __wt_config_item {
type;
};
+#if !defined(SWIG) && !defined(DOXYGEN)
+/*!
+ * Validate a configuration string for a WiredTiger API.
+ * This API is outside the scope of a WiredTiger connection handle, since
+ * applications may need to validate configuration strings prior to calling
+ * ::wiredtiger_open.
+ * @param session the session handle (may be \c NULL if the database not yet
+ * opened).
+ * @param errhandler An error handler (used if \c session is \c NULL; if both
+ * \c session and \c errhandler are \c NULL, error messages will be written to
+ * stderr).
+ * @param name the WiredTiger function or method to validate.
+ * @param config the configuration string being parsed.
+ * @returns zero for success, non-zero to indicate an error.
+ *
+ * @snippet ex_all.c Validate a configuration string
+ */
+int wiredtiger_config_validate(WT_SESSION *session,
+ WT_EVENT_HANDLER *errhandler, const char *name, const char *config);
+#endif
+
/*!
* Create a handle that can be used to parse or create configuration strings
* compatible with WiredTiger APIs.
@@ -2567,6 +2588,8 @@ struct __wt_config_item {
* @param len the number of valid bytes in \c config
* @param[out] config_parserp A pointer to the newly opened handle
* @errors
+ *
+ * @snippet ex_config_parse.c Create a configuration parser
*/
int wiredtiger_config_parser_open(WT_SESSION *session,
const char *config, size_t len, WT_CONFIG_PARSER **config_parserp);
diff --git a/src/log/log.c b/src/log/log.c
index 31729a8eddd..db5aa189994 100644
--- a/src/log/log.c
+++ b/src/log/log.c
@@ -1051,7 +1051,7 @@ __log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot, int *freep)
* be holes in the log file.
*/
WT_STAT_FAST_CONN_INCR(session, log_release_write_lsn);
- while (LOG_CMP(&log->write_lsn, &slot->slot_release_lsn) != 0) {
+ while (WT_LOG_CMP(&log->write_lsn, &slot->slot_release_lsn) != 0) {
if (++yield_count < 1000)
__wt_yield();
else
@@ -1114,7 +1114,7 @@ __log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot, int *freep)
* Sync the log file if needed.
*/
if (F_ISSET(slot, SLOT_SYNC) &&
- LOG_CMP(&log->sync_lsn, &slot->slot_end_lsn) < 0) {
+ WT_LOG_CMP(&log->sync_lsn, &slot->slot_end_lsn) < 0) {
WT_ERR(__wt_verbose(session, WT_VERB_LOG,
"log_release: sync log %s", log->log_fh->name));
WT_STAT_FAST_CONN_INCR(session, log_sync);
@@ -1593,7 +1593,7 @@ advance:
/* Truncate if we're in recovery. */
if (LF_ISSET(WT_LOGSCAN_RECOVER) &&
- LOG_CMP(&rd_lsn, &log->trunc_lsn) < 0)
+ WT_LOG_CMP(&rd_lsn, &log->trunc_lsn) < 0)
WT_ERR(__log_truncate(session,
&rd_lsn, WT_LOG_FILENAME, 0));
@@ -1928,13 +1928,13 @@ __log_write_internal(WT_SESSION_IMPL *session, WT_ITEM *record, WT_LSN *lsnp,
WT_ERR(__wt_log_slot_free(session, myslot.slot));
} else if (LF_ISSET(WT_LOG_FSYNC)) {
/* Wait for our writes to reach disk */
- while (LOG_CMP(&log->sync_lsn, &lsn) <= 0 &&
+ while (WT_LOG_CMP(&log->sync_lsn, &lsn) <= 0 &&
myslot.slot->slot_error == 0)
(void)__wt_cond_wait(
session, log->log_sync_cond, 10000);
} else if (LF_ISSET(WT_LOG_FLUSH)) {
/* Wait for our writes to reach the OS */
- while (LOG_CMP(&log->write_lsn, &lsn) <= 0 &&
+ while (WT_LOG_CMP(&log->write_lsn, &lsn) <= 0 &&
myslot.slot->slot_error == 0)
(void)__wt_cond_wait(
session, log->log_write_cond, 10000);
diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c
index 19b4cc6595e..7c9ac35d489 100644
--- a/src/lsm/lsm_cursor.c
+++ b/src/lsm/lsm_cursor.c
@@ -413,7 +413,7 @@ __clsm_open_cursors(
if (lsm_tree->nchunks == 0)
return (0);
- ckpt_cfg[0] = WT_CONFIG_BASE(session, session_open_cursor);
+ ckpt_cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_open_cursor);
ckpt_cfg[1] = "checkpoint=" WT_CHECKPOINT ",raw";
ckpt_cfg[2] = NULL;
diff --git a/src/lsm/lsm_manager.c b/src/lsm/lsm_manager.c
index 12b24984fcb..3d9fc27d1d2 100644
--- a/src/lsm/lsm_manager.c
+++ b/src/lsm/lsm_manager.c
@@ -327,8 +327,7 @@ __wt_lsm_manager_destroy(WT_SESSION_IMPL *session)
WT_TRET(wt_session->close(wt_session, NULL));
}
}
- WT_STAT_FAST_CONN_INCRV(session,
- lsm_work_units_discarded, removed);
+ WT_STAT_FAST_CONN_INCRV(session, lsm_work_units_discarded, removed);
/* Free resources that are allocated in connection initialize */
__wt_spin_destroy(session, &manager->switch_lock);
diff --git a/src/lsm/lsm_merge.c b/src/lsm/lsm_merge.c
index 6ca1b0f04ab..d75f3b0619b 100644
--- a/src/lsm/lsm_merge.c
+++ b/src/lsm/lsm_merge.c
@@ -244,7 +244,7 @@ __wt_lsm_merge(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int id)
int create_bloom, locked, in_sync, tret;
const char *cfg[3];
const char *drop_cfg[] =
- { WT_CONFIG_BASE(session, session_drop), "force", NULL };
+ { WT_CONFIG_BASE(session, WT_SESSION_drop), "force", NULL };
bloom = NULL;
chunk = NULL;
@@ -337,7 +337,7 @@ __wt_lsm_merge(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int id)
/* Discard pages we read as soon as we're done with them. */
F_SET(session, WT_SESSION_NO_CACHE);
- cfg[0] = WT_CONFIG_BASE(session, session_open_cursor);
+ cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_open_cursor);
cfg[1] = "bulk,raw,skip_sort_check";
cfg[2] = NULL;
WT_ERR(__wt_open_cursor(session, chunk->uri, NULL, cfg, &dest));
diff --git a/src/lsm/lsm_stat.c b/src/lsm/lsm_stat.c
index e994300d4d3..5398982aef4 100644
--- a/src/lsm/lsm_stat.c
+++ b/src/lsm/lsm_stat.c
@@ -26,9 +26,9 @@ __curstat_lsm_init(
int locked;
char config[64];
const char *cfg[] = {
- WT_CONFIG_BASE(session, session_open_cursor), NULL, NULL };
+ WT_CONFIG_BASE(session, WT_SESSION_open_cursor), NULL, NULL };
const char *disk_cfg[] = {
- WT_CONFIG_BASE(session, session_open_cursor),
+ WT_CONFIG_BASE(session, WT_SESSION_open_cursor),
"checkpoint=" WT_CHECKPOINT, NULL, NULL };
locked = 0;
diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c
index 2bded10cb96..cce49984f43 100644
--- a/src/lsm/lsm_tree.c
+++ b/src/lsm/lsm_tree.c
@@ -230,7 +230,7 @@ __lsm_tree_cleanup_old(WT_SESSION_IMPL *session, const char *uri)
{
WT_DECL_RET;
const char *cfg[] =
- { WT_CONFIG_BASE(session, session_drop), "force", NULL };
+ { WT_CONFIG_BASE(session, WT_SESSION_drop), "force", NULL };
int exists;
WT_RET(__wt_exist(session, uri + strlen("file:"), &exists));
@@ -303,7 +303,7 @@ __wt_lsm_tree_create(WT_SESSION_IMPL *session,
WT_DECL_RET;
WT_LSM_TREE *lsm_tree;
const char *cfg[] =
- { WT_CONFIG_BASE(session, session_create), config, NULL };
+ { WT_CONFIG_BASE(session, WT_SESSION_create), config, NULL };
char *tmpconfig;
/* If the tree is open, it already exists. */
@@ -372,7 +372,7 @@ __wt_lsm_tree_create(WT_SESSION_IMPL *session,
cval.len -= 2;
}
WT_ERR(__wt_config_check(session,
- WT_CONFIG_REF(session, session_create), cval.str, cval.len));
+ WT_CONFIG_REF(session, WT_SESSION_create), cval.str, cval.len));
WT_ERR(__wt_strndup(
session, cval.str, cval.len, &lsm_tree->bloom_config));
@@ -513,7 +513,7 @@ __lsm_tree_open_check(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
WT_CONFIG_ITEM cval;
uint64_t maxleafpage, required;
const char *cfg[] = { WT_CONFIG_BASE(
- session, session_create), lsm_tree->file_config, NULL };
+ session, WT_SESSION_create), lsm_tree->file_config, NULL };
WT_RET(__wt_config_gets(session, cfg, "leaf_page_max", &cval));
maxleafpage = (uint64_t)cval.val;
@@ -539,8 +539,7 @@ __lsm_tree_open_check(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree)
* Open an LSM tree structure.
*/
static int
-__lsm_tree_open(
- WT_SESSION_IMPL *session, const char *uri, WT_LSM_TREE **treep)
+__lsm_tree_open(WT_SESSION_IMPL *session, const char *uri, WT_LSM_TREE **treep)
{
WT_CONNECTION_IMPL *conn;
WT_DECL_RET;
diff --git a/src/lsm/lsm_work_unit.c b/src/lsm/lsm_work_unit.c
index dea012ccb9e..74a52ad7402 100644
--- a/src/lsm/lsm_work_unit.c
+++ b/src/lsm/lsm_work_unit.c
@@ -344,7 +344,7 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session,
WT_RET_MSG(session, ret, "LSM metadata write");
/*
- * Clear the "cache resident" flag so the primary can be evicted and
+ * Clear the no-eviction flag so the primary can be evicted and
* eventually closed. Only do this once the checkpoint has succeeded:
* otherwise, accessing the leaf page during the checkpoint can trigger
* forced eviction.
@@ -457,7 +457,7 @@ __lsm_discard_handle(
WT_RET(__wt_session_get_btree(session, uri, checkpoint, NULL,
WT_DHANDLE_EXCLUSIVE | WT_DHANDLE_LOCK_ONLY));
- F_SET(session->dhandle, WT_DHANDLE_DISCARD);
+ F_SET(session->dhandle, WT_DHANDLE_DISCARD_FORCE);
return (__wt_session_release_btree(session));
}
@@ -469,9 +469,8 @@ static int
__lsm_drop_file(WT_SESSION_IMPL *session, const char *uri)
{
WT_DECL_RET;
- const char *drop_cfg[] = {
- WT_CONFIG_BASE(session, session_drop), "remove_files=false", NULL
- };
+ const char *drop_cfg[] = { WT_CONFIG_BASE(
+ session, WT_SESSION_drop), "remove_files=false", NULL };
/*
* We need to grab the schema lock to drop the file, so first try to
diff --git a/src/meta/meta_table.c b/src/meta/meta_table.c
index fb568361f74..a2e4a2f8e9f 100644
--- a/src/meta/meta_table.c
+++ b/src/meta/meta_table.c
@@ -60,7 +60,7 @@ __wt_metadata_cursor(
WT_DATA_HANDLE *saved_dhandle;
WT_DECL_RET;
const char *cfg[] =
- { WT_CONFIG_BASE(session, session_open_cursor), config, NULL };
+ { WT_CONFIG_BASE(session, WT_SESSION_open_cursor), config, NULL };
saved_dhandle = session->dhandle;
WT_ERR(__wt_metadata_open(session));
@@ -71,7 +71,7 @@ __wt_metadata_cursor(
* We use the metadata a lot, so we have a handle cached; lock it and
* increment the in-use counter once the cursor is open.
*/
- WT_ERR(__wt_session_lock_dhandle(session, 0));
+ WT_ERR(__wt_session_lock_dhandle(session, 0, NULL));
WT_ERR(__wt_curfile_create(session, NULL, cfg, 0, 0, cursorp));
__wt_cursor_dhandle_incr_use(session);
diff --git a/src/meta/meta_track.c b/src/meta/meta_track.c
index 3bc6a1f9d60..62d4df47ff6 100644
--- a/src/meta/meta_track.c
+++ b/src/meta/meta_track.c
@@ -184,6 +184,35 @@ free: trk->op = WT_ST_EMPTY;
}
/*
+ * __wt_meta_track_find_handle --
+ * Check if we have already seen a handle.
+ */
+int
+__wt_meta_track_find_handle(
+ WT_SESSION_IMPL *session, const char *name, const char *checkpoint)
+{
+ WT_META_TRACK *trk, *trk_orig;
+
+ WT_ASSERT(session,
+ WT_META_TRACKING(session) && session->meta_track_nest > 0);
+
+ trk_orig = session->meta_track;
+ trk = session->meta_track_next;
+
+ while (--trk >= trk_orig) {
+ if (trk->op != WT_ST_LOCK)
+ continue;
+ if (strcmp(trk->dhandle->name, name) == 0 &&
+ ((trk->dhandle->checkpoint == NULL && checkpoint == NULL) ||
+ (trk->dhandle->checkpoint != NULL &&
+ strcmp(trk->dhandle->checkpoint, checkpoint) == 0)))
+ return (0);
+ }
+
+ return (WT_NOTFOUND);
+}
+
+/*
* __wt_meta_track_off --
* Turn off metadata operation tracking, unrolling on error.
*/
diff --git a/src/os_posix/os_alloc.c b/src/os_posix/os_alloc.c
index 7e2cc3c486b..e0613197642 100644
--- a/src/os_posix/os_alloc.c
+++ b/src/os_posix/os_alloc.c
@@ -9,6 +9,21 @@
#include "wt_internal.h"
/*
+ * On systems with poor default allocators for allocations greater than 16 KB,
+ * we provide an option to use TCMalloc explicitly.
+ * This is important on Windows which does not have a builtin mechanism
+ * to replace C run-time memory management functions with alternatives.
+ */
+#ifdef HAVE_LIBTCMALLOC
+#include <gperftools/tcmalloc.h>
+
+#define calloc tc_calloc
+#define realloc tc_realloc
+#define posix_memalign tc_posix_memalign
+#define free tc_free
+#endif
+
+/*
* There's no malloc interface, WiredTiger never calls malloc.
*
* The problem is an application might allocate memory, write secret stuff in
diff --git a/src/os_win/os_fallocate.c b/src/os_win/os_fallocate.c
index a54b4cb044f..ee1335af12e 100644
--- a/src/os_win/os_fallocate.c
+++ b/src/os_win/os_fallocate.c
@@ -18,16 +18,12 @@ __wt_fallocate_config(WT_SESSION_IMPL *session, WT_FH *fh)
WT_UNUSED(session);
/*
- * fallocate on Windows is implemented using SetEndOfFile which can
- * also truncate the file. WiredTiger expects fallocate to ignore
- * requests to truncate the file which Windows does not do.
+ * fallocate on Windows would be implemented using SetEndOfFile, which
+ * can also truncate the file. WiredTiger expects fallocate to ignore
+ * requests to truncate the file which Windows does not do, so we don't
+ * support the call.
*/
fh->fallocate_available = WT_FALLOCATE_NOT_AVAILABLE;
-
- /*
- * We use a separate handle for file size changes, so there's no need
- * for locking.
- */
fh->fallocate_requires_locking = 0;
}
@@ -39,5 +35,10 @@ int
__wt_fallocate(
WT_SESSION_IMPL *session, WT_FH *fh, wt_off_t offset, wt_off_t len)
{
+ WT_UNUSED(session);
+ WT_UNUSED(fh);
+ WT_UNUSED(offset);
+ WT_UNUSED(len);
+
return (ENOTSUP);
}
diff --git a/src/schema/schema_create.c b/src/schema/schema_create.c
index 80e443d8a21..c003ad90ca7 100644
--- a/src/schema/schema_create.c
+++ b/src/schema/schema_create.c
@@ -180,10 +180,11 @@ __create_colgroup(WT_SESSION_IMPL *session,
const char **cfgp, *cfg[4] =
{ WT_CONFIG_BASE(session, colgroup_meta), config, NULL, NULL };
const char *sourcecfg[] = { config, NULL, NULL };
- const char *cgname, *source, *tablename;
- char *cgconf, *sourceconf, *oldconf;
+ const char *cgname, *source, *sourceconf, *tablename;
+ char *cgconf, *oldconf;
- cgconf = sourceconf = oldconf = NULL;
+ sourceconf = NULL;
+ cgconf = oldconf = NULL;
WT_CLEAR(fmt);
WT_CLEAR(confbuf);
WT_CLEAR(namebuf);
@@ -244,7 +245,7 @@ __create_colgroup(WT_SESSION_IMPL *session,
table, cval.str, cval.len, NULL, 1, &fmt));
}
sourcecfg[1] = fmt.data;
- WT_ERR(__wt_config_concat(session, sourcecfg, &sourceconf));
+ WT_ERR(__wt_config_merge(session, sourcecfg, NULL, &sourceconf));
WT_ERR(__wt_schema_create(session, source, sourceconf));
@@ -322,13 +323,14 @@ __create_index(WT_SESSION_IMPL *session,
const char *cfg[4] =
{ WT_CONFIG_BASE(session, index_meta), NULL, NULL, NULL };
const char *sourcecfg[] = { config, NULL, NULL };
- const char *source, *idxname, *tablename;
- char *sourceconf, *idxconf;
+ const char *source, *sourceconf, *idxname, *tablename;
+ char *idxconf;
size_t tlen;
int have_extractor;
u_int i, npublic_cols;
- idxconf = sourceconf = NULL;
+ sourceconf = NULL;
+ idxconf = NULL;
WT_CLEAR(confbuf);
WT_CLEAR(fmt);
WT_CLEAR(extra_cols);
@@ -458,7 +460,7 @@ __create_index(WT_SESSION_IMPL *session,
session, &fmt, ",index_key_columns=%u", npublic_cols));
sourcecfg[1] = fmt.data;
- WT_ERR(__wt_config_concat(session, sourcecfg, &sourceconf));
+ WT_ERR(__wt_config_merge(session, sourcecfg, NULL, &sourceconf));
WT_ERR(__wt_schema_create(session, source, sourceconf));
@@ -573,7 +575,7 @@ __create_data_source(WT_SESSION_IMPL *session,
{
WT_CONFIG_ITEM cval;
const char *cfg[] = {
- WT_CONFIG_BASE(session, session_create), config, NULL };
+ WT_CONFIG_BASE(session, WT_SESSION_create), config, NULL };
/*
* Check to be sure the key/value formats are legal: the underlying
diff --git a/src/schema/schema_truncate.c b/src/schema/schema_truncate.c
index 1eb76226aad..be9f6bcfb57 100644
--- a/src/schema/schema_truncate.c
+++ b/src/schema/schema_truncate.c
@@ -84,7 +84,7 @@ __truncate_dsrc(WT_SESSION_IMPL *session, const char *uri)
const char *cfg[2];
/* Open a cursor and traverse the object, removing every entry. */
- cfg[0] = WT_CONFIG_BASE(session, session_open_cursor);
+ cfg[0] = WT_CONFIG_BASE(session, WT_SESSION_open_cursor);
cfg[1] = NULL;
WT_RET(__wt_open_cursor(session, uri, NULL, cfg, &cursor));
while ((ret = cursor->next(cursor)) == 0)
diff --git a/src/session/session_api.c b/src/session/session_api.c
index 599c7bdf44a..ac24ae18c1d 100644
--- a/src/session/session_api.c
+++ b/src/session/session_api.c
@@ -385,7 +385,7 @@ __wt_session_create_strip(WT_SESSION *wt_session,
{
WT_SESSION_IMPL *session = (WT_SESSION_IMPL *)wt_session;
const char *cfg[] =
- { WT_CONFIG_BASE(session, session_create), v1, v2, NULL };
+ { WT_CONFIG_BASE(session, WT_SESSION_create), v1, v2, NULL };
return (__wt_config_collapse(session, cfg, value_ret));
}
diff --git a/src/session/session_dhandle.c b/src/session/session_dhandle.c
index 0825f783ca3..ce5f95a40d0 100644
--- a/src/session/session_dhandle.c
+++ b/src/session/session_dhandle.c
@@ -47,7 +47,7 @@ __session_add_dhandle(
* the schema lock.
*/
int
-__wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags)
+__wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags, int *deadp)
{
enum { NOLOCK, READLOCK, WRITELOCK } locked;
WT_BTREE *btree;
@@ -57,6 +57,8 @@ __wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags)
btree = S2BT(session);
dhandle = session->dhandle;
locked = NOLOCK;
+ if (deadp != NULL)
+ *deadp = 0;
/*
* Special operation flags will cause the handle to be reopened.
@@ -95,7 +97,10 @@ __wt_session_lock_dhandle(WT_SESSION_IMPL *session, uint32_t flags)
* required, we're done. Otherwise, check that the handle is open and
* that no special flags are required.
*/
- if (LF_ISSET(WT_DHANDLE_LOCK_ONLY) ||
+ if (F_ISSET(dhandle, WT_DHANDLE_DEAD)) {
+ WT_ASSERT(session, deadp != NULL);
+ *deadp = 1;
+ } else if (LF_ISSET(WT_DHANDLE_LOCK_ONLY) ||
(F_ISSET(dhandle, WT_DHANDLE_OPEN) && special_flags == 0))
return (0);
@@ -135,46 +140,25 @@ __wt_session_release_btree(WT_SESSION_IMPL *session)
dhandle = session->dhandle;
locked = F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE) ? WRITELOCK : READLOCK;
- if (F_ISSET(dhandle, WT_DHANDLE_DISCARD_CLOSE)) {
- /*
- * If configured to discard on last close, trade any read lock
- * for an exclusive lock. If the exchange succeeds, setup for
- * discard. It is expected acquiring an exclusive lock will fail
- * sometimes since the handle may still be in use: in that case
- * we're done.
- */
- if (locked == READLOCK) {
- locked = NOLOCK;
- WT_ERR(__wt_readunlock(session, dhandle->rwlock));
- ret = __wt_try_writelock(session, dhandle->rwlock);
- if (ret != 0) {
- if (ret == EBUSY)
- ret = 0;
- goto err;
- }
- locked = WRITELOCK;
- F_CLR(dhandle, WT_DHANDLE_DISCARD_CLOSE);
- F_SET(dhandle,
- WT_DHANDLE_DISCARD | WT_DHANDLE_EXCLUSIVE);
- }
- }
-
/*
* If we had special flags set, close the handle so that future access
* can get a handle without special flags.
*/
- if (F_ISSET(dhandle, WT_DHANDLE_DISCARD) ||
+ if (F_ISSET(dhandle, WT_DHANDLE_DISCARD_FORCE)) {
+ WT_WITH_DHANDLE_LOCK(session,
+ ret = __wt_conn_btree_sync_and_close(session, 0, 1));
+ F_CLR(dhandle, WT_DHANDLE_DISCARD_FORCE);
+ } else if (F_ISSET(dhandle, WT_DHANDLE_DISCARD) ||
F_ISSET(btree, WT_BTREE_SPECIAL_FLAGS)) {
WT_ASSERT(session, F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE));
+ ret = __wt_conn_btree_sync_and_close(session, 0, 0);
F_CLR(dhandle, WT_DHANDLE_DISCARD);
-
- WT_TRET(__wt_conn_btree_sync_and_close(session, 0, 0));
}
if (F_ISSET(dhandle, WT_DHANDLE_EXCLUSIVE))
F_CLR(dhandle, WT_DHANDLE_EXCLUSIVE);
-err: switch (locked) {
+ switch (locked) {
case NOLOCK:
break;
case READLOCK:
@@ -312,7 +296,8 @@ __session_dhandle_sweep(WT_SESSION_IMPL *session)
dhandle = dhandle_cache->dhandle;
if (dhandle != session->dhandle &&
dhandle->session_inuse == 0 &&
- now - dhandle->timeofdeath > conn->sweep_idle_time) {
+ (F_ISSET(dhandle, WT_DHANDLE_DEAD) ||
+ now - dhandle->timeofdeath > conn->sweep_idle_time)) {
WT_STAT_FAST_CONN_INCR(session, dh_session_handles);
__session_discard_btree(session, dhandle_cache);
}
@@ -348,6 +333,7 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
WT_DATA_HANDLE_CACHE *dhandle_cache;
WT_DECL_RET;
uint64_t bucket;
+ int is_dead;
WT_ASSERT(session, !F_ISSET(session, WT_SESSION_NO_DATA_HANDLES));
WT_ASSERT(session, !LF_ISSET(WT_DHANDLE_HAVE_REF));
@@ -381,7 +367,8 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
if (dhandle != NULL) {
/* Try to lock the handle; if this succeeds, we're done. */
- if ((ret = __wt_session_lock_dhandle(session, flags)) == 0)
+ if ((ret =
+ __wt_session_lock_dhandle(session, flags, &is_dead)) == 0)
goto done;
/* Propagate errors we don't expect. */
@@ -389,17 +376,23 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
return (ret);
/*
- * Don't try harder to get the btree handle if our caller
- * hasn't allowed us to take the schema lock - they do so on
- * purpose and will handle error returns.
+ * Don't try harder to get the handle if we're only checking
+ * for locks or our caller hasn't allowed us to take the schema
+ * lock - they do so on purpose and will handle error returns.
*/
- if (!F_ISSET(session, WT_SESSION_SCHEMA_LOCKED) &&
+ if ((LF_ISSET(WT_DHANDLE_LOCK_ONLY) && ret == EBUSY) ||
+ (!F_ISSET(session, WT_SESSION_SCHEMA_LOCKED) &&
F_ISSET(session,
- WT_SESSION_HANDLE_LIST_LOCKED | WT_SESSION_TABLE_LOCKED))
+ WT_SESSION_HANDLE_LIST_LOCKED | WT_SESSION_TABLE_LOCKED)))
return (ret);
- /* We found the data handle, don't try to get it again. */
- LF_SET(WT_DHANDLE_HAVE_REF);
+ /* If we found the handle and it isn't dead, reopen it. */
+ if (is_dead) {
+ __session_discard_btree(session, dhandle_cache);
+ dhandle_cache = NULL;
+ session->dhandle = dhandle = NULL;
+ } else
+ LF_SET(WT_DHANDLE_HAVE_REF);
}
/*
@@ -419,11 +412,11 @@ __wt_session_get_btree(WT_SESSION_IMPL *session,
WT_RET(__session_add_dhandle(session, NULL));
WT_ASSERT(session, LF_ISSET(WT_DHANDLE_LOCK_ONLY) ||
- F_ISSET(session->dhandle, WT_DHANDLE_OPEN));
+ (F_ISSET(session->dhandle, WT_DHANDLE_OPEN) &&
+ !F_ISSET(session->dhandle, WT_DHANDLE_DEAD)));
done: WT_ASSERT(session, LF_ISSET(WT_DHANDLE_EXCLUSIVE) ==
F_ISSET(session->dhandle, WT_DHANDLE_EXCLUSIVE));
- F_SET(session->dhandle, LF_ISSET(WT_DHANDLE_DISCARD_CLOSE));
return (0);
}
@@ -438,9 +431,18 @@ __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *checkpoint)
WT_DATA_HANDLE *dhandle, *saved_dhandle;
WT_DECL_RET;
+ WT_ASSERT(session, WT_META_TRACKING(session));
saved_dhandle = session->dhandle;
/*
+ * If we already have the checkpoint locked, don't attempt to lock
+ * it again.
+ */
+ if ((ret = __wt_meta_track_find_handle(
+ session, saved_dhandle->name, checkpoint)) != WT_NOTFOUND)
+ return (ret);
+
+ /*
* Get the checkpoint handle exclusive, so no one else can access it
* while we are creating the new checkpoint.
*/
@@ -463,7 +465,6 @@ __wt_session_lock_checkpoint(WT_SESSION_IMPL *session, const char *checkpoint)
dhandle = session->dhandle;
F_SET(dhandle, WT_DHANDLE_DISCARD);
- WT_ASSERT(session, WT_META_TRACKING(session));
WT_ERR(__wt_meta_track_handle_lock(session, 0));
/* Restore the original btree in the session. */
diff --git a/src/support/err.c b/src/support/err.c
index 34e44701ea0..e9b7a53a2ab 100644
--- a/src/support/err.c
+++ b/src/support/err.c
@@ -188,10 +188,10 @@ __wt_eventv(WT_SESSION_IMPL *session, int msg_event, int error,
end = s + sizeof(s);
/*
- * We have several prefixes for the error message:
- * a timestamp and the process and thread ids, the database error
- * prefix, the data-source's name, and the session's name. Write them
- * as a comma-separate list, followed by a colon.
+ * We have several prefixes for the error message: a timestamp and the
+ * process and thread ids, the database error prefix, the data-source's
+ * name, and the session's name. Write them as a comma-separate list,
+ * followed by a colon.
*/
prefix_cnt = 0;
if (__wt_epoch(session, &ts) == 0) {
diff --git a/src/support/hazard.c b/src/support/hazard.c
index bc44f7967a5..37cb8bf6ce0 100644
--- a/src/support/hazard.c
+++ b/src/support/hazard.c
@@ -33,7 +33,7 @@ __wt_hazard_set(WT_SESSION_IMPL *session, WT_REF *ref, int *busyp
*busyp = 0;
/* If a file can never be evicted, hazard pointers aren't required. */
- if (F_ISSET(btree, WT_BTREE_NO_HAZARD))
+ if (F_ISSET(btree, WT_BTREE_IN_MEMORY))
return (0);
/*
@@ -142,7 +142,7 @@ __wt_hazard_clear(WT_SESSION_IMPL *session, WT_PAGE *page)
btree = S2BT(session);
/* If a file can never be evicted, hazard pointers aren't required. */
- if (F_ISSET(btree, WT_BTREE_NO_HAZARD))
+ if (F_ISSET(btree, WT_BTREE_IN_MEMORY))
return (0);
/*
diff --git a/src/txn/txn.c b/src/txn/txn.c
index a1bec569ce7..fb0a4b7fa6d 100644
--- a/src/txn/txn.c
+++ b/src/txn/txn.c
@@ -34,8 +34,11 @@ __txn_sort_snapshot(WT_SESSION_IMPL *session, uint32_t n, uint64_t snap_max)
txn = &session->txn;
- if (n > 1)
+ if (n <= 10)
+ WT_INSERTION_SORT(txn->snapshot, n, uint64_t, TXNID_LT);
+ else
qsort(txn->snapshot, n, sizeof(uint64_t), __wt_txnid_cmp);
+
txn->snapshot_count = n;
txn->snap_max = snap_max;
txn->snap_min = (n > 0 && TXNID_LE(txn->snapshot[0], snap_max)) ?
@@ -261,11 +264,11 @@ __wt_txn_refresh(WT_SESSION_IMPL *session, int get_snapshot)
}
/*
- * __wt_txn_begin --
- * Begin a transaction.
+ * __wt_txn_config --
+ * Configure a transaction.
*/
int
-__wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
+__wt_txn_config(WT_SESSION_IMPL *session, const char *cfg[])
{
WT_CONFIG_ITEM cval;
WT_TXN *txn;
@@ -273,9 +276,7 @@ __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
txn = &session->txn;
WT_RET(__wt_config_gets_def(session, cfg, "isolation", 0, &cval));
- if (cval.len == 0)
- txn->isolation = session->isolation;
- else
+ if (cval.len != 0)
txn->isolation =
WT_STRING_MATCH("snapshot", cval.str, cval.len) ?
TXN_ISO_SNAPSHOT :
@@ -291,18 +292,11 @@ __wt_txn_begin(WT_SESSION_IMPL *session, const char *cfg[])
* the connection-wide flag and not overridden here, we end up clearing
* all flags.
*/
- txn->txn_logsync = S2C(session)->txn_logsync;
WT_RET(__wt_config_gets_def(session, cfg, "sync",
FLD_ISSET(txn->txn_logsync, WT_LOG_FLUSH) ? 1 : 0, &cval));
if (!cval.val)
txn->txn_logsync = 0;
- F_SET(txn, TXN_RUNNING);
- if (txn->isolation == TXN_ISO_SNAPSHOT) {
- if (session->ncursors > 0)
- WT_RET(__wt_session_copy_values(session));
- __wt_txn_refresh(session, 1);
- }
return (0);
}
diff --git a/src/txn/txn_ckpt.c b/src/txn/txn_ckpt.c
index 7c1532390f9..45560ff897a 100644
--- a/src/txn/txn_ckpt.c
+++ b/src/txn/txn_ckpt.c
@@ -349,9 +349,8 @@ __wt_txn_checkpoint(WT_SESSION_IMPL *session, const char *cfg[])
WT_TXN *txn;
WT_TXN_GLOBAL *txn_global;
WT_TXN_ISOLATION saved_isolation;
- const char *txn_cfg[] =
- { WT_CONFIG_BASE(session, session_begin_transaction),
- "isolation=snapshot", NULL };
+ const char *txn_cfg[] = { WT_CONFIG_BASE(session,
+ WT_SESSION_begin_transaction), "isolation=snapshot", NULL };
void *saved_meta_next;
int full, logging, tracking;
u_int i;
@@ -1090,7 +1089,7 @@ __wt_checkpoint_sync(WT_SESSION_IMPL *session, const char *cfg[])
* Checkpoint a single file as part of closing the handle.
*/
int
-__wt_checkpoint_close(WT_SESSION_IMPL *session, int final, int force)
+__wt_checkpoint_close(WT_SESSION_IMPL *session, int final)
{
WT_BTREE *btree;
WT_DECL_RET;
@@ -1099,8 +1098,8 @@ __wt_checkpoint_close(WT_SESSION_IMPL *session, int final, int force)
btree = S2BT(session);
bulk = F_ISSET(btree, WT_BTREE_BULK) ? 1 : 0;
- /* Handle forced discard (when dropping a file). */
- if (force)
+ /* If the handle is already dead, force the discard. */
+ if (F_ISSET(session->dhandle, WT_DHANDLE_DEAD))
return (__wt_cache_op(session, NULL, WT_SYNC_DISCARD_FORCE));
/*
diff --git a/src/txn/txn_recover.c b/src/txn/txn_recover.c
index f6cd384417f..53d0a9bfc1e 100644
--- a/src/txn/txn_recover.c
+++ b/src/txn/txn_recover.c
@@ -41,8 +41,8 @@ __recovery_cursor(WT_SESSION_IMPL *session, WT_RECOVERY *r,
WT_LSN *lsnp, u_int id, int duplicate, WT_CURSOR **cp)
{
WT_CURSOR *c;
- const char *cfg[] = { WT_CONFIG_BASE(session, session_open_cursor),
- "overwrite", NULL };
+ const char *cfg[] = { WT_CONFIG_BASE(
+ session, WT_SESSION_open_cursor), "overwrite", NULL };
int metadata_op;
c = NULL;
@@ -65,7 +65,7 @@ __recovery_cursor(WT_SESSION_IMPL *session, WT_RECOVERY *r,
"No file found with ID %u (max %u)",
id, r->nfiles));
r->missing = 1;
- } else if (LOG_CMP(lsnp, &r->files[id].ckpt_lsn) >= 0) {
+ } else if (WT_LOG_CMP(lsnp, &r->files[id].ckpt_lsn) >= 0) {
/*
* We're going to apply the operation. Get the cursor, opening
* one if none is cached.
diff --git a/src/utilities/util_load.c b/src/utilities/util_load.c
index e6fe721e53e..f4f173b90c2 100644
--- a/src/utilities/util_load.c
+++ b/src/utilities/util_load.c
@@ -349,8 +349,10 @@ config_reorder(WT_SESSION *session, char **list)
int
config_update(WT_SESSION *session, char **list)
{
+ WT_DECL_RET;
int found;
- const char *p, *cfg[] = { NULL, NULL, NULL };
+ size_t cnt;
+ const char *p, **cfg;
char **configp, **listp;
/*
@@ -378,64 +380,29 @@ config_update(WT_SESSION *session, char **list)
}
/*
- * New filenames will be chosen as part of the table load, remove all
- * "filename=", "source=" and other configurations that foil loading
- * from the values; we call an unpublished API to do the removal.
- */
- for (listp = list; *listp != NULL; listp += 2) {
- cfg[0] = listp[1];
- cfg[1] = NULL;
- if (__wt_config_merge((WT_SESSION_IMPL *)session,
- cfg,
- "filename=,id=,"
- "checkpoint=,checkpoint_lsn=,version=,source=,",
- &p))
- return (1);
- free(listp[1]);
- listp[1] = (char *)p;
- }
-
- /*
- * It's possible to update everything except the key/value formats.
+ * Updating the key/value formats seems like an easy mistake to make.
* If there were command-line configuration pairs, walk the list of
- * command-line configuration strings, and check.
+ * command-line configuration strings and check.
*/
for (configp = cmdconfig;
- cmdconfig != NULL && *configp != NULL; configp += 2)
+ configp != NULL && *configp != NULL; configp += 2)
if (strstr(configp[1], "key_format=") ||
strstr(configp[1], "value_format="))
return (util_err(session, 0,
- "the command line configuration string may not "
- "modify the object's key or value format"));
+ "an object's key or value format may not be "
+ "modified"));
/*
* If there were command-line configuration pairs, walk the list of
- * command-line URIs and find a matching dump URI. For each match,
- * rewrite the dump configuration as described by the command-line
- * configuration. It is an error if a command-line URI doesn't find
- * a single, exact match, that's likely a mistake.
+ * command-line URIs and find a matching dump URI. It is an error
+ * if a command-line URI doesn't find a single, exact match, that's
+ * likely a mistake.
*/
for (configp = cmdconfig;
- cmdconfig != NULL && *configp != NULL; configp += 2) {
- found = 0;
- for (listp = list; *listp != NULL; listp += 2) {
- if (strncmp(*configp, listp[0], strlen(*configp)) != 0)
- continue;
- /*
- * !!!
- * We support JSON configuration strings, which leads to
- * configuration strings with brackets. Unfortunately,
- * that implies we can't simply append new configuration
- * strings to existing ones, we call an unpublished API
- * to do the concatenation.
- */
- cfg[0] = listp[1];
- cfg[1] = configp[1];
- if (__wt_config_concat(
- (WT_SESSION_IMPL *)session, cfg, &listp[1]) != 0)
- return (1);
- ++found;
- }
+ configp != NULL && *configp != NULL; configp += 2) {
+ for (found = 0, listp = list; *listp != NULL; listp += 2)
+ if (strncmp(*configp, listp[0], strlen(*configp)) == 0)
+ ++found;
switch (found) {
case 0:
return (util_err(session, 0,
@@ -451,8 +418,46 @@ config_update(WT_SESSION *session, char **list)
}
}
- /* Leak the memory, I don't care. */
- return (0);
+ /*
+ * Allocate a big enough configuration stack to hold all of the command
+ * line arguments, a list of configuration values to remove, and the
+ * base configuration values, plus some slop.
+ */
+ for (cnt = 0, configp = cmdconfig;
+ cmdconfig != NULL && *configp != NULL; configp += 2)
+ ++cnt;
+ if ((cfg = calloc(cnt + 10, sizeof(cfg[0]))) == NULL)
+ return (util_err(session, errno, NULL));
+
+ /*
+ * For each match, rewrite the dump configuration as described by any
+ * command-line configuration arguments.
+ *
+ * New filenames will be chosen as part of the table load, remove all
+ * "filename=", "source=" and other configurations that foil loading
+ * from the values; we call an unpublished API to do the work.
+ */
+ for (listp = list; *listp != NULL; listp += 2) {
+ cnt = 0;
+ cfg[cnt++] = listp[1];
+ for (configp = cmdconfig;
+ cmdconfig != NULL && *configp != NULL; configp += 2)
+ if (strncmp(*configp, listp[0], strlen(*configp)) == 0)
+ cfg[cnt++] = configp[1];
+ cfg[cnt++] = NULL;
+
+ if ((ret = __wt_config_merge((WT_SESSION_IMPL *)session,
+ cfg,
+ "filename=,id=,"
+ "checkpoint=,checkpoint_lsn=,version=,source=,",
+ &p)) != 0)
+ break;
+
+ free(listp[1]);
+ listp[1] = (char *)p;
+ }
+ free(cfg);
+ return (ret);
}
/*
diff --git a/test/suite/test_bug007.py b/test/suite/test_bug007.py
index ab03657c944..8a10175d28b 100644
--- a/test/suite/test_bug007.py
+++ b/test/suite/test_bug007.py
@@ -51,7 +51,7 @@ class test_bug007(wttest.WiredTigerTestCase):
# Salvage should fail.
self.assertRaisesWithMessage(
wiredtiger.WiredTigerError,
- lambda: self.session.salvage(uri), "/session.salvage/")
+ lambda: self.session.salvage(uri), "/WT_SESSION.salvage/")
# Forced salvage should succeed.
self.session.salvage(uri, "force")
diff --git a/test/suite/test_util02.py b/test/suite/test_util02.py
index f55542e3d3f..33672411671 100644
--- a/test/suite/test_util02.py
+++ b/test/suite/test_util02.py
@@ -30,6 +30,7 @@ import string, os
import wiredtiger, wttest
from suite_subprocess import suite_subprocess
from wtscenario import check_scenarios
+from helper import complex_populate
# test_util02.py
# Utilities: wt load
@@ -110,7 +111,8 @@ class test_util02(wttest.WiredTigerTestCase, suite_subprocess):
result += "%0.2x" % ord(c)
elif c == '\\':
result += '\\\\'
- elif c == ' ' or (c in string.printable and not c in string.whitespace):
+ elif c == ' ' or \
+ (c in string.printable and not c in string.whitespace):
result += c
else:
result += '\\' + "%0.2x" % ord(c)
@@ -121,7 +123,8 @@ class test_util02(wttest.WiredTigerTestCase, suite_subprocess):
return result
def table_config(self):
- return 'key_format=' + self.key_format + ',value_format=' + self.value_format
+ return 'key_format=' + \
+ self.key_format + ',value_format=' + self.value_format
def load_process(self, hexoutput):
params = self.table_config()
@@ -142,7 +145,8 @@ class test_util02(wttest.WiredTigerTestCase, suite_subprocess):
self.runWt(["load", "-f", "dump.out", "-r", self.tablename2])
- cursor = self.session.open_cursor('table:' + self.tablename2, None, None)
+ cursor =\
+ self.session.open_cursor('table:' + self.tablename2, None, None)
self.assertEqual(cursor.key_format, self.key_format)
self.assertEqual(cursor.value_format, self.value_format)
i = 0
@@ -158,5 +162,63 @@ class test_util02(wttest.WiredTigerTestCase, suite_subprocess):
def test_load_process_hex(self):
self.load_process(True)
+
+# test_load_commandline --
+# Test the command-line processing.
+class test_load_commandline(wttest.WiredTigerTestCase, suite_subprocess):
+ uri = "table:command_line"
+
+ def load_commandline(self, args, fail):
+ errfile= "errfile"
+ complex_populate(self, self.uri, "key_format=S,value_format=S", 20)
+ self.runWt(["dump", self.uri], outfilename="dump.out")
+ loadargs = ["load", "-f", "dump.out"] + args
+ self.runWt(loadargs, errfilename=errfile)
+ if fail:
+ self.check_non_empty_file(errfile)
+ else:
+ self.check_empty_file(errfile)
+
+ # Empty arguments should suceed.
+ def test_load_commandline_1(self):
+ self.load_commandline([], 0)
+
+ # Arguments are in pairs.
+ def test_load_commandline_2(self):
+ self.load_commandline(["table"], 1)
+ self.load_commandline([self.uri, "block_allocation=first", self.uri], 1)
+
+ # You can use short-hand URIs for a single object, but cannot match multiple
+ # objects.
+ def test_load_commandline_3(self):
+ self.load_commandline(["table", "block_allocation=first"], 0)
+ self.load_commandline(["colgroup", "block_allocation=first"], 1)
+
+ # You can't reference non-existent objects.
+ def test_load_commandline_4(self):
+ self.load_commandline([self.uri, "block_allocation=first"], 0)
+ self.load_commandline(["table:bar", "block_allocation=first"], 1)
+
+ # You can specify multipleconfiguration arguments for the same object.
+ def test_load_commandline_5(self):
+ self.load_commandline([
+ self.uri, "block_allocation=first",
+ self.uri, "block_allocation=best",
+ self.uri, "block_allocation=first",
+ self.uri, "block_allocation=best"], 0)
+
+ # You can't modify a format.
+ def test_load_commandline_6(self):
+ self.load_commandline(["table", "key_format=d"], 1)
+ self.load_commandline(["table", "value_format=d"], 1)
+
+ # You can set the source or version, but it gets stripped; confirm the
+ # attempt succeeds, so we know they configuration values are stripped.
+ def test_load_commandline_7(self):
+ self.load_commandline(["table", "filename=bar"], 0)
+ self.load_commandline(["table", "source=bar"], 0)
+ self.load_commandline(["table", "version=(100,200)"], 0)
+
+
if __name__ == '__main__':
wttest.run()
diff --git a/test/suite/test_verify.py b/test/suite/test_verify.py
index 48a965141f0..5889054f269 100644
--- a/test/suite/test_verify.py
+++ b/test/suite/test_verify.py
@@ -138,7 +138,7 @@ class test_verify(wttest.WiredTigerTestCase, suite_subprocess):
self.session = self.setUpSessionOpen(self.conn)
self.assertRaisesWithMessage(wiredtiger.WiredTigerError,
lambda: self.session.verify('table:' + self.tablename, None),
- "/session.verify/")
+ "/WT_SESSION.verify/")
def test_verify_process_75pct_null(self):
"""