From 4bf52367a745bd4d33d4727e2a8c574f2da9094d Mon Sep 17 00:00:00 2001 From: Ilya Verbin <iverbin@tarantool.org> Date: Fri, 13 May 2022 17:57:53 +0300 Subject: [PATCH] wal: allow spurious wakeups in wal_write It's possible to wakeup a fiber, which is waiting for WAL write completion, using Tarantool C API. This results in an error like: ``` main/118/lua F> Journal result code -1 can't be converted to an error ``` This patch introduces a flag, which is set when WAL write is finished, that allows fibers to yield until the flag is set. Closes #6506 NO_DOC=bugfix --- ...506-allow-spurious-wakeups-in-wal_write.md | 4 ++ src/box/journal.h | 8 ++++ src/box/wal.c | 7 +-- test/CMakeLists.txt | 1 + test/box-luatest/CMakeLists.txt | 1 + .../gh_6506_wakeup_writing_to_wal_fiber.c | 17 ++++++++ ..._6506_wakeup_writing_to_wal_fiber_test.lua | 43 +++++++++++++++++++ 7 files changed, 78 insertions(+), 3 deletions(-) create mode 100644 changelogs/unreleased/gh-6506-allow-spurious-wakeups-in-wal_write.md create mode 100644 test/box-luatest/CMakeLists.txt create mode 100644 test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber.c create mode 100644 test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber_test.lua diff --git a/changelogs/unreleased/gh-6506-allow-spurious-wakeups-in-wal_write.md b/changelogs/unreleased/gh-6506-allow-spurious-wakeups-in-wal_write.md new file mode 100644 index 0000000000..012556cb58 --- /dev/null +++ b/changelogs/unreleased/gh-6506-allow-spurious-wakeups-in-wal_write.md @@ -0,0 +1,4 @@ +## bugfix/core + +* Allowed spurious wakeup of a fiber, which is waiting for WAL write completion + (gh-6506). diff --git a/src/box/journal.h b/src/box/journal.h index 8572457791..7d3e525f8f 100644 --- a/src/box/journal.h +++ b/src/box/journal.h @@ -101,6 +101,11 @@ struct journal_entry { * Approximate size of this request when encoded. */ size_t approx_len; + /** + * Set to true when execution of a batch that contains this + * journal entry is completed. + */ + bool is_complete; /** * The number of rows in the request. */ @@ -128,6 +133,7 @@ journal_entry_create(struct journal_entry *entry, size_t n_rows, entry->n_rows = n_rows; entry->res = JOURNAL_ENTRY_ERR_UNKNOWN; entry->flags = 0; + entry->is_complete = false; } /** @@ -244,6 +250,8 @@ journal_async_complete(struct journal_entry *entry) { assert(entry->write_async_cb != NULL); + entry->is_complete = true; + journal_queue_on_complete(entry); entry->write_async_cb(entry); diff --git a/src/box/wal.c b/src/box/wal.c index 57742632e7..c50fc4f9b4 100644 --- a/src/box/wal.c +++ b/src/box/wal.c @@ -1309,9 +1309,10 @@ wal_write(struct journal *journal, struct journal_entry *entry) if (wal_write_async(journal, entry) != 0) return -1; - bool cancellable = fiber_set_cancellable(false); - fiber_yield(); - fiber_set_cancellable(cancellable); + assert(!entry->is_complete); + do { + fiber_yield(); + } while (!entry->is_complete); return 0; } diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 6e206e065e..1f8632adf3 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -60,6 +60,7 @@ add_subdirectory(app) add_subdirectory(app-tap) add_subdirectory(box) add_subdirectory(box-tap) +add_subdirectory(box-luatest) add_subdirectory(sql-tap) add_subdirectory(sql-luatest) if(ENABLE_FUZZER) diff --git a/test/box-luatest/CMakeLists.txt b/test/box-luatest/CMakeLists.txt new file mode 100644 index 0000000000..d654163f05 --- /dev/null +++ b/test/box-luatest/CMakeLists.txt @@ -0,0 +1 @@ +build_module(gh_6506_lib gh_6506_wakeup_writing_to_wal_fiber.c) diff --git a/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber.c b/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber.c new file mode 100644 index 0000000000..ef65040b86 --- /dev/null +++ b/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber.c @@ -0,0 +1,17 @@ +#include "module.h" + +static struct fiber *saved = NULL; + +int +save_fiber(box_function_ctx_t *ctx, const char *args, const char *args_end) +{ + saved = fiber_self(); + return 0; +} + +int +wakeup_saved(box_function_ctx_t *ctx, const char *args, const char *args_end) +{ + fiber_wakeup(saved); + return 0; +} diff --git a/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber_test.lua b/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber_test.lua new file mode 100644 index 0000000000..23e505bb5e --- /dev/null +++ b/test/box-luatest/gh_6506_wakeup_writing_to_wal_fiber_test.lua @@ -0,0 +1,43 @@ +local server = require('test.luatest_helpers.server') +local t = require('luatest') +local g = t.group() + +g.before_all = function() + g.server = server:new{alias = 'master'} + g.server:start() +end + +g.after_all = function() + g.server:drop() +end + +g.test_wakeup_writing_to_wal_fiber = function() + g.server:exec(function() + local t = require('luatest') + local fiber = require('fiber') + + local build_path = os.getenv("BUILDDIR") + package.cpath = build_path..'/test/box-luatest/?.so;'..build_path..'/test/box-luatest/?.dylib;'..package.cpath + local lib = box.lib.load('gh_6506_lib') + local save_fiber = lib:load('save_fiber') + local wakeup_saved = lib:load('wakeup_saved') + + local s = box.schema.create_space('test') + s:create_index('pk') + + local f = fiber.new(function() + save_fiber() + s:replace{1} + fiber.yield() + end) + f:set_joinable(true) + + -- Start fiber f + fiber.yield() + -- Wakeup f while it is writing to WAL + wakeup_saved() + -- Check that f did not crash + local st, _ = f:join() + t.assert(st) + end) +end -- GitLab