diff options
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{ 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): """ |