Commit 279529c1 authored by unknown's avatar unknown

Bug #22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB

fix binlog-writing so that end_log_pos is given correctly even
within transactions for both SHOW BINLOG and SHOW MASTER STATUS,
that is as absolute values (from log start) rather than relative
values (from transaction's start).
---
Merge tnurnberg@bk-internal.mysql.com:/home/bk/mysql-5.0-maint
into  sin.intern.azundris.com:/home/tnurnberg/22540/50-22540


mysql-test/r/binlog.result:
  Bug #22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
  
  show that end_log_pos in SHOW BINLOG EVENTS is correct even in transactions.
  show that SHOW MASTER STATUS returns correct values while in transactions
  (so that mysqldump --master-data will work correctly).
  also remove bdb dependency.
  ---
  manual merge
mysql-test/t/binlog.test:
  Bug #22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
  
  show that end_log_pos in SHOW BINLOG EVENTS is correct even in transactions.
  show that SHOW MASTER STATUS returns correct values while in transactions
  (so that mysqldump --master-data will work correctly).
  also remove bdb dependency.
sql/log.cc:
  Bug #22540: Incorrect value in column End_log_pos of SHOW BINLOG EVENTS using InnoDB
  
  fix output for SHOW BINLOG EVENTS so that end_log_pos is given correctly
  even within transactions. do this by rewriting the commit-buffer in place.
parent 7724e28f
drop table if exists t1, t2;
reset master;
create table t1 (a int) engine=bdb;
create table t1 (a int) engine=innodb;
create table t2 (a int) engine=innodb;
begin;
insert t1 values (5);
......@@ -10,11 +10,11 @@ insert t2 values (5);
commit;
show binlog events from 98;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=bdb
master-bin.000001 # Query 1 # use `test`; create table t1 (a int) engine=innodb
master-bin.000001 # Query 1 # use `test`; create table t2 (a int) engine=innodb
master-bin.000001 # Query 1 # use `test`; BEGIN
master-bin.000001 # Query 1 # use `test`; insert t1 values (5)
master-bin.000001 # Query 1 # use `test`; COMMIT
master-bin.000001 # Xid 1 # COMMIT /* XID */
master-bin.000001 # Query 1 # use `test`; BEGIN
master-bin.000001 # Query 1 # use `test`; insert t2 values (5)
master-bin.000001 # Xid 1 # COMMIT /* XID */
......@@ -133,3 +133,119 @@ master-bin.000001 # Rotate 1 # master-bin.000002;pos=4
show binlog events in 'master-bin.000002' from 98;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000002 # Query 1 # use `test`; drop table t1
set @ac = @@autocommit;
set autocommit= 0;
reset master;
create table t1(n int) engine=innodb;
begin;
insert into t1 values (1);
insert into t1 values (2);
insert into t1 values (3);
commit;
drop table t1;
show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4
master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb
master-bin.000001 197 Query 1 265 use `test`; BEGIN
master-bin.000001 265 Query 1 353 use `test`; insert into t1 values (1)
master-bin.000001 353 Query 1 441 use `test`; insert into t1 values (2)
master-bin.000001 441 Query 1 529 use `test`; insert into t1 values (3)
master-bin.000001 529 Xid 1 556 COMMIT /* XID */
master-bin.000001 556 Query 1 632 use `test`; drop table t1
set autocommit= 1;
reset master;
create table t1(n int) engine=innodb;
insert into t1 values (1);
insert into t1 values (2);
insert into t1 values (3);
commit;
drop table t1;
show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4
master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb
master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (1)
master-bin.000001 285 Xid 1 312 COMMIT /* XID */
master-bin.000001 312 Query 1 400 use `test`; insert into t1 values (2)
master-bin.000001 400 Xid 1 427 COMMIT /* XID */
master-bin.000001 427 Query 1 515 use `test`; insert into t1 values (3)
master-bin.000001 515 Xid 1 542 COMMIT /* XID */
master-bin.000001 542 Query 1 618 use `test`; drop table t1
reset master;
create table t1(n int) engine=myisam;
begin;
insert into t1 values (4);
insert into t1 values (5);
insert into t1 values (6);
commit;
drop table t1;
show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4
master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=myisam
master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (4)
master-bin.000001 285 Query 1 373 use `test`; insert into t1 values (5)
master-bin.000001 373 Query 1 461 use `test`; insert into t1 values (6)
master-bin.000001 461 Query 1 537 use `test`; drop table t1
set autocommit= 1;
reset master;
create table t1(n int) engine=innodb;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 197
insert into t1 values (1);
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 312
insert into t1 values (2);
insert into t1 values (3);
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 542
commit;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 542
drop table t1;
show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4
master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=innodb
master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (1)
master-bin.000001 285 Xid 1 312 COMMIT /* XID */
master-bin.000001 312 Query 1 400 use `test`; insert into t1 values (2)
master-bin.000001 400 Xid 1 427 COMMIT /* XID */
master-bin.000001 427 Query 1 515 use `test`; insert into t1 values (3)
master-bin.000001 515 Xid 1 542 COMMIT /* XID */
master-bin.000001 542 Query 1 618 use `test`; drop table t1
set autocommit= 0;
reset master;
create table t1(n int) engine=myisam;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 197
insert into t1 values (4);
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 285
insert into t1 values (5);
insert into t1 values (6);
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 461
commit;
show master status;
File Position Binlog_Do_DB Binlog_Ignore_DB
master-bin.000001 461
drop table t1;
show binlog events from 0;
Log_name Pos Event_type Server_id End_log_pos Info
master-bin.000001 4 Format_desc 1 98 Server version, Binlog ver: 4
master-bin.000001 98 Query 1 197 use `test`; create table t1(n int) engine=myisam
master-bin.000001 197 Query 1 285 use `test`; insert into t1 values (4)
master-bin.000001 285 Query 1 373 use `test`; insert into t1 values (5)
master-bin.000001 373 Query 1 461 use `test`; insert into t1 values (6)
master-bin.000001 461 Query 1 537 use `test`; drop table t1
set session autocommit = @ac;
End of 5.0 tests
......@@ -3,7 +3,6 @@
#
-- source include/have_log_bin.inc
-- source include/not_embedded.inc
-- source include/have_bdb.inc
-- source include/have_innodb.inc
-- source include/have_log_bin.inc
......@@ -12,7 +11,7 @@ drop table if exists t1, t2;
--enable_warnings
reset master;
create table t1 (a int) engine=bdb;
create table t1 (a int) engine=innodb;
create table t2 (a int) engine=innodb;
begin;
insert t1 values (5);
......@@ -49,3 +48,93 @@ show binlog events in 'master-bin.000001' from 98;
--replace_column 2 # 5 #
show binlog events in 'master-bin.000002' from 98;
#
# Bug#22540 - Incorrect value in column End_log_pos of
# SHOW BINLOG EVENTS using InnoDB
#
# the following tests will show that certain queries now return
# absolute offsets (from binlog start, rather than relative to
# the beginning of the current transaction). under what
# conditions it should be allowed / is sensible to put the
# slider into the middle of a transaction is not our concern
# here; we just guarantee that if and when it's done, the
# user has valid offsets to use. if the setter function still
# wants to throw a "positioning into middle of transaction"
# warning, that's its prerogative and handled elsewhere.
set @ac = @@autocommit;
# first show this to work for SHOW BINLOG EVENTS
set autocommit= 0;
reset master;
create table t1(n int) engine=innodb;
begin;
insert into t1 values (1);
insert into t1 values (2);
insert into t1 values (3);
commit;
drop table t1;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/
show binlog events from 0;
set autocommit= 1;
reset master;
create table t1(n int) engine=innodb;
insert into t1 values (1);
insert into t1 values (2);
insert into t1 values (3);
commit;
drop table t1;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/
show binlog events from 0;
reset master;
create table t1(n int) engine=myisam;
begin;
insert into t1 values (4);
insert into t1 values (5);
insert into t1 values (6);
commit;
drop table t1;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/
show binlog events from 0;
# now show this also works for SHOW MASTER STATUS
# as this is what "mysqldump --master-data=1" uses.
set autocommit= 1;
reset master;
create table t1(n int) engine=innodb;
show master status;
insert into t1 values (1);
show master status;
insert into t1 values (2);
insert into t1 values (3);
show master status;
commit;
show master status;
drop table t1;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/
show binlog events from 0;
set autocommit= 0;
reset master;
create table t1(n int) engine=myisam;
show master status;
insert into t1 values (4);
show master status;
insert into t1 values (5);
insert into t1 values (6);
show master status;
commit;
show master status;
drop table t1;
--replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /Server ver: [^,]*,/Server version,/
show binlog events from 0;
set session autocommit = @ac;
--echo End of 5.0 tests
......@@ -134,7 +134,7 @@ static int binlog_commit(THD *thd, bool all)
// we're here because trans_log was flushed in MYSQL_LOG::log_xid()
DBUG_RETURN(0);
}
if (all)
if (all)
{
Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE);
qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
......@@ -1835,7 +1835,9 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
if (likely(is_open())) // Should always be true
{
uint length;
uint length, group, carry, hdr_offs;
long val;
byte header[LOG_EVENT_HEADER_LEN];
/*
Log "BEGIN" at the beginning of the transaction.
......@@ -1867,13 +1869,66 @@ bool MYSQL_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event)
/* Read from the file used to cache the queries .*/
if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
goto err;
length=my_b_bytes_in_cache(cache);
length= my_b_bytes_in_cache(cache);
DBUG_EXECUTE_IF("half_binlogged_transaction", length-=100;);
group= my_b_tell(&log_file);
hdr_offs= carry= 0;
do
{
if (likely(carry > 0))
{
DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN);
memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
val= uint4korr(&header[LOG_POS_OFFSET]) + group;
int4store(&header[LOG_POS_OFFSET], val);
if (my_b_write(&log_file, header, carry))
goto err;
memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry);
hdr_offs = LOG_EVENT_HEADER_LEN - carry +
uint4korr(&header[EVENT_LEN_OFFSET]);
carry= 0;
}
if(likely(length > 0))
{
do {
DBUG_ASSERT((hdr_offs + max(EVENT_LEN_OFFSET, LOG_POS_OFFSET) + 4) <= length);
val= uint4korr((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET) + group;
int4store((char *)cache->read_pos + hdr_offs + LOG_POS_OFFSET, val);
hdr_offs += uint4korr((char *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET);
/* header beyond current read-buffer? */
if (hdr_offs >= length)
{
hdr_offs -= length;
break;
}
/* split header? */
if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
{
carry= length - hdr_offs;
memcpy(header, (char *)cache->read_pos + hdr_offs, carry);
length -= carry;
}
} while (hdr_offs < length);
}
/* Write data to the binary log file */
if (my_b_write(&log_file, cache->read_pos, length))
goto err;
goto err;
cache->read_pos=cache->read_end; // Mark buffer used up
DBUG_EXECUTE_IF("half_binlogged_transaction", goto DBUG_skip_commit;);
} while ((length=my_b_fill(cache)));
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment