diff options
author | Don Anderson <dda@mongodb.com> | 2016-06-16 20:20:21 -0400 |
---|---|---|
committer | Michael Cahill <michael.cahill@mongodb.com> | 2016-06-17 10:20:21 +1000 |
commit | d34a6c4867533a57da0b546dc3d43f69411eef0d (patch) | |
tree | eb4af491ec97be5a775354c7fa75aaa518029503 | |
parent | ecdefb8f46870c209091f163cacc0808a74197d8 (diff) | |
download | mongo-d34a6c4867533a57da0b546dc3d43f69411eef0d.tar.gz |
WT-2605 Add C tests used in testing joins (#2787)
-rw-r--r-- | dist/s_string.ok | 1 | ||||
-rw-r--r-- | test/csuite/Makefile.am | 6 | ||||
-rw-r--r-- | test/csuite/wt2447_join_main_table/main.c | 188 | ||||
-rw-r--r-- | test/csuite/wt2592_join_schema/main.c | 221 |
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); +} |