From 04347ee7567402c4460468c7f80540ff532c2e45 Mon Sep 17 00:00:00 2001 From: Vladimir Davydov <vdavydov@tarantool.org> Date: Thu, 11 Jul 2024 19:14:56 +0300 Subject: [PATCH] vinyl: use broadcast instead of signal to notify about dump completion There may be more than one fiber waiting on `vy_scheduler::dump_cond`: ``` box.snapshot vinyl_engine_wait_checkpoint vy_scheduler_wait_checkpoint space.create_index vinyl_space_build_index vy_scheduler_dump ``` To avoid hang, we should use `fiber_cond_broadcast`. Closes #10233 NO_DOC=bug fix (cherry picked from commit 30547157db74a2869b7da4247e8c97c9ec39a6a9) --- .../gh-10233-vy-snapshot-hang-fix.md | 4 ++ src/box/vy_scheduler.c | 4 +- .../gh_10233_index_build_vs_snapshot_test.lua | 42 +++++++++++++++++++ 3 files changed, 48 insertions(+), 2 deletions(-) create mode 100644 changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md create mode 100644 test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua diff --git a/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md b/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md new file mode 100644 index 0000000000..bf58a263f3 --- /dev/null +++ b/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md @@ -0,0 +1,4 @@ +## bugfix/vinyl + +* Fixed a bug when `box.snapshot` hanged if executed concurrently with creation + of a new index (gh-10233). diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c index ea9b438bdb..29e9c19245 100644 --- a/src/box/vy_scheduler.c +++ b/src/box/vy_scheduler.c @@ -670,7 +670,7 @@ vy_scheduler_complete_dump(struct vy_scheduler *scheduler) scheduler->stat.dump_count++; scheduler->dump_complete_cb(scheduler, min_generation - 1, dump_duration); - fiber_cond_signal(&scheduler->dump_cond); + fiber_cond_broadcast(&scheduler->dump_cond); } int @@ -2068,7 +2068,7 @@ vy_scheduler_f(va_list va) continue; error: /* Abort pending checkpoint. */ - fiber_cond_signal(&scheduler->dump_cond); + fiber_cond_broadcast(&scheduler->dump_cond); /* * A task can fail either due to lack of memory or IO * error. In either case it is pointless to schedule diff --git a/test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua b/test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua new file mode 100644 index 0000000000..3a9ddec743 --- /dev/null +++ b/test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua @@ -0,0 +1,42 @@ +local server = require('luatest.server') +local t = require('luatest') + +local g = t.group() + +g.before_all(function(cg) + cg.server = server:new() + cg.server:start() +end) + +g.after_all(function(cg) + cg.server:drop() +end) + +g.after_each(function(cg) + cg.server:exec(function() + if box.space.test ~= nil then + box.space.test:drop() + end + end) +end) + +g.test_index_build_vs_snapshot = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + local s = box.schema.space.create('test', {engine = 'vinyl'}) + s:create_index('pk') + s:insert({1, 1}) + local f1 = fiber.new(function() + s:create_index('sk', {parts = {2, 'unsigned'}}) + end) + f1:set_joinable(true) + local f2 = fiber.new(function() + box.snapshot() + end) + f2:set_joinable(true) + fiber.sleep(0.1) + local timeout = 5 + t.assert_equals({f1:join(timeout)}, {true}) + t.assert_equals({f2:join(timeout)}, {true}) + end) +end -- GitLab