diff --git a/changelogs/unreleased/gh-10094-vy-index-drop-crash-fix.md b/changelogs/unreleased/gh-10094-vy-index-drop-crash-fix.md new file mode 100644 index 0000000000000000000000000000000000000000..f02db6f5fc393f90b730fdb9bed953855a2ebd85 --- /dev/null +++ b/changelogs/unreleased/gh-10094-vy-index-drop-crash-fix.md @@ -0,0 +1,4 @@ +## bugfix/vinyl + +* Fixed a bug when a DDL operation dropping a unique index could crash + if performed concurrently with DML requests (gh-10094). diff --git a/src/box/vinyl.c b/src/box/vinyl.c index 135b3e030debb9c7df7b00b0e5edc49b2604fb26..cd76d065aa2711dfd95211ca9197ec2a9e4a82c6 100644 --- a/src/box/vinyl.c +++ b/src/box/vinyl.c @@ -1410,6 +1410,11 @@ vy_get(struct vy_lsm *lsm, struct vy_tx *tx, * space.index.get({key}). */ assert(tx == NULL || tx->state == VINYL_TX_READY); + /* + * Make sure the LSM tree isn't deleted while we are + * reading from it. + */ + vy_lsm_ref(lsm); int rc; struct vy_entry partial, entry; @@ -1425,15 +1430,15 @@ vy_get(struct vy_lsm *lsm, struct vy_tx *tx, * Use point lookup for a full key. */ if (tx != NULL && vy_tx_track_point(tx, lsm, key) != 0) - return -1; + goto fail; if (vy_point_lookup(lsm, tx, rv, key, &partial) != 0) - return -1; + goto fail; if (lsm->index_id > 0 && partial.stmt != NULL) { rc = vy_get_by_secondary_tuple(lsm, tx, rv, partial, &entry); tuple_unref(partial.stmt); if (rc != 0) - return -1; + goto fail; } else { entry = partial; } @@ -1459,7 +1464,7 @@ vy_get(struct vy_lsm *lsm, struct vy_tx *tx, vy_read_iterator_cache_add(&itr, entry); vy_read_iterator_close(&itr); if (rc != 0) - return -1; + goto fail; out: *result = entry.stmt; @@ -1474,7 +1479,11 @@ vy_get(struct vy_lsm *lsm, struct vy_tx *tx, } if (*result != NULL) vy_stmt_counter_acct_tuple(&lsm->stat.get, *result); + vy_lsm_unref(lsm); return 0; +fail: + vy_lsm_unref(lsm); + return -1; } /** @@ -3856,14 +3865,8 @@ vinyl_index_get(struct index *index, const char *key, tx = &tx_autocommit; vy_tx_create(env->xm, tx); } - /* - * Make sure the LSM tree isn't deleted while we are - * reading from it. - */ - vy_lsm_ref(lsm); int rc = vy_get_by_raw_key(lsm, tx, vy_tx_read_view(tx), key, part_count, ret); - vy_lsm_unref(lsm); if (tx == &tx_autocommit) vy_tx_destroy(tx); if (rc != 0) diff --git a/src/box/vy_lsm.c b/src/box/vy_lsm.c index 51150e45fbd1f54c47c4b7460e4d4623483641c5..82631f2c32f8cd3a5a7e52699a2b5b26968e05a3 100644 --- a/src/box/vy_lsm.c +++ b/src/box/vy_lsm.c @@ -256,7 +256,7 @@ vy_range_tree_free_cb(vy_range_tree_t *t, struct vy_range *range, void *arg) (void)arg; struct vy_slice *slice; rlist_foreach_entry(slice, &range->slices, in_range) - vy_slice_wait_pinned(slice); + assert(slice->pin_count == 0); vy_range_delete(range); return NULL; } diff --git a/test/vinyl-luatest/gh_10094_index_drop_test.lua b/test/vinyl-luatest/gh_10094_index_drop_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..8e260148db453869772419890d5710d7c5a9636d --- /dev/null +++ b/test/vinyl-luatest/gh_10094_index_drop_test.lua @@ -0,0 +1,44 @@ +local server = require('luatest.server') +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() + cg.server:exec(function() + box.cfg{vinyl_cache = 0} + end) +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 + box.error.injection.set('ERRINJ_VY_READ_PAGE_DELAY', false) + end) +end) + +g.test_index_drop = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + local s = box.schema.create_space('test', {engine = 'vinyl'}) + s:create_index('pk') + s:create_index('sk', {parts = {{2, 'unsigned'}}}) + s:insert{1, 10} + box.snapshot() + box.error.injection.set('ERRINJ_VY_READ_PAGE_DELAY', true) + fiber.create(function() + s:insert{2, 10} + end) + s.index.sk:drop() + box.error.injection.set('ERRINJ_VY_READ_PAGE_DELAY', false) + t.assert_equals(s:select({}, {fullscan = true}), {{1, 10}}) + end) +end