summaryrefslogtreecommitdiff
path: root/test/csuite
diff options
context:
space:
mode:
authorKeith Bostic <keith.bostic@mongodb.com>2017-03-13 20:53:11 -0400
committerAlex Gorrod <alexander.gorrod@mongodb.com>2017-03-14 11:53:11 +1100
commit28a883f7b4acd020a8d92a733cb9df415a6be482 (patch)
treee6bef4d3be146c9abbac30473826ab4765649833 /test/csuite
parentf72c78b74d42c9e89bc98ad56ba184536e8efcae (diff)
downloadmongo-28a883f7b4acd020a8d92a733cb9df415a6be482.tar.gz
WT-3211 WT_CURSOR.remove cannot always retain its position. (#3321)
Diffstat (limited to 'test/csuite')
-rw-r--r--test/csuite/Makefile.am7
-rw-r--r--test/csuite/scope/main.c288
2 files changed, 294 insertions, 1 deletions
diff --git a/test/csuite/Makefile.am b/test/csuite/Makefile.am
index e2b72532703..10ab890f2f5 100644
--- a/test/csuite/Makefile.am
+++ b/test/csuite/Makefile.am
@@ -4,8 +4,13 @@ LDADD = $(top_builddir)/test/utility/libtest_util.la \
$(top_builddir)/libwiredtiger.la
AM_LDFLAGS = -static
+noinst_PROGRAMS=
+
+test_scope_SOURCES = scope/main.c
+noinst_PROGRAMS += test_scope
+
test_wt1965_col_efficiency_SOURCES = wt1965_col_efficiency/main.c
-noinst_PROGRAMS = test_wt1965_col_efficiency
+noinst_PROGRAMS += test_wt1965_col_efficiency
test_wt2403_lsm_workload_SOURCES = wt2403_lsm_workload/main.c
noinst_PROGRAMS += test_wt2403_lsm_workload
diff --git a/test/csuite/scope/main.c b/test/csuite/scope/main.c
new file mode 100644
index 00000000000..15dabd97c40
--- /dev/null
+++ b/test/csuite/scope/main.c
@@ -0,0 +1,288 @@
+/*-
+ * Public Domain 2014-2016 MongoDB, Inc.
+ * Public Domain 2008-2014 WiredTiger, Inc.
+ *
+ * This is free and unencumbered software released into the public domain.
+ *
+ * Anyone is free to copy, modify, publish, use, compile, sell, or
+ * distribute this software, either in source code form or as a compiled
+ * binary, for any purpose, commercial or non-commercial, and by any
+ * means.
+ *
+ * In jurisdictions that recognize copyright laws, the author or authors
+ * of this software dedicate any and all copyright interest in the
+ * software to the public domain. We make this dedication for the benefit
+ * of the public at large and to the detriment of our heirs and
+ * successors. We intend this dedication to be an overt act of
+ * relinquishment in perpetuity of all present and future rights to this
+ * software under copyright law.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+#include "test_util.h"
+
+#define KEY "key"
+#define VALUE "value"
+
+static int ignore_errors;
+
+static int
+handle_error(WT_EVENT_HANDLER *handler,
+ WT_SESSION *session, int error, const char *message)
+{
+ (void)(handler);
+
+ /* Skip the error messages we're expecting to see. */
+ if (ignore_errors > 0 &&
+ (strstr(message, "requires key be set") != NULL ||
+ strstr(message, "requires value be set") != NULL)) {
+ --ignore_errors;
+ return (0);
+ }
+
+ (void)fprintf(stderr, "%s: %s\n",
+ message, session->strerror(session, error));
+ return (0);
+}
+
+static WT_EVENT_HANDLER event_handler = {
+ handle_error,
+ NULL,
+ NULL,
+ NULL
+};
+
+static void
+cursor_scope_ops(WT_SESSION *session, const char *uri)
+{
+ struct {
+ const char *op;
+ enum { INSERT, SEARCH, SEARCH_NEAR,
+ REMOVE, REMOVE_POS, RESERVE, UPDATE } func;
+ const char *config;
+ } *op, ops[] = {
+ /*
+ * The ops order is fixed and shouldn't change, that is, insert
+ * has to happen first so search, update and remove operations
+ * are possible, and remove has to be last.
+ */
+ { "insert", INSERT, NULL, },
+ { "search", SEARCH, NULL, },
+ { "search", SEARCH_NEAR, NULL, },
+#if 0
+ { "reserve", RESERVE, NULL, },
+#endif
+ { "update", UPDATE, NULL, },
+ { "remove", REMOVE, NULL, },
+ { "remove", REMOVE_POS, NULL, },
+ { NULL, INSERT, NULL }
+ };
+ WT_CURSOR *cursor;
+ uint64_t keyr;
+ const char *key, *value;
+ char keybuf[100], valuebuf[100];
+ int exact;
+ bool recno;
+
+ /* Reserve requires a running transaction. */
+ testutil_check(session->begin_transaction(session, NULL));
+
+ cursor = NULL;
+ for (op = ops; op->op != NULL; op++) {
+ key = value = NULL;
+
+ /* Open a cursor. */
+ if (cursor != NULL)
+ testutil_check(cursor->close(cursor));
+ testutil_check(session->open_cursor(
+ session, uri, NULL, op->config, &cursor));
+ recno = strcmp(cursor->key_format, "r") == 0;
+
+ /*
+ * Set up application buffers so we can detect overwrites
+ * or failure to copy application information into library
+ * memory.
+ */
+ if (recno)
+ cursor->set_key(cursor, (uint64_t)1);
+ else {
+ strcpy(keybuf, KEY);
+ cursor->set_key(cursor, keybuf);
+ }
+ strcpy(valuebuf, VALUE);
+ cursor->set_value(cursor, valuebuf);
+
+ /*
+ * The application must keep key and value memory valid until
+ * the next operation that positions the cursor, modifies the
+ * data, or resets or closes the cursor.
+ *
+ * Modifying either the key or value buffers is not permitted.
+ */
+ switch (op->func) {
+ case INSERT:
+ testutil_check(cursor->insert(cursor));
+ break;
+ case SEARCH:
+ testutil_check(cursor->search(cursor));
+ break;
+ case SEARCH_NEAR:
+ testutil_check(cursor->search_near(cursor, &exact));
+ break;
+ case REMOVE_POS:
+ /*
+ * Remove has two modes, one where the remove is based
+ * on a cursor position, the other where it's based on
+ * a set key. The results are different, so test them
+ * separately.
+ */
+ testutil_check(cursor->search(cursor));
+ /* FALLTHROUGH */
+ case REMOVE:
+ testutil_check(cursor->remove(cursor));
+ break;
+ case RESERVE:
+#if 0
+ testutil_check(cursor->reserve(cursor));
+#endif
+ break;
+ case UPDATE:
+ testutil_check(cursor->update(cursor));
+ break;
+ }
+
+ /*
+ * The cursor should no longer reference application memory,
+ * and application buffers can be safely overwritten.
+ */
+ memset(keybuf, 'K', sizeof(keybuf));
+ memset(valuebuf, 'V', sizeof(valuebuf));
+
+ /*
+ * Check that get_key/get_value behave as expected after the
+ * operation.
+ */
+ switch (op->func) {
+ case INSERT:
+ case REMOVE:
+ /*
+ * Insert and remove configured with a search key do
+ * not position the cursor and have no key or value.
+ *
+ * There should be two error messages, ignore them.
+ */
+ ignore_errors = 2;
+ if (recno)
+ testutil_assert(
+ cursor->get_key(cursor, &keyr) != 0);
+ else
+ testutil_assert(
+ cursor->get_key(cursor, &key) != 0);
+ testutil_assert(cursor->get_value(cursor, &value) != 0);
+ testutil_assert(ignore_errors == 0);
+ break;
+ case REMOVE_POS:
+ /*
+ * Remove configured with a cursor position has a key,
+ * but no value.
+ *
+ * There should be one error message, ignore it.
+ */
+ if (recno) {
+ testutil_assert(
+ cursor->get_key(cursor, &keyr) == 0);
+ testutil_assert(keyr == 1);
+ } else {
+ testutil_assert(
+ cursor->get_key(cursor, &key) == 0);
+ testutil_assert(key != keybuf);
+ testutil_assert(strcmp(key, KEY) == 0);
+ }
+ ignore_errors = 1;
+ testutil_assert(cursor->get_value(cursor, &value) != 0);
+ testutil_assert(ignore_errors == 0);
+ break;
+ case RESERVE:
+ case SEARCH:
+ case SEARCH_NEAR:
+ case UPDATE:
+ /*
+ * Reserve, search, search-near and update position the
+ * cursor and have both a key and value.
+ *
+ * Any key/value should not reference application
+ * memory.
+ */
+ if (recno) {
+ testutil_assert(
+ cursor->get_key(cursor, &keyr) == 0);
+ testutil_assert(keyr == 1);
+ } else {
+ testutil_assert(
+ cursor->get_key(cursor, &key) == 0);
+ testutil_assert(key != keybuf);
+ testutil_assert(strcmp(key, KEY) == 0);
+ }
+ testutil_assert(cursor->get_value(cursor, &value) == 0);
+ testutil_assert(value != valuebuf);
+ testutil_assert(strcmp(value, VALUE) == 0);
+ break;
+ }
+
+ /*
+ * We have more than one remove operation, add the key back
+ * in.
+ */
+ if (op->func == REMOVE || op->func == REMOVE_POS) {
+ if (recno)
+ cursor->set_key(cursor, (uint64_t)1);
+ else {
+ cursor->set_key(cursor, KEY);
+ }
+ cursor->set_value(cursor, VALUE);
+ testutil_check(cursor->insert(cursor));
+ }
+ }
+}
+
+static void
+run(WT_CONNECTION *conn, const char *uri, const char *config)
+{
+ WT_SESSION *session;
+
+ testutil_check(conn->open_session(conn, NULL, NULL, &session));
+ testutil_check(session->create(session, uri, config));
+ cursor_scope_ops(session, uri);
+ testutil_check(session->close(session, NULL));
+}
+
+int
+main(int argc, char *argv[])
+{
+ TEST_OPTS *opts, _opts;
+
+ opts = &_opts;
+ memset(opts, 0, sizeof(*opts));
+ testutil_check(testutil_parse_opts(argc, argv, opts));
+ testutil_make_work_dir(opts->home);
+
+ testutil_check(
+ wiredtiger_open(opts->home, &event_handler, "create", &opts->conn));
+
+ run(opts->conn, "file:file.SS", "key_format=S,value_format=S");
+ run(opts->conn, "file:file.rS", "key_format=r,value_format=S");
+ run(opts->conn, "lsm:lsm.SS", "key_format=S,value_format=S");
+ run(opts->conn, "lsm:lsm.rS", "key_format=r,value_format=S");
+ run(opts->conn, "table:table.SS", "key_format=S,value_format=S");
+ run(opts->conn, "table:table.rS", "key_format=r,value_format=S");
+
+ testutil_cleanup(opts);
+
+ return (EXIT_SUCCESS);
+}