diff --git a/changelogs/unreleased/gh-6778-vinyl-recovery-crash.md b/changelogs/unreleased/gh-6778-vinyl-recovery-crash.md new file mode 100644 index 0000000000000000000000000000000000000000..cb336b1ca6e745d091fb44c94a2715b33f21b248 --- /dev/null +++ b/changelogs/unreleased/gh-6778-vinyl-recovery-crash.md @@ -0,0 +1,4 @@ +## bugfix/vinyl + +* Fixed crash during recovery of a secondary index in case the primary index + contains incompatible phantom tuples (gh-6778). diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 4b90ee57fae10f2097acead445a421eb1f929694..5d04a0b1e9c566feee464f701a1ba59dea19e798 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -4101,6 +4101,7 @@ vy_build_recover_stmt(struct vy_lsm *lsm, struct vy_lsm *pk, static int vy_build_recover_mem(struct vy_lsm *lsm, struct vy_lsm *pk, struct vy_mem *mem) { + assert(lsm->dump_lsn >= 0); /* * Recover statements starting from the oldest one. * Key order doesn't matter so we simply iterate over @@ -4131,6 +4132,18 @@ vy_build_recover_mem(struct vy_lsm *lsm, struct vy_lsm *pk, struct vy_mem *mem) static int vy_build_recover(struct vy_env *env, struct vy_lsm *lsm, struct vy_lsm *pk) { + if (lsm->dump_lsn < 0) { + /* + * The new index was never dumped, because the space's empty + * so there's nothing to do. + * + * Note: the primary index may still have some cancelling + * each other statements; we shouldn't try to apply them, + * because they may be incompatible with the new index. + */ + return 0; + } + int rc = 0; struct vy_mem *mem; size_t mem_used_before, mem_used_after; diff --git a/test/vinyl-luatest/gh_6778_recovery_crash_test.lua b/test/vinyl-luatest/gh_6778_recovery_crash_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..328700b25bcfab5a0e1dc7b51c46f1d501ab814b --- /dev/null +++ b/test/vinyl-luatest/gh_6778_recovery_crash_test.lua @@ -0,0 +1,33 @@ +local common = require('test.vinyl-luatest.common') +local server = require('test.luatest_helpers.server') +local t = require('luatest') +local g = t.group() + +g.before_test('test_recovery_crash', function() + g.server = server:new({ + alias = 'master', + box_cfg = common.default_box_cfg(), + }) + g.server:start() +end) + +g.after_test('test_recovery_crash', function() + g.server:drop() +end) + +g.test_recovery_crash = function() + g.server:exec(function() + local s = box.schema.create_space('test', {engine = 'vinyl'}) + s:create_index('pk') + s:replace{0} + s:delete{0} + s:create_index('sk', {parts = {{2, 'unsigned'}}}) + end) + g.server:restart() + g.server:exec(function() + local t = require('luatest') + local s = box.space.test + t.assert_equals(s.index.pk:select(), {}) + t.assert_equals(s.index.sk:select(), {}) + end) +end