Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
limbo: fix commit/rollback failures with triggers
Currently some transactions on synchronous space fail to complete with the `ER_CURSOR_NO_TRANSACTION` error, when on_rollback/on_commit triggers are set. This is caused due to the fact, that some rollback/commit triggers require in_txn fiber variable to be set but it's not done when a transaction is completed from the limbo. Callbacks, which are used to work with iterators (`lbox_txn_pairs` and `lbox_txn_iterator_next`), acquire tnx statements from the current transactions, but they cannot do that, when this transaction is not assigned to the current fiber, so `ER_CURSOR_NO_TRANSACTION` is thrown. Let's assign in_txn variable when we complete transaction from the limbo. Moreover, let's add assertions, which check whether in_txn() is correct, in order to be sure, that `txn_complete_success/fail` always run with in_txn set. Closes #8505 NO_DOC=bugfix (cherry picked from commit 6fadc8a)
- Loading branch information
1 parent
1527193
commit a7a51ae
Showing
4 changed files
with
106 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
## bugfix/core | ||
|
||
* Fixed a bug causing the `ER_CURSOR_NO_TRANSACTION` failure for transactions | ||
on synchronous spaces when the `on_commit/on_rollback` triggers are set | ||
(gh-8505). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
80 changes: 80 additions & 0 deletions
80
test/replication-luatest/gh_8505_synchro_triggers_test.lua
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
local t = require('luatest') | ||
local replica_set = require('luatest.replica_set') | ||
local server = require('luatest.server') | ||
local proxy = require('luatest.replica_proxy') | ||
|
||
local g = t.group('gh-8505-synchro-triggers') | ||
|
||
g.before_all(function(g) | ||
g.replica_set = replica_set:new({}) | ||
local rs_id = g.replica_set.id | ||
g.box_cfg = { | ||
replication_timeout = 0.01, | ||
election_fencing_mode = 'off', | ||
replication = { | ||
server.build_listen_uri('server1', rs_id), | ||
server.build_listen_uri('server2', rs_id), | ||
}, | ||
} | ||
|
||
g.box_cfg.election_mode = 'candidate' | ||
g.server1 = g.replica_set:build_and_add_server{ | ||
alias = 'server1', | ||
box_cfg = g.box_cfg, | ||
} | ||
|
||
g.proxy1 = proxy:new{ | ||
client_socket_path = server.build_listen_uri('server1_proxy'), | ||
server_socket_path = server.build_listen_uri('server1', rs_id), | ||
} | ||
t.assert(g.proxy1:start{force = true}, 'Proxy from 2 to 1 started') | ||
g.box_cfg.replication[1] = server.build_listen_uri('server1_proxy') | ||
g.box_cfg.election_mode = 'voter' | ||
g.server2 = g.replica_set:build_and_add_server{ | ||
alias = 'server2', | ||
box_cfg = g.box_cfg, | ||
} | ||
|
||
g.replica_set:start() | ||
g.server1:wait_for_election_leader() | ||
g.server1:exec(function() | ||
box.schema.create_space('test', {is_sync = true}):create_index('pk') | ||
end) | ||
g.server2:wait_for_vclock_of(g.server1) | ||
end) | ||
|
||
g.after_all(function(g) | ||
g.replica_set:drop() | ||
end) | ||
|
||
g.test_on_commit_trigger = function(g) | ||
g.server1:exec(function() | ||
box.begin() | ||
box.on_commit(function(iter) iter() end) | ||
box.space.test:upsert({1}, {{'=', 1, 1}}) | ||
box.commit() | ||
end) | ||
end | ||
|
||
g.test_on_rollback_trigger = function(g) | ||
-- Force ACK gathering to fail and cause rollback. It's not enough | ||
-- to set a small timeout, as a transaction can be committed anyway: | ||
-- fibers don't yield so often, compared to such a tiny timeout, ACKs | ||
-- can be processed before the transaction's rollback happens due to | ||
-- a timeout error. So, let's break connection with proxy. | ||
g.server1:update_box_cfg({ replication_synchro_timeout = 1e-9 }) | ||
g.server1:wait_for_election_leader() | ||
g.proxy1:pause() | ||
|
||
g.server1:exec(function() | ||
box.begin() | ||
box.on_rollback(function(iter) iter() end) | ||
box.space.test:upsert({1}, {{'=', 1, 1}}) | ||
local _, err = pcall(box.commit) | ||
t.assert_equals(err.code, box.error.SYNC_QUORUM_TIMEOUT) | ||
end) | ||
|
||
g.proxy1:resume() | ||
g.server1:update_box_cfg({ replication_synchro_timeout = 5 }) | ||
g.server1:wait_for_election_leader() | ||
end |