From b5b3fcc4c38cd289e9c0d3192946ed715d7e576f Mon Sep 17 00:00:00 2001 From: Luke Chen Date: Mon, 26 Feb 2018 17:13:06 +1100 Subject: Import wiredtiger: 8f5b5544d8e2ca861956a255cf079b3ad34ca0f3 from branch mongodb-3.8 ref: a6e72378a6..8f5b5544d8 for: 3.7.3 WT-1228 Improve performance of WT_SESSION::open_cursor WT-3805 Avoid reading lookaside pages in truncate fast path WT-3829 WiredTiger metadata can be logically inconsistent. WT-3848 Enhance new prepare transaction API to enforce post conditions WT-3850 Implement WT_SESSSION::prepare_transaction WT-3867 Bi-weekly WT codebase lint WT-3901 Corruption of operation tracking log files WT-3904 Reconsider error path in log server thread WT-3905 Save the timestamp used for a checkpoint WT-3912 fast-delete pages should re-instantiate the delete transaction's timestamp. WT-3923 __wt_txn_context_prepare_check() requires API initialization WT-3925 Fix test format operation selection code WT-3926 Allow read_timestamp to be set after begin_transaction WT-3927 LSM truncate operations are too slow. WT-3932 WiredTiger memory allocation failure in js_test WT-3933 test/format failure illegal WT_REF.state rolling back deleted page --- src/third_party/wiredtiger/src/cursor/cur_std.c | 269 +++++++++++++++++++++++- 1 file changed, 263 insertions(+), 6 deletions(-) (limited to 'src/third_party/wiredtiger/src/cursor/cur_std.c') diff --git a/src/third_party/wiredtiger/src/cursor/cur_std.c b/src/third_party/wiredtiger/src/cursor/cur_std.c index d7b23be75d6..32c4588b9fa 100644 --- a/src/third_party/wiredtiger/src/cursor/cur_std.c +++ b/src/third_party/wiredtiger/src/cursor/cur_std.c @@ -20,6 +20,19 @@ __wt_cursor_noop(WT_CURSOR *cursor) return (0); } +/* + * __wt_cursor_cached -- + * No actions on a closed and cached cursor are allowed. + */ +int +__wt_cursor_cached(WT_CURSOR *cursor) +{ + WT_SESSION_IMPL *session; + + session = (WT_SESSION_IMPL *)cursor->session; + WT_RET_MSG(session, ENOTSUP, "Cursor has been closed"); +} + /* * __wt_cursor_notsup -- * Unsupported cursor actions. @@ -134,6 +147,18 @@ __wt_cursor_reconfigure_notsup(WT_CURSOR *cursor, const char *config) return (__wt_cursor_notsup(cursor)); } +/* + * __wt_cursor_reopen_notsup -- + * Unsupported cursor reopen. + */ +int +__wt_cursor_reopen_notsup(WT_CURSOR *cursor, bool check_only) +{ + WT_UNUSED(check_only); + + return (__wt_cursor_notsup(cursor)); +} + /* * __wt_cursor_set_notsup -- * Reset the cursor methods to not-supported. @@ -556,6 +581,237 @@ err: cursor->saved_err = ret; API_END(session, ret); } +/* + * __wt_cursor_cache -- + * Add this cursor to the cache. + */ +int +__wt_cursor_cache(WT_CURSOR *cursor, WT_DATA_HANDLE *dhandle) +{ + WT_DECL_RET; + WT_SESSION_IMPL *session; + uint64_t bucket; + + session = (WT_SESSION_IMPL *)cursor->session; + WT_ASSERT(session, !F_ISSET(cursor, WT_CURSTD_CACHED) && + dhandle != NULL); + + WT_TRET(cursor->reset(cursor)); + + /* + * Acquire a reference while decrementing the in-use counter. + * After this point, the dhandle may be marked dead, but the + * actual handle won't be removed. + */ + session->dhandle = dhandle; + WT_DHANDLE_ACQUIRE(dhandle); + __wt_cursor_dhandle_decr_use(session); + + /* Move the cursor from the open list to the caching hash table. */ + if (cursor->uri_hash == 0) + cursor->uri_hash = __wt_hash_city64( + cursor->uri, strlen(cursor->uri)); + bucket = cursor->uri_hash % WT_HASH_ARRAY_SIZE; + TAILQ_REMOVE(&session->cursors, cursor, q); + TAILQ_INSERT_HEAD(&session->cursor_cache[bucket], cursor, q); + + (void)__wt_atomic_sub32(&S2C(session)->open_cursor_count, 1); + WT_STAT_DATA_DECR(session, session_cursor_open); + WT_STAT_DATA_INCR(session, session_cursor_cached); + F_SET(cursor, WT_CURSTD_CACHED); + return (ret); +} + +/* + * __wt_cursor_reopen -- + * Reopen this cursor from the cached state. + */ +void +__wt_cursor_reopen(WT_CURSOR *cursor, WT_DATA_HANDLE *dhandle) +{ + WT_SESSION_IMPL *session; + uint64_t bucket; + + session = (WT_SESSION_IMPL *)cursor->session; + WT_ASSERT(session, F_ISSET(cursor, WT_CURSTD_CACHED)); + + if (dhandle != NULL) { + session->dhandle = dhandle; + __wt_cursor_dhandle_incr_use(session); + WT_DHANDLE_RELEASE(dhandle); + } + (void)__wt_atomic_add32(&S2C(session)->open_cursor_count, 1); + WT_STAT_DATA_INCR(session, session_cursor_open); + WT_STAT_DATA_DECR(session, session_cursor_cached); + + bucket = cursor->uri_hash % WT_HASH_ARRAY_SIZE; + TAILQ_REMOVE(&session->cursor_cache[bucket], cursor, q); + TAILQ_INSERT_HEAD(&session->cursors, cursor, q); + F_CLR(cursor, WT_CURSTD_CACHED); +} + +/* + * __wt_cursor_cache_release -- + * Put the cursor into a cached state, called during cursor close + * operations. + */ +int +__wt_cursor_cache_release(WT_SESSION_IMPL *session, WT_CURSOR *cursor, + bool *released) +{ + WT_DECL_RET; + + *released = false; + if (!F_ISSET(cursor, WT_CURSTD_CACHEABLE) || + !F_ISSET(session, WT_SESSION_CACHE_CURSORS)) + return (0); + + WT_ASSERT(session, !F_ISSET(cursor, WT_CURSTD_BULK | WT_CURSTD_CACHED)); + + /* + * Do any sweeping first, if there are errors, it will + * be easier to clean up if the cursor is not already cached. + */ + if (--session->cursor_sweep_countdown == 0) + WT_RET(__wt_session_cursor_cache_sweep(session)); + + WT_ERR(cursor->cache(cursor)); + WT_STAT_CONN_INCR(session, cursor_cache); + WT_STAT_DATA_INCR(session, cursor_cache); + WT_ASSERT(session, F_ISSET(cursor, WT_CURSTD_CACHED)); + *released = true; + + if (0) { + /* + * If caching fails, we must restore the state of the + * cursor back to open so that the close works from + * a known state. The reopen may also fail, but that + * doesn't matter at this point. + */ +err: WT_TRET(cursor->reopen(cursor, false)); + WT_ASSERT(session, !F_ISSET(cursor, WT_CURSTD_CACHED)); + } + + return (ret); +} + +/* + * __wt_cursor_cache_get -- + * Open a matching cursor from the cache. + */ +int +__wt_cursor_cache_get(WT_SESSION_IMPL *session, const char *uri, + WT_CURSOR *owner, const char *cfg[], WT_CURSOR **cursorp) +{ + WT_CONFIG_ITEM cval; + WT_CONFIG_ITEM_STATIC_INIT(false_value); + WT_CURSOR *cursor; + WT_DECL_RET; + uint64_t bucket, hash_value; + bool have_config; + + if (owner != NULL && F_ISSET(owner, WT_CURSTD_CACHEABLE)) + return (WT_NOTFOUND); + have_config = (cfg != NULL && cfg[0] != NULL && cfg[1] != NULL); + if (have_config) { + + /* + * Any cursors that have special configuration cannot + * be cached. There are some exceptions for configurations + * that only differ by a cursor flag, which we can patch + * up if we find a matching cursor. + */ + WT_RET(__wt_config_gets_def(session, cfg, "bulk", 0, &cval)); + if (cval.val) + return (WT_NOTFOUND); + + WT_RET(__wt_config_gets_def(session, cfg, "dump", 0, &cval)); + if (cval.len != 0) + return (WT_NOTFOUND); + + WT_RET(__wt_config_gets_def( + session, cfg, "next_random", 0, &cval)); + if (cval.val != 0) + return (WT_NOTFOUND); + + WT_RET(__wt_config_gets_def( + session, cfg, "readonly", 0, &cval)); + if (cval.val) + return (WT_NOTFOUND); + + /* + * Look for checkpoint last, the value will stay in 'cval'. + */ + WT_RET_NOTFOUND_OK( + __wt_config_gets_def(session, cfg, "checkpoint", 0, &cval)); + + /* + * The internal checkpoint name is special, don't + * look for it. + */ + if (cval.len != 0 && + WT_STRING_MATCH(WT_CHECKPOINT, cval.str, cval.len)) + return (WT_NOTFOUND); + } else + cval = false_value; + +#define CHECKPOINT_MATCH(s) \ + ((s == NULL && cval.len == 0) || \ + (s != NULL && WT_STRING_MATCH(s, cval.str, cval.len))) + + /* + * Walk through all cursors, if there is a cached + * cursor that matches uri and configuration, use it. + */ + hash_value = __wt_hash_city64(uri, strlen(uri)); + bucket = hash_value % WT_HASH_ARRAY_SIZE; + TAILQ_FOREACH(cursor, &session->cursor_cache[bucket], q) { + if (cursor->uri_hash == hash_value && + WT_STREQ(cursor->uri, uri) && + CHECKPOINT_MATCH(cursor->checkpoint)) { + if ((ret = cursor->reopen(cursor, false)) != 0) { + F_CLR(cursor, WT_CURSTD_CACHEABLE); + session->dhandle = NULL; + (void)cursor->close(cursor); + return (ret); + } + + F_CLR(cursor, WT_CURSTD_APPEND | WT_CURSTD_OVERWRITE | + WT_CURSTD_RAW); + + if (have_config) { + /* + * For these configuration values, there + * is no difference in the resulting + * cursor other than flag values, so fix + * them up now. + */ + WT_RET(__wt_config_gets_def( + session, cfg, "append", 0, &cval)); + if (cval.val != 0) + F_SET(cursor, WT_CURSTD_APPEND); + + WT_RET(__wt_config_gets_def( + session, cfg, "overwrite", 1, &cval)); + if (cval.val != 0) + F_SET(cursor, WT_CURSTD_OVERWRITE); + + WT_RET(__wt_config_gets_def( + session, cfg, "raw", 0, &cval)); + if (cval.val != 0) + F_SET(cursor, WT_CURSTD_RAW); + } + + WT_STAT_CONN_INCR(session, cursor_reopen); + WT_STAT_DATA_INCR(session, cursor_reopen); + + *cursorp = cursor; + return (0); + } + } + return (WT_NOTFOUND); +} + /* * __wt_cursor_close -- * WT_CURSOR->close default implementation. @@ -573,7 +829,6 @@ __wt_cursor_close(WT_CURSOR *cursor) (void)__wt_atomic_sub32(&S2C(session)->open_cursor_count, 1); WT_STAT_DATA_DECR(session, session_cursor_open); } - __wt_buf_free(session, &cursor->key); __wt_buf_free(session, &cursor->value); @@ -653,10 +908,10 @@ __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config) WT_DECL_RET; WT_SESSION_IMPL *session; - session = (WT_SESSION_IMPL *)cursor->session; + CURSOR_API_CALL(cursor, session, reconfigure, NULL); /* Reconfiguration resets the cursor. */ - WT_RET(cursor->reset(cursor)); + WT_ERR(cursor->reset(cursor)); /* * append @@ -670,7 +925,7 @@ __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config) else F_CLR(cursor, WT_CURSTD_APPEND); } else - WT_RET_NOTFOUND_OK(ret); + WT_ERR_NOTFOUND_OK(ret); } /* @@ -683,9 +938,9 @@ __wt_cursor_reconfigure(WT_CURSOR *cursor, const char *config) else F_CLR(cursor, WT_CURSTD_OVERWRITE); } else - WT_RET_NOTFOUND_OK(ret); + WT_ERR_NOTFOUND_OK(ret); - return (0); +err: API_END_RET(session, ret); } /* @@ -782,6 +1037,7 @@ __wt_cursor_init(WT_CURSOR *cursor, cursor->remove = __wt_cursor_notsup; cursor->reserve = __wt_cursor_notsup; cursor->update = __wt_cursor_notsup; + F_CLR(cursor, WT_CURSTD_CACHEABLE); } /* @@ -805,6 +1061,7 @@ __wt_cursor_init(WT_CURSOR *cursor, */ WT_RET(__wt_curdump_create(cursor, owner, &cdump)); owner = cdump; + F_CLR(cursor, WT_CURSTD_CACHEABLE); } else cdump = NULL; -- cgit v1.2.1