summaryrefslogtreecommitdiff
path: root/src/third_party/wiredtiger/src/cursor/cur_std.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/third_party/wiredtiger/src/cursor/cur_std.c')
-rw-r--r--src/third_party/wiredtiger/src/cursor/cur_std.c269
1 files changed, 263 insertions, 6 deletions
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
@@ -21,6 +21,19 @@ __wt_cursor_noop(WT_CURSOR *cursor)
}
/*
+ * __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.
*/
@@ -135,6 +148,18 @@ __wt_cursor_reconfigure_notsup(WT_CURSOR *cursor, const char *config)
}
/*
+ * __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.
*/
@@ -557,6 +582,237 @@ err: cursor->saved_err = 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;