diff --git a/changelogs/unreleased/gh-10262-inconsistency-between-caches-and-data.md b/changelogs/unreleased/gh-10262-inconsistency-between-caches-and-data.md new file mode 100644 index 0000000000000000000000000000000000000000..b719d5a5b727f7e5863a3e7b94bea284af93095d --- /dev/null +++ b/changelogs/unreleased/gh-10262-inconsistency-between-caches-and-data.md @@ -0,0 +1,4 @@ +## bugfix/box + +* Fixed an inconsistency between internal caches and system spaces with + MVCC enabled that could lead to unexplainable errors (gh-10262). diff --git a/src/box/memtx_tx.c b/src/box/memtx_tx.c index 6e3f8bd0e15319656319e94c45737b682bb82289..bc436c19eacca833f8b9e16acd7bc28393ca7727 100644 --- a/src/box/memtx_tx.c +++ b/src/box/memtx_tx.c @@ -2657,8 +2657,10 @@ memtx_tx_tuple_clarify_impl(struct txn *txn, struct space *space, * Detect whether the transaction can see prepared, but unconfirmed commits. */ static bool -detect_whether_prepared_ok(struct txn *txn) +detect_whether_prepared_ok(struct txn *txn, struct space *space) { + if (space_is_system(space)) + return true; if (txn == NULL) return false; else if (txn->isolation == TXN_ISOLATION_READ_COMMITTED) @@ -2690,7 +2692,7 @@ memtx_tx_tuple_clarify_slow(struct txn *txn, struct space *space, memtx_tx_track_read(txn, space, tuple); return tuple; } - bool is_prepared_ok = detect_whether_prepared_ok(txn); + bool is_prepared_ok = detect_whether_prepared_ok(txn, space); struct tuple *res = memtx_tx_tuple_clarify_impl(txn, space, tuple, index, mk_index, is_prepared_ok); @@ -2728,7 +2730,7 @@ memtx_tx_index_invisible_count_slow(struct txn *txn, } struct tuple *visible = NULL; - bool is_prepared_ok = detect_whether_prepared_ok(txn); + bool is_prepared_ok = detect_whether_prepared_ok(txn, space); bool unused; memtx_tx_story_find_visible_tuple(story, txn, index->dense_id, is_prepared_ok, &visible, diff --git a/test/box-luatest/gh_10262_inconsistency_between_caches_and_data_test.lua b/test/box-luatest/gh_10262_inconsistency_between_caches_and_data_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..c80edd2859b8ccd44936dbc82c1c719ed49283fd --- /dev/null +++ b/test/box-luatest/gh_10262_inconsistency_between_caches_and_data_test.lua @@ -0,0 +1,80 @@ +local t = require('luatest') +local server = require('luatest.server') + +local g = t.group() + +g.before_each(function(cg) + t.tarantool.skip_if_not_debug() + cg.server = server:new{box_cfg = {memtx_use_mvcc_engine = true}} + cg.server:start() +end) + +g.after_each(function(cg) + cg.server:drop() +end) + +g.test_reproducer_from_issue = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + local space = box.schema.space.create('test') + box.error.injection.set('ERRINJ_WAL_WRITE', true) + box.error.injection.set('ERRINJ_BUILD_INDEX_TIMEOUT', 0.01) + local index + fiber.create(function() + box.begin() + index = space:create_index('pk') + for i = 1, 100 do + space:replace({i, 2}) + end + box.commit() + end) + local function alter_index() + index:alter({parts = {{1, 'unsigned'}, {2, 'unsigned'}}}) + end + t.assert_error_msg_content_equals( + "Can't modify space '512': the space was concurrently modified", + alter_index) + end) +end + +g.test_space_cache_consistent_with_data = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + local space = box.schema.space.create('test') + box.error.injection.set('ERRINJ_WAL_DELAY', true) + fiber.create(function() + space:create_index('pk') + end) + t.assert_not_equals(space.index[0], nil) + t.assert_not_equals(box.space._index:get{space.id, 0}, nil) + box.error.injection.set('ERRINJ_WAL_DELAY', false) + end) +end + +g.test_func_cache_consistent_with_data = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + box.error.injection.set('ERRINJ_WAL_DELAY', true) + fiber.create(function() + box.schema.func.create('test', { + language = 'Lua', body = 'function() return 42 end'}) + end) + t.assert_not_equals(box.func.test, nil) + t.assert_not_equals(box.space._func.index[2]:get('test'), nil) + box.error.injection.set('ERRINJ_WAL_DELAY', false) + end) +end + +-- Reproducer from ghs-131 +g.test_crash_on_caches_inconsistency = function(cg) + cg.server:exec(function() + local fiber = require('fiber') + box.schema.space.create('test') + fiber.create(function() + box.space.test:drop() + end) + box.begin({txn_isolation = 'read-confirmed'}) + box.space._space:delete(512) + box.commit() + end) +end