Skip to content

Commit 78338fa

Browse files
mcouceirodahlerlend
authored andcommitted
BUG#26137159 SLAVE STOPS WITH HA_ERR_KEY_NOT_FOUND (1032) WHEN PARTITIONING + INDEX USED
Problem: When table partitions and indexes are used simultaneously, and the index key is not in the partition function, in some situations replication would stop because a given key could not be found when executing an update or delete statement. This issue only happened when slave-rows-search-algorithms is set to hash_scan. Analysis: When slave-rows-search-algorithms is set to hash_scan, the applier searches for keys(hashes) of the rows that will be modified. Since in this case, the index key was not in the partition function, the retrieved rows could not always be a match. If the key to the retrieved row happened to be different than the key currently being searched, we would advance to the next key, even if not all rows up to that key had been retrieved yet. Fix: Advance to the next key to search (or return an error) only when the search for a given key value ends without finding the corresponding key, instead of advancing to the next key when the index key is different than the key being searched.
1 parent 3ea6ece commit 78338fa

File tree

3 files changed

+265
-10
lines changed

3 files changed

+265
-10
lines changed

mysql-test/suite/rpl/r/rpl_row_hash_scan_sanity.result

Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,135 @@ INSERT INTO t5 VALUES (1,1,"ab"),(2,2,"cde"),(3,1,"12345"),(4,4,"random"),(5,NUL
6464
DELETE FROM t5 ORDER BY c1;
6565
DROP TABLE t5;
6666
include/sync_slave_sql_with_master.inc
67+
SET @@global.slave_rows_search_algorithms= 'INDEX_SCAN,HASH_SCAN';
68+
call mtr.add_suppression("Could not execute Delete_rows event on table test.t6");
69+
call mtr.add_suppression("Could not execute Update_rows event on table test.t6");
70+
call mtr.add_suppression("Can't find record in 't6'");
71+
call mtr.add_suppression("The slave coordinator and worker threads are stopped");
72+
[connection master]
73+
CREATE TABLE t6(num INT, year INT, KEY year (year))
74+
PARTITION BY HASH(num) PARTITIONS 5;
75+
INSERT INTO t6 VALUES(6, 1977);
76+
INSERT INTO t6 VALUES(1, 1983);
77+
INSERT INTO t6 VALUES(9, 1977);
78+
DELETE FROM t6 WHERE num= 9;
79+
include/sync_slave_sql_with_master.inc
80+
[connection master]
81+
include/diff_tables.inc [master:t6, slave:t6]
82+
DROP TABLE t6;
83+
include/sync_slave_sql_with_master.inc
84+
[connection master]
85+
CREATE TABLE t6(num INT, year INT, KEY year (year))
86+
PARTITION BY HASH(num) PARTITIONS 5;
87+
INSERT INTO t6 VALUES(6, 1977);
88+
INSERT INTO t6 VALUES(1, 1983);
89+
INSERT INTO t6 VALUES(9, 1977);
90+
INSERT INTO t6 VALUES(9, 1977);
91+
INSERT INTO t6 VALUES(9, 1987);
92+
INSERT INTO t6 VALUES(9, 9);
93+
INSERT INTO t6 VALUES(9, 1555555500);
94+
DELETE FROM t6 WHERE num= 9;
95+
include/sync_slave_sql_with_master.inc
96+
[connection master]
97+
include/diff_tables.inc [master:t6, slave:t6]
98+
DROP TABLE t6;
99+
include/sync_slave_sql_with_master.inc
100+
[connection master]
101+
CREATE TABLE t6(num INT, year INT, num_2 INT, KEY year (year))
102+
PARTITION BY HASH(num_2-num) PARTITIONS 5;
103+
INSERT INTO t6 VALUES(6, 1977, 1);
104+
INSERT INTO t6 VALUES(1, 1983, 2);
105+
INSERT INTO t6 VALUES(9, 1977, 1);
106+
INSERT INTO t6 VALUES(9, 1983, 1);
107+
INSERT INTO t6 VALUES(9, 1977, 3);
108+
DELETE FROM t6 WHERE num_2= 1;
109+
include/sync_slave_sql_with_master.inc
110+
[connection master]
111+
include/diff_tables.inc [master:t6, slave:t6]
112+
DROP TABLE t6;
113+
include/sync_slave_sql_with_master.inc
114+
include/stop_slave_sql.inc
115+
[connection master]
116+
CREATE TABLE t6(num INT, year INT, KEY year (year))
117+
PARTITION BY HASH(num) PARTITIONS 5;
118+
INSERT INTO t6 VALUES(6, 1977);
119+
INSERT INTO t6 VALUES(1, 1983);
120+
INSERT INTO t6 VALUES(9, 1977);
121+
SET SQL_LOG_BIN= 0;
122+
INSERT INTO t6 VALUES(10, 1977);
123+
SET SQL_LOG_BIN= 1;
124+
DELETE FROM t6 WHERE num= 10;
125+
[connection slave]
126+
START SLAVE SQL_THREAD;
127+
include/wait_for_slave_sql_error.inc [errno=1032]
128+
include/stop_slave.inc
129+
INSERT INTO t6 VALUES(10, 1977);
130+
include/start_slave.inc
131+
[connection master]
132+
DROP TABLE t6;
133+
include/sync_slave_sql_with_master.inc
134+
[connection master]
135+
CREATE TABLE t6(num INT, year INT, KEY year (year))
136+
PARTITION BY HASH(num) PARTITIONS 5;
137+
INSERT INTO t6 VALUES(6, 1977);
138+
INSERT INTO t6 VALUES(1, 1983);
139+
INSERT INTO t6 VALUES(9, 1977);
140+
UPDATE t6 SET num= 10 WHERE num= 9;
141+
include/sync_slave_sql_with_master.inc
142+
[connection master]
143+
include/diff_tables.inc [master:t6, slave:t6]
144+
DROP TABLE t6;
145+
include/sync_slave_sql_with_master.inc
146+
[connection master]
147+
CREATE TABLE t6(num INT, year INT, KEY year (year))
148+
PARTITION BY HASH(num) PARTITIONS 5;
149+
INSERT INTO t6 VALUES(6, 1977);
150+
INSERT INTO t6 VALUES(1, 1983);
151+
INSERT INTO t6 VALUES(9, 1977);
152+
INSERT INTO t6 VALUES(9, 1977);
153+
INSERT INTO t6 VALUES(9, 1987);
154+
INSERT INTO t6 VALUES(9, 9);
155+
INSERT INTO t6 VALUES(9, 1555555500);
156+
UPDATE t6 SET num= 10 WHERE num= 9;
157+
include/sync_slave_sql_with_master.inc
158+
[connection master]
159+
include/diff_tables.inc [master:t6, slave:t6]
160+
DROP TABLE t6;
161+
include/sync_slave_sql_with_master.inc
162+
[connection master]
163+
CREATE TABLE t6(num INT, year INT, num_2 INT, KEY year (year))
164+
PARTITION BY HASH(num_2-num) PARTITIONS 5;
165+
INSERT INTO t6 VALUES(6, 1977, 1);
166+
INSERT INTO t6 VALUES(1, 1983, 2);
167+
INSERT INTO t6 VALUES(9, 1977, 1);
168+
INSERT INTO t6 VALUES(9, 1983, 1);
169+
INSERT INTO t6 VALUES(9, 1977, 3);
170+
UPDATE t6 SET num= 10 WHERE num_2= 1;
171+
include/sync_slave_sql_with_master.inc
172+
[connection master]
173+
include/diff_tables.inc [master:t6, slave:t6]
174+
DROP TABLE t6;
175+
include/sync_slave_sql_with_master.inc
176+
include/stop_slave_sql.inc
177+
[connection master]
178+
CREATE TABLE t6(num INT, year INT, KEY year (year))
179+
PARTITION BY HASH(num) PARTITIONS 5;
180+
INSERT INTO t6 VALUES(6, 1977);
181+
INSERT INTO t6 VALUES(1, 1983);
182+
INSERT INTO t6 VALUES(9, 1977);
183+
SET SQL_LOG_BIN= 0;
184+
INSERT INTO t6 VALUES(10, 1977);
185+
SET SQL_LOG_BIN= 1;
186+
UPDATE t6 SET num= 9 WHERE num= 10;
187+
[connection slave]
188+
START SLAVE SQL_THREAD;
189+
include/wait_for_slave_sql_error.inc [errno=1032]
190+
include/stop_slave.inc
191+
INSERT INTO t6 VALUES(10, 1977);
192+
include/start_slave.inc
193+
[connection master]
194+
DROP TABLE t6;
195+
include/sync_slave_sql_with_master.inc
67196
SET @@global.slave_rows_search_algorithms= @saved_slave_rows_search_algorithms;
68197
DROP TABLE IF EXISTS t1, t2, t3, t4;
69198
include/sync_slave_sql_with_master.inc

mysql-test/suite/rpl/t/rpl_row_hash_scan_sanity.test

Lines changed: 128 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,137 @@ DROP TABLE t5;
202202
--source include/sync_slave_sql_with_master.inc
203203
# End of Test cases for Bug#18860225
204204

205-
-- connection slave
205+
# Test cases for BUG#26137159
206+
# Verify that update and delete operations can be safely replicated when the
207+
# partition function does not include the key used in the index
208+
209+
SET @@global.slave_rows_search_algorithms= 'INDEX_SCAN,HASH_SCAN';
210+
211+
call mtr.add_suppression("Could not execute Delete_rows event on table test.t6");
212+
call mtr.add_suppression("Could not execute Update_rows event on table test.t6");
213+
call mtr.add_suppression("Can't find record in 't6'");
214+
# when mts is enabled
215+
call mtr.add_suppression("The slave coordinator and worker threads are stopped");
216+
217+
--let $i= 1
218+
219+
while ($i<3)
220+
{
221+
# Check that the slave can delete/update a value that is not the index key
222+
--source include/rpl_connection_master.inc
223+
CREATE TABLE t6(num INT, year INT, KEY year (year))
224+
PARTITION BY HASH(num) PARTITIONS 5;
225+
INSERT INTO t6 VALUES(6, 1977);
226+
INSERT INTO t6 VALUES(1, 1983);
227+
INSERT INTO t6 VALUES(9, 1977);
228+
if ($i==1)
229+
{
230+
DELETE FROM t6 WHERE num= 9;
231+
}
232+
if ($i==2)
233+
{
234+
UPDATE t6 SET num= 10 WHERE num= 9;
235+
}
236+
--source include/sync_slave_sql_with_master.inc
237+
--source include/rpl_connection_master.inc
238+
--let $diff_tables= master:t6, slave:t6
239+
--source include/diff_tables.inc
240+
DROP TABLE t6;
241+
--source include/sync_slave_sql_with_master.inc
242+
243+
# Check that the slave can delete/update a repeated value that is not the
244+
# index key
245+
--source include/rpl_connection_master.inc
246+
CREATE TABLE t6(num INT, year INT, KEY year (year))
247+
PARTITION BY HASH(num) PARTITIONS 5;
248+
INSERT INTO t6 VALUES(6, 1977);
249+
INSERT INTO t6 VALUES(1, 1983);
250+
INSERT INTO t6 VALUES(9, 1977);
251+
INSERT INTO t6 VALUES(9, 1977);
252+
INSERT INTO t6 VALUES(9, 1987);
253+
INSERT INTO t6 VALUES(9, 9);
254+
INSERT INTO t6 VALUES(9, 1555555500);
255+
if ($i==1)
256+
{
257+
DELETE FROM t6 WHERE num= 9;
258+
}
259+
if ($i==2)
260+
{
261+
UPDATE t6 SET num= 10 WHERE num= 9;
262+
}
263+
--source include/sync_slave_sql_with_master.inc
264+
--source include/rpl_connection_master.inc
265+
--let $diff_tables= master:t6, slave:t6
266+
--source include/diff_tables.inc
267+
DROP TABLE t6;
268+
--source include/sync_slave_sql_with_master.inc
269+
270+
# Check that the slave can delete/update a repeated value that is not the
271+
# index key when using another column for key and a more complex partition
272+
# function
273+
--source include/rpl_connection_master.inc
274+
CREATE TABLE t6(num INT, year INT, num_2 INT, KEY year (year))
275+
PARTITION BY HASH(num_2-num) PARTITIONS 5;
276+
INSERT INTO t6 VALUES(6, 1977, 1);
277+
INSERT INTO t6 VALUES(1, 1983, 2);
278+
INSERT INTO t6 VALUES(9, 1977, 1);
279+
INSERT INTO t6 VALUES(9, 1983, 1);
280+
INSERT INTO t6 VALUES(9, 1977, 3);
281+
if ($i==1)
282+
{
283+
DELETE FROM t6 WHERE num_2= 1;
284+
}
285+
if ($i==2)
286+
{
287+
UPDATE t6 SET num= 10 WHERE num_2= 1;
288+
}
289+
--source include/sync_slave_sql_with_master.inc
290+
--source include/rpl_connection_master.inc
291+
--let $diff_tables= master:t6, slave:t6
292+
--source include/diff_tables.inc
293+
DROP TABLE t6;
294+
--source include/sync_slave_sql_with_master.inc
295+
296+
# Check that the slave will error if trying to delete a non-existing value
297+
--source include/stop_slave_sql.inc
298+
--source include/rpl_connection_master.inc
299+
CREATE TABLE t6(num INT, year INT, KEY year (year))
300+
PARTITION BY HASH(num) PARTITIONS 5;
301+
INSERT INTO t6 VALUES(6, 1977);
302+
INSERT INTO t6 VALUES(1, 1983);
303+
INSERT INTO t6 VALUES(9, 1977);
304+
SET SQL_LOG_BIN= 0;
305+
INSERT INTO t6 VALUES(10, 1977);
306+
SET SQL_LOG_BIN= 1;
307+
if ($i==1)
308+
{
309+
DELETE FROM t6 WHERE num= 10;
310+
}
311+
if ($i==2)
312+
{
313+
UPDATE t6 SET num= 9 WHERE num= 10;
314+
}
315+
316+
--source include/rpl_connection_slave.inc
317+
START SLAVE SQL_THREAD;
318+
--let $slave_sql_errno= convert_error(ER_KEY_NOT_FOUND)
319+
--source include/wait_for_slave_sql_error.inc
320+
321+
# update the slave to clear the error
322+
--source include/stop_slave.inc
323+
INSERT INTO t6 VALUES(10, 1977);
324+
-- source include/start_slave.inc
325+
326+
--source include/rpl_connection_master.inc
327+
DROP TABLE t6;
328+
--source include/sync_slave_sql_with_master.inc
329+
330+
--inc $i
331+
}
206332

207-
SET @@global.slave_rows_search_algorithms= @saved_slave_rows_search_algorithms;
208333

209334
#clean Up
335+
SET @@global.slave_rows_search_algorithms= @saved_slave_rows_search_algorithms;
210336
--connection master
211337
DROP TABLE IF EXISTS t1, t2, t3, t4;
212338
--source include/sync_slave_sql_with_master.inc

sql/log_event.cc

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8924,20 +8924,19 @@ Rows_log_event::next_record_scan(bool first_read)
89248924
if (!first_read)
89258925
{
89268926
/*
8927-
if we fail to fetch next record corresponding to an index value, we
8927+
if we fail to fetch next record corresponding to a key value, we
89288928
move to the next key value. If we are out of key values as well an error
89298929
will be returned.
89308930
*/
8931-
error= table->file->ha_index_next(table->record[0]);
8931+
error= table->file->ha_index_next_same(table->record[0], m_key,
8932+
m_key_info->key_length);
89328933
if(m_rows_lookup_algorithm == ROW_LOOKUP_HASH_SCAN)
8934+
{
89338935
/*
8934-
if we are out of rows for this particular key value
8935-
or we have jumped to the next key value, we reposition the
8936-
marker according to the next key value that we have in the
8937-
list.
8936+
if we are out of rows for this particular key value, we reposition the
8937+
marker according to the next key value that we have in the list.
89388938
*/
8939-
if ((error) ||
8940-
(key_cmp(m_key_info->key_part, m_key, m_key_info->key_length) != 0))
8939+
if (error)
89418940
{
89428941
if (m_itr != m_distinct_keys.end())
89438942
{
@@ -8948,6 +8947,7 @@ Rows_log_event::next_record_scan(bool first_read)
89488947
else
89498948
error= HA_ERR_KEY_NOT_FOUND;
89508949
}
8950+
}
89518951
}
89528952

89538953
if (first_read)

0 commit comments

Comments
 (0)