diff options
author | sueloverso <sue@mongodb.com> | 2016-12-15 13:06:31 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2016-12-15 13:06:31 -0500 |
commit | e8d8fd81109554f7ae845b92c716ed54364b433d (patch) | |
tree | 61e71c809512dc5acab8955e62221ce825fdd48a | |
parent | 2142d32fd6b747022da2bab0cf76b30941bab918 (diff) | |
download | mongo-e8d8fd81109554f7ae845b92c716ed54364b433d.tar.gz |
WT-283 Add WT_SESSION::alter method (#3177)
* WT-283 Add WT_SESSION:alter method
* Add new method to ex_all.c
* Typo
* Add testing and fixes for LSM, column groups and indexes for alter.
* Fix WITH_*_LOCK macro usage.
* Whitespace
* Change table alter to not walk down into column groups and indexes.
* Whitespace
* Use base file meta config and compare strings.
* Add skip stat
* Add alter support to wt command.
* Add util_alter.c to SConstruct
* Fix subsection in doc.
* Add alter thread to test/format
* Swap the value we send into alter in test/format.
* Add data-source alter support
* Only alter access pattern hint in test/format.
* Make LSM alter not exclusive.
* Whitespace
* Use access_pattern_hint in example.
* Include base lsm metadata configuration.
* Fix text/comment.
* Minor changes from review comments.
* Unused variable warning.
32 files changed, 792 insertions, 105 deletions
diff --git a/SConstruct b/SConstruct index 0ccdf59babc..df7a66238e8 100644 --- a/SConstruct +++ b/SConstruct @@ -294,6 +294,7 @@ env.Depends(wtdll, [filelistfile, version_file]) Default(wtlib, wtdll) wtbin = env.Program("wt", [ + "src/utilities/util_alter.c", "src/utilities/util_backup.c", "src/utilities/util_cpyright.c", "src/utilities/util_compact.c", diff --git a/build_posix/Make.base b/build_posix/Make.base index 5b945aca5e0..9354eb4b183 100644 --- a/build_posix/Make.base +++ b/build_posix/Make.base @@ -17,6 +17,7 @@ endif bin_PROGRAMS = wt wt_SOURCES =\ + src/utilities/util_alter.c \ src/utilities/util_backup.c \ src/utilities/util_cpyright.c \ src/utilities/util_compact.c \ diff --git a/dist/api_data.py b/dist/api_data.py index acbbf0f2a68..98f9b5a230a 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -118,8 +118,7 @@ lsm_config = [ ]), ] -# Per-file configuration -file_config = format_meta + [ +file_runtime_config = [ Config('access_pattern_hint', 'none', r''' It is recommended that workloads that consist primarily of updates and/or point queries specify \c random. Workloads that @@ -128,6 +127,14 @@ file_config = format_meta + [ option leads to an advisory call to an appropriate operating system API where available''', choices=['none', 'random', 'sequential']), + Config('cache_resident', 'false', r''' + do not ever evict the object's pages from cache. Not compatible with + LSM tables; see @ref tuning_cache_resident for more information''', + type='boolean'), +] + +# Per-file configuration +file_config = format_meta + file_runtime_config + [ Config('block_allocation', 'best', r''' configure block allocation. Permitted values are \c "first" or \c "best"; the \c "first" configuration uses a first-available @@ -146,10 +153,6 @@ file_config = format_meta + [ WT_CONNECTION::add_compressor. If WiredTiger has builtin support for \c "lz4", \c "snappy", \c "zlib" or \c "zstd" compression, these names are also available. See @ref compression for more information'''), - Config('cache_resident', 'false', r''' - do not ever evict the object's pages from cache. Not compatible with - LSM tables; see @ref tuning_cache_resident for more information''', - type='boolean'), Config('checksum', 'uncompressed', r''' configure block checksums; permitted values are <code>on</code> (checksum all blocks), <code>off</code> (checksum no blocks) and @@ -834,6 +837,8 @@ methods = { 'WT_CURSOR.reconfigure' : Method(cursor_runtime_config), +'WT_SESSION.alter' : Method(file_runtime_config), + 'WT_SESSION.close' : Method([]), 'WT_SESSION.compact' : Method([ diff --git a/dist/filelist b/dist/filelist index fe9a17b7799..13d67ef961b 100644 --- a/dist/filelist +++ b/dist/filelist @@ -159,6 +159,7 @@ src/packing/pack_impl.c src/packing/pack_stream.c src/reconcile/rec_track.c src/reconcile/rec_write.c +src/schema/schema_alter.c src/schema/schema_create.c src/schema/schema_drop.c src/schema/schema_list.c diff --git a/dist/stat_data.py b/dist/stat_data.py index bcf5201bd90..022810d5c49 100644 --- a/dist/stat_data.py +++ b/dist/stat_data.py @@ -367,6 +367,9 @@ connection_stats = [ ########################################## SessionStat('session_cursor_open', 'open cursor count', 'no_clear,no_scale'), SessionStat('session_open', 'open session count', 'no_clear,no_scale'), + SessionStat('session_table_alter_fail', 'table alter failed calls', 'no_clear,no_scale'), + SessionStat('session_table_alter_skip', 'table alter unchanged and skipped', 'no_clear,no_scale'), + SessionStat('session_table_alter_success', 'table alter successful calls', 'no_clear,no_scale'), SessionStat('session_table_compact_fail', 'table compact failed calls', 'no_clear,no_scale'), SessionStat('session_table_compact_success', 'table compact successful calls', 'no_clear,no_scale'), SessionStat('session_table_create_fail', 'table create failed calls', 'no_clear,no_scale'), diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c index ea646604a76..8a1533011b2 100644 --- a/examples/c/ex_all.c +++ b/examples/c/ex_all.c @@ -557,6 +557,12 @@ session_ops(WT_SESSION *session) /*! [Create a column-store table] */ ret = session->create(session, "table:mytable", "key_format=r,value_format=S"); + + /*! [Alter a table] */ + ret = session->alter(session, + "table:mytable", "access_pattern_hint=random"); + /*! [Alter a table] */ + /*! [Create a column-store table] */ ret = session->drop(session, "table:mytable", NULL); diff --git a/examples/c/ex_data_source.c b/examples/c/ex_data_source.c index 6ed80dfcf19..387248f6ae2 100644 --- a/examples/c/ex_data_source.c +++ b/examples/c/ex_data_source.c @@ -46,6 +46,21 @@ my_data_source_init(WT_CONNECTION *connection) } /*! [WT_EXTENSION_API declaration] */ +/*! [WT_DATA_SOURCE alter] */ +static int +my_alter(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config) +/*! [WT_DATA_SOURCE alter] */ +{ + /* Unused parameters */ + (void)dsrc; + (void)session; + (void)uri; + (void)config; + + return (0); +} + /*! [WT_DATA_SOURCE create] */ static int my_create(WT_DATA_SOURCE *dsrc, WT_SESSION *session, @@ -604,6 +619,7 @@ main(void) { /*! [WT_DATA_SOURCE register] */ static WT_DATA_SOURCE my_dsrc = { + my_alter, my_create, my_compact, my_drop, diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i index 2264cb31ef1..3606bed1d69 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -27,6 +27,7 @@ COPYDOC(__wt_async_op, WT_ASYNC_OP, remove) COPYDOC(__wt_async_op, WT_ASYNC_OP, compact) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_id) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_type) +COPYDOC(__wt_session, WT_SESSION, alter) COPYDOC(__wt_session, WT_SESSION, close) COPYDOC(__wt_session, WT_SESSION, reconfigure) COPYDOC(__wt_session, WT_SESSION, open_cursor) diff --git a/src/config/config_def.c b/src/config/config_def.c index 9d886cbf0bd..e4fd7937a40 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -162,6 +162,14 @@ static const WT_CONFIG_CHECK confchk_WT_CURSOR_reconfigure[] = { { NULL, NULL, NULL, NULL, NULL, 0 } }; +static const WT_CONFIG_CHECK confchk_WT_SESSION_alter[] = { + { "access_pattern_hint", "string", + NULL, "choices=[\"none\",\"random\",\"sequential\"]", + NULL, 0 }, + { "cache_resident", "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\"," @@ -1066,6 +1074,10 @@ static const WT_CONFIG_ENTRY config_entries[] = { "append=false,overwrite=true", confchk_WT_CURSOR_reconfigure, 2 }, + { "WT_SESSION.alter", + "access_pattern_hint=none,cache_resident=false", + confchk_WT_SESSION_alter, 2 + }, { "WT_SESSION.begin_transaction", "isolation=,name=,priority=0,snapshot=,sync=", confchk_WT_SESSION_begin_transaction, 5 diff --git a/src/docs/command-line.dox b/src/docs/command-line.dox index 0f5c56d25ce..5726a1d19a1 100644 --- a/src/docs/command-line.dox +++ b/src/docs/command-line.dox @@ -37,6 +37,39 @@ In general, commands that modify the database or tables will run recovery by default and commands that only read data will not run recovery. <hr> +@section util_alter wt alter +Alter a table. + +@subsection util_alter_synopsis Synopsis +<code>wt [-RVv] [-C config] [-E secretkey ] [-h directory] alter uri configuration ...</code> + +The \c uri and \c configuration pairs may be specified to the +\c alter command. These configuration pairs can be used to modify the +configuration values from those passed to the WT_SESSION::create +call. + +The \c uri part of the configuration pair should match only one of the +objects being altered, 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 altering a single table named \c xxx. + +@code +table access_pattern_hint=sequential +table:xxx access_pattern_hint=sequential +@endcode + +It's an error, however, to specify a matching prefix that matches more +than a single object being altered. + +Multiple \c configuration arguments may be specified. For example, the +following two sets of configuration pairs are equivalent: + +@code +table:xxx access_pattern_hint=random,cache_resident=false +table:xxx access_pattern_hint=random table:xxx cache_resident=false +@endcode + +<hr> @section util_backup wt backup Perform a backup of a database or set of data sources. diff --git a/src/include/config.h b/src/include/config.h index 486aa50e86c..f2746fc76d9 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -62,39 +62,40 @@ struct __wt_config_parser_impl { #define WT_CONFIG_ENTRY_WT_CONNECTION_set_file_system 10 #define WT_CONFIG_ENTRY_WT_CURSOR_close 11 #define WT_CONFIG_ENTRY_WT_CURSOR_reconfigure 12 -#define WT_CONFIG_ENTRY_WT_SESSION_begin_transaction 13 -#define WT_CONFIG_ENTRY_WT_SESSION_checkpoint 14 -#define WT_CONFIG_ENTRY_WT_SESSION_close 15 -#define WT_CONFIG_ENTRY_WT_SESSION_commit_transaction 16 -#define WT_CONFIG_ENTRY_WT_SESSION_compact 17 -#define WT_CONFIG_ENTRY_WT_SESSION_create 18 -#define WT_CONFIG_ENTRY_WT_SESSION_drop 19 -#define WT_CONFIG_ENTRY_WT_SESSION_join 20 -#define WT_CONFIG_ENTRY_WT_SESSION_log_flush 21 -#define WT_CONFIG_ENTRY_WT_SESSION_log_printf 22 -#define WT_CONFIG_ENTRY_WT_SESSION_open_cursor 23 -#define WT_CONFIG_ENTRY_WT_SESSION_rebalance 24 -#define WT_CONFIG_ENTRY_WT_SESSION_reconfigure 25 -#define WT_CONFIG_ENTRY_WT_SESSION_rename 26 -#define WT_CONFIG_ENTRY_WT_SESSION_reset 27 -#define WT_CONFIG_ENTRY_WT_SESSION_rollback_transaction 28 -#define WT_CONFIG_ENTRY_WT_SESSION_salvage 29 -#define WT_CONFIG_ENTRY_WT_SESSION_snapshot 30 -#define WT_CONFIG_ENTRY_WT_SESSION_strerror 31 -#define WT_CONFIG_ENTRY_WT_SESSION_transaction_sync 32 -#define WT_CONFIG_ENTRY_WT_SESSION_truncate 33 -#define WT_CONFIG_ENTRY_WT_SESSION_upgrade 34 -#define WT_CONFIG_ENTRY_WT_SESSION_verify 35 -#define WT_CONFIG_ENTRY_colgroup_meta 36 -#define WT_CONFIG_ENTRY_file_config 37 -#define WT_CONFIG_ENTRY_file_meta 38 -#define WT_CONFIG_ENTRY_index_meta 39 -#define WT_CONFIG_ENTRY_lsm_meta 40 -#define WT_CONFIG_ENTRY_table_meta 41 -#define WT_CONFIG_ENTRY_wiredtiger_open 42 -#define WT_CONFIG_ENTRY_wiredtiger_open_all 43 -#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 44 -#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 45 +#define WT_CONFIG_ENTRY_WT_SESSION_alter 13 +#define WT_CONFIG_ENTRY_WT_SESSION_begin_transaction 14 +#define WT_CONFIG_ENTRY_WT_SESSION_checkpoint 15 +#define WT_CONFIG_ENTRY_WT_SESSION_close 16 +#define WT_CONFIG_ENTRY_WT_SESSION_commit_transaction 17 +#define WT_CONFIG_ENTRY_WT_SESSION_compact 18 +#define WT_CONFIG_ENTRY_WT_SESSION_create 19 +#define WT_CONFIG_ENTRY_WT_SESSION_drop 20 +#define WT_CONFIG_ENTRY_WT_SESSION_join 21 +#define WT_CONFIG_ENTRY_WT_SESSION_log_flush 22 +#define WT_CONFIG_ENTRY_WT_SESSION_log_printf 23 +#define WT_CONFIG_ENTRY_WT_SESSION_open_cursor 24 +#define WT_CONFIG_ENTRY_WT_SESSION_rebalance 25 +#define WT_CONFIG_ENTRY_WT_SESSION_reconfigure 26 +#define WT_CONFIG_ENTRY_WT_SESSION_rename 27 +#define WT_CONFIG_ENTRY_WT_SESSION_reset 28 +#define WT_CONFIG_ENTRY_WT_SESSION_rollback_transaction 29 +#define WT_CONFIG_ENTRY_WT_SESSION_salvage 30 +#define WT_CONFIG_ENTRY_WT_SESSION_snapshot 31 +#define WT_CONFIG_ENTRY_WT_SESSION_strerror 32 +#define WT_CONFIG_ENTRY_WT_SESSION_transaction_sync 33 +#define WT_CONFIG_ENTRY_WT_SESSION_truncate 34 +#define WT_CONFIG_ENTRY_WT_SESSION_upgrade 35 +#define WT_CONFIG_ENTRY_WT_SESSION_verify 36 +#define WT_CONFIG_ENTRY_colgroup_meta 37 +#define WT_CONFIG_ENTRY_file_config 38 +#define WT_CONFIG_ENTRY_file_meta 39 +#define WT_CONFIG_ENTRY_index_meta 40 +#define WT_CONFIG_ENTRY_lsm_meta 41 +#define WT_CONFIG_ENTRY_table_meta 42 +#define WT_CONFIG_ENTRY_wiredtiger_open 43 +#define WT_CONFIG_ENTRY_wiredtiger_open_all 44 +#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 45 +#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 46 /* * configuration section: END * DO NOT EDIT: automatically built by dist/flags.py. diff --git a/src/include/extern.h b/src/include/extern.h index c7506e55976..be042bcd6cb 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -423,7 +423,7 @@ extern int __wt_lsm_manager_push_entry(WT_SESSION_IMPL *session, uint32_t type, extern int __wt_lsm_merge_update_tree(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int start_chunk, u_int nchunks, WT_LSM_CHUNK *chunk) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_merge(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int id) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_meta_read(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); -extern int __wt_lsm_meta_write(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); +extern int __wt_lsm_meta_write(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, const char *newconfig) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_curstat_lsm_init( WT_SESSION_IMPL *session, const char *uri, WT_CURSOR_STAT *cst) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_close_all(WT_SESSION_IMPL *session) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_bloom_name(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, uint32_t id, const char **retp) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); @@ -437,6 +437,7 @@ extern void __wt_lsm_tree_release(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tre extern void __wt_lsm_tree_throttle( WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, bool decrease_only) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_switch(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_retire_chunks(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int start_chunk, u_int nchunks) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); +extern int __wt_lsm_tree_alter( WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_drop( WT_SESSION_IMPL *session, const char *name, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_rename(WT_SESSION_IMPL *session, const char *olduri, const char *newuri, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_lsm_tree_truncate( WT_SESSION_IMPL *session, const char *name, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); @@ -551,6 +552,7 @@ extern int __wt_bulk_insert_row(WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk) extern int __wt_bulk_insert_fix( WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk, bool deleted) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_bulk_insert_fix_bitmap(WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_bulk_insert_var( WT_SESSION_IMPL *session, WT_CURSOR_BULK *cbulk, bool deleted) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); +extern int __wt_schema_alter(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_direct_io_size_check(WT_SESSION_IMPL *session, const char **cfg, const char *config_name, uint32_t *allocsizep) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_schema_colgroup_source(WT_SESSION_IMPL *session, WT_TABLE *table, const char *cgname, const char *config, WT_ITEM *buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); extern int __wt_schema_index_source(WT_SESSION_IMPL *session, WT_TABLE *table, const char *idxname, const char *config, WT_ITEM *buf) WT_GCC_FUNC_DECL_ATTRIBUTE((warn_unused_result)) WT_GCC_FUNC_DECL_ATTRIBUTE((visibility("hidden"))); diff --git a/src/include/stat.h b/src/include/stat.h index e53414fc0c9..0daab83e166 100644 --- a/src/include/stat.h +++ b/src/include/stat.h @@ -445,6 +445,9 @@ struct __wt_connection_stats { int64_t rec_split_stashed_objects; int64_t session_cursor_open; int64_t session_open; + int64_t session_table_alter_fail; + int64_t session_table_alter_success; + int64_t session_table_alter_skip; int64_t session_table_compact_fail; int64_t session_table_compact_success; int64_t session_table_create_fail; diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 4c72df0f073..a6deed7e14e 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -800,6 +800,34 @@ struct __wt_session { #endif /*! + * Alter a table. + * + * This will allow modification of some table settings after + * creation. + * + * @snippet ex_all.c Alter a table + * + * @param session the session handle + * @param name the URI of the object to alter, such as \c "table:stock" + * @configstart{WT_SESSION.alter, see dist/api_data.py} + * @config{access_pattern_hint, It is recommended that workloads that + * consist primarily of updates and/or point queries specify \c random. + * Workloads that do many cursor scans through large ranges of data + * specify \c sequential and other workloads specify \c none. The + * option leads to an advisory call to an appropriate operating system + * API where available., a string\, chosen from the following options: + * \c "none"\, \c "random"\, \c "sequential"; default \c none.} + * @config{cache_resident, do not ever evict the object's pages from + * cache. Not compatible with LSM tables; see @ref + * tuning_cache_resident for more information., a boolean flag; default + * \c false.} + * @configend + * @errors + */ + int __F(alter)(WT_HANDLE_CLOSED(WT_SESSION) *session, + const char *name, const char *config); + + /*! * Close the session handle. * * This will release the resources associated with the session handle, @@ -3437,6 +3465,14 @@ struct __wt_compressor { */ struct __wt_data_source { /*! + * Callback to alter an object. + * + * @snippet ex_data_source.c WT_DATA_SOURCE alter + */ + int (*alter)(WT_DATA_SOURCE *dsrc, WT_SESSION *session, + const char *uri, WT_CONFIG_ARG *config); + + /*! * Callback to create a new object. * * @snippet ex_data_source.c WT_DATA_SOURCE create @@ -4669,114 +4705,120 @@ extern int wiredtiger_extension_terminate(WT_CONNECTION *connection); #define WT_STAT_CONN_SESSION_CURSOR_OPEN 1186 /*! session: open session count */ #define WT_STAT_CONN_SESSION_OPEN 1187 +/*! session: table alter failed calls */ +#define WT_STAT_CONN_SESSION_TABLE_ALTER_FAIL 1188 +/*! session: table alter successful calls */ +#define WT_STAT_CONN_SESSION_TABLE_ALTER_SUCCESS 1189 +/*! session: table alter unchanged and skipped */ +#define WT_STAT_CONN_SESSION_TABLE_ALTER_SKIP 1190 /*! session: table compact failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1188 +#define WT_STAT_CONN_SESSION_TABLE_COMPACT_FAIL 1191 /*! session: table compact successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1189 +#define WT_STAT_CONN_SESSION_TABLE_COMPACT_SUCCESS 1192 /*! session: table create failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1190 +#define WT_STAT_CONN_SESSION_TABLE_CREATE_FAIL 1193 /*! session: table create successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1191 +#define WT_STAT_CONN_SESSION_TABLE_CREATE_SUCCESS 1194 /*! session: table drop failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1192 +#define WT_STAT_CONN_SESSION_TABLE_DROP_FAIL 1195 /*! session: table drop successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1193 +#define WT_STAT_CONN_SESSION_TABLE_DROP_SUCCESS 1196 /*! session: table rebalance failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1194 +#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_FAIL 1197 /*! session: table rebalance successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1195 +#define WT_STAT_CONN_SESSION_TABLE_REBALANCE_SUCCESS 1198 /*! session: table rename failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1196 +#define WT_STAT_CONN_SESSION_TABLE_RENAME_FAIL 1199 /*! session: table rename successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1197 +#define WT_STAT_CONN_SESSION_TABLE_RENAME_SUCCESS 1200 /*! session: table salvage failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1198 +#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_FAIL 1201 /*! session: table salvage successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1199 +#define WT_STAT_CONN_SESSION_TABLE_SALVAGE_SUCCESS 1202 /*! session: table truncate failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1200 +#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_FAIL 1203 /*! session: table truncate successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1201 +#define WT_STAT_CONN_SESSION_TABLE_TRUNCATE_SUCCESS 1204 /*! session: table verify failed calls */ -#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1202 +#define WT_STAT_CONN_SESSION_TABLE_VERIFY_FAIL 1205 /*! session: table verify successful calls */ -#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1203 +#define WT_STAT_CONN_SESSION_TABLE_VERIFY_SUCCESS 1206 /*! thread-state: active filesystem fsync calls */ -#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1204 +#define WT_STAT_CONN_THREAD_FSYNC_ACTIVE 1207 /*! thread-state: active filesystem read calls */ -#define WT_STAT_CONN_THREAD_READ_ACTIVE 1205 +#define WT_STAT_CONN_THREAD_READ_ACTIVE 1208 /*! thread-state: active filesystem write calls */ -#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1206 +#define WT_STAT_CONN_THREAD_WRITE_ACTIVE 1209 /*! thread-yield: application thread time evicting (usecs) */ -#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1207 +#define WT_STAT_CONN_APPLICATION_EVICT_TIME 1210 /*! thread-yield: application thread time waiting for cache (usecs) */ -#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1208 +#define WT_STAT_CONN_APPLICATION_CACHE_TIME 1211 /*! thread-yield: page acquire busy blocked */ -#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1209 +#define WT_STAT_CONN_PAGE_BUSY_BLOCKED 1212 /*! thread-yield: page acquire eviction blocked */ -#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1210 +#define WT_STAT_CONN_PAGE_FORCIBLE_EVICT_BLOCKED 1213 /*! thread-yield: page acquire locked blocked */ -#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1211 +#define WT_STAT_CONN_PAGE_LOCKED_BLOCKED 1214 /*! thread-yield: page acquire read blocked */ -#define WT_STAT_CONN_PAGE_READ_BLOCKED 1212 +#define WT_STAT_CONN_PAGE_READ_BLOCKED 1215 /*! thread-yield: page acquire time sleeping (usecs) */ -#define WT_STAT_CONN_PAGE_SLEEP 1213 +#define WT_STAT_CONN_PAGE_SLEEP 1216 /*! transaction: number of named snapshots created */ -#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1214 +#define WT_STAT_CONN_TXN_SNAPSHOTS_CREATED 1217 /*! transaction: number of named snapshots dropped */ -#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1215 +#define WT_STAT_CONN_TXN_SNAPSHOTS_DROPPED 1218 /*! transaction: transaction begins */ -#define WT_STAT_CONN_TXN_BEGIN 1216 +#define WT_STAT_CONN_TXN_BEGIN 1219 /*! transaction: transaction checkpoint currently running */ -#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1217 +#define WT_STAT_CONN_TXN_CHECKPOINT_RUNNING 1220 /*! transaction: transaction checkpoint generation */ -#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1218 +#define WT_STAT_CONN_TXN_CHECKPOINT_GENERATION 1221 /*! transaction: transaction checkpoint max time (msecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1219 +#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MAX 1222 /*! transaction: transaction checkpoint min time (msecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1220 +#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_MIN 1223 /*! transaction: transaction checkpoint most recent time (msecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1221 +#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_RECENT 1224 /*! transaction: transaction checkpoint scrub dirty target */ -#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1222 +#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TARGET 1225 /*! transaction: transaction checkpoint scrub time (msecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1223 +#define WT_STAT_CONN_TXN_CHECKPOINT_SCRUB_TIME 1226 /*! transaction: transaction checkpoint total time (msecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1224 +#define WT_STAT_CONN_TXN_CHECKPOINT_TIME_TOTAL 1227 /*! transaction: transaction checkpoints */ -#define WT_STAT_CONN_TXN_CHECKPOINT 1225 +#define WT_STAT_CONN_TXN_CHECKPOINT 1228 /*! * transaction: transaction checkpoints skipped because database was * clean */ -#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1226 +#define WT_STAT_CONN_TXN_CHECKPOINT_SKIPPED 1229 /*! transaction: transaction failures due to cache overflow */ -#define WT_STAT_CONN_TXN_FAIL_CACHE 1227 +#define WT_STAT_CONN_TXN_FAIL_CACHE 1230 /*! * transaction: transaction fsync calls for checkpoint after allocating * the transaction ID */ -#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1228 +#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST 1231 /*! * transaction: transaction fsync duration for checkpoint after * allocating the transaction ID (usecs) */ -#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1229 +#define WT_STAT_CONN_TXN_CHECKPOINT_FSYNC_POST_DURATION 1232 /*! transaction: transaction range of IDs currently pinned */ -#define WT_STAT_CONN_TXN_PINNED_RANGE 1230 +#define WT_STAT_CONN_TXN_PINNED_RANGE 1233 /*! transaction: transaction range of IDs currently pinned by a checkpoint */ -#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1231 +#define WT_STAT_CONN_TXN_PINNED_CHECKPOINT_RANGE 1234 /*! * transaction: transaction range of IDs currently pinned by named * snapshots */ -#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1232 +#define WT_STAT_CONN_TXN_PINNED_SNAPSHOT_RANGE 1235 /*! transaction: transaction sync calls */ -#define WT_STAT_CONN_TXN_SYNC 1233 +#define WT_STAT_CONN_TXN_SYNC 1236 /*! transaction: transactions committed */ -#define WT_STAT_CONN_TXN_COMMIT 1234 +#define WT_STAT_CONN_TXN_COMMIT 1237 /*! transaction: transactions rolled back */ -#define WT_STAT_CONN_TXN_ROLLBACK 1235 +#define WT_STAT_CONN_TXN_ROLLBACK 1238 /*! * @} diff --git a/src/lsm/lsm_cursor_bulk.c b/src/lsm/lsm_cursor_bulk.c index bae8206515e..7a6a40e380f 100644 --- a/src/lsm/lsm_cursor_bulk.c +++ b/src/lsm/lsm_cursor_bulk.c @@ -45,7 +45,7 @@ __clsm_close_bulk(WT_CURSOR *cursor) total_chunks /= avg_chunks) ++chunk->generation; - WT_RET(__wt_lsm_meta_write(session, lsm_tree)); + WT_RET(__wt_lsm_meta_write(session, lsm_tree, NULL)); ++lsm_tree->dsk_gen; /* Close the LSM cursor */ diff --git a/src/lsm/lsm_merge.c b/src/lsm/lsm_merge.c index f05a9c4b2b7..ceb5f03a2f5 100644 --- a/src/lsm/lsm_merge.c +++ b/src/lsm/lsm_merge.c @@ -579,7 +579,7 @@ __wt_lsm_merge(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, u_int id) * Any errors that happened after the tree was locked are * fatal - we can't guarantee the state of the tree. */ - if ((ret = __wt_lsm_meta_write(session, lsm_tree)) != 0) + if ((ret = __wt_lsm_meta_write(session, lsm_tree, NULL)) != 0) WT_PANIC_ERR(session, ret, "Failed finalizing LSM merge"); lsm_tree->dsk_gen++; diff --git a/src/lsm/lsm_meta.c b/src/lsm/lsm_meta.c index ec52af96231..46ead6d6ac4 100644 --- a/src/lsm/lsm_meta.c +++ b/src/lsm/lsm_meta.c @@ -454,13 +454,14 @@ __wt_lsm_meta_read(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) * Write the metadata for an LSM tree. */ int -__wt_lsm_meta_write(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) +__wt_lsm_meta_write(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree, + const char *newconfig) { WT_DECL_ITEM(buf); WT_DECL_RET; WT_LSM_CHUNK *chunk; u_int i; - const char *new_cfg[] = { NULL, NULL, NULL }; + const char *new_cfg[] = { NULL, NULL, NULL, NULL, NULL }; char *new_metadata; bool first; @@ -504,8 +505,10 @@ __wt_lsm_meta_write(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) WT_ERR(__wt_buf_catfmt(session, buf, "]")); /* Update the existing configuration with the new values. */ - new_cfg[0] = lsm_tree->config; - new_cfg[1] = buf->data; + new_cfg[0] = WT_CONFIG_BASE(session, lsm_meta); + new_cfg[1] = lsm_tree->config; + new_cfg[2] = buf->data; + new_cfg[3] = newconfig; WT_ERR(__wt_config_collapse(session, new_cfg, &new_metadata)); ret = __wt_metadata_update(session, lsm_tree->name, new_metadata); WT_ERR(ret); diff --git a/src/lsm/lsm_tree.c b/src/lsm/lsm_tree.c index b0616fb8ec1..38d87dd852b 100644 --- a/src/lsm/lsm_tree.c +++ b/src/lsm/lsm_tree.c @@ -756,7 +756,7 @@ __wt_lsm_tree_switch(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) lsm_tree->chunk[lsm_tree->nchunks++] = chunk; WT_ERR(__wt_lsm_tree_setup_chunk(session, lsm_tree, chunk)); - WT_ERR(__wt_lsm_meta_write(session, lsm_tree)); + WT_ERR(__wt_lsm_meta_write(session, lsm_tree, NULL)); lsm_tree->need_switch = false; ++lsm_tree->dsk_gen; @@ -841,6 +841,47 @@ __wt_lsm_tree_retire_chunks(WT_SESSION_IMPL *session, } /* + * __wt_lsm_tree_alter -- + * Alter an LSM tree. + */ +int +__wt_lsm_tree_alter( + WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) +{ + WT_DECL_RET; + WT_LSM_CHUNK *chunk; + WT_LSM_TREE *lsm_tree; + u_int i; + bool locked; + + locked = false; + + /* Get the LSM tree. */ + WT_WITH_HANDLE_LIST_LOCK(session, + ret = __wt_lsm_tree_get(session, uri, false, &lsm_tree)); + WT_RET(ret); + + /* Prevent any new opens. */ + __wt_lsm_tree_writelock(session, lsm_tree); + locked = true; + + /* Alter the chunks. */ + for (i = 0; i < lsm_tree->nchunks; i++) { + chunk = lsm_tree->chunk[i]; + WT_ERR(__wt_schema_alter(session, chunk->uri, cfg)); + if (F_ISSET(chunk, WT_LSM_CHUNK_BLOOM)) + WT_ERR( + __wt_schema_alter(session, chunk->bloom_uri, cfg)); + } + WT_ERR(__wt_lsm_meta_write(session, lsm_tree, cfg[0])); + +err: if (locked) + __wt_lsm_tree_writeunlock(session, lsm_tree); + __wt_lsm_tree_release(session, lsm_tree); + return (ret); +} + +/* * __wt_lsm_tree_drop -- * Drop an LSM tree. */ @@ -953,7 +994,7 @@ __wt_lsm_tree_rename(WT_SESSION_IMPL *session, } } - WT_ERR(__wt_lsm_meta_write(session, lsm_tree)); + WT_ERR(__wt_lsm_meta_write(session, lsm_tree, NULL)); locked = false; __wt_lsm_tree_writeunlock(session, lsm_tree); WT_ERR(__wt_metadata_remove(session, olduri)); @@ -1008,7 +1049,7 @@ __wt_lsm_tree_truncate( WT_ERR(__wt_lsm_merge_update_tree( session, lsm_tree, 0, lsm_tree->nchunks, chunk)); - WT_ERR(__wt_lsm_meta_write(session, lsm_tree)); + WT_ERR(__wt_lsm_meta_write(session, lsm_tree, NULL)); locked = false; __wt_lsm_tree_writeunlock(session, lsm_tree); diff --git a/src/lsm/lsm_work_unit.c b/src/lsm/lsm_work_unit.c index f3414363e3e..d9c185a3f58 100644 --- a/src/lsm/lsm_work_unit.c +++ b/src/lsm/lsm_work_unit.c @@ -364,7 +364,7 @@ __wt_lsm_checkpoint_chunk(WT_SESSION_IMPL *session, /* Lock the tree, mark the chunk as on disk and update the metadata. */ __wt_lsm_tree_writelock(session, lsm_tree); F_SET(chunk, WT_LSM_CHUNK_ONDISK); - ret = __wt_lsm_meta_write(session, lsm_tree); + ret = __wt_lsm_meta_write(session, lsm_tree, NULL); ++lsm_tree->dsk_gen; /* Update the throttle time. */ @@ -469,7 +469,7 @@ __lsm_bloom_create(WT_SESSION_IMPL *session, /* Ensure the bloom filter is in the metadata. */ __wt_lsm_tree_writelock(session, lsm_tree); F_SET(chunk, WT_LSM_CHUNK_BLOOM); - ret = __wt_lsm_meta_write(session, lsm_tree); + ret = __wt_lsm_meta_write(session, lsm_tree, NULL); ++lsm_tree->dsk_gen; __wt_lsm_tree_writeunlock(session, lsm_tree); @@ -659,7 +659,7 @@ __wt_lsm_free_chunks(WT_SESSION_IMPL *session, WT_LSM_TREE *lsm_tree) err: /* Flush the metadata unless the system is in panic */ if (flush_metadata && ret != WT_PANIC) { __wt_lsm_tree_writelock(session, lsm_tree); - WT_TRET(__wt_lsm_meta_write(session, lsm_tree)); + WT_TRET(__wt_lsm_meta_write(session, lsm_tree, NULL)); __wt_lsm_tree_writeunlock(session, lsm_tree); } __lsm_unpin_chunks(session, &cookie); diff --git a/src/schema/schema_alter.c b/src/schema/schema_alter.c new file mode 100644 index 00000000000..e8b619737ed --- /dev/null +++ b/src/schema/schema_alter.c @@ -0,0 +1,181 @@ +/*- + * Copyright (c) 2014-2016 MongoDB, Inc. + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "wt_internal.h" + +/* + * __alter_file -- + * Alter a file. + */ +static int +__alter_file( + WT_SESSION_IMPL *session, const char *uri, const char *newcfg[]) +{ + WT_DECL_RET; + const char *cfg[4], *filename; + char *config, *newconfig; + + filename = uri; + newconfig = NULL; + if (!WT_PREFIX_SKIP(filename, "file:")) + return (__wt_unexpected_object_type(session, uri, "file:")); + + /* Find the URI */ + WT_RET(__wt_metadata_search(session, uri, &config)); + + WT_ASSERT(session, newcfg[0] != NULL); + /* + * Start with the base configuration because collapse is like + * a projection and if we are reading older metadata, it may not + * have all the components. + */ + cfg[0] = WT_CONFIG_BASE(session, file_meta); + cfg[1] = config; + cfg[2] = newcfg[0]; + cfg[3] = NULL; + WT_ERR(__wt_config_collapse(session, cfg, &newconfig)); + /* + * Only rewrite if there are changes. + */ + if (strcmp(config, newconfig) != 0) + WT_ERR(__wt_metadata_update(session, uri, newconfig)); + else + WT_STAT_CONN_INCR(session, session_table_alter_skip); + +err: __wt_free(session, config); + __wt_free(session, newconfig); + return (ret); +} + +/* + * __alter_colgroup -- + * WT_SESSION::alter for a colgroup. + */ +static int +__alter_colgroup( + WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) +{ + WT_COLGROUP *colgroup; + WT_DECL_RET; + + WT_ASSERT(session, F_ISSET(session, WT_SESSION_LOCKED_TABLE)); + + /* If we can get the colgroup, perform any potential alterations. */ + if ((ret = __wt_schema_get_colgroup( + session, uri, false, NULL, &colgroup)) == 0) + WT_TRET(__wt_schema_alter(session, colgroup->source, cfg)); + + return (ret); +} + +/* + * __alter_index -- + * WT_SESSION::alter for an index. + */ +static int +__alter_index( + WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) +{ + WT_INDEX *idx; + WT_DECL_RET; + + /* If we can get the index, perform any potential alterations. */ + if ((ret = __wt_schema_get_index( + session, uri, false, NULL, &idx)) == 0) + WT_TRET(__wt_schema_alter(session, idx->source, cfg)); + + return (ret); +} + +/* + * __alter_table -- + * WT_SESSION::alter for a table. + */ +static int +__alter_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) +{ + WT_COLGROUP *colgroup; + WT_DECL_RET; + WT_TABLE *table; + const char *name; + u_int i; + + name = uri; + (void)WT_PREFIX_SKIP(name, "table:"); + + WT_RET(__wt_schema_get_table( + session, name, strlen(name), true, &table)); + + /* + * Alter the column groups only if we are using the default + * column group. Otherwise the user should alter each + * index or column group explicitly. + */ + if (table->ncolgroups == 0) + for (i = 0; i < WT_COLGROUPS(table); i++) { + if ((colgroup = table->cgroups[i]) == NULL) + continue; + /* + * Alter the column group before updating the metadata + * to avoid the metadata for the table becoming + * inconsistent if we can't get exclusive access. + */ + WT_ERR(__wt_schema_alter( + session, colgroup->source, cfg)); + } +err: __wt_schema_release_table(session, table); + return (ret); +} + +/* + * __wt_schema_alter -- + * Process a WT_SESSION::alter operation for all supported types. + */ +int +__wt_schema_alter(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) +{ + WT_DATA_SOURCE *dsrc; + WT_DECL_RET; + + WT_RET(__wt_meta_track_on(session)); + + /* Paranoia: clear any handle from our caller. */ + session->dhandle = NULL; + + if (WT_PREFIX_MATCH(uri, "colgroup:")) + ret = __alter_colgroup(session, uri, cfg); + else if (WT_PREFIX_MATCH(uri, "file:")) + ret = __alter_file(session, uri, cfg); + else if (WT_PREFIX_MATCH(uri, "index:")) + ret = __alter_index(session, uri, cfg); + else if (WT_PREFIX_MATCH(uri, "lsm:")) + ret = __wt_lsm_tree_alter(session, uri, cfg); + else if (WT_PREFIX_MATCH(uri, "table:")) + ret = __alter_table(session, uri, cfg); + else if ((dsrc = __wt_schema_get_source(session, uri)) != NULL) + ret = dsrc->alter == NULL ? + __wt_object_unsupported(session, uri) : + dsrc->alter(dsrc, + &session->iface, uri, (WT_CONFIG_ARG *)cfg); + else + ret = __wt_bad_object_type(session, uri); + + /* + * Map WT_NOTFOUND to ENOENT, based on the assumption WT_NOTFOUND means + * there was no metadata entry. + */ + if (ret == WT_NOTFOUND) + ret = ENOENT; + + /* Bump the schema generation so that stale data is ignored. */ + ++S2C(session)->schema_gen; + + WT_TRET(__wt_meta_track_off(session, true, ret != 0)); + + return (ret); +} diff --git a/src/schema/schema_drop.c b/src/schema/schema_drop.c index 65c955cf1e9..c1a4f257648 100644 --- a/src/schema/schema_drop.c +++ b/src/schema/schema_drop.c @@ -75,7 +75,7 @@ __drop_colgroup( /* * __drop_index -- - * WT_SESSION::drop for a colgroup. + * WT_SESSION::drop for an index. */ static int __drop_index( @@ -85,7 +85,7 @@ __drop_index( WT_DECL_RET; WT_TABLE *table; - /* If we can get the colgroup, detach it from the table. */ + /* If we can get the index, detach it from the table. */ if ((ret = __wt_schema_get_index( session, uri, force, &table, &idx)) == 0) { table->idx_complete = false; @@ -136,7 +136,7 @@ __drop_table(WT_SESSION_IMPL *session, const char *uri, const char *cfg[]) if ((idx = table->indices[i]) == NULL) continue; /* - * Drop the column group before updating the metadata to avoid + * Drop the index before updating the metadata to avoid * the metadata for the table becoming inconsistent if we can't * get exclusive access. */ diff --git a/src/session/session_api.c b/src/session/session_api.c index 88a3c32ee11..fe1bf821d3b 100644 --- a/src/session/session_api.c +++ b/src/session/session_api.c @@ -137,6 +137,42 @@ __session_clear(WT_SESSION_IMPL *session) } /* + * __session_alter -- + * Alter a table setting. + */ +static int +__session_alter(WT_SESSION *wt_session, const char *uri, const char *config) +{ + WT_DECL_RET; + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)wt_session; + + SESSION_API_CALL(session, alter, config, cfg); + + /* Disallow objects in the WiredTiger name space. */ + WT_ERR(__wt_str_name_check(session, uri)); + + /* + * We replace the default configuration listing with the current + * configuration. Otherwise the defaults for values that can be + * altered would override settings used by the user in create. + */ + cfg[0] = cfg[1]; + cfg[1] = NULL; + WT_WITH_CHECKPOINT_LOCK(session, + WT_WITH_SCHEMA_LOCK(session, + WT_WITH_TABLE_LOCK(session, + ret = __wt_schema_alter(session, uri, cfg)))); + +err: if (ret != 0) + WT_STAT_CONN_INCR(session, session_table_alter_fail); + else + WT_STAT_CONN_INCR(session, session_table_alter_success); + API_END_RET_NOTFOUND_MAP(session, ret); +} + +/* * __session_close -- * WT_SESSION->close method. */ @@ -1691,6 +1727,7 @@ __open_session(WT_CONNECTION_IMPL *conn, static const WT_SESSION stds = { NULL, NULL, + __session_alter, __session_close, __session_reconfigure, __wt_session_strerror, @@ -1718,6 +1755,7 @@ __open_session(WT_CONNECTION_IMPL *conn, }, stds_readonly = { NULL, NULL, + __session_alter, __session_close, __session_reconfigure, __wt_session_strerror, diff --git a/src/support/stat.c b/src/support/stat.c index 5acd9fc713f..a9c0b24ef29 100644 --- a/src/support/stat.c +++ b/src/support/stat.c @@ -808,6 +808,9 @@ static const char * const __stats_connection_desc[] = { "reconciliation: split objects currently awaiting free", "session: open cursor count", "session: open session count", + "session: table alter failed calls", + "session: table alter successful calls", + "session: table alter unchanged and skipped", "session: table compact failed calls", "session: table compact successful calls", "session: table create failed calls", @@ -1086,6 +1089,9 @@ __wt_stat_connection_clear_single(WT_CONNECTION_STATS *stats) /* not clearing rec_split_stashed_objects */ /* not clearing session_cursor_open */ /* not clearing session_open */ + /* not clearing session_table_alter_fail */ + /* not clearing session_table_alter_success */ + /* not clearing session_table_alter_skip */ /* not clearing session_table_compact_fail */ /* not clearing session_table_compact_success */ /* not clearing session_table_create_fail */ @@ -1397,6 +1403,12 @@ __wt_stat_connection_aggregate( WT_STAT_READ(from, rec_split_stashed_objects); to->session_cursor_open += WT_STAT_READ(from, session_cursor_open); to->session_open += WT_STAT_READ(from, session_open); + to->session_table_alter_fail += + WT_STAT_READ(from, session_table_alter_fail); + to->session_table_alter_success += + WT_STAT_READ(from, session_table_alter_success); + to->session_table_alter_skip += + WT_STAT_READ(from, session_table_alter_skip); to->session_table_compact_fail += WT_STAT_READ(from, session_table_compact_fail); to->session_table_compact_success += diff --git a/src/utilities/util.h b/src/utilities/util.h index c2cf6c22aa4..2658d877b63 100644 --- a/src/utilities/util.h +++ b/src/utilities/util.h @@ -26,6 +26,7 @@ extern int __wt_optopt; /* character checked for validity */ extern int __wt_optreset; /* reset getopt */ extern char *__wt_optarg; /* argument associated with option */ +int util_alter(WT_SESSION *, int, char *[]); int util_backup(WT_SESSION *, int, char *[]); int util_cerr(WT_CURSOR *, const char *, int); int util_compact(WT_SESSION *, int, char *[]); diff --git a/src/utilities/util_alter.c b/src/utilities/util_alter.c new file mode 100644 index 00000000000..d228c15cd48 --- /dev/null +++ b/src/utilities/util_alter.c @@ -0,0 +1,50 @@ +/*- + * Copyright (c) 2014-2016 MongoDB, Inc. + * Copyright (c) 2008-2014 WiredTiger, Inc. + * All rights reserved. + * + * See the file LICENSE for redistribution information. + */ + +#include "util.h" + +static int usage(void); + +int +util_alter(WT_SESSION *session, int argc, char *argv[]) +{ + WT_DECL_RET; + int ch; + char **configp; + + while ((ch = __wt_getopt(progname, argc, argv, "")) != EOF) + switch (ch) { + case '?': + default: + return (usage()); + } + + argc -= __wt_optind; + argv += __wt_optind; + + /* The remaining arguments are uri/string pairs. */ + if (argc % 2 != 0) + return (usage()); + + for (configp = argv; + configp != NULL && *configp != NULL; configp += 2) + if ((ret = session->alter( + session, configp[0], configp[1])) != 0) + break; + return (ret); +} + +static int +usage(void) +{ + (void)fprintf(stderr, + "usage: %s %s " + "alter uri configuration ...\n", + progname, usage_prefix); + return (1); +} diff --git a/src/utilities/util_main.c b/src/utilities/util_main.c index 2054b94e3ce..1da56adf137 100644 --- a/src/utilities/util_main.c +++ b/src/utilities/util_main.c @@ -117,6 +117,10 @@ main(int argc, char *argv[]) func = NULL; switch (command[0]) { + case 'a': + if (strcmp(command, "alter") == 0) + func = util_alter; + break; case 'b': if (strcmp(command, "backup") == 0) func = util_backup; @@ -252,6 +256,7 @@ usage(void) "\t" "-v\t" "verbose\n"); fprintf(stderr, "commands:\n" + "\t" "alter\t alter an object\n" "\t" "backup\t database backup\n" "\t" "compact\t compact an object\n" "\t" "copyright copyright information\n" diff --git a/test/format/config.h b/test/format/config.h index 9bfba3cd0df..e4f7af2e1b2 100644 --- a/test/format/config.h +++ b/test/format/config.h @@ -65,6 +65,10 @@ static CONFIG c[] = { "if timed run should drop core", /* 0% */ C_BOOL, 0, 0, 0, &g.c_abort, NULL }, + { "alter", + "if altering the table is enabled", /* 10% */ + C_BOOL, 10, 0, 0, &g.c_alter, NULL }, + { "auto_throttle", "if LSM inserts are throttled", /* 90% */ C_BOOL, 90, 0, 0, &g.c_auto_throttle, NULL }, diff --git a/test/format/format.h b/test/format/format.h index 530156fe661..c1f4875dbb2 100644 --- a/test/format/format.h +++ b/test/format/format.h @@ -140,6 +140,7 @@ typedef struct { char *config_open; /* Command-line configuration */ uint32_t c_abort; /* Config values */ + uint32_t c_alter; uint32_t c_auto_throttle; uint32_t c_backups; uint32_t c_bitcnt; @@ -276,6 +277,7 @@ void bdb_remove(uint64_t, int *); void bdb_update(const void *, size_t, const void *, size_t); #endif +void *alter(void *); void *backup(void *); void *compact(void *); void config_clear(void); diff --git a/test/format/ops.c b/test/format/ops.c index b50ce3c2e2f..940318c87a9 100644 --- a/test/format/ops.c +++ b/test/format/ops.c @@ -53,7 +53,7 @@ wts_ops(int lastrun) TINFO **tinfo_list, *tinfo, total; WT_CONNECTION *conn; WT_SESSION *session; - pthread_t backup_tid, compact_tid, lrt_tid; + pthread_t alter_tid, backup_tid, compact_tid, lrt_tid; int64_t fourths, thread_ops; uint32_t i; int running; @@ -61,6 +61,7 @@ wts_ops(int lastrun) conn = g.wts_conn; session = NULL; /* -Wconditional-uninitialized */ + memset(&alter_tid, 0, sizeof(alter_tid)); memset(&backup_tid, 0, sizeof(backup_tid)); memset(&compact_tid, 0, sizeof(compact_tid)); memset(&lrt_tid, 0, sizeof(lrt_tid)); @@ -118,6 +119,8 @@ wts_ops(int lastrun) * If a multi-threaded run, start optional backup, compaction and * long-running reader threads. */ + if (g.c_alter) + testutil_check(pthread_create(&alter_tid, NULL, alter, NULL)); if (g.c_backups) testutil_check(pthread_create(&backup_tid, NULL, backup, NULL)); if (g.c_compact) @@ -183,6 +186,8 @@ wts_ops(int lastrun) /* Wait for the backup, compaction, long-running reader threads. */ g.workers_finished = 1; + if (g.c_alter) + (void)pthread_join(alter_tid, NULL); if (g.c_backups) (void)pthread_join(backup_tid, NULL); if (g.c_compact) @@ -461,7 +466,7 @@ ops(void *arg) * 10% of the time, perform some read-only operations * from a checkpoint. * - * Skip that if we single-threaded and doing checks + * Skip that if we are single-threaded and doing checks * against a Berkeley DB database, because that won't * work because the Berkeley DB database records won't * match the checkpoint. Also skip if we are using diff --git a/test/format/util.c b/test/format/util.c index a709aa93a2e..2575130e4bb 100644 --- a/test/format/util.c +++ b/test/format/util.c @@ -459,3 +459,46 @@ fclose_and_clear(FILE **fpp) testutil_die(errno, "fclose"); return; } + +/* + * alter -- + * Periodically alter a table's metadata. + */ +void * +alter(void *arg) +{ + WT_CONNECTION *conn; + WT_DECL_RET; + WT_SESSION *session; + u_int period; + bool access; + char buf[32]; + + (void)(arg); + conn = g.wts_conn; + + /* + * Only alter the access pattern hint. If we alter the + * cache resident setting we may end up with a setting that + * fills cache and doesn't allow it to be evicted. + */ + access = false; + /* Open a session */ + testutil_check(conn->open_session(conn, NULL, NULL, &session)); + + while (!g.workers_finished) { + period = mmrand(NULL, 1, 10); + + snprintf(buf, 32, "access_pattern_hint=%s", + access ? "random" : "none"); + access = !access; + if ((ret = session->alter(session, g.uri, buf)) != 0) + break; + while (period > 0 && !g.workers_finished) { + --period; + sleep(1); + } + } + testutil_check(session->close(session, NULL)); + return (NULL); +} diff --git a/test/suite/test_alter01.py b/test/suite/test_alter01.py new file mode 100644 index 00000000000..dfdf6b7a17e --- /dev/null +++ b/test/suite/test_alter01.py @@ -0,0 +1,169 @@ +#!/usr/bin/env python +# +# Public Domain 2014-2016 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. +# +# This is free and unencumbered software released into the public domain. +# +# Anyone is free to copy, modify, publish, use, compile, sell, or +# distribute this software, either in source code form or as a compiled +# binary, for any purpose, commercial or non-commercial, and by any +# means. +# +# In jurisdictions that recognize copyright laws, the author or authors +# of this software dedicate any and all copyright interest in the +# software to the public domain. We make this dedication for the benefit +# of the public at large and to the detriment of our heirs and +# successors. We intend this dedication to be an overt act of +# relinquishment in perpetuity of all present and future rights to this +# software under copyright law. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. +# IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR +# OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, +# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR +# OTHER DEALINGS IN THE SOFTWARE. + +import wiredtiger, wttest +from wtscenario import make_scenarios + +# test_alter01.py +# Smoke-test the session alter operations. +class test_alter01(wttest.WiredTigerTestCase): + name = "alter01" + entries = 100 + # Settings for access_pattern_hint + types = [ + ('file', dict(uri='file:', use_cg=False, use_index=False)), + ('lsm', dict(uri='lsm:', use_cg=False, use_index=False)), + ('table-cg', dict(uri='table:', use_cg=True, use_index=False)), + ('table-index', dict(uri='table:', use_cg=False, use_index=True)), + ('table-simple', dict(uri='table:', use_cg=False, use_index=False)), + ] + hints = [ + ('default', dict(acreate='')), + ('none', dict(acreate='none')), + ('random', dict(acreate='random')), + ('sequential', dict(acreate='sequential')), + ] + access_alter=('', 'none', 'random', 'sequential') + # Settings for cache_resident + resid = [ + ('default', dict(ccreate='')), + ('false', dict(ccreate='false')), + ('true', dict(ccreate='true')), + ] + reopen = [ + ('no-reopen', dict(reopen=False)), + ('reopen', dict(reopen=True)), + ] + cache_alter=('', 'false', 'true') + scenarios = make_scenarios(types, hints, resid, reopen) + + def verify_metadata(self, metastr): + if metastr == '': + return + cursor = self.session.open_cursor('metadata:', None, None) + # + # Walk through all the metadata looking for the entries that are + # the file URIs for components of the table. + # + found = False + while True: + ret = cursor.next() + if ret != 0: + break + key = cursor.get_key() + check_meta = ((key.find("lsm:") != -1 or key.find("file:") != -1) \ + and key.find(self.name) != -1) + if check_meta: + value = cursor[key] + found = True + self.assertTrue(value.find(metastr) != -1) + cursor.close() + self.assertTrue(found == True) + + # Alter: Change the access pattern hint after creation + def test_alter01_access(self): + uri = self.uri + self.name + create_params = 'key_format=i,value_format=i,' + complex_params = '' + # + # If we're not explicitly setting the parameter, then don't + # modify create_params to test using the default. + # + if self.acreate != '': + access_param = 'access_pattern_hint=%s' % self.acreate + create_params += '%s,' % access_param + complex_params += '%s,' % access_param + else: + # NOTE: This is hard-coding the default value. If the default + # changes then this will fail and need to be fixed. + access_param = 'access_pattern_hint=none' + if self.ccreate != '': + cache_param = 'cache_resident=%s' % self.ccreate + create_params += '%s,' % cache_param + complex_params += '%s,' % cache_param + else: + # NOTE: This is hard-coding the default value. If the default + # changes then this will fail and need to be fixed. + cache_param = 'cache_resident=false' + + cgparam = '' + if self.use_cg or self.use_index: + cgparam = 'columns=(k,v),' + if self.use_cg: + cgparam += 'colgroups=(g0),' + + self.session.create(uri, create_params + cgparam) + # Add in column group or index settings. + if self.use_cg: + cgparam = 'columns=(v),' + suburi = 'colgroup:' + self.name + ':g0' + self.session.create(suburi, complex_params + cgparam) + if self.use_index: + suburi = 'index:' + self.name + ':i0' + self.session.create(suburi, complex_params + cgparam) + + # Put some data in table. + c = self.session.open_cursor(uri, None) + for k in range(self.entries): + c[k+1] = 1 + c.close() + + # Verify the string in the metadata + self.verify_metadata(access_param) + self.verify_metadata(cache_param) + + # Run through all combinations of the alter commands + # for all allowed settings. This tests having only one or + # the other set as well as having both set. It will also + # cover trying to change the setting to its current value. + for a in self.access_alter: + alter_param = '' + access_str = '' + if a != '': + access_str = 'access_pattern_hint=%s' % a + for c in self.cache_alter: + alter_param = '%s' % access_str + cache_str = '' + if c != '': + cache_str = 'cache_resident=%s' % c + alter_param += ',%s' % cache_str + if alter_param != '': + self.session.alter(uri, alter_param) + if self.reopen: + self.reopen_conn() + special = self.use_cg or self.use_index + if not special: + self.verify_metadata(access_str) + self.verify_metadata(cache_str) + else: + self.session.alter(suburi, alter_param) + self.verify_metadata(access_str) + self.verify_metadata(cache_str) + +if __name__ == '__main__': + wttest.run() diff --git a/tools/wtstats/stat_data.py b/tools/wtstats/stat_data.py index 635e710c469..d925dd67b80 100644 --- a/tools/wtstats/stat_data.py +++ b/tools/wtstats/stat_data.py @@ -34,6 +34,9 @@ no_scale_per_second_list = [ 'reconciliation: split objects currently awaiting free', 'session: open cursor count', 'session: open session count', + 'session: table alter failed calls', + 'session: table alter successful calls', + 'session: table alter unchanged and skipped', 'session: table compact failed calls', 'session: table compact successful calls', 'session: table create failed calls', @@ -147,6 +150,9 @@ no_clear_list = [ 'reconciliation: split objects currently awaiting free', 'session: open cursor count', 'session: open session count', + 'session: table alter failed calls', + 'session: table alter successful calls', + 'session: table alter unchanged and skipped', 'session: table compact failed calls', 'session: table compact successful calls', 'session: table create failed calls', |