From 59e4cf614baadaf9131f3bda9dd66e050277d7aa Mon Sep 17 00:00:00 2001 From: Andrey Saranchin <Andrey22102001@gmail.com> Date: Wed, 28 Aug 2024 12:47:34 +0300 Subject: [PATCH] memtx: do not rollback prepared statements on DDL Currently, when DDL is being committed, we delete all the stories and rollback prepared delete statements. The problem is such rollback is likely to fail because of assertion. When transaction is rolled back, all the statements are rolled back in reversed order, but when rollback happened because of DDL, order is not specified and some invariants are violated. Let's simply unlink delete statement instead of rollback. Rollback does two things: unlink delete statement and abort readers (including gaps) of prepared stories. The commit actually drops the second part - it's safe because after the previous commits we delete stories right after aborting all concurrent transactions so there is no need to abort anything anymore. Part of #10146 Closes #10474 NO_CHANGELOG=later NO_DOC=bugfix (cherry picked from commit 6a11224c85c1be28e7d1570cd4ba01efc033c34f) --- src/box/memtx_tx.c | 2 +- test/box-luatest/mvcc_ddl_test.lua | 56 ++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) diff --git a/src/box/memtx_tx.c b/src/box/memtx_tx.c index 4c0980598c..97b0ee2088 100644 --- a/src/box/memtx_tx.c +++ b/src/box/memtx_tx.c @@ -2353,7 +2353,7 @@ memtx_tx_history_remove_added_story(struct txn_stmt *stmt) static void memtx_tx_history_remove_deleted_story(struct txn_stmt *stmt) { - memtx_tx_history_rollback_deleted_story(stmt); + memtx_tx_story_unlink_deleted_by(stmt->del_story, stmt); } /* diff --git a/test/box-luatest/mvcc_ddl_test.lua b/test/box-luatest/mvcc_ddl_test.lua index 0c5c8f7afd..0279172c55 100644 --- a/test/box-luatest/mvcc_ddl_test.lua +++ b/test/box-luatest/mvcc_ddl_test.lua @@ -416,3 +416,59 @@ g.test_rollback_prepared_dml_and_ddl = function(cg) t.assert_equals(s:select{}, saved_select) end) end + +-- The test checks if DDL correctly handles stories of prepared statements +-- on DDL +-- gh-10474, case 2 +g.test_ddl_handles_prepared = function(cg) + t.tarantool.skip_if_not_debug() + cg.server:exec(function() + local fiber = require('fiber') + box.schema.space.create('test') + box.space.test:create_index('pk') + + box.space.test:replace{1} + + local teardown = false + + local function writer(do_not_commit) + box.begin{txn_isolation = 'read-committed'} + box.space.test:replace{1} + if do_not_commit then + while not teardown do + fiber.sleep(0) + end + box.rollback() + else + box.commit() + end + end + + box.error.injection.set('ERRINJ_WAL_DELAY', true) + -- Start preparing writers and then update the space + local fibers = {} + for _ = 1, 5 do + local f = fiber.create(writer) + f:set_joinable(true) + table.insert(fibers, f) + f = fiber.create(writer, true) + f:set_joinable(true) + table.insert(fibers, f) + end + local f = fiber.create(function() + box.space.test:format{{name = 'field1', type = 'scalar'}} + end) + f:set_joinable(true) + + box.error.injection.set('ERRINJ_WAL_DELAY', false) + + -- Wait for DDL and DML are over and successful + local ok = f:join() + t.assert(ok) + teardown = true + for _, f in pairs(fibers) do + ok = f:join() + t.assert(ok) + end + end) +end -- GitLab