Binlog-in-engine: Fix binary search for GTID position

When finding the midpoint for each step in the binary search, that
midpoint was not correctly rounded to the nearest page containing a
GTID state record (when the range from the low to the high point is an
odd multiple of number of innodb_binlog_state_interval bytes). This
caused the search to look at the wrong page (and assert in debug
build).

Signed-off-by: Kristian Nielsen <knielsen@knielsen-hq.org>
This commit is contained in:
Kristian Nielsen 2025-10-06 14:07:29 +02:00
commit 649851f52b
6 changed files with 18 additions and 12 deletions

View file

@ -1,5 +1,5 @@
--max-binlog-size=64k
--innodb-binlog-state-interval=16k
--innodb-binlog-state-interval=32k
--log-bin
--binlog-cache-size=8192
--binlog-stmt-cache-size=8192

View file

@ -85,7 +85,7 @@ connection master;
*** Switch to a larger binlog size
SET @old_binlog_size= @@GLOBAL.max_binlog_size;
SET GLOBAL max_binlog_size= 16*1024*1024;
*** Testing 1000 GTIDs with 100 test connects
*** Testing 4000 GTIDs with 100 test connects
connection master;
DELETE FROM t1 WHERE a >= 1000;
FLUSH NO_WRITE_TO_BINLOG BINARY LOGS;
@ -96,10 +96,10 @@ INSERT INTO rand_data(idx, domain_id, server_id)
SELECT seq,
@tmp:=floor(10*POW(rand(666),2)),
100 + 5*@tmp + floor(5*rand(666))
FROM seq_1_to_1000;
FROM seq_1_to_4000;
SELECT COUNT(*), SUM(domain_id), SUM(server_id) FROM rand_data;
COUNT(*) SUM(domain_id) SUM(server_id)
1001 2986 116966
4001 11733 466721
CREATE TABLE gtid_data(
idx INT PRIMARY KEY,
gtid VARCHAR(44),
@ -119,7 +119,7 @@ SET gtid_domain_id= @orig_domain_id;
SET server_id= @orig_server_id;
SELECT COUNT(*) FROM gtid_data;
COUNT(*)
1000
4000
connection slave;
SET @orig_pos= @@GLOBAL.gtid_slave_pos;
SET @orig_t1_limit= (SELECT MAX(a) FROM t1);

View file

@ -18,7 +18,7 @@
--echo *** Switch to a larger binlog size
SET @old_binlog_size= @@GLOBAL.max_binlog_size;
SET GLOBAL max_binlog_size= 16*1024*1024;
--let $NUM_POS= 1000
--let $NUM_POS= 4000
--let $RND_SEED= 666
--source suite/rpl/include/rpl_gtid_index.inc

View file

@ -97,8 +97,8 @@ SESSION_VALUE NULL
DEFAULT_VALUE 2097152
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE BIGINT UNSIGNED
VARIABLE_COMMENT Interval (in bytes) at which to write the GTID binlog state to binlog files to speed up GTID lookups. Must be a multiple of the binlog page size (4096 bytes)
NUMERIC_MIN_VALUE 8192
VARIABLE_COMMENT Interval (in bytes) at which to write the GTID binlog state to binlog files to speed up GTID lookups. Must be a multiple of the binlog page size (16384 bytes)
NUMERIC_MIN_VALUE 32768
NUMERIC_MAX_VALUE 18446744073709551615
NUMERIC_BLOCK_SIZE 0
ENUM_VALUE_LIST NULL

View file

@ -19828,9 +19828,9 @@ static MYSQL_SYSVAR_ULONGLONG(binlog_state_interval,
PLUGIN_VAR_RQCMDARG | PLUGIN_VAR_READONLY,
"Interval (in bytes) at which to write the GTID binlog state to binlog "
"files to speed up GTID lookups. Must be a multiple of the binlog page "
"size (4096 bytes)",
"size (16384 bytes)",
NULL, NULL, 2*1024*1024,
8192, ULONGLONG_MAX, 0);
32768, ULONGLONG_MAX, 0);
static struct st_mysql_sys_var* innobase_system_variables[]= {
MYSQL_SYSVAR(autoextend_increment),

View file

@ -3259,7 +3259,10 @@ gtid_search::find_gtid_pos(slave_connection_state *pos,
((chunk_reader.cur_end_offset - 1) >> ibb_page_size_shift));
/* Round to the next diff_state_page_interval after file end. */
page2-= page2 % (uint32_t)diff_state_page_interval;
uint32_t page1= (page0 + page2) / 2;
uint32_t page1= page0 +
((page2 - page0) /
(2*(uint32_t)diff_state_page_interval) *
(uint32_t)diff_state_page_interval);
page0_diff_state.init();
page0_diff_state.load_nolock(&base_state);
tmp_diff_state.init();
@ -3290,7 +3293,10 @@ gtid_search::find_gtid_pos(slave_connection_state *pos,
}
else
page2= page1;
page1= (page0 + page2) / 2;
page1= page0 +
((page2 - page0) /
(2*(uint32_t)diff_state_page_interval) *
(uint32_t)diff_state_page_interval);
}
ut_ad(page1 >= page0);
out_state->load_nolock(&page0_diff_state);