diff options
Diffstat (limited to 'src/third_party/wiredtiger/test/csuite/wt4803_cache_overflow_abort/main.c')
-rw-r--r-- | src/third_party/wiredtiger/test/csuite/wt4803_cache_overflow_abort/main.c | 239 |
1 files changed, 239 insertions, 0 deletions
diff --git a/src/third_party/wiredtiger/test/csuite/wt4803_cache_overflow_abort/main.c b/src/third_party/wiredtiger/test/csuite/wt4803_cache_overflow_abort/main.c new file mode 100644 index 00000000000..7d9b0baf132 --- /dev/null +++ b/src/third_party/wiredtiger/test/csuite/wt4803_cache_overflow_abort/main.c @@ -0,0 +1,239 @@ +/*- + * Public Domain 2014-2019 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" + +#include <signal.h> +#include <sys/wait.h> + +/* + * JIRA ticket reference: WT-4803 + * Test case description: This test is checking the functionality of the + * lookaside file_max configuration. When the size of the lookaside file exceeds + * this value, we expect to panic. + * Failure mode: If we receive a panic in the test cases we weren't expecting to + * and vice versa. + */ + +#define NUM_KEYS 2000 + +/* + * This is a global flag that should be set before running test_las_workload. + * It lets the child process know whether it should be expecting a panic or not + * so that it can adjust its exit code as needed. + */ +static bool expect_panic; + +static int +handle_message(WT_EVENT_HANDLER *handler, + WT_SESSION *session, int error, const char *message) +{ + WT_UNUSED(handler); + WT_UNUSED(session); + + (void)fprintf( + stderr, "%s: %s\n", message, session->strerror(session, error)); + + if (error == WT_PANIC && + strstr(message, "exceeds maximum size") != NULL) { + fprintf(stderr, "Got cache overflow error (expect_panic=%s)\n", + expect_panic ? "true" : "false"); + + /* + * If we're expecting a panic, exit with zero to indicate to the + * parent that this test was successful. + * + * If not, don't intercept. We'll naturally exit with non-zero + * if we're terminating due to panic. + */ + if (expect_panic) + exit(EXIT_SUCCESS); + } + + return (0); +} + +static WT_EVENT_HANDLER event_handler = { + handle_message, + NULL, + NULL, + NULL +}; + +static void +las_workload(TEST_OPTS *opts, const char *las_file_max) +{ + WT_CURSOR *cursor; + WT_SESSION *other_session, *session; + int i; + char buf[WT_MEGABYTE], open_config[128]; + + testutil_check(__wt_snprintf(open_config, sizeof(open_config), + "create,cache_size=50MB,cache_overflow=(file_max=%s)", + las_file_max)); + + testutil_check(wiredtiger_open( + opts->home, &event_handler, open_config, &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=S")); + testutil_check( + session->open_cursor(session, opts->uri, NULL, NULL, &cursor)); + + memset(buf, 0xA, WT_MEGABYTE); + buf[WT_MEGABYTE - 1] = '\0'; + + /* Populate the table. */ + for (i = 0; i < NUM_KEYS; ++i) { + cursor->set_key(cursor, i); + cursor->set_value(cursor, buf); + testutil_check(cursor->insert(cursor)); + } + + /* + * Open a snapshot isolation transaction in another session. This forces + * the cache to retain all previous values. Then update all keys with a + * new value in the original session while keeping that snapshot + * transaction open. With the large value buffer, small cache and lots + * of keys, this will force a lot of lookaside usage. + * + * When the file_max setting is small, the maximum size should easily be + * reached and we should panic. When the maximum size is large or not + * set, then we should succeed. + */ + testutil_check( + opts->conn->open_session(opts->conn, NULL, NULL, &other_session)); + testutil_check(other_session->begin_transaction( + other_session, "isolation=snapshot")); + + memset(buf, 0xB, WT_MEGABYTE); + buf[WT_MEGABYTE - 1] = '\0'; + + for (i = 0; i < NUM_KEYS; ++i) { + cursor->set_key(cursor, i); + cursor->set_value(cursor, buf); + testutil_check(cursor->update(cursor)); + } + + /* + * Cleanup. + * We do not get here when the file_max size is small because we will + * have already hit the maximum and exited. This code only executes on + * the successful path. + */ + testutil_check( + other_session->rollback_transaction(other_session, NULL)); + testutil_check(other_session->close(other_session, NULL)); + + testutil_check(cursor->close(cursor)); + testutil_check(session->close(session, NULL)); +} + +static int +test_las_workload(TEST_OPTS *opts, const char *las_file_max) +{ + pid_t pid; + int status; + + /* + * We're going to run this workload for different configurations of + * file_max. So clean out the work directory each time. + */ + testutil_make_work_dir(opts->home); + + /* + * Since it's possible that the workload will panic and abort, we will + * fork the process and execute the workload in the child process. + * + * This way, we can safely check the exit code of the child process and + * confirm that it is what we expected. + */ + pid = fork(); + if (pid < 0) + /* Failed fork. */ + testutil_die(errno, "fork"); + else if (pid == 0) { + /* Child process from here. */ + las_workload(opts, las_file_max); + + /* + * If we're expecting a panic during the workload, we shouldn't + * get to this point. Exit with non-zero to indicate to parent + * that we should fail this test. + */ + fprintf(stderr, + "Successfully completed workload (expect_panic=%s)\n", + expect_panic ? "true" : "false"); + + if (expect_panic) + exit(EXIT_FAILURE); + else + exit(EXIT_SUCCESS); + } + + /* Parent process from here. */ + if (waitpid(pid, &status, 0) == -1) + testutil_die(errno, "waitpid"); + + return (status); +} + +int +main(int argc, char **argv) +{ + TEST_OPTS opts; + + memset(&opts, 0x0, sizeof(opts)); + testutil_check(testutil_parse_opts(argc, argv, &opts)); + + /* + * The lookaside is unbounded. + * We don't expect any failure since we can use as much as needed. + */ + expect_panic = false; + testutil_check(test_las_workload(&opts, "0")); + + /* + * The lookaside is limited to 5GB. + * This is more than enough for this workload so we don't expect any + * failure. + */ + expect_panic = false; + testutil_check(test_las_workload(&opts, "5GB")); + + /* + * The lookaside is limited to 100MB. + * This is insufficient for this workload so we're expecting a failure. + */ + expect_panic = true; + testutil_check(test_las_workload(&opts, "100MB")); + + testutil_cleanup(&opts); + + return (0); +} |