Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
70 changes: 70 additions & 0 deletions mysql-test/suite/galera_3nodes/r/galera_vote_majority_dml.result
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
connection node_2;
connection node_1;
CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 BLOB) ENGINE=InnoDB;
connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3;
connection node_3;
SET GLOBAL wsrep_on=OFF;
ALTER TABLE t1 MODIFY f2 LONGTEXT;
SET GLOBAL wsrep_on=ON;
INSERT INTO t1 VALUES (3, 'a');
connection node_1;
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status Primary
connection node_2;
SHOW STATUS LIKE 'wsrep_cluster_status';
Variable_name Value
wsrep_cluster_status Primary
INSERT INTO t1 VALUES (2, 'a');
connection node_3;
SET SESSION wsrep_sync_wait=0;
SET SESSION wsrep_on=OFF;
# restart
SET SESSION wsrep_on=ON;
INSERT INTO t1 VALUES (3, 'a');
connection node_1;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL,
`f2` blob DEFAULT NULL,
PRIMARY KEY (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT * FROM t1;
f1 f2
2 a
3 a
connection node_2;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL,
`f2` blob DEFAULT NULL,
PRIMARY KEY (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT * FROM t1;
f1 f2
2 a
3 a
connection node_3;
SHOW CREATE TABLE t1;
Table Create Table
t1 CREATE TABLE `t1` (
`f1` int(11) NOT NULL,
`f2` blob DEFAULT NULL,
PRIMARY KEY (`f1`)
) ENGINE=InnoDB DEFAULT CHARSET=latin1 COLLATE=latin1_swedish_ci
SELECT * FROM t1;
f1 f2
2 a
3 a
DROP TABLE t1;
connection node_1;
CALL mtr.add_suppression("Replica SQL: Column 1 of table 'test.t1' cannot be converted from type 'longblob' to type 'blob', Error_code: MY-013146");
CALL mtr.add_suppression("Event 3 Write_rows_v1 apply failed: 3, seqno");
connection node_2;
CALL mtr.add_suppression("Replica SQL: Column 1 of table 'test.t1' cannot be converted from type 'longblob' to type 'blob', Error_code: MY-013146");
CALL mtr.add_suppression("Event 3 Write_rows_v1 apply failed: 3, seqno");
connection node_3;
CALL mtr.add_suppression("Vote 0 \\(success\\) on (.*) is inconsistent with group. Leaving cluster.");
CALL mtr.add_suppression("Plugin 'InnoDB' will be forced to shutdown");
5 changes: 5 additions & 0 deletions mysql-test/suite/galera_3nodes/t/galera_vote_majority_dml.cnf
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
!include ../galera_3nodes.cnf

[mysqld]
wsrep-ignore-apply-errors=0

67 changes: 67 additions & 0 deletions mysql-test/suite/galera_3nodes/t/galera_vote_majority_dml.test
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
#
# MDEV-37494: Inconsistency voting: create conditions where applying would
# fail on replicas in table_def::compatible_with() and check that
# that replicas survive and the primary (trx source) bails out.
#
--source include/galera_cluster.inc

CREATE TABLE t1 (f1 INTEGER PRIMARY KEY, f2 BLOB) ENGINE=InnoDB;

--connect node_3, 127.0.0.1, root, , test, $NODE_MYPORT_3
--connection node_3
SET GLOBAL wsrep_on=OFF;
ALTER TABLE t1 MODIFY f2 LONGTEXT; # Introducing schema inconsistency
SET GLOBAL wsrep_on=ON;
INSERT INTO t1 VALUES (3, 'a'); # Nodes 1 and 2 should fail to apply this

--connection node_1
# Wait until node #3 leaves the cluster
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_size'
--source include/wait_condition.inc
SHOW STATUS LIKE 'wsrep_cluster_status';

--connection node_2
--let $wait_condition = SELECT VARIABLE_VALUE = 2 FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_size'
# Wait until node #3 leaves the cluster
--source include/wait_condition.inc
SHOW STATUS LIKE 'wsrep_cluster_status';

INSERT INTO t1 VALUES (2, 'a'); # Nodes 1 and 2 should successfully apply this

--connection node_3
SET SESSION wsrep_sync_wait=0;
--let $wait_condition = SELECT VARIABLE_VALUE = 'Disconnected' FROM performance_schema.global_status WHERE VARIABLE_NAME = 'wsrep_cluster_status';
--source include/wait_condition.inc
SET SESSION wsrep_on=OFF;
--source include/restart_mysqld.inc
--source include/wait_wsrep_ready.inc
SET SESSION wsrep_on=ON;

INSERT INTO t1 VALUES (3, 'a'); # All nodes should successfully apply this

# Check that consistency is restored
--connection node_1
SHOW CREATE TABLE t1;
SELECT * FROM t1;

--connection node_2
SHOW CREATE TABLE t1;
SELECT * FROM t1;

--connection node_3
SHOW CREATE TABLE t1;
SELECT * FROM t1;

DROP TABLE t1;

--connection node_1
CALL mtr.add_suppression("Replica SQL: Column 1 of table 'test.t1' cannot be converted from type 'longblob' to type 'blob', Error_code: MY-013146");
CALL mtr.add_suppression("Event 3 Write_rows_v1 apply failed: 3, seqno");

--connection node_2
CALL mtr.add_suppression("Replica SQL: Column 1 of table 'test.t1' cannot be converted from type 'longblob' to type 'blob', Error_code: MY-013146");
CALL mtr.add_suppression("Event 3 Write_rows_v1 apply failed: 3, seqno");

--connection node_3
CALL mtr.add_suppression("Vote 0 \\(success\\) on (.*) is inconsistent with group. Leaving cluster.");
CALL mtr.add_suppression("Plugin 'InnoDB' will be forced to shutdown");
58 changes: 54 additions & 4 deletions sql/wsrep_applier.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,9 +83,35 @@ wsrep_get_apply_format(THD* thd)
return thd->wsrep_rgi->rli->relay_log.description_event_for_exec;
}

void wsrep_store_error(const THD* const thd,
wsrep::mutable_buffer& dst,
bool const include_msg)
/* store error from rli */
static void wsrep_store_error_rli(const THD* const thd,
wsrep::mutable_buffer& dst,
bool const include_msg)
{
Slave_reporting_capability* const rli= thd->wsrep_rgi->rli;
if (rli && rli->last_error().number != 0)
{
auto error= rli->last_error();
std::ostringstream os;
if (include_msg)
{
os << error.message << ",";
}
os << " Error_code: " << error.number << ';';
std::string const err_str= os.str();
dst.resize(err_str.length() + 1);
sprintf(dst.data(), "%s", err_str.c_str());

WSREP_DEBUG("Error buffer (RLI) for thd %u seqno %lld, %zu bytes: '%s'",
thd->thread_id, (long long)wsrep_thd_trx_seqno(thd),
dst.size(), dst.size() ? dst.data() : "(null)");
}
}

/* store error from diagnostic area */
static void wsrep_store_error_da(const THD* const thd,
wsrep::mutable_buffer& dst,
bool const include_msg)
{
Diagnostics_area::Sql_condition_iterator it=
thd->get_stmt_da()->sql_conditions();
Expand Down Expand Up @@ -123,11 +149,35 @@ void wsrep_store_error(const THD* const thd,

dst.resize(slider - dst.data());

WSREP_DEBUG("Error buffer for thd %llu seqno %lld, %zu bytes: '%s'",
WSREP_DEBUG("Error buffer (DA) for thd %llu seqno %lld, %zu bytes: '%s'",
thd->thread_id, (long long)wsrep_thd_trx_seqno(thd),
dst.size(), dst.size() ? dst.data() : "(null)");
}

/* store error info after applying error */
void wsrep_store_error(const THD* const thd,
wsrep::mutable_buffer& dst,
bool const include_msg)
{
dst.clear();
wsrep_store_error_da(thd, dst, include_msg);
if (dst.size() == 0)
{
wsrep_store_error_rli(thd, dst, include_msg);
}
if (dst.size() == 0)
{
WSREP_WARN("Failed to get apply error description from either "
"Relay_log_info or Diagnostics_area, will use random data.");
DBUG_ASSERT(0);
uintptr_t const n1= reinterpret_cast<uintptr_t>(&dst);
uintptr_t const n2= reinterpret_cast<uintptr_t>(thd);
uintptr_t const data= n1 ^ (n2 < 1);
const char* const data_ptr= reinterpret_cast<const char*>(&data);
dst.push_back(data_ptr, data_ptr + sizeof(data));
}
}

int wsrep_apply_events(THD* thd,
Relay_log_info* rli,
const void* events_buf,
Expand Down