Skip to content

Commit 8162de5

Browse files
author
Jaideep Karande
committed
Bug#27401817: ENFORCE THAT ALL MEMBERS DO HAVE THE SAME LOWER_CASE_TABLE_NAMES VALUE
Description: Group Replication conflict detection does use schema and table names as part of the Primary Key Equivalent (PKE) in order to detect and disallow conflicting transactions. The value of lower_case_table_names option does change how schema and tables names are stored and externalized, which depending on the configuration value may persist a T1 as t1. This difference on a group can cause inconsistencies: Example: M1: lower_case_table_names=0 M2: lower_case_table_names=0 M3: lower_case_table_names=1 CREATE TABLE T1; would be stored as T1 on M1 and M2, but as t1 on M3. Resolution: When a server tries to join a group, its lower_case_table_names value must be compared with the group one, if the value is different the server must not be allowed to join.
1 parent 62f55b4 commit 8162de5

File tree

11 files changed

+260
-17
lines changed

11 files changed

+260
-17
lines changed

rapid/plugin/group_replication/include/member_info.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -104,8 +104,11 @@ class Group_member_info: public Plugin_gcs_message
104104
// Length of the payload item: 2 bytes
105105
PIT_MEMBER_WEIGHT= 14,
106106

107+
// Length of the payload item: 2 bytes
108+
PIT_LOWER_CASE_TABLE_NAME= 15,
109+
107110
// No valid type codes can appear after this one.
108-
PIT_MAX= 15
111+
PIT_MAX= 16
109112
};
110113

111114
/*
@@ -151,6 +154,8 @@ class Group_member_info: public Plugin_gcs_message
151154
@param[in] role_arg member role within the group
152155
@param[in] in_single_primary_mode is member in single mode
153156
@param[in] has_enforces_update_everywhere_checks has member enforce update check
157+
@param[in] member_weight_arg member weight
158+
@param[in] lower_case_table_names_arg lower case table names
154159
*/
155160
Group_member_info(char* hostname_arg,
156161
uint port_arg,
@@ -163,7 +168,8 @@ class Group_member_info: public Plugin_gcs_message
163168
Group_member_info::Group_member_role role_arg,
164169
bool in_single_primary_mode,
165170
bool has_enforces_update_everywhere_checks,
166-
uint member_weight_arg);
171+
uint member_weight_arg,
172+
uint lower_case_table_names_arg);
167173

168174
/**
169175
Copy constructor
@@ -245,6 +251,11 @@ class Group_member_info: public Plugin_gcs_message
245251
*/
246252
uint32 get_configuration_flags();
247253

254+
/**
255+
@return the global-variable lower case table names value
256+
*/
257+
uint get_lower_case_table_names() const;
258+
248259
/**
249260
@return the member state of system variable
250261
group_replication_single_primary_mode
@@ -394,6 +405,7 @@ class Group_member_info: public Plugin_gcs_message
394405
uint32 configuration_flags;
395406
bool conflict_detection_enable;
396407
uint member_weight;
408+
uint lower_case_table_names;
397409
};
398410

399411

rapid/plugin/group_replication/src/gcs_event_handlers.cc

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -1683,6 +1683,22 @@ Plugin_gcs_events_handler::compare_member_option_compatibility() const
16831683
Group_member_info::get_configuration_flags_string(member_configuration_flags).c_str());
16841684
goto cleaning;
16851685
}
1686+
1687+
if (local_member_info->get_lower_case_table_names() !=
1688+
(*all_members_it)->get_lower_case_table_names())
1689+
{
1690+
result= 1;
1691+
log_message(MY_ERROR_LEVEL,
1692+
"The member is configured with a lower_case_table_names "
1693+
"option value '%lu' different from the group '%lu'. "
1694+
"The member will now exit the group. If there is existing "
1695+
"data on member, it may be incompatible with group if "
1696+
"created with a lower_case_table_names value different from "
1697+
"the group.",
1698+
local_member_info->get_lower_case_table_names(),
1699+
(*all_members_it)->get_lower_case_table_names());
1700+
goto cleaning;
1701+
}
16861702
}
16871703

16881704
cleaning:

rapid/plugin/group_replication/src/member_info.cc

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -32,7 +32,8 @@ Group_member_info(char* hostname_arg,
3232
Group_member_info::Group_member_role role_arg,
3333
bool in_single_primary_mode,
3434
bool has_enforces_update_everywhere_checks,
35-
uint member_weight_arg)
35+
uint member_weight_arg,
36+
uint lower_case_table_names_arg)
3637
: Plugin_gcs_message(CT_MEMBER_INFO_MESSAGE),
3738
hostname(hostname_arg), port(port_arg), uuid(uuid_arg),
3839
status(status_arg),
@@ -41,7 +42,8 @@ Group_member_info(char* hostname_arg,
4142
unreachable(false),
4243
role(role_arg),
4344
configuration_flags(0), conflict_detection_enable(false),
44-
member_weight(member_weight_arg)
45+
member_weight(member_weight_arg),
46+
lower_case_table_names(lower_case_table_names_arg)
4547
{
4648
gcs_member_id= new Gcs_member_identifier(gcs_member_id_arg);
4749
member_version= new Member_version(member_version_arg.get_version());
@@ -69,7 +71,8 @@ Group_member_info::Group_member_info(Group_member_info& other)
6971
role(other.get_role()),
7072
configuration_flags(other.get_configuration_flags()),
7173
conflict_detection_enable(other.is_conflict_detection_enabled()),
72-
member_weight(other.get_member_weight())
74+
member_weight(other.get_member_weight()),
75+
lower_case_table_names(other.get_lower_case_table_names())
7376
{
7477
gcs_member_id= new Gcs_member_identifier(other.get_gcs_member_id()
7578
.get_member_id());
@@ -154,6 +157,10 @@ Group_member_info::encode_payload(std::vector<unsigned char>* buffer) const
154157
encode_payload_item_int2(buffer, PIT_MEMBER_WEIGHT,
155158
member_weight_aux);
156159

160+
uint16 lower_case_table_names_aux= static_cast <uint16> (lower_case_table_names);
161+
encode_payload_item_int2(buffer, PIT_LOWER_CASE_TABLE_NAME,
162+
lower_case_table_names_aux);
163+
157164
DBUG_VOID_RETURN;
158165
}
159166

@@ -267,6 +274,15 @@ Group_member_info::decode_payload(const unsigned char* buffer,
267274
member_weight= (uint)member_weight_aux;
268275
}
269276
break;
277+
278+
case PIT_LOWER_CASE_TABLE_NAME:
279+
if (slider + payload_item_length <= end)
280+
{
281+
uint16 lower_case_table_names_aux= uint2korr(slider);
282+
slider += payload_item_length;
283+
lower_case_table_names= static_cast <uint>(lower_case_table_names_aux);
284+
}
285+
break;
270286
}
271287
}
272288

@@ -365,6 +381,12 @@ Group_member_info::get_configuration_flags()
365381
return configuration_flags;
366382
}
367383

384+
uint
385+
Group_member_info::get_lower_case_table_names() const
386+
{
387+
return lower_case_table_names;
388+
}
389+
368390
bool Group_member_info::in_primary_mode()
369391
{
370392
return get_configuration_flags() & CNF_SINGLE_PRIMARY_MODE_F;

rapid/plugin/group_replication/src/plugin.cc

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
/* Copyright (c) 2014, 2017, Oracle and/or its affiliates. All rights reserved.
1+
/* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
22
33
This program is free software; you can redistribute it and/or modify
44
it under the terms of the GNU General Public License as published by
@@ -150,6 +150,9 @@ ulong recovery_reconnect_interval_var= 0;
150150
/* Write set extraction algorithm*/
151151
int write_set_extraction_algorithm= HASH_ALGORITHM_OFF;
152152

153+
/* Lower case table name */
154+
uint gr_lower_case_table_names= 0;
155+
153156
/* Generic components variables */
154157
ulong components_stop_timeout_var= LONG_TIMEOUT;
155158

@@ -672,7 +675,8 @@ int configure_group_member_manager(char *hostname, char *uuid,
672675
Group_member_info::MEMBER_ROLE_SECONDARY,
673676
single_primary_mode_var,
674677
enforce_update_everywhere_checks_var,
675-
member_weight_var);
678+
member_weight_var,
679+
gr_lower_case_table_names);
676680

677681
//Create the membership info visible for the group
678682
delete group_member_mgr;
@@ -1650,6 +1654,9 @@ static int check_if_server_properly_configured()
16501654
DBUG_RETURN(1);
16511655
}
16521656

1657+
gr_lower_case_table_names= startup_pre_reqs.lower_case_table_names;
1658+
DBUG_ASSERT (gr_lower_case_table_names <= 2);
1659+
16531660
DBUG_RETURN(0);
16541661
}
16551662

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
include/group_replication.inc
2+
Warnings:
3+
Note #### Sending passwords in plain text without SSL/TLS is extremely insecure.
4+
Note #### Storing MySQL user name or password information in the master info repository is not secure and is therefore not recommended. Please consider using the USER and PASSWORD connection options for START SLAVE; see the 'START SLAVE Syntax' in the MySQL Manual for more information.
5+
[connection server1]
6+
7+
## 1. Verify lower_case_table_names cannot be set while server is
8+
## running and start GR on server-1.
9+
10+
[connection server1]
11+
SET GLOBAL lower_case_table_names= 1;
12+
ERROR HY000: Variable 'lower_case_table_names' is a read only variable
13+
include/start_and_bootstrap_group_replication.inc
14+
15+
## 2. Store variables of server-2 for restart.
16+
17+
[connection server2]
18+
set session sql_log_bin=0;
19+
call mtr.add_suppression("The member is configured with a lower_case_table_names option value .*");
20+
call mtr.add_suppression("lower_case_table_names was set to 2, .*");
21+
set session sql_log_bin=1;
22+
23+
## 3A. Test GR start with command when lower_case_table_names matches.
24+
25+
include/start_group_replication.inc
26+
include/assert.inc ['Assert server-1 and server-2 are ONLINE']
27+
28+
## 3B. Test GR start on boot when lower_case_table_names matches.
29+
30+
# restart:--group_replication_start_on_boot=1 --group_replication_local_address=GROUP_REPLICATION_LOCAL_ADDRESS --group_replication_group_seeds=GROUP_REPLICATION_GROUP_SEEDS --group_replication_group_name=GROUP_REPLICATION_GROUP_NAME --lower_case_table_names=1
31+
include/rpl_reconnect.inc
32+
33+
## 4A. Test GR does not start on boot when lower_case_table_names
34+
## does not match.
35+
36+
# restart:--group_replication_start_on_boot=1 --group_replication_local_address=GROUP_REPLICATION_LOCAL_ADDRESS --group_replication_group_seeds=GROUP_REPLICATION_GROUP_SEEDS --group_replication_group_name=GROUP_REPLICATION_GROUP_NAME --lower_case_table_names=2
37+
include/rpl_reconnect.inc
38+
include/rpl_gr_wait_for_number_of_members.inc
39+
40+
## 4B. Test GR does not start with command when lower_case_table_names
41+
## does not match.
42+
43+
START GROUP_REPLICATION;
44+
ERROR HY000: The server is not configured properly to be an active member of the group. Please see more details on error log.
45+
include/assert_grep.inc [Found the expected error about lower_case_table_names]
46+
include/assert.inc ['Assert server-2 is OFFLINE']
47+
48+
## 5. Cleanup.
49+
50+
include/group_replication_end.inc
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--lower_case_table_names=1
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
--lower_case_table_names=1
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
################################################################################
2+
## This test proves that group replication does not start on server when it's
3+
## lower_case_table_names does not match with the group.
4+
##
5+
## Test:
6+
## 0. This test requires 2 members.
7+
## 1. Verify lower_case_table_names cannot be set while server is
8+
## running and start GR on server-1.
9+
## 2. Store variables of server-2 for restart.
10+
## 3. Test GR start on server when lower_case_table_names matches.
11+
## 3A. Test GR start with command when lower_case_table_names matches.
12+
## 3B. Test GR start on boot when lower_case_table_names matches.
13+
## 4. Test GR does not start on server when lower_case_table_names
14+
## does not match.
15+
## 4A. Test GR does not start on boot when lower_case_table_names
16+
## does not match.
17+
## 4B. Test GR does not start with command when lower_case_table_names
18+
## does not match.
19+
## 5. Cleanup.
20+
################################################################################
21+
22+
--source include/big_test.inc
23+
--source ../inc/have_group_replication_plugin.inc
24+
--let $rpl_skip_group_replication_start= 1
25+
--source ../inc/group_replication.inc
26+
--source include/force_restart.inc
27+
28+
--let $allow_rpl_inited=1
29+
30+
--echo
31+
--echo ## 1. Verify lower_case_table_names cannot be set while server is
32+
--echo ## running and start GR on server-1.
33+
--echo
34+
--let $rpl_connection_name= server1
35+
--source include/rpl_connection.inc
36+
37+
## Verify lower_case_table_names cannot be set while server is running.
38+
## This make sures we do not need to test variable changes while GR is running.
39+
--error ER_INCORRECT_GLOBAL_LOCAL_VAR
40+
SET GLOBAL lower_case_table_names= 1;
41+
42+
--source ../inc/start_and_bootstrap_group_replication.inc
43+
44+
--echo
45+
--echo ## 2. Store variables of server-2 for restart.
46+
--echo
47+
--let $rpl_connection_name= server2
48+
--source include/rpl_connection.inc
49+
50+
--let $_group_replication_local_address= `SELECT @@GLOBAL.group_replication_local_address`
51+
--let $_group_replication_group_seeds= `SELECT @@GLOBAL.group_replication_group_seeds`
52+
53+
set session sql_log_bin=0;
54+
call mtr.add_suppression("The member is configured with a lower_case_table_names option value .*");
55+
call mtr.add_suppression("lower_case_table_names was set to 2, .*");
56+
set session sql_log_bin=1;
57+
58+
--echo
59+
--echo ## 3A. Test GR start with command when lower_case_table_names matches.
60+
--echo
61+
--source include/start_group_replication.inc
62+
63+
--let $assert_text= 'Assert server-1 and server-2 are ONLINE'
64+
--let $assert_cond= "[SELECT COUNT(*) from performance_schema.replication_group_members WHERE MEMBER_STATE=\"ONLINE\"]" = 2
65+
--source include/assert.inc
66+
67+
--echo
68+
--echo ## 3B. Test GR start on boot when lower_case_table_names matches.
69+
--echo
70+
--let $restart_parameters=restart:--group_replication_start_on_boot=1 --group_replication_local_address=$_group_replication_local_address --group_replication_group_seeds=$_group_replication_group_seeds --group_replication_group_name=$group_replication_group_name --lower_case_table_names=1
71+
--replace_result $group_replication_group_name GROUP_REPLICATION_GROUP_NAME $_group_replication_local_address GROUP_REPLICATION_LOCAL_ADDRESS $_group_replication_group_seeds GROUP_REPLICATION_GROUP_SEEDS
72+
--source include/restart_mysqld.inc
73+
74+
#Needed as we are not using rpl_restart_server.inc
75+
--let $rpl_server_number= 2
76+
--source include/rpl_reconnect.inc
77+
78+
--let $wait_condition= SELECT COUNT(*) = 2 FROM performance_schema.replication_group_members WHERE MEMBER_STATE="ONLINE"
79+
--source include/wait_condition.inc
80+
81+
--echo
82+
--echo ## 4A. Test GR does not start on boot when lower_case_table_names
83+
--echo ## does not match.
84+
--echo
85+
86+
--let $restart_parameters=restart:--group_replication_start_on_boot=1 --group_replication_local_address=$_group_replication_local_address --group_replication_group_seeds=$_group_replication_group_seeds --group_replication_group_name=$group_replication_group_name --lower_case_table_names=2
87+
--replace_result $group_replication_group_name GROUP_REPLICATION_GROUP_NAME $_group_replication_local_address GROUP_REPLICATION_LOCAL_ADDRESS $_group_replication_group_seeds GROUP_REPLICATION_GROUP_SEEDS
88+
--source include/restart_mysqld.inc
89+
90+
#Needed as we are not using rpl_restart_server.inc
91+
--let $rpl_server_number= 2
92+
--source include/rpl_reconnect.inc
93+
94+
## Wait for server-2 to join group, needed to get group lower_case_table_names
95+
--let $group_replication_number_of_members=2
96+
--source ../inc/gr_wait_for_number_of_members.inc
97+
98+
--let $wait_condition= SELECT COUNT(*) = 1 FROM performance_schema.replication_group_members WHERE MEMBER_STATE="OFFLINE"
99+
--source include/wait_condition.inc
100+
101+
--echo
102+
--echo ## 4B. Test GR does not start with command when lower_case_table_names
103+
--echo ## does not match.
104+
--echo
105+
106+
--error ER_GROUP_REPLICATION_CONFIGURATION
107+
START GROUP_REPLICATION;
108+
109+
--let $assert_only_after = CURRENT_TEST: group_replication.gr_lower_case_table_names
110+
--let $assert_file= $MYSQLTEST_VARDIR/log/mysqld.2.err
111+
--let $assert_text = Found the expected error about lower_case_table_names
112+
--let $assert_select = The member is configured with a lower_case_table_names option value
113+
--let $assert_count = 2
114+
--source include/assert_grep.inc
115+
116+
--let $assert_text= 'Assert server-2 is OFFLINE'
117+
--let $assert_cond= "[SELECT COUNT(*) from performance_schema.replication_group_members WHERE MEMBER_STATE=\"OFFLINE\"]" = 1
118+
--source include/assert.inc
119+
120+
--echo
121+
--echo ## 5. Cleanup.
122+
--echo
123+
124+
--source ../inc/group_replication_end.inc

0 commit comments

Comments
 (0)