From 4c26d2324bae1d7030b0142d50dbd2ccf11ddeb6 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Thu, 11 Dec 2014 19:32:50 -0500 Subject: [PATCH 01/16] Add support for a WT_CURSOR.reconfigure method, reference #1381. --- dist/api_data.py | 41 ++++++----- examples/c/ex_all.c | 12 ++-- lang/java/java_doc.i | 4 ++ src/config/config_def.c | 11 +++ src/cursor/cur_backup.c | 1 + src/cursor/cur_config.c | 1 + src/cursor/cur_ds.c | 1 + src/cursor/cur_dump.c | 1 + src/cursor/cur_file.c | 1 + src/cursor/cur_index.c | 1 + src/cursor/cur_log.c | 1 + src/cursor/cur_metadata.c | 13 +++- src/cursor/cur_stat.c | 1 + src/cursor/cur_std.c | 127 +++++++++++++++++++++------------- src/cursor/cur_table.c | 58 ++++++++-------- src/include/config.h | 47 +++++++------ src/include/cursor.h | 5 ++ src/include/extern.h | 2 +- src/include/wiredtiger.in | 21 ++++-- src/lsm/lsm_cursor.c | 3 +- test/suite/helper.py | 6 +- test/suite/test_cursor06.py | 89 ++++++++++++++++++++++++ test/suite/test_truncate01.py | 5 +- 23 files changed, 312 insertions(+), 140 deletions(-) create mode 100644 test/suite/test_cursor06.py diff --git a/dist/api_data.py b/dist/api_data.py index 42ec64ff344..2f7757dce6b 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -571,6 +571,26 @@ common_wiredtiger_open = [ ]), ] +cursor_config = [ + Config('append', 'false', r''' + append the value as a new record, creating a new record + number key; valid only for cursors with record number keys''', + type='boolean'), + Config('overwrite', 'true', r''' + configures whether the cursor's insert, update and remove + methods check the existing state of the record. If \c overwrite + is \c false, WT_CURSOR::insert fails with ::WT_DUPLICATE_KEY + if the record exists, WT_CURSOR::update and WT_CURSOR::remove + fail with ::WT_NOTFOUND if the record does not exist''', + type='boolean'), + Config('readonly', 'false', r''' + only query operations are supported by this cursor. An error is + returned if a modification is attempted using the cursor. The + default is false for all cursor types except for log and metadata + cursors''', + type='boolean'), +] + methods = { 'file.meta' : Method(file_meta), @@ -582,6 +602,8 @@ methods = { 'cursor.close' : Method([]), +'cursor.reconfigure' : Method(cursor_config), + 'session.close' : Method([]), 'session.compact' : Method([ @@ -612,11 +634,7 @@ methods = { 'session.log_printf' : Method([]), -'session.open_cursor' : Method([ - Config('append', 'false', r''' - append the value as a new record, creating a new record - number key; valid only for cursors with record number keys''', - type='boolean'), +'session.open_cursor' : Method(cursor_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 @@ -653,23 +671,10 @@ methods = { WT_CURSOR::next and WT_CURSOR::close methods. See @ref cursor_random for details''', type='boolean'), - Config('overwrite', 'true', r''' - configures whether the cursor's insert, update and remove - methods check the existing state of the record. If \c overwrite - is \c false, WT_CURSOR::insert fails with ::WT_DUPLICATE_KEY - if the record exists, WT_CURSOR::update and WT_CURSOR::remove - fail with ::WT_NOTFOUND if the record does not exist''', - type='boolean'), Config('raw', 'false', r''' ignore the encodings for the key and value, manage data as if the formats were \c "u". See @ref cursor_raw for details''', type='boolean'), - Config('readonly', 'false', r''' - only query operations are supported by this cursor. An error is - returned if a modification is attempted using the cursor. The - default is false for all cursor types except for log and metadata - cursors''', - type='boolean'), Config('skip_sort_check', 'false', r''' skip the check of the sort order of each bulk-loaded key''', type='boolean', undoc=True), diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c index 4fe6a2f265a..db418deed9d 100644 --- a/examples/c/ex_all.c +++ b/examples/c/ex_all.c @@ -94,20 +94,16 @@ cursor_ops(WT_SESSION *session) } { - WT_CURSOR *overwrite_cursor; const char *key = "some key", *value = "some value"; /*! [Reconfigure a cursor] */ ret = session->open_cursor( - session, "table:mytable", NULL, NULL, &cursor); + session, "table:mytable", NULL, "overwrite=false", &cursor); cursor->set_key(cursor, key); + cursor->set_value(cursor, value); /* Reconfigure the cursor to overwrite the record. */ - ret = session->open_cursor( - session, NULL, cursor, "overwrite", &overwrite_cursor); - ret = cursor->close(cursor); - - overwrite_cursor->set_value(overwrite_cursor, value); - ret = overwrite_cursor->insert(cursor); + ret = cursor->reconfigure(cursor, "overwrite=true"); + ret = cursor->insert(cursor); /*! [Reconfigure a cursor] */ } diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i index 31bad525330..2c4eab0a3b2 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -13,7 +13,11 @@ COPYDOC(__wt_cursor, WT_CURSOR, search_near) COPYDOC(__wt_cursor, WT_CURSOR, insert) COPYDOC(__wt_cursor, WT_CURSOR, update) COPYDOC(__wt_cursor, WT_CURSOR, remove) +COPYDOC(__wt_cursor, WT_CURSOR, reconfigure) COPYDOC(__wt_cursor, WT_CURSOR, close) +COPYDOC(__wt_cursor, WT_CURSOR, insert_orig) +COPYDOC(__wt_cursor, WT_CURSOR, remove_orig) +COPYDOC(__wt_cursor, WT_CURSOR, update_orig) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_key) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_value) COPYDOC(__wt_async_op, WT_ASYNC_OP, set_key) diff --git a/src/config/config_def.c b/src/config/config_def.c index 7751a4ece40..23f7b27338f 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -110,6 +110,13 @@ static const WT_CONFIG_CHECK confchk_connection_reconfigure[] = { { NULL, NULL, NULL, NULL } }; +static const WT_CONFIG_CHECK confchk_cursor_reconfigure[] = { + { "append", "boolean", NULL, NULL }, + { "overwrite", "boolean", NULL, NULL }, + { "readonly", "boolean", NULL, NULL }, + { NULL, NULL, NULL, NULL } +}; + static const WT_CONFIG_CHECK confchk_file_meta[] = { { "allocation_size", "int", "min=512B,max=128MB", NULL }, { "app_metadata", "string", NULL, NULL }, @@ -551,6 +558,10 @@ static const WT_CONFIG_ENTRY config_entries[] = { "", NULL }, + { "cursor.reconfigure", + "append=0,overwrite=,readonly=0", + confchk_cursor_reconfigure + }, { "file.meta", "allocation_size=4KB,app_metadata=,block_allocation=best," "block_compressor=,cache_resident=0,checkpoint=,checkpoint_lsn=," diff --git a/src/cursor/cur_backup.c b/src/cursor/cur_backup.c index b993e3f1af4..41bfaea7ee3 100644 --- a/src/cursor/cur_backup.c +++ b/src/cursor/cur_backup.c @@ -116,6 +116,7 @@ __wt_curbackup_open(WT_SESSION_IMPL *session, __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curbackup_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_BACKUP *cb; diff --git a/src/cursor/cur_config.c b/src/cursor/cur_config.c index 868b144efc1..5e7ca487ae2 100644 --- a/src/cursor/cur_config.c +++ b/src/cursor/cur_config.c @@ -39,6 +39,7 @@ __wt_curconfig_open(WT_SESSION_IMPL *session, __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curconfig_close); WT_CURSOR_CONFIG *cconfig; WT_CURSOR *cursor; diff --git a/src/cursor/cur_ds.c b/src/cursor/cur_ds.c index fc742ae7c3d..096a0e27f8d 100644 --- a/src/cursor/cur_ds.c +++ b/src/cursor/cur_ds.c @@ -461,6 +461,7 @@ __wt_curds_open( __curds_insert, /* insert */ __curds_update, /* update */ __curds_remove, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curds_close); /* close */ WT_CONFIG_ITEM cval, metadata; WT_CURSOR *cursor, *source; diff --git a/src/cursor/cur_dump.c b/src/cursor/cur_dump.c index 003b7e1f961..5760752d406 100644 --- a/src/cursor/cur_dump.c +++ b/src/cursor/cur_dump.c @@ -359,6 +359,7 @@ __wt_curdump_create(WT_CURSOR *child, WT_CURSOR *owner, WT_CURSOR **cursorp) __curdump_insert, /* insert */ __curdump_update, /* update */ __curdump_remove, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curdump_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_DUMP *cdump; diff --git a/src/cursor/cur_file.c b/src/cursor/cur_file.c index 5d6072ceb3e..c833dfa0677 100644 --- a/src/cursor/cur_file.c +++ b/src/cursor/cur_file.c @@ -363,6 +363,7 @@ __wt_curfile_create(WT_SESSION_IMPL *session, __curfile_insert, /* insert */ __curfile_update, /* update */ __curfile_remove, /* remove */ + __wt_cursor_reconfigure, /* reconfigure */ __curfile_close); /* close */ WT_BTREE *btree; WT_CONFIG_ITEM cval; diff --git a/src/cursor/cur_index.c b/src/cursor/cur_index.c index 936337047b8..b516b5c58b1 100644 --- a/src/cursor/cur_index.c +++ b/src/cursor/cur_index.c @@ -350,6 +350,7 @@ __wt_curindex_open(WT_SESSION_IMPL *session, __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curindex_close); /* close */ WT_CURSOR_INDEX *cindex; WT_CURSOR *cursor; diff --git a/src/cursor/cur_log.c b/src/cursor/cur_log.c index 1c8371fb9b5..bdb19d05c01 100644 --- a/src/cursor/cur_log.c +++ b/src/cursor/cur_log.c @@ -321,6 +321,7 @@ __wt_curlog_open(WT_SESSION_IMPL *session, __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curlog_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_LOG *cl; diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c index 5543dccec30..d6c76c48ab9 100644 --- a/src/cursor/cur_metadata.c +++ b/src/cursor/cur_metadata.c @@ -416,12 +416,14 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, __curmetadata_insert, /* insert */ __curmetadata_update, /* update */ __curmetadata_remove, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curmetadata_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_METADATA *mdc; WT_DECL_RET; + WT_CONFIG_ITEM cval; - WT_RET(__wt_calloc(session, 1, sizeof(WT_CURSOR_METADATA), &mdc)); + WT_RET(__wt_calloc_def(session, 1, &mdc)); cursor = &mdc->iface; *cursor = iface; @@ -434,8 +436,13 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp)); - /* Metadata cursors default to read only. */ - WT_ERR(__wt_cursor_config_readonly(cursor, cfg, 1)); + /* Metadata cursors default to readonly. */ + WT_ERR(__wt_config_gets_def(session, cfg, "readonly", 1, &cval)); + if (cval.val != 0) { + cursor->insert = cursor->insert_orig = __wt_cursor_notsup; + cursor->update = cursor->update_orig = __wt_cursor_notsup; + cursor->remove = cursor->remove_orig = __wt_cursor_notsup; + } if (0) { err: __wt_free(session, mdc); diff --git a/src/cursor/cur_stat.c b/src/cursor/cur_stat.c index b9bc4039619..cc12077024f 100644 --- a/src/cursor/cur_stat.c +++ b/src/cursor/cur_stat.c @@ -492,6 +492,7 @@ __wt_curstat_open(WT_SESSION_IMPL *session, __wt_cursor_notsup, /* insert */ __wt_cursor_notsup, /* update */ __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ __curstat_close); /* close */ WT_CONFIG_ITEM cval, sval; WT_CURSOR *cursor; diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c index cba83b1d088..6f7168a5cc6 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -57,28 +57,6 @@ __wt_cursor_set_notsup(WT_CURSOR *cursor) cursor->remove = __wt_cursor_notsup; } -/* - * __wt_cursor_config_readonly -- - * Parse read only configuration and setup cursor appropriately. - */ -int -__wt_cursor_config_readonly(WT_CURSOR *cursor, const char *cfg[], int def) -{ - WT_CONFIG_ITEM cval; - WT_SESSION_IMPL *session; - - session = (WT_SESSION_IMPL *)cursor->session; - - WT_RET(__wt_config_gets_def(session, cfg, "readonly", def, &cval)); - if (cval.val != 0) { - /* Reset all cursor methods that could modify data. */ - cursor->insert = __wt_cursor_notsup; - cursor->update = __wt_cursor_notsup; - cursor->remove = __wt_cursor_notsup; - } - return (0); -} - /* * __wt_cursor_kv_not_set -- * Standard error message for key/values not set. @@ -501,29 +479,72 @@ __wt_cursor_close(WT_CURSOR *cursor) } /* - * __cursor_runtime_config -- + * __wt_cursor_reconfigure -- * Set runtime-configurable settings. */ -static int -__cursor_runtime_config(WT_CURSOR *cursor, const char *cfg[]) +int +__wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config) { WT_CONFIG_ITEM cval; + WT_DECL_RET; WT_SESSION_IMPL *session; session = (WT_SESSION_IMPL *)cursor->session; - /* - * !!! - * There's no way yet to reconfigure cursor flags at runtime; if, in - * the future there is a way to do that, similar support needs to be - * added for data-source cursors, or, this call needs to return an - * error in the case of a data-source cursor. + /* Reconfiguration resets the cursor. */ + WT_RET(cursor->reset(cursor)); + + /* + * append + * Only relevant to column stores. */ - WT_RET(__wt_config_gets_def(session, cfg, "overwrite", 1, &cval)); - if (cval.val) - F_SET(cursor, WT_CURSTD_OVERWRITE); - else - F_CLR(cursor, WT_CURSTD_OVERWRITE); + if (WT_CURSOR_RECNO(cursor)) { + if ((ret = __wt_config_getones( + session, config, "append", &cval)) == 0) { + if (cval.val) + F_SET(cursor, WT_CURSTD_APPEND); + else + F_CLR(cursor, WT_CURSTD_APPEND); + } else + WT_RET_NOTFOUND_OK(ret); + } + + /* + * overwrite + */ + if ((ret = __wt_config_getones( + session, config, "overwrite", &cval)) == 0) { + if (cval.val) + F_SET(cursor, WT_CURSTD_OVERWRITE); + else + F_CLR(cursor, WT_CURSTD_OVERWRITE); + } else + WT_RET_NOTFOUND_OK(ret); + + /* + * readonly + */ + if ((ret = __wt_config_getones( + session, config, "readonly", &cval)) == 0) { + if (cval.val == 0) { + /* + * Fail if the user is turning readonly off and the + * cursor never supported writing in the first place. + */ + if (cursor->insert_orig == + (int (*)(WT_CURSOR *))__wt_cursor_set_notsup) + WT_RET_MSG(session, EINVAL, + "cursor cannot be used for data update"); + cursor->insert = cursor->insert_orig; + cursor->remove = cursor->remove_orig; + cursor->update = cursor->update_orig; + } else { + cursor->insert = __wt_cursor_notsup; + cursor->remove = __wt_cursor_notsup; + cursor->update = __wt_cursor_notsup; + } + } else + WT_RET_NOTFOUND_OK(ret); return (0); } @@ -580,15 +601,13 @@ __wt_cursor_init(WT_CURSOR *cursor, WT_CONFIG_ITEM cval; WT_CURSOR *cdump; WT_SESSION_IMPL *session; + int readonly; session = (WT_SESSION_IMPL *)cursor->session; if (cursor->internal_uri == NULL) WT_RET(__wt_strdup(session, uri, &cursor->internal_uri)); - /* Set runtime-configurable settings. */ - WT_RET(__cursor_runtime_config(cursor, cfg)); - /* * append * The append flag is only relevant to column stores. @@ -600,14 +619,22 @@ __wt_cursor_init(WT_CURSOR *cursor, } /* - * checkpoint - * Checkpoint cursors are read-only. + * checkpoint, readonly + * Checkpoint cursors are read-only, avoid any extra work. */ + readonly = 0; WT_RET(__wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); - if (cval.len != 0) { - cursor->insert = __wt_cursor_notsup; - cursor->update = __wt_cursor_notsup; - cursor->remove = __wt_cursor_notsup; + if (cval.len == 0) { + WT_RET( + __wt_config_gets_def(session, cfg, "readonly", 0, &cval)); + if (cval.val != 0) + readonly = 1; + } else + readonly = 1; + if (readonly) { + cursor->insert = cursor->insert_orig = __wt_cursor_notsup; + cursor->update = cursor->update_orig = __wt_cursor_notsup; + cursor->remove = cursor->remove_orig = __wt_cursor_notsup; } /* @@ -634,14 +661,18 @@ __wt_cursor_init(WT_CURSOR *cursor, } else cdump = NULL; + /* overwrite */ + WT_RET(__wt_config_gets_def(session, cfg, "overwrite", 1, &cval)); + if (cval.val) + F_SET(cursor, WT_CURSTD_OVERWRITE); + else + F_CLR(cursor, WT_CURSTD_OVERWRITE); + /* raw */ WT_RET(__wt_config_gets_def(session, cfg, "raw", 0, &cval)); if (cval.val != 0) F_SET(cursor, WT_CURSTD_RAW); - /* readonly */ - WT_RET(__wt_cursor_config_readonly(cursor, cfg, 0)); - /* * Cursors that are internal to some other cursor (such as file cursors * inside a table cursor) should be closed after the containing cursor. diff --git a/src/cursor/cur_table.c b/src/cursor/cur_table.c index 25479a166b1..50d76609411 100644 --- a/src/cursor/cur_table.c +++ b/src/cursor/cur_table.c @@ -76,20 +76,21 @@ __curextract_insert(WT_CURSOR *cursor) { static int __apply_idx(WT_CURSOR_TABLE *ctable, size_t func_off, int skip_immutable) { WT_CURSOR_STATIC_INIT(iface, - __wt_cursor_get_key, /* get-key */ - __wt_cursor_get_value, /* get-value */ - __wt_cursor_set_key, /* set-key */ - __wt_cursor_set_value, /* set-value */ - __wt_cursor_notsup, /* compare */ - __wt_cursor_notsup, /* next */ - __wt_cursor_notsup, /* prev */ - __wt_cursor_notsup, /* reset */ - __wt_cursor_notsup, /* search */ - __wt_cursor_notsup, /* search-near */ - __curextract_insert, /* insert */ - __wt_cursor_notsup, /* update */ - __wt_cursor_notsup, /* remove */ - __wt_cursor_notsup); /* close */ + __wt_cursor_get_key, /* get-key */ + __wt_cursor_get_value, /* get-value */ + __wt_cursor_set_key, /* set-key */ + __wt_cursor_set_value, /* set-value */ + __wt_cursor_notsup, /* compare */ + __wt_cursor_notsup, /* next */ + __wt_cursor_notsup, /* prev */ + __wt_cursor_notsup, /* reset */ + __wt_cursor_notsup, /* search */ + __wt_cursor_notsup, /* search-near */ + __curextract_insert, /* insert */ + __wt_cursor_notsup, /* update */ + __wt_cursor_notsup, /* remove */ + __wt_cursor_notsup, /* reconfigure */ + __wt_cursor_notsup); /* close */ WT_CURSOR **cp; WT_CURSOR_EXTRACTOR extract_cursor; WT_DECL_RET; @@ -829,20 +830,21 @@ __wt_curtable_open(WT_SESSION_IMPL *session, const char *uri, const char *cfg[], WT_CURSOR **cursorp) { WT_CURSOR_STATIC_INIT(iface, - __wt_curtable_get_key, /* get-key */ - __wt_curtable_get_value, /* get-value */ - __wt_curtable_set_key, /* set-key */ - __wt_curtable_set_value, /* set-value */ - __curtable_compare, /* compare */ - __curtable_next, /* next */ - __curtable_prev, /* prev */ - __curtable_reset, /* reset */ - __curtable_search, /* search */ - __curtable_search_near, /* search-near */ - __curtable_insert, /* insert */ - __curtable_update, /* update */ - __curtable_remove, /* remove */ - __curtable_close); /* close */ + __wt_curtable_get_key, /* get-key */ + __wt_curtable_get_value, /* get-value */ + __wt_curtable_set_key, /* set-key */ + __wt_curtable_set_value, /* set-value */ + __curtable_compare, /* compare */ + __curtable_next, /* next */ + __curtable_prev, /* prev */ + __curtable_reset, /* reset */ + __curtable_search, /* search */ + __curtable_search_near, /* search-near */ + __curtable_insert, /* insert */ + __curtable_update, /* update */ + __curtable_remove, /* remove */ + __wt_cursor_reconfigure, /* reconfigure */ + __curtable_close); /* close */ WT_CONFIG_ITEM cval; WT_CURSOR *cursor; WT_CURSOR_TABLE *ctable; diff --git a/src/include/config.h b/src/include/config.h index b9c4c97fa00..27872fc7c4a 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -56,29 +56,30 @@ struct __wt_config_parser_impl { #define WT_CONFIG_ENTRY_connection_open_session 8 #define WT_CONFIG_ENTRY_connection_reconfigure 9 #define WT_CONFIG_ENTRY_cursor_close 10 -#define WT_CONFIG_ENTRY_file_meta 11 -#define WT_CONFIG_ENTRY_index_meta 12 -#define WT_CONFIG_ENTRY_session_begin_transaction 13 -#define WT_CONFIG_ENTRY_session_checkpoint 14 -#define WT_CONFIG_ENTRY_session_close 15 -#define WT_CONFIG_ENTRY_session_commit_transaction 16 -#define WT_CONFIG_ENTRY_session_compact 17 -#define WT_CONFIG_ENTRY_session_create 18 -#define WT_CONFIG_ENTRY_session_drop 19 -#define WT_CONFIG_ENTRY_session_log_printf 20 -#define WT_CONFIG_ENTRY_session_open_cursor 21 -#define WT_CONFIG_ENTRY_session_reconfigure 22 -#define WT_CONFIG_ENTRY_session_rename 23 -#define WT_CONFIG_ENTRY_session_rollback_transaction 24 -#define WT_CONFIG_ENTRY_session_salvage 25 -#define WT_CONFIG_ENTRY_session_truncate 26 -#define WT_CONFIG_ENTRY_session_upgrade 27 -#define WT_CONFIG_ENTRY_session_verify 28 -#define WT_CONFIG_ENTRY_table_meta 29 -#define WT_CONFIG_ENTRY_wiredtiger_open 30 -#define WT_CONFIG_ENTRY_wiredtiger_open_all 31 -#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 32 -#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 33 +#define WT_CONFIG_ENTRY_cursor_reconfigure 11 +#define WT_CONFIG_ENTRY_file_meta 12 +#define WT_CONFIG_ENTRY_index_meta 13 +#define WT_CONFIG_ENTRY_session_begin_transaction 14 +#define WT_CONFIG_ENTRY_session_checkpoint 15 +#define WT_CONFIG_ENTRY_session_close 16 +#define WT_CONFIG_ENTRY_session_commit_transaction 17 +#define WT_CONFIG_ENTRY_session_compact 18 +#define WT_CONFIG_ENTRY_session_create 19 +#define WT_CONFIG_ENTRY_session_drop 20 +#define WT_CONFIG_ENTRY_session_log_printf 21 +#define WT_CONFIG_ENTRY_session_open_cursor 22 +#define WT_CONFIG_ENTRY_session_reconfigure 23 +#define WT_CONFIG_ENTRY_session_rename 24 +#define WT_CONFIG_ENTRY_session_rollback_transaction 25 +#define WT_CONFIG_ENTRY_session_salvage 26 +#define WT_CONFIG_ENTRY_session_truncate 27 +#define WT_CONFIG_ENTRY_session_upgrade 28 +#define WT_CONFIG_ENTRY_session_verify 29 +#define WT_CONFIG_ENTRY_table_meta 30 +#define WT_CONFIG_ENTRY_wiredtiger_open 31 +#define WT_CONFIG_ENTRY_wiredtiger_open_all 32 +#define WT_CONFIG_ENTRY_wiredtiger_open_basecfg 33 +#define WT_CONFIG_ENTRY_wiredtiger_open_usercfg 34 /* * configuration section: END * DO NOT EDIT: automatically built by dist/flags.py. diff --git a/src/include/cursor.h b/src/include/cursor.h index 1013128c644..082f3ee86e9 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -22,6 +22,7 @@ insert, \ update, \ remove, \ + reconfigure, \ close) \ static const WT_CURSOR n = { \ NULL, /* session */ \ @@ -41,6 +42,7 @@ insert, \ update, \ remove, \ + (int (*)(WT_CURSOR *, const char *))(reconfigure), \ close, \ { NULL, NULL }, /* TAILQ_ENTRY q */ \ 0, /* recno key */ \ @@ -51,6 +53,9 @@ { NULL, 0, 0, NULL, 0 }, /* WT_ITEM value */ \ 0, /* int saved_err */ \ NULL, /* internal_uri */ \ + insert, /* original insert */ \ + update, /* original update */ \ + remove, /* original remove */ \ 0 /* uint32_t flags */ \ } diff --git a/src/include/extern.h b/src/include/extern.h index bc75a6eda26..5a5601160c8 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -264,7 +264,6 @@ extern int __wt_curstat_open(WT_SESSION_IMPL *session, const char *uri, const ch extern int __wt_cursor_notsup(WT_CURSOR *cursor); extern int __wt_cursor_noop(WT_CURSOR *cursor); extern void __wt_cursor_set_notsup(WT_CURSOR *cursor); -extern int __wt_cursor_config_readonly(WT_CURSOR *cursor, const char *cfg[], int def); extern int __wt_cursor_kv_not_set(WT_CURSOR *cursor, int key); extern int __wt_cursor_get_key(WT_CURSOR *cursor, ...); extern void __wt_cursor_set_key(WT_CURSOR *cursor, ...); @@ -279,6 +278,7 @@ extern int __wt_cursor_get_valuev(WT_CURSOR *cursor, va_list ap); extern void __wt_cursor_set_value(WT_CURSOR *cursor, ...); extern void __wt_cursor_set_valuev(WT_CURSOR *cursor, va_list ap); extern int __wt_cursor_close(WT_CURSOR *cursor); +extern int __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config); extern int __wt_cursor_dup_position(WT_CURSOR *to_dup, WT_CURSOR *cursor); extern int __wt_cursor_init(WT_CURSOR *cursor, const char *uri, WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp); extern int __wt_curtable_get_key(WT_CURSOR *cursor, ...); diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index b5df4d49cdd..100bc771798 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -480,6 +480,19 @@ struct __wt_cursor { int __F(remove)(WT_CURSOR *cursor); /*! @} */ + /*! + * Reconfigure the cursor. + * + * The cursor is reset. + * + * @snippet ex_all.c Reconfigure a cursor + * + * @param cursor the cursor handle + * @param config the configuration string + * @errors + */ + int __F(reconfigure)(WT_CURSOR *cursor, const char *config); + /*! * Close the cursor. * @@ -521,6 +534,10 @@ struct __wt_cursor { * user on open. */ const char *internal_uri; + /* Saved modification methods. */ + int __F(insert_orig)(WT_CURSOR *cursor); + int __F(remove_orig)(WT_CURSOR *cursor); + int __F(update_orig)(WT_CURSOR *cursor); #define WT_CURSTD_APPEND 0x0001 #define WT_CURSTD_BULK 0x0002 @@ -801,10 +818,6 @@ struct __wt_session { * duplicated cursors are positioned at the same place in the data * source as the original. * - * To reconfigure a cursor, duplicate it with a new configuration value: - * - * @snippet ex_all.c Reconfigure a cursor - * * Cursor handles should be discarded by calling WT_CURSOR::close. * * Cursors capable of supporting transactional operations operate in the diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c index 9ff071af0ee..103a506287d 100644 --- a/src/lsm/lsm_cursor.c +++ b/src/lsm/lsm_cursor.c @@ -1437,6 +1437,7 @@ __wt_clsm_open(WT_SESSION_IMPL *session, __clsm_insert, /* insert */ __clsm_update, /* update */ __clsm_remove, /* remove */ + __wt_cursor_reconfigure, /* reconfigure */ __clsm_close); /* close */ WT_CURSOR *cursor; WT_CURSOR_LSM *clsm; @@ -1468,8 +1469,6 @@ __wt_clsm_open(WT_SESSION_IMPL *session, cursor->key_format = lsm_tree->key_format; cursor->value_format = lsm_tree->value_format; - WT_ERR(__wt_cursor_config_readonly(cursor, cfg, 0)); - clsm->lsm_tree = lsm_tree; /* diff --git a/test/suite/helper.py b/test/suite/helper.py index 41e0996c21e..14d01a57078 100644 --- a/test/suite/helper.py +++ b/test/suite/helper.py @@ -155,7 +155,7 @@ def simple_populate_check(self, uri, rows): cursor.close() # Return the value stored in a complex object. -def value_populate_complex(i): +def complex_value_populate(cursor, i): return [str(i) + ': abcdefghijklmnopqrstuvwxyz'[0:i%26], i, str(i) + ': abcdefghijklmnopqrstuvwxyz'[0:i%23], @@ -198,7 +198,7 @@ def complex_populate_type(self, uri, config, rows, type): cursor = self.session.open_cursor(uri, None) for i in range(1, rows + 1): cursor.set_key(key_populate(cursor, i)) - v = value_populate_complex(i) + v = complex_value_populate(cursor, i) cursor.set_value(v[0], v[1], v[2], v[3]) cursor.insert() cursor.close() @@ -208,7 +208,7 @@ def complex_populate_check_cursor(self, cursor, rows): for key, s1, i2, s3, s4 in cursor: i += 1 self.assertEqual(key, key_populate(cursor, i)) - v = value_populate_complex(i) + v = complex_value_populate(cursor, i) self.assertEqual(s1, v[0]) self.assertEqual(i2, v[1]) self.assertEqual(s3, v[2]) diff --git a/test/suite/test_cursor06.py b/test/suite/test_cursor06.py new file mode 100644 index 00000000000..c880f64b826 --- /dev/null +++ b/test/suite/test_cursor06.py @@ -0,0 +1,89 @@ +#!/usr/bin/env python +# +# 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 helper import key_populate, value_populate, simple_populate +from helper import complex_value_populate, complex_populate +from wtscenario import multiply_scenarios, number_scenarios + +# test_cursor06.py +# Test cursor reconfiguration. +class test_cursor06(wttest.WiredTigerTestCase): + name = 'reconfigure' + scenarios = [ + ('file-r', dict(type='file:',keyfmt='r',complex=0)), + ('file-S', dict(type='file:',keyfmt='S',complex=0)), + ('lsm-S', dict(type='lsm:',keyfmt='S',complex=0)), + ('table-r', dict(type='table:',keyfmt='r',complex=0)), + ('table-S', dict(type='table:',keyfmt='S',complex=0)), + ('table-r', dict(type='table:',keyfmt='r',complex=1)), + ('table-S', dict(type='table:',keyfmt='S',complex=1)), + ] + + def pop(self, uri): + if self.complex == 1: + complex_populate(self, uri, 'key_format=' + self.keyfmt, 100) + else: + simple_populate(self, uri, 'key_format=' + self.keyfmt, 100) + + def set_kv(self, cursor): + cursor.set_key(key_populate(cursor, 10)) + if self.complex == 1: + v = complex_value_populate(cursor, 10) + cursor.set_value(v[0], v[1], v[2], v[3]) + else: + cursor.set_value(value_populate(cursor, 10)) + + def test_reconfigure_overwrite(self): + uri = self.type + self.name + self.pop(uri) + cursor = self.session.open_cursor(uri, None) + for i in range(0, 10): + self.set_kv(cursor) + cursor.insert() + cursor.reconfigure("overwrite=0") + self.set_kv(cursor) + self.assertRaises(wiredtiger.WiredTigerError, lambda: + cursor.insert()) + cursor.reconfigure("overwrite=1") + + def test_reconfigure_readonly(self): + uri = self.type + self.name + self.pop(uri) + cursor = self.session.open_cursor(uri, None) + for i in range(0, 10): + self.set_kv(cursor) + cursor.update() + cursor.reconfigure("readonly=1") + self.set_kv(cursor) + self.assertRaises(wiredtiger.WiredTigerError, lambda: + cursor.update()) + cursor.reconfigure("readonly=0") + + +if __name__ == '__main__': + wttest.run() diff --git a/test/suite/test_truncate01.py b/test/suite/test_truncate01.py index 12a523d4d51..2df0cfaea56 100644 --- a/test/suite/test_truncate01.py +++ b/test/suite/test_truncate01.py @@ -32,7 +32,7 @@ import wiredtiger, wttest from helper import confirm_empty,\ key_populate, value_populate, simple_populate,\ - value_populate_complex, complex_populate + complex_populate, complex_value_populate from wtscenario import multiply_scenarios, number_scenarios # Test truncation arguments. @@ -441,7 +441,8 @@ class test_truncate_cursor(wttest.WiredTigerTestCase): cursor = self.session.open_cursor(uri, None) expected = {} for i in range(1, self.nentries + 1): - expected[key_populate(cursor, i)] = value_populate_complex(i) + expected[key_populate(cursor, i)] = \ + complex_value_populate(cursor, i) cursor.close() # Optionally close and re-open the object to get a disk image From 8662942d711b25e5cea0583ba6b87ce6a0edeb58 Mon Sep 17 00:00:00 2001 From: Michael Cahill Date: Mon, 22 Dec 2014 16:22:51 +1100 Subject: [PATCH 02/16] Add more tests for WT_CURSOR::reconfigure. --- test/suite/test_cursor06.py | 55 ++++++++++++++++++++++--------------- 1 file changed, 33 insertions(+), 22 deletions(-) diff --git a/test/suite/test_cursor06.py b/test/suite/test_cursor06.py index c880f64b826..c97df89a6bf 100644 --- a/test/suite/test_cursor06.py +++ b/test/suite/test_cursor06.py @@ -60,30 +60,41 @@ class test_cursor06(wttest.WiredTigerTestCase): def test_reconfigure_overwrite(self): uri = self.type + self.name - self.pop(uri) - cursor = self.session.open_cursor(uri, None) - for i in range(0, 10): - self.set_kv(cursor) - cursor.insert() - cursor.reconfigure("overwrite=0") - self.set_kv(cursor) - self.assertRaises(wiredtiger.WiredTigerError, lambda: - cursor.insert()) - cursor.reconfigure("overwrite=1") - + for open_config in ( None, "overwrite=0", "overwrite=1" ): + self.session.drop(uri, "force") + self.pop(uri) + cursor = self.session.open_cursor(uri, None, open_config) + if open_config != "overwrite=0": + self.set_kv(cursor) + cursor.insert() + for i in range(0, 10): + cursor.reconfigure("overwrite=0") + self.set_kv(cursor) + self.assertRaises(wiredtiger.WiredTigerError, + lambda: cursor.insert()) + cursor.reconfigure("overwrite=1") + self.set_kv(cursor) + cursor.insert() + cursor.close() + def test_reconfigure_readonly(self): uri = self.type + self.name - self.pop(uri) - cursor = self.session.open_cursor(uri, None) - for i in range(0, 10): - self.set_kv(cursor) - cursor.update() - cursor.reconfigure("readonly=1") - self.set_kv(cursor) - self.assertRaises(wiredtiger.WiredTigerError, lambda: - cursor.update()) - cursor.reconfigure("readonly=0") - + for open_config in ( None, "readonly=0", "readonly=1" ): + self.session.drop(uri, "force") + self.pop(uri) + cursor = self.session.open_cursor(uri, None, open_config) + if open_config != "readonly=1": + self.set_kv(cursor) + cursor.update() + for i in range(0, 10): + cursor.reconfigure("readonly=1") + self.set_kv(cursor) + self.assertRaises(wiredtiger.WiredTigerError, + lambda: cursor.update()) + cursor.reconfigure("readonly=0") + self.set_kv(cursor) + cursor.update() + cursor.close() if __name__ == '__main__': wttest.run() From a32c46025c2bdb8016b7a4b5e18bbe944c6de79b Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 16:03:15 -0500 Subject: [PATCH 03/16] fix formatting (I think) --- test/suite/test_cursor06.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/test/suite/test_cursor06.py b/test/suite/test_cursor06.py index c97df89a6bf..c713957f624 100644 --- a/test/suite/test_cursor06.py +++ b/test/suite/test_cursor06.py @@ -60,7 +60,7 @@ class test_cursor06(wttest.WiredTigerTestCase): def test_reconfigure_overwrite(self): uri = self.type + self.name - for open_config in ( None, "overwrite=0", "overwrite=1" ): + for open_config in (None, "overwrite=0", "overwrite=1"): self.session.drop(uri, "force") self.pop(uri) cursor = self.session.open_cursor(uri, None, open_config) @@ -79,7 +79,7 @@ class test_cursor06(wttest.WiredTigerTestCase): def test_reconfigure_readonly(self): uri = self.type + self.name - for open_config in ( None, "readonly=0", "readonly=1" ): + for open_config in (None, "readonly=0", "readonly=1"): self.session.drop(uri, "force") self.pop(uri) cursor = self.session.open_cursor(uri, None, open_config) @@ -90,7 +90,7 @@ class test_cursor06(wttest.WiredTigerTestCase): cursor.reconfigure("readonly=1") self.set_kv(cursor) self.assertRaises(wiredtiger.WiredTigerError, - lambda: cursor.update()) + lambda: cursor.update()) cursor.reconfigure("readonly=0") self.set_kv(cursor) cursor.update() From 94b9c2774da529c42839ed34a6f186d888ddabe0 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 16:43:46 -0500 Subject: [PATCH 04/16] Fix order of original cursor functions. --- lang/java/java_doc.i | 2 +- src/include/wiredtiger.in | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i index 2c4eab0a3b2..a6973e7fa54 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -16,8 +16,8 @@ COPYDOC(__wt_cursor, WT_CURSOR, remove) COPYDOC(__wt_cursor, WT_CURSOR, reconfigure) COPYDOC(__wt_cursor, WT_CURSOR, close) COPYDOC(__wt_cursor, WT_CURSOR, insert_orig) -COPYDOC(__wt_cursor, WT_CURSOR, remove_orig) COPYDOC(__wt_cursor, WT_CURSOR, update_orig) +COPYDOC(__wt_cursor, WT_CURSOR, remove_orig) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_key) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_value) COPYDOC(__wt_async_op, WT_ASYNC_OP, set_key) diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index ed17e151c8c..9b77249367f 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -536,8 +536,8 @@ struct __wt_cursor { const char *internal_uri; /* Saved modification methods. */ int __F(insert_orig)(WT_CURSOR *cursor); - int __F(remove_orig)(WT_CURSOR *cursor); int __F(update_orig)(WT_CURSOR *cursor); + int __F(remove_orig)(WT_CURSOR *cursor); #define WT_CURSTD_APPEND 0x0001 #define WT_CURSTD_BULK 0x0002 From 66fae1fc5f2f53ee47136b4fa1c02ad0dde1fa21 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 16:45:22 -0500 Subject: [PATCH 05/16] Now that you can reconfigure cursors, configuring a cursor read-only initially doesn't necessarily mean it stays read-only. --- src/cursor/cur_metadata.c | 5 ++++- src/cursor/cur_std.c | 20 +++++++++++--------- 2 files changed, 15 insertions(+), 10 deletions(-) diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c index e1e08c307fc..a24c3289a7c 100644 --- a/src/cursor/cur_metadata.c +++ b/src/cursor/cur_metadata.c @@ -436,7 +436,10 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, WT_ERR(__wt_cursor_init(cursor, uri, owner, cfg, cursorp)); - /* Metadata cursors default to readonly. */ + /* + * Metadata cursors default to readonly; if not set to not-readonly, + * they are permanently readonly and cannot be reconfigured. + */ WT_ERR(__wt_config_gets_def(session, cfg, "readonly", 1, &cval)); if (cval.val != 0) { cursor->insert = cursor->insert_orig = __wt_cursor_notsup; diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c index 6f7168a5cc6..61241b82024 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -620,21 +620,23 @@ __wt_cursor_init(WT_CURSOR *cursor, /* * checkpoint, readonly - * Checkpoint cursors are read-only, avoid any extra work. + * Checkpoint cursors are permanently read-only, avoid the extra work + * of two configuration string checks. */ readonly = 0; WT_RET(__wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); - if (cval.len == 0) { - WT_RET( - __wt_config_gets_def(session, cfg, "readonly", 0, &cval)); - if (cval.val != 0) - readonly = 1; - } else - readonly = 1; - if (readonly) { + if (cval.len == 1) { cursor->insert = cursor->insert_orig = __wt_cursor_notsup; cursor->update = cursor->update_orig = __wt_cursor_notsup; cursor->remove = cursor->remove_orig = __wt_cursor_notsup; + } else { + WT_RET( + __wt_config_gets_def(session, cfg, "readonly", 0, &cval)); + if (cval.val != 0) { + cursor->insert = __wt_cursor_notsup; + cursor->update = __wt_cursor_notsup; + cursor->remove = __wt_cursor_notsup; + } } /* From ec4d6b11a12463dc788b45a20402c8896483601c Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 16:49:18 -0500 Subject: [PATCH 06/16] lint, variable no longer used. --- src/cursor/cur_std.c | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c index 61241b82024..9a36b628835 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -601,7 +601,6 @@ __wt_cursor_init(WT_CURSOR *cursor, WT_CONFIG_ITEM cval; WT_CURSOR *cdump; WT_SESSION_IMPL *session; - int readonly; session = (WT_SESSION_IMPL *)cursor->session; @@ -623,7 +622,6 @@ __wt_cursor_init(WT_CURSOR *cursor, * Checkpoint cursors are permanently read-only, avoid the extra work * of two configuration string checks. */ - readonly = 0; WT_RET(__wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); if (cval.len == 1) { cursor->insert = cursor->insert_orig = __wt_cursor_notsup; From 24d46594c37bc8092fc66299102413ebefef3e8e Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 17:35:03 -0500 Subject: [PATCH 07/16] Turn off the read-only configuration during table, index, and column-group creation. --- src/cursor/cur_table.c | 34 ++++++++++++++++++++-------------- 1 file changed, 20 insertions(+), 14 deletions(-) diff --git a/src/cursor/cur_table.c b/src/cursor/cur_table.c index 1825d641c49..d994c44357f 100644 --- a/src/cursor/cur_table.c +++ b/src/cursor/cur_table.c @@ -753,11 +753,11 @@ __curtable_open_colgroups(WT_CURSOR_TABLE *ctable, const char *cfg_arg[]) WT_TABLE *table; WT_CURSOR **cp; /* - * Underlying column groups are always opened without dump, and only - * the primary is opened with next_random. + * Underlying column groups are always opened without dump or readonly, + * and only the primary is opened with next_random. */ const char *cfg[] = { - cfg_arg[0], cfg_arg[1], "dump=\"\"", NULL, NULL + cfg_arg[0], cfg_arg[1], "dump=\"\",readonly=0", NULL, NULL }; u_int i; int complete; @@ -891,8 +891,8 @@ __wt_curtable_open(WT_SESSION_IMPL *session, ctable->plan = table->plan; /* Handle projections. */ + WT_RET(__wt_scr_alloc(session, 0, &tmp)); if (columns != NULL) { - WT_ERR(__wt_scr_alloc(session, 0, &tmp)); WT_ERR(__wt_struct_reformat(session, table, columns, strlen(columns), NULL, 1, tmp)); WT_ERR(__wt_strndup( @@ -934,22 +934,28 @@ __wt_curtable_open(WT_SESSION_IMPL *session, WT_ERR(__curtable_open_colgroups(ctable, cfg)); /* - * We'll need to squirrel away a copy of the cursor configuration - * for if/when we open indices. + * We'll need to squirrel away a copy of the cursor configuration for + * if/when we open indices. * * cfg[0] is the baseline configuration for the cursor open and we can * acquire another copy from the configuration structures, so it would * be reasonable not to copy it here: but I'd rather be safe than sorry. * - * Underlying indices are always opened without dump. + * cfg[1] is the application configuration. + * + * Underlying indices are always opened without dump or readonly; that + * information is appended to cfg[1] so later "fast" configuration calls + * (checking only cfg[0] and cfg[1]) work. I don't expect to see more + * than two configuration strings here, but it's written to compact into + * two configuration strings, a copy of cfg[0] and the rest in cfg[1]. */ - for (cfg_cnt = 0; cfg[cfg_cnt] != NULL; ++cfg_cnt) - ; - WT_ERR(__wt_calloc_def(session, cfg_cnt + 2, &ctable->cfg)); - for (cfg_cnt = 0; cfg[cfg_cnt] != NULL; ++cfg_cnt) - WT_ERR( - __wt_strdup(session, cfg[cfg_cnt], &ctable->cfg[cfg_cnt])); - WT_ERR(__wt_strdup(session, "dump=\"\"", &ctable->cfg[cfg_cnt])); + WT_ERR(__wt_calloc_def(session, 3, &ctable->cfg)); + WT_ERR(__wt_strdup(session, cfg[0], &ctable->cfg[0])); + WT_ERR(__wt_buf_set(session, tmp, "", 0)); + for (cfg_cnt = 1; cfg[cfg_cnt] != NULL; ++cfg_cnt) + WT_ERR(__wt_buf_catfmt(session, tmp, "%s,", cfg[cfg_cnt])); + WT_ERR(__wt_buf_catfmt(session, tmp, "dump=\"\",readonly=0")); + WT_ERR(__wt_strdup(session, tmp->data, &ctable->cfg[1])); if (0) { err: WT_TRET(__curtable_close(cursor)); From 71355ac442db3e001c120fcfc398de71d34075e3 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Mon, 22 Dec 2014 18:03:58 -0500 Subject: [PATCH 08/16] Typo, the test for a configuration string is (cval.len != 0). --- src/cursor/cur_std.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c index 9a36b628835..f0eb5a4ec73 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -623,7 +623,7 @@ __wt_cursor_init(WT_CURSOR *cursor, * of two configuration string checks. */ WT_RET(__wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); - if (cval.len == 1) { + if (cval.len != 0) { cursor->insert = cursor->insert_orig = __wt_cursor_notsup; cursor->update = cursor->update_orig = __wt_cursor_notsup; cursor->remove = cursor->remove_orig = __wt_cursor_notsup; From 1b033e5b2b4caba973f24a85c3591eb45e991538 Mon Sep 17 00:00:00 2001 From: Michael Cahill Date: Sat, 17 Jan 2015 05:15:04 +1100 Subject: [PATCH 09/16] Don't allow "readonly" to be reconfigured on cursors. refs #1467 --- dist/api_data.py | 18 +++++++++--------- lang/java/java_doc.i | 3 --- src/config/config_def.c | 3 +-- src/cursor/cur_metadata.c | 6 +++--- src/cursor/cur_std.c | 31 +++---------------------------- src/include/cursor.h | 3 --- src/include/wiredtiger.in | 3 --- test/suite/test_cursor06.py | 1 + 8 files changed, 17 insertions(+), 51 deletions(-) diff --git a/dist/api_data.py b/dist/api_data.py index d356ee27ed4..0141526285c 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -559,7 +559,7 @@ common_wiredtiger_open = [ ]), ] -cursor_config = [ +cursor_runtime_config = [ Config('append', 'false', r''' append the value as a new record, creating a new record number key; valid only for cursors with record number keys''', @@ -571,12 +571,6 @@ cursor_config = [ if the record exists, WT_CURSOR::update and WT_CURSOR::remove fail with ::WT_NOTFOUND if the record does not exist''', type='boolean'), - Config('readonly', 'false', r''' - only query operations are supported by this cursor. An error is - returned if a modification is attempted using the cursor. The - default is false for all cursor types except for log and metadata - cursors''', - type='boolean'), ] methods = { @@ -590,7 +584,7 @@ methods = { 'cursor.close' : Method([]), -'cursor.reconfigure' : Method(cursor_config), +'cursor.reconfigure' : Method(cursor_runtime_config), 'session.close' : Method([]), @@ -622,7 +616,7 @@ methods = { 'session.log_printf' : Method([]), -'session.open_cursor' : Method(cursor_config + [ +'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 @@ -663,6 +657,12 @@ methods = { ignore the encodings for the key and value, manage data as if the formats were \c "u". See @ref cursor_raw for details''', type='boolean'), + Config('readonly', 'false', r''' + only query operations are supported by this cursor. An error is + returned if a modification is attempted using the cursor. The + default is false for all cursor types except for log and metadata + cursors''', + type='boolean'), Config('skip_sort_check', 'false', r''' skip the check of the sort order of each bulk-loaded key''', type='boolean', undoc=True), diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i index a6973e7fa54..07910687cf5 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -15,9 +15,6 @@ COPYDOC(__wt_cursor, WT_CURSOR, update) COPYDOC(__wt_cursor, WT_CURSOR, remove) COPYDOC(__wt_cursor, WT_CURSOR, reconfigure) COPYDOC(__wt_cursor, WT_CURSOR, close) -COPYDOC(__wt_cursor, WT_CURSOR, insert_orig) -COPYDOC(__wt_cursor, WT_CURSOR, update_orig) -COPYDOC(__wt_cursor, WT_CURSOR, remove_orig) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_key) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_value) COPYDOC(__wt_async_op, WT_ASYNC_OP, set_key) diff --git a/src/config/config_def.c b/src/config/config_def.c index bf806ea6101..ec44e8839b0 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -113,7 +113,6 @@ static const WT_CONFIG_CHECK confchk_connection_reconfigure[] = { static const WT_CONFIG_CHECK confchk_cursor_reconfigure[] = { { "append", "boolean", NULL, NULL }, { "overwrite", "boolean", NULL, NULL }, - { "readonly", "boolean", NULL, NULL }, { NULL, NULL, NULL, NULL } }; @@ -569,7 +568,7 @@ static const WT_CONFIG_ENTRY config_entries[] = { NULL }, { "cursor.reconfigure", - "append=0,overwrite=,readonly=0", + "append=0,overwrite=", confchk_cursor_reconfigure }, { "file.meta", diff --git a/src/cursor/cur_metadata.c b/src/cursor/cur_metadata.c index ae92a6ee371..562ac51d8ea 100644 --- a/src/cursor/cur_metadata.c +++ b/src/cursor/cur_metadata.c @@ -443,9 +443,9 @@ __wt_curmetadata_open(WT_SESSION_IMPL *session, */ WT_ERR(__wt_config_gets_def(session, cfg, "readonly", 1, &cval)); if (cval.val != 0) { - cursor->insert = cursor->insert_orig = __wt_cursor_notsup; - cursor->update = cursor->update_orig = __wt_cursor_notsup; - cursor->remove = cursor->remove_orig = __wt_cursor_notsup; + cursor->insert = __wt_cursor_notsup; + cursor->update = __wt_cursor_notsup; + cursor->remove = __wt_cursor_notsup; } if (0) { diff --git a/src/cursor/cur_std.c b/src/cursor/cur_std.c index 176e9d9efdf..7d6876361ac 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -522,31 +522,6 @@ __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config) } else WT_RET_NOTFOUND_OK(ret); - /* - * readonly - */ - if ((ret = __wt_config_getones( - session, config, "readonly", &cval)) == 0) { - if (cval.val == 0) { - /* - * Fail if the user is turning readonly off and the - * cursor never supported writing in the first place. - */ - if (cursor->insert_orig == - (int (*)(WT_CURSOR *))__wt_cursor_set_notsup) - WT_RET_MSG(session, EINVAL, - "cursor cannot be used for data update"); - cursor->insert = cursor->insert_orig; - cursor->remove = cursor->remove_orig; - cursor->update = cursor->update_orig; - } else { - cursor->insert = __wt_cursor_notsup; - cursor->remove = __wt_cursor_notsup; - cursor->update = __wt_cursor_notsup; - } - } else - WT_RET_NOTFOUND_OK(ret); - return (0); } @@ -625,9 +600,9 @@ __wt_cursor_init(WT_CURSOR *cursor, */ WT_RET(__wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); if (cval.len != 0) { - cursor->insert = cursor->insert_orig = __wt_cursor_notsup; - cursor->update = cursor->update_orig = __wt_cursor_notsup; - cursor->remove = cursor->remove_orig = __wt_cursor_notsup; + cursor->insert = __wt_cursor_notsup; + cursor->update = __wt_cursor_notsup; + cursor->remove = __wt_cursor_notsup; } else { WT_RET( __wt_config_gets_def(session, cfg, "readonly", 0, &cval)); diff --git a/src/include/cursor.h b/src/include/cursor.h index 0a563b879c9..eceeb9216e7 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -54,9 +54,6 @@ { NULL, 0, 0, NULL, 0 }, /* WT_ITEM value */ \ 0, /* int saved_err */ \ NULL, /* internal_uri */ \ - insert, /* original insert */ \ - update, /* original update */ \ - remove, /* original remove */ \ 0 /* uint32_t flags */ \ } diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index f582186f54c..0db347c1413 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -536,9 +536,6 @@ struct __wt_cursor { */ const char *internal_uri; /* Saved modification methods. */ - int __F(insert_orig)(WT_CURSOR *cursor); - int __F(update_orig)(WT_CURSOR *cursor); - int __F(remove_orig)(WT_CURSOR *cursor); #define WT_CURSTD_APPEND 0x0001 #define WT_CURSTD_BULK 0x0002 diff --git a/test/suite/test_cursor06.py b/test/suite/test_cursor06.py index c713957f624..e5f500052a9 100644 --- a/test/suite/test_cursor06.py +++ b/test/suite/test_cursor06.py @@ -1,5 +1,6 @@ #!/usr/bin/env python # +# Public Domain 2014-2015 MongoDB, Inc. # Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. From f91fbc7bcc6d92c18ddf13af9ee0a1458b431015 Mon Sep 17 00:00:00 2001 From: Michael Cahill Date: Sat, 17 Jan 2015 05:53:09 +1100 Subject: [PATCH 10/16] Clip readonly reconfigure tests. --- test/suite/test_cursor06.py | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/test/suite/test_cursor06.py b/test/suite/test_cursor06.py index e5f500052a9..589bcd215ee 100644 --- a/test/suite/test_cursor06.py +++ b/test/suite/test_cursor06.py @@ -84,15 +84,11 @@ class test_cursor06(wttest.WiredTigerTestCase): self.session.drop(uri, "force") self.pop(uri) cursor = self.session.open_cursor(uri, None, open_config) - if open_config != "readonly=1": - self.set_kv(cursor) - cursor.update() - for i in range(0, 10): - cursor.reconfigure("readonly=1") + if open_config == "readonly=1": self.set_kv(cursor) self.assertRaises(wiredtiger.WiredTigerError, lambda: cursor.update()) - cursor.reconfigure("readonly=0") + else: self.set_kv(cursor) cursor.update() cursor.close() From 2894268cca330aab01910d450e1679df2d053ba0 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:01:36 -0500 Subject: [PATCH 11/16] Put the WT_CURSOR public methods in alphabetical order. --- lang/java/java_doc.i | 2 +- src/include/cursor.h | 2 +- src/include/wiredtiger.in | 26 +++++++++++++------------- 3 files changed, 15 insertions(+), 15 deletions(-) diff --git a/lang/java/java_doc.i b/lang/java/java_doc.i index 07910687cf5..0214bfd2a35 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -13,8 +13,8 @@ COPYDOC(__wt_cursor, WT_CURSOR, search_near) COPYDOC(__wt_cursor, WT_CURSOR, insert) COPYDOC(__wt_cursor, WT_CURSOR, update) COPYDOC(__wt_cursor, WT_CURSOR, remove) -COPYDOC(__wt_cursor, WT_CURSOR, reconfigure) COPYDOC(__wt_cursor, WT_CURSOR, close) +COPYDOC(__wt_cursor, WT_CURSOR, reconfigure) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_key) COPYDOC(__wt_async_op, WT_ASYNC_OP, get_value) COPYDOC(__wt_async_op, WT_ASYNC_OP, set_key) diff --git a/src/include/cursor.h b/src/include/cursor.h index eceeb9216e7..f751ed74354 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -43,8 +43,8 @@ insert, \ update, \ remove, \ - (int (*)(WT_CURSOR *, const char *))(reconfigure), \ close, \ + (int (*)(WT_CURSOR *, const char *))(reconfigure), \ { NULL, NULL }, /* TAILQ_ENTRY q */ \ 0, /* recno key */ \ { 0 }, /* recno raw buffer */ \ diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 0db347c1413..23986e023b6 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -481,19 +481,6 @@ struct __wt_cursor { int __F(remove)(WT_CURSOR *cursor); /*! @} */ - /*! - * Reconfigure the cursor. - * - * The cursor is reset. - * - * @snippet ex_all.c Reconfigure a cursor - * - * @param cursor the cursor handle - * @param config the configuration string - * @errors - */ - int __F(reconfigure)(WT_CURSOR *cursor, const char *config); - /*! * Close the cursor. * @@ -508,6 +495,19 @@ struct __wt_cursor { */ int __F(close)(WT_HANDLE_CLOSED(WT_CURSOR) *cursor); + /*! + * Reconfigure the cursor. + * + * The cursor is reset. + * + * @snippet ex_all.c Reconfigure a cursor + * + * @param cursor the cursor handle + * @param config the configuration string + * @errors + */ + int __F(reconfigure)(WT_CURSOR *cursor, const char *config); + /* * Protected fields, only to be used by cursor implementations. */ From 976013beaea066cfb16f9c7f6d2605cff1d7fc09 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:03:51 -0500 Subject: [PATCH 12/16] Add the list of valid configuration strings to the WT_CURSOR.reconfigure documentation. --- src/include/wiredtiger.in | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/include/wiredtiger.in b/src/include/wiredtiger.in index 23986e023b6..80b917e37cb 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -503,7 +503,17 @@ struct __wt_cursor { * @snippet ex_all.c Reconfigure a cursor * * @param cursor the cursor handle - * @param config the configuration string + * @configstart{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.} + * @config{overwrite, configures whether the cursor's insert\, update + * and remove methods check the existing state of the record. If \c + * overwrite is \c false\, WT_CURSOR::insert fails with + * ::WT_DUPLICATE_KEY if the record exists\, WT_CURSOR::update and + * WT_CURSOR::remove fail with ::WT_NOTFOUND if the record does not + * exist., a boolean flag; default \c true.} + * @configend * @errors */ int __F(reconfigure)(WT_CURSOR *cursor, const char *config); From 4939921edb593d460df357d67225a6c75ff67748 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:27:46 -0500 Subject: [PATCH 13/16] Fix up copyright notices. --- tools/test/test_wtstats.py | 30 +++++++++++++++++++++++++++++- tools/wtstats.py | 1 + 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/tools/test/test_wtstats.py b/tools/test/test_wtstats.py index 2a79d776528..4aa2fdf2151 100644 --- a/tools/test/test_wtstats.py +++ b/tools/test/test_wtstats.py @@ -1,3 +1,32 @@ +#!/usr/bin/env python +# +# Copyright (c) 2014-2015 MongoDB, Inc. +# Public Domain 2008-2015 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. +# + """ To run this test suite, install nose with `pip install nose` and then run `nosetests -v` from the `./tools` directory. @@ -268,4 +297,3 @@ def test_all_option(): series_keys = map(lambda x: x['key'], data['series']) for key in series_keys: assert key.startswith('transaction:') - diff --git a/tools/wtstats.py b/tools/wtstats.py index 95f23b444bd..ded2c5702b6 100755 --- a/tools/wtstats.py +++ b/tools/wtstats.py @@ -1,5 +1,6 @@ #!/usr/bin/env python # +# Copyright (c) 2014-2015 MongoDB, Inc. # Public Domain 2008-2015 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. From 16cea1d411354db3ab994871a0c6860f1a0ca9ab Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:29:06 -0500 Subject: [PATCH 14/16] Flexelint: symbol 'close_end_lsn' (line 862) not accessed. --- src/log/log.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/log/log.c b/src/log/log.c index c48fc7536b2..b2631a73946 100644 --- a/src/log/log.c +++ b/src/log/log.c @@ -859,7 +859,7 @@ __log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot) WT_CONNECTION_IMPL *conn; WT_DECL_RET; WT_LOG *log; - WT_LSN close_end_lsn, close_lsn, sync_lsn; + WT_LSN close_lsn, sync_lsn; size_t write_size; int locked; WT_DECL_SPINLOCK_ID(id); /* Must appear last */ @@ -873,7 +873,6 @@ __log_release(WT_SESSION_IMPL *session, WT_LOGSLOT *slot) * of the file handle structure. */ WT_INIT_LSN(&close_lsn); - WT_INIT_LSN(&close_end_lsn); /* Write the buffered records */ if (F_ISSET(slot, SLOT_BUFFERED)) { From 3f37a7e968ff61ea61691d1d3360d052993ba9b4 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:32:21 -0500 Subject: [PATCH 15/16] Fix up the copyright notice. --- tools/test/test_wtstats.py | 2 +- tools/wtstats.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test/test_wtstats.py b/tools/test/test_wtstats.py index 4aa2fdf2151..09ba63c8945 100644 --- a/tools/test/test_wtstats.py +++ b/tools/test/test_wtstats.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2014-2015 MongoDB, Inc. +# Public Domain 2014-2015 MongoDB, Inc. # Public Domain 2008-2015 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. diff --git a/tools/wtstats.py b/tools/wtstats.py index ded2c5702b6..98a254bdf33 100755 --- a/tools/wtstats.py +++ b/tools/wtstats.py @@ -1,6 +1,6 @@ #!/usr/bin/env python # -# Copyright (c) 2014-2015 MongoDB, Inc. +# Public Domain 2014-2015 MongoDB, Inc. # Public Domain 2008-2015 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. From 2bd04ab9f9d841a525a21612b90a835a9c517985 Mon Sep 17 00:00:00 2001 From: Keith Bostic Date: Fri, 16 Jan 2015 15:33:45 -0500 Subject: [PATCH 16/16] One more try, fix up the copyright notices. --- tools/test/test_wtstats.py | 2 +- tools/wtstats.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/test/test_wtstats.py b/tools/test/test_wtstats.py index 09ba63c8945..80078d97667 100644 --- a/tools/test/test_wtstats.py +++ b/tools/test/test_wtstats.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # Public Domain 2014-2015 MongoDB, Inc. -# Public Domain 2008-2015 WiredTiger, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. # diff --git a/tools/wtstats.py b/tools/wtstats.py index 98a254bdf33..031b7cb546f 100755 --- a/tools/wtstats.py +++ b/tools/wtstats.py @@ -1,7 +1,7 @@ #!/usr/bin/env python # # Public Domain 2014-2015 MongoDB, Inc. -# Public Domain 2008-2015 WiredTiger, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. #