diff --git a/changelogs/unreleased/gh-7286-false-positive-split-brain.md b/changelogs/unreleased/gh-7286-false-positive-split-brain.md new file mode 100644 index 0000000000000000000000000000000000000000..54f2049fb3f3ccd527ecc769e289687a11a0184d --- /dev/null +++ b/changelogs/unreleased/gh-7286-false-positive-split-brain.md @@ -0,0 +1,3 @@ +## bugfix/replication + +* Fixed a false positive split-brain error after `box.ctl.demote()` (gh-7286). diff --git a/src/box/applier.cc b/src/box/applier.cc index 3d2bae24652d24e3d8cdfd028cc339bfca72cc12..c842e44a8482b1e8c1fa44cfb06b5783f41b0cea 100644 --- a/src/box/applier.cc +++ b/src/box/applier.cc @@ -1205,14 +1205,15 @@ applier_synchro_filter_tx(struct stailq *rows) * This means the only filtered out transactions are synchronous ones or * the ones depending on them. * - * Any asynchronous transaction from an obsolete term is a marker of - * split-brain by itself: consider it a synchronous transaction, which - * is committed with quorum 1. + * Any asynchronous transaction from an obsolete term when limbo is + * claimed by someone is a marker of split-brain by itself: consider it + * a synchronous transaction, which is committed with quorum 1. */ struct xrow_header *last_row = &stailq_last_entry(rows, struct applier_tx_row, next)->row; if (!last_row->wait_sync) { - if (iproto_type_is_dml(last_row->type)) { + if (iproto_type_is_dml(last_row->type) && + txn_limbo.owner_id != REPLICA_ID_NIL) { tnt_raise(ClientError, ER_SPLIT_BRAIN, "got an async transaction from an old term"); } diff --git a/test/replication-luatest/gh_7286_split_brain_false_positive_test.lua b/test/replication-luatest/gh_7286_split_brain_false_positive_test.lua new file mode 100644 index 0000000000000000000000000000000000000000..5a8b96aa6f58b387506350c5f9c688df5c4874d0 --- /dev/null +++ b/test/replication-luatest/gh_7286_split_brain_false_positive_test.lua @@ -0,0 +1,47 @@ +local t = require('luatest') +local cluster = require('test.luatest_helpers.cluster') +local server = require('test.luatest_helpers.server') + +local g = t.group('gh-7286') + +-- gh-7286: false positive ER_SPLIT_BRAIN error after box.ctl.demote() with +-- disabled elections. +g.before_all(function(cg) + cg.cluster = cluster:new{} + + cg.box_cfg = { + -- Just in case it's turned on by default sometime. + election_mode = 'off', + replication_timeout = 0.1, + replication = { + server.build_instance_uri('node1'), + server.build_instance_uri('node2'), + }, + } + cg.node1 = cg.cluster:build_and_add_server{ + alias = 'node1', + box_cfg = cg.box_cfg, + } + cg.node2 = cg.cluster:build_and_add_server{ + alias = 'node2', + box_cfg = cg.box_cfg, + } + cg.cluster:start() +end) + +g.after_all(function(cg) + cg.cluster:drop() +end) + +g.test_false_positive_split_brain = function(cg) + cg.node1:exec(function() + box.ctl.promote() + box.ctl.demote() + end) + cg.node2:wait_vclock_of(cg.node1) + cg.node2:exec(function() + box.space._schema:replace{'smth'} + end) + cg.node1:wait_vclock_of(cg.node2) + cg.node1:assert_follows_upstream(cg.node2:instance_id()) +end