summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDon Anderson <dda@mongodb.com>2016-06-16 20:20:21 -0400
committerMichael Cahill <michael.cahill@mongodb.com>2016-06-17 10:20:21 +1000
commitd34a6c4867533a57da0b546dc3d43f69411eef0d (patch)
treeeb4af491ec97be5a775354c7fa75aaa518029503
parentecdefb8f46870c209091f163cacc0808a74197d8 (diff)
downloadmongo-d34a6c4867533a57da0b546dc3d43f69411eef0d.tar.gz
WT-2605 Add C tests used in testing joins (#2787)
-rw-r--r--dist/s_string.ok1
-rw-r--r--test/csuite/Makefile.am6
-rw-r--r--test/csuite/wt2447_join_main_table/main.c188
-rw-r--r--test/csuite/wt2592_join_schema/main.c221
4 files changed, 416 insertions, 0 deletions
diff --git a/dist/s_string.ok b/dist/s_string.ok
index 48290ad1675..420006ccc6c 100644
--- a/dist/s_string.ok
+++ b/dist/s_string.ok
@@ -698,6 +698,7 @@ ibackup
icount
idx
ifdef's
+iiu
ikey
im
impl
diff --git a/test/csuite/Makefile.am b/test/csuite/Makefile.am
index 6058a05431b..f842bc1316f 100644
--- a/test/csuite/Makefile.am
+++ b/test/csuite/Makefile.am
@@ -13,6 +13,12 @@ noinst_PROGRAMS += test_wt2246_col_append
test_wt2535_insert_race_SOURCES = wt2535_insert_race/main.c
noinst_PROGRAMS += test_wt2535_insert_race
+test_wt2447_join_main_table_SOURCES = wt2447_join_main_table/main.c
+noinst_PROGRAMS += test_wt2447_join_main_table
+
+test_wt2592_join_schema_SOURCES = wt2592_join_schema/main.c
+noinst_PROGRAMS += test_wt2592_join_schema
+
# Run this during a "make check" smoke test.
TESTS = $(noinst_PROGRAMS)
LOG_COMPILER = $(TEST_WRAPPER)
diff --git a/test/csuite/wt2447_join_main_table/main.c b/test/csuite/wt2447_join_main_table/main.c
new file mode 100644
index 00000000000..a797a4223a2
--- /dev/null
+++ b/test/csuite/wt2447_join_main_table/main.c
@@ -0,0 +1,188 @@
+/*-
+ * 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"
+
+/*
+ * JIRA ticket reference: WT-2447
+ *
+ * Test case description: This test case is adapted from the submitted test
+ * program in the JIRA ticket. We create a database of 10,000 entries, with
+ * every key i having pair of values (i, i). Create indices on both values,
+ * and establish a join: table.v1 >= 5000 AND table.v2 < 5001. There's a
+ * Bloom filter on v2. We expect that although we iterate from 5000 to
+ * 10000, we'll only have accesses to the main table for key 5000, as
+ * 5001-10000 will generally not be in the Bloom filter. For key 5000,
+ * we technically have two accesses to the main table - one occurs when we
+ * see key 5000 is in the Bloom filter, and we need to do a full test, we
+ * make an access to the projection table:tablename(v2), that's just to get
+ * the value of v2, which we'll check by comparison to the cursor at 5001.
+ * That counts as a main table access, and when we see it is satisfied and
+ * return the complete set of values, we'll access the main table with the
+ * full projection (that's the second main table access).
+ *
+ * Failure mode: Before fixes of WT-2447, we saw lots of accesses to the main
+ * table.
+ */
+
+void (*custom_die)(void) = NULL;
+
+static int N_RECORDS = 10000;
+
+static int
+get_stat_total(WT_SESSION *session, WT_CURSOR *jcursor, const char *descmatch,
+ uint64_t *pval)
+{
+ WT_CURSOR *statcursor;
+ char *desc, *valstr;
+ uint64_t val;
+ int ret;
+ bool match;
+
+ match = false;
+ *pval = 0;
+ testutil_check(session->open_cursor(session, "statistics:join", jcursor,
+ NULL, &statcursor));
+
+ while ((ret = statcursor->next(statcursor)) == 0) {
+ statcursor->get_value(statcursor, &desc, &valstr, &val);
+
+ printf("statistics: %s: %s: %" PRIu64 "\n", desc, valstr, val);
+
+ if (strstr(desc, descmatch) != NULL) {
+ *pval += val;
+ match = true;
+ }
+ }
+ testutil_assert(ret == WT_NOTFOUND);
+ testutil_check(statcursor->close(statcursor));
+ testutil_assert(match);
+ return (0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ TEST_OPTS *opts, _opts;
+ WT_CURSOR *cursor1, *cursor2, *jcursor;
+ WT_ITEM d;
+ WT_SESSION *session;
+ uint64_t maincount;
+ int half, i, j;
+ const char *tablename;
+ char bloom_cfg[128], index1uri[256], index2uri[256], joinuri[256];
+
+ opts = &_opts;
+ memset(opts, 0, sizeof(*opts));
+ testutil_check(testutil_parse_opts(argc, argv, opts));
+ testutil_make_work_dir(opts->home);
+
+ testutil_assert((tablename = strchr(opts->uri, ':')) != 0);
+ tablename++;
+ snprintf(index1uri, sizeof(index1uri), "index:%s:index1", tablename);
+ snprintf(index2uri, sizeof(index2uri), "index:%s:index2", tablename);
+ snprintf(joinuri, sizeof(joinuri), "join:%s", opts->uri);
+
+ testutil_check(wiredtiger_open(opts->home, NULL,
+ "statistics=(all),create", &opts->conn));
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+
+ testutil_check(session->create(session, opts->uri,
+ "key_format=i,value_format=iiu,columns=(k,v1,v2,d)"));
+ testutil_check(session->create(session, index1uri, "columns=(v1)"));
+ testutil_check(session->create(session, index2uri, "columns=(v2)"));
+
+ testutil_check(session->open_cursor(session, opts->uri, NULL, NULL,
+ &cursor1));
+
+ d.size = 4100;
+ d.data = malloc(d.size);
+ memset((char *)d.data, 7, d.size);
+
+ for (i = 0; i < N_RECORDS; ++i)
+ {
+ cursor1->set_key(cursor1, i);
+ cursor1->set_value(cursor1, i, i, &d);
+ testutil_check(cursor1->insert(cursor1));
+ }
+
+ free((void*)d.data);
+
+ testutil_check(opts->conn->close(opts->conn, NULL));
+ testutil_check(wiredtiger_open(opts->home, NULL,
+ "statistics=(all),create,cache_size=1GB", &opts->conn));
+ testutil_check(opts->conn->open_session(opts->conn, NULL, NULL,
+ &session));
+
+ testutil_check(session->open_cursor(session, index1uri, NULL, NULL,
+ &cursor1));
+ testutil_check(session->open_cursor(session, index2uri, NULL, NULL,
+ &cursor2));
+
+ half = N_RECORDS / 2;
+ cursor1->set_key(cursor1, half);
+ testutil_check(cursor1->search(cursor1));
+
+ cursor2->set_key(cursor2, half + 1);
+ testutil_check(cursor2->search(cursor2));
+
+ sprintf(bloom_cfg, "compare=lt,strategy=bloom,count=%u", half);
+
+ testutil_check(session->open_cursor(session, joinuri, NULL, NULL,
+ &jcursor));
+ testutil_check(session->join(session, jcursor, cursor1, "compare=ge"));
+ testutil_check(session->join(session, jcursor, cursor2, bloom_cfg));
+
+ /* Expect one value returned */
+ testutil_assert(jcursor->next(jcursor) == 0);
+ i = 0;
+ jcursor->get_key(jcursor, &i);
+ testutil_assert(i == (int)half);
+ i = j = 0;
+ memset(&d, 0, sizeof(d));
+ jcursor->get_value(jcursor, &i, &j, &d);
+ testutil_assert(i == (int)half);
+ testutil_assert(j == (int)half);
+ testutil_assert(d.size == 4100);
+ for (i = 0; i < 4100; i++)
+ testutil_assert(((char *)d.data)[i] == 7);
+
+ testutil_assert(jcursor->next(jcursor) == WT_NOTFOUND);
+
+ /*
+ * Make sure there have been 2 accesses to the main table,
+ * explained in the discussion above.
+ */
+ get_stat_total(session, jcursor, "accesses to the main table",
+ &maincount);
+ testutil_assert(maincount == 2);
+
+ testutil_cleanup(opts);
+
+ return (0);
+}
diff --git a/test/csuite/wt2592_join_schema/main.c b/test/csuite/wt2592_join_schema/main.c
new file mode 100644
index 00000000000..7a735fd5d94
--- /dev/null
+++ b/test/csuite/wt2592_join_schema/main.c
@@ -0,0 +1,221 @@
+/*-
+ * 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"
+
+/*
+ * JIRA ticket reference: WT-2592
+ * Test case description: This is an adaptation of the join parts of
+ * ex_schema.c, but written as a test. Though we have join tests in the
+ * Python test suite, the Python API uses raw mode for cursors, so errors
+ * that are specific to non-raw mode are undetected in Python.
+ * Failure mode: The failure seen in WT-2592 was that no items were returned
+ * by a join.
+ */
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <wiredtiger.h>
+
+/* The C struct for the data we are storing in a WiredTiger table. */
+typedef struct {
+ char country[5];
+ uint16_t year;
+ uint64_t population;
+} POP_RECORD;
+
+static POP_RECORD pop_data[] = {
+ { "AU", 1900, 4000000 },
+ { "AU", 1950, 8267337 },
+ { "AU", 2000, 19053186 },
+ { "CAN", 1900, 5500000 },
+ { "CAN", 1950, 14011422 },
+ { "CAN", 2000, 31099561 },
+ { "UK", 1900, 369000000 },
+ { "UK", 1950, 50127000 },
+ { "UK", 2000, 59522468 },
+ { "USA", 1900, 76212168 },
+ { "USA", 1950, 150697361 },
+ { "USA", 2000, 301279593 },
+ { "", 0, 0 }
+};
+
+void (*custom_die)(void) = NULL;
+
+int
+main(int argc, char *argv[])
+{
+ POP_RECORD *p;
+ TEST_OPTS *opts, _opts;
+ WT_CURSOR *country_cursor, *country_cursor2, *cursor, *join_cursor,
+ *subjoin_cursor, *year_cursor;
+ WT_SESSION *session;
+ const char *basename, *country;
+ char countryuri[256], joinuri[256], yearuri[256];
+ uint64_t recno, population;
+ uint16_t year;
+ int count, ret;
+
+ opts = &_opts;
+ memset(opts, 0, sizeof(*opts));
+ testutil_check(testutil_parse_opts(argc, argv, opts));
+ testutil_make_work_dir(opts->home);
+
+ testutil_assert((basename = strchr(opts->uri, ':')) != 0);
+ basename++;
+ snprintf(countryuri, sizeof(countryuri), "index:%s:country", basename);
+ snprintf(yearuri, sizeof(yearuri), "index:%s:year", basename);
+ snprintf(joinuri, sizeof(joinuri), "join:%s", opts->uri);
+
+ testutil_check(wiredtiger_open(opts->home, NULL,
+ "create,cache_size=200M", &opts->conn));
+ testutil_check(
+ opts->conn->open_session(opts->conn, NULL, NULL, &session));
+ testutil_check(session->create(session, opts->uri,
+ "key_format=i,"
+ "value_format=5sHQ,"
+ "columns=(id,country,year,population)"));
+
+ /* Create an index with a simple key. */
+ testutil_check(session->create(session,
+ countryuri, "columns=(country)"));
+
+ /* Create an immutable index. */
+ testutil_check(session->create(session,
+ yearuri, "columns=(year),immutable"));
+
+ /* Insert the records into the table. */
+ testutil_check(session->open_cursor(
+ session, opts->uri, NULL, "append", &cursor));
+ count = 1;
+ for (p = pop_data; p->year != 0; p++) {
+ cursor->set_key(cursor, count);
+ cursor->set_value(cursor, p->country, p->year, p->population);
+ testutil_check(cursor->insert(cursor));
+ count++;
+ }
+ testutil_check(cursor->close(cursor));
+
+ /* Open cursors needed by the join. */
+ testutil_check(session->open_cursor(session,
+ joinuri, NULL, NULL, &join_cursor));
+ testutil_check(session->open_cursor(session,
+ countryuri, NULL, NULL, &country_cursor));
+ testutil_check(session->open_cursor(session,
+ yearuri, NULL, NULL, &year_cursor));
+
+ /* select values WHERE country == "AU" AND year > 1900 */
+ country_cursor->set_key(country_cursor, "AU\0\0\0");
+ testutil_check(country_cursor->search(country_cursor));
+ testutil_check(session->join(session, join_cursor, country_cursor,
+ "compare=eq,count=10"));
+ year_cursor->set_key(year_cursor, (uint16_t)1900);
+ testutil_check(year_cursor->search(year_cursor));
+ testutil_check(session->join(session, join_cursor, year_cursor,
+ "compare=gt,count=10,strategy=bloom"));
+
+ count = 0;
+ /* List the values that are joined */
+ while ((ret = join_cursor->next(join_cursor)) == 0) {
+ testutil_check(join_cursor->get_key(join_cursor, &recno));
+ testutil_check(join_cursor->get_value(join_cursor, &country,
+ &year, &population));
+ printf("ID %" PRIu64, recno);
+ printf(
+ ": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
+ country, year, population);
+ count++;
+ }
+ testutil_assert(ret == WT_NOTFOUND);
+ testutil_assert(count == 2);
+
+ testutil_check(join_cursor->close(join_cursor));
+ testutil_check(year_cursor->close(year_cursor));
+ testutil_check(country_cursor->close(country_cursor));
+
+ /* Open cursors needed by the join. */
+ testutil_check(session->open_cursor(session,
+ joinuri, NULL, NULL, &join_cursor));
+ testutil_check(session->open_cursor(session,
+ joinuri, NULL, NULL, &subjoin_cursor));
+ testutil_check(session->open_cursor(session,
+ countryuri, NULL, NULL, &country_cursor));
+ testutil_check(session->open_cursor(session,
+ countryuri, NULL, NULL, &country_cursor2));
+ testutil_check(session->open_cursor(session,
+ yearuri, NULL, NULL, &year_cursor));
+
+ /*
+ * select values WHERE (country == "AU" OR country == "UK")
+ * AND year > 1900
+ *
+ * First, set up the join representing the country clause.
+ */
+ country_cursor->set_key(country_cursor, "AU\0\0\0");
+ testutil_check(country_cursor->search(country_cursor));
+ testutil_check(session->join(session, subjoin_cursor, country_cursor,
+ "operation=or,compare=eq,count=10"));
+ country_cursor2->set_key(country_cursor2, "UK\0\0\0");
+ testutil_check(country_cursor2->search(country_cursor2));
+ testutil_check(session->join(session, subjoin_cursor, country_cursor2,
+ "operation=or,compare=eq,count=10"));
+
+ /* Join that to the top join, and add the year clause */
+ testutil_check(session->join(session, join_cursor, subjoin_cursor,
+ NULL));
+ year_cursor->set_key(year_cursor, (uint16_t)1900);
+ testutil_check(year_cursor->search(year_cursor));
+ testutil_check(session->join(session, join_cursor, year_cursor,
+ "compare=gt,count=10,strategy=bloom"));
+
+ count = 0;
+ /* List the values that are joined */
+ while ((ret = join_cursor->next(join_cursor)) == 0) {
+ testutil_check(join_cursor->get_key(join_cursor, &recno));
+ testutil_check(join_cursor->get_value(join_cursor, &country,
+ &year, &population));
+ printf("ID %" PRIu64, recno);
+ printf(
+ ": country %s, year %" PRIu16 ", population %" PRIu64 "\n",
+ country, year, population);
+ count++;
+ }
+ testutil_assert(ret == WT_NOTFOUND);
+ testutil_assert(count == 4);
+
+ testutil_check(join_cursor->close(join_cursor));
+ testutil_check(subjoin_cursor->close(subjoin_cursor));
+ testutil_check(country_cursor->close(country_cursor));
+ testutil_check(country_cursor2->close(country_cursor2));
+ testutil_check(year_cursor->close(year_cursor));
+ testutil_check(session->close(session, NULL));
+
+ testutil_cleanup(opts);
+ return (EXIT_SUCCESS);
+}