diff --git a/dist/api_data.py b/dist/api_data.py index 7e964252c83..0141526285c 100644 --- a/dist/api_data.py +++ b/dist/api_data.py @@ -559,6 +559,20 @@ common_wiredtiger_open = [ ]), ] +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''', + 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'), +] + methods = { 'file.meta' : Method(file_meta), @@ -570,6 +584,8 @@ methods = { 'cursor.close' : Method([]), +'cursor.reconfigure' : Method(cursor_runtime_config), + 'session.close' : Method([]), 'session.compact' : Method([ @@ -600,11 +616,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_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 @@ -641,13 +653,6 @@ 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''', diff --git a/examples/c/ex_all.c b/examples/c/ex_all.c index 108cca583a8..51b4bb42040 100644 --- a/examples/c/ex_all.c +++ b/examples/c/ex_all.c @@ -95,20 +95,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 0890b14fa65..53785a3bab4 100644 --- a/lang/java/java_doc.i +++ b/lang/java/java_doc.i @@ -15,6 +15,7 @@ COPYDOC(__wt_cursor, WT_CURSOR, insert) COPYDOC(__wt_cursor, WT_CURSOR, update) COPYDOC(__wt_cursor, WT_CURSOR, remove) 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/config/config_def.c b/src/config/config_def.c index 9d2e5ba9c86..ec44e8839b0 100644 --- a/src/config/config_def.c +++ b/src/config/config_def.c @@ -110,6 +110,12 @@ 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 }, + { 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 }, @@ -561,6 +567,10 @@ static const WT_CONFIG_ENTRY config_entries[] = { "", NULL }, + { "cursor.reconfigure", + "append=0,overwrite=", + 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 c7f5a370641..c85e9e24fb2 100644 --- a/src/cursor/cur_backup.c +++ b/src/cursor/cur_backup.c @@ -118,6 +118,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 77cc3eb0b2e..348cfbab1dd 100644 --- a/src/cursor/cur_config.c +++ b/src/cursor/cur_config.c @@ -41,6 +41,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 4cf5dadf705..c58d6899150 100644 --- a/src/cursor/cur_ds.c +++ b/src/cursor/cur_ds.c @@ -463,6 +463,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 cd9fbf0801b..00281054d22 100644 --- a/src/cursor/cur_dump.c +++ b/src/cursor/cur_dump.c @@ -361,6 +361,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 fd044ff87b6..2f24d8ed59a 100644 --- a/src/cursor/cur_file.c +++ b/src/cursor/cur_file.c @@ -398,6 +398,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 3c626b15cb2..abc6a106cc9 100644 --- a/src/cursor/cur_index.c +++ b/src/cursor/cur_index.c @@ -352,6 +352,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 96fc6623496..5de3762217f 100644 --- a/src/cursor/cur_log.c +++ b/src/cursor/cur_log.c @@ -353,6 +353,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 a2cb1301c77..9860eb65a55 100644 --- a/src/cursor/cur_metadata.c +++ b/src/cursor/cur_metadata.c @@ -418,10 +418,12 @@ __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_one(session, &mdc)); @@ -436,8 +438,16 @@ __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; 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 = __wt_cursor_notsup; + cursor->update = __wt_cursor_notsup; + cursor->remove = __wt_cursor_notsup; + } if (0) { err: if (mdc->file_cursor != NULL) diff --git a/src/cursor/cur_stat.c b/src/cursor/cur_stat.c index 20f669b4776..5086160b233 100644 --- a/src/cursor/cur_stat.c +++ b/src/cursor/cur_stat.c @@ -494,6 +494,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 494b54890e5..858c6af6853 100644 --- a/src/cursor/cur_std.c +++ b/src/cursor/cur_std.c @@ -58,28 +58,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. @@ -523,29 +501,47 @@ err: API_END(session, ret); } /* - * __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); return (0); } @@ -608,9 +604,6 @@ __wt_cursor_init(WT_CURSOR *cursor, 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. @@ -622,14 +615,23 @@ __wt_cursor_init(WT_CURSOR *cursor, } /* - * checkpoint - * Checkpoint cursors are read-only. + * checkpoint, readonly + * Checkpoint cursors are permanently read-only, avoid the extra work + * of two configuration string checks. */ 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; + } 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; + } } /* @@ -656,14 +658,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 1adef6342bb..494277bb2f1 100644 --- a/src/cursor/cur_table.c +++ b/src/cursor/cur_table.c @@ -90,6 +90,7 @@ __apply_idx(WT_CURSOR_TABLE *ctable, size_t func_off, int skip_immutable) { __wt_cursor_notsup, /* search-near */ __curextract_insert, /* insert */ __wt_cursor_notsup, /* update */ + __wt_cursor_notsup, /* reconfigure */ __wt_cursor_notsup, /* remove */ __wt_cursor_notsup); /* close */ WT_CURSOR **cp; @@ -756,11 +757,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; @@ -847,6 +848,7 @@ __wt_curtable_open(WT_SESSION_IMPL *session, __curtable_insert, /* insert */ __curtable_update, /* update */ __curtable_remove, /* remove */ + __wt_cursor_reconfigure, /* reconfigure */ __curtable_close); /* close */ WT_CONFIG_ITEM cval; WT_CURSOR *cursor; @@ -894,8 +896,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( @@ -937,22 +939,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)); diff --git a/src/include/config.h b/src/include/config.h index 277a22063d1..65757c2ef6d 100644 --- a/src/include/config.h +++ b/src/include/config.h @@ -57,29 +57,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 249702c26ad..ba53bd23c78 100644 --- a/src/include/cursor.h +++ b/src/include/cursor.h @@ -24,6 +24,7 @@ insert, \ update, \ remove, \ + reconfigure, \ close) \ static const WT_CURSOR n = { \ NULL, /* session */ \ @@ -45,6 +46,7 @@ update, \ remove, \ close, \ + (int (*)(WT_CURSOR *, const char *))(reconfigure), \ { NULL, NULL }, /* TAILQ_ENTRY q */ \ 0, /* recno key */ \ { 0 }, /* recno raw buffer */ \ diff --git a/src/include/extern.h b/src/include/extern.h index 5555fe832ff..4872e48eeed 100644 --- a/src/include/extern.h +++ b/src/include/extern.h @@ -266,7 +266,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, ...); @@ -282,6 +281,7 @@ 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_equals(WT_CURSOR *cursor, WT_CURSOR *other, int *equalp); +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 2c2ee187fe3..982e850241b 100644 --- a/src/include/wiredtiger.in +++ b/src/include/wiredtiger.in @@ -511,6 +511,29 @@ 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 + * @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); + /* * Protected fields, only to be used by cursor implementations. */ @@ -538,6 +561,7 @@ struct __wt_cursor { * user on open. */ const char *internal_uri; + /* Saved modification methods. */ #define WT_CURSTD_APPEND 0x0001 #define WT_CURSTD_BULK 0x0002 @@ -829,10 +853,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/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)) { diff --git a/src/lsm/lsm_cursor.c b/src/lsm/lsm_cursor.c index c7d0d1ded9f..bf5ae465664 100644 --- a/src/lsm/lsm_cursor.c +++ b/src/lsm/lsm_cursor.c @@ -1438,6 +1438,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; @@ -1469,8 +1470,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 f0c149aeee3..21eac2359b6 100644 --- a/test/suite/helper.py +++ b/test/suite/helper.py @@ -156,7 +156,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], @@ -199,7 +199,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() @@ -209,7 +209,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..589bcd215ee --- /dev/null +++ b/test/suite/test_cursor06.py @@ -0,0 +1,97 @@ +#!/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. +# +# 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 + 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 + 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) + self.assertRaises(wiredtiger.WiredTigerError, + lambda: cursor.update()) + else: + self.set_kv(cursor) + cursor.update() + cursor.close() + +if __name__ == '__main__': + wttest.run() diff --git a/test/suite/test_truncate01.py b/test/suite/test_truncate01.py index 80590e876a6..c74c9bdfe91 100644 --- a/test/suite/test_truncate01.py +++ b/test/suite/test_truncate01.py @@ -33,7 +33,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. @@ -442,7 +442,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 diff --git a/tools/test/test_wtstats.py b/tools/test/test_wtstats.py index 2a79d776528..80078d97667 100644 --- a/tools/test/test_wtstats.py +++ b/tools/test/test_wtstats.py @@ -1,3 +1,32 @@ +#!/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. +# +# 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..031b7cb546f 100755 --- a/tools/wtstats.py +++ b/tools/wtstats.py @@ -1,6 +1,7 @@ #!/usr/bin/env python # -# Public Domain 2008-2015 WiredTiger, Inc. +# Public Domain 2014-2015 MongoDB, Inc. +# Public Domain 2008-2014 WiredTiger, Inc. # # This is free and unencumbered software released into the public domain. #