diff --git a/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md b/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md index bf58a263f32d650d3d89f012262ac292d2660c52..151f366d769619832f993aa3cf1465a0961f181c 100644 --- a/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md +++ b/changelogs/unreleased/gh-10233-vy-snapshot-hang-fix.md @@ -1,4 +1,4 @@ ## bugfix/vinyl -* Fixed a bug when `box.snapshot` hanged if executed concurrently with creation - of a new index (gh-10233). +* Fixed a bug when a race between `box.snapshot` and the creation of a new + index could lead to a fiber hang (gh-10233, gh-10267). diff --git a/src/box/vy_scheduler.c b/src/box/vy_scheduler.c index 88a29a81eba79e1c6499f56899cdef1730c1bc22..f893e808c7f3714b14440fb0348e6e2a3890d40c 100644 --- a/src/box/vy_scheduler.c +++ b/src/box/vy_scheduler.c @@ -792,6 +792,8 @@ vy_scheduler_end_checkpoint(struct vy_scheduler *scheduler) return; scheduler->checkpoint_in_progress = false; + fiber_cond_broadcast(&scheduler->dump_cond); + if (scheduler->dump_pending) { /* * Dump was triggered while checkpoint was 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 index 3a9ddec7434560580dd6a892a22d209f1c8cb415..7e3e56af49281626475d7fe9c0a82b89d8dc8879 100644 --- a/test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua +++ b/test/vinyl-luatest/gh_10233_index_build_vs_snapshot_test.lua @@ -4,6 +4,7 @@ local t = require('luatest') local g = t.group() g.before_all(function(cg) + t.tarantool.skip_if_not_debug() cg.server = server:new() cg.server:start() end) @@ -17,24 +18,53 @@ g.after_each(function(cg) if box.space.test ~= nil then box.space.test:drop() end + box.error.injection.set('ERRINJ_VY_DUMP_DELAY', false) + box.error.injection.set('ERRINJ_SNAP_COMMIT_DELAY', false) end) end) -g.test_index_build_vs_snapshot = function(cg) +g.test_case_1 = 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}) + box.error.injection.set('ERRINJ_VY_DUMP_DELAY', true) local f1 = fiber.new(function() s:create_index('sk', {parts = {2, 'unsigned'}}) end) f1:set_joinable(true) + fiber.sleep(0.1) local f2 = fiber.new(function() box.snapshot() end) f2:set_joinable(true) fiber.sleep(0.1) + box.error.injection.set('ERRINJ_VY_DUMP_DELAY', false) + local timeout = 5 + t.assert_equals({f1:join(timeout)}, {true}) + t.assert_equals({f2:join(timeout)}, {true}) + end) +end + +g.test_case_2 = 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}) + box.error.injection.set('ERRINJ_SNAP_COMMIT_DELAY', true) + local f1 = fiber.new(function() + box.snapshot() + end) + f1:set_joinable(true) + fiber.sleep(0.1) + local f2 = fiber.new(function() + s:create_index('sk', {parts = {2, 'unsigned'}}) + end) + f2:set_joinable(true) + fiber.sleep(0.1) + box.error.injection.set('ERRINJ_SNAP_COMMIT_DELAY', false) local timeout = 5 t.assert_equals({f1:join(timeout)}, {true}) t.assert_equals({f2:join(timeout)}, {true})