#At file:///home/acorreia/workspace.sun/repository.mysql.new/bzrwork/bug-56343/mysql-5.5-bugfixing/ based on revid:mats.kindahl@stripped
3203 Alfranio Correia 2010-10-06
BUG#56343 binlog_cache_use status is bigger than expected
The binlog_cache_use is incremented twice when changes to a transactional table
are committed, i.e. TC_LOG_BINLOG::log_xid calls is called. The problem happens
because log_xid calls both binlog_flush_stmt_cache and binlog_flush_trx_cache
without checking if such caches are empty thus unintentionally increasing the
binlog_cache_use value twice.
To fix the problem we avoided incrementing the binlog_cache_use if the cache is
empty. We also decided to increment binlog_cache_use when the cache is truncated
as the cache is used although its content is discarded and is not written to the
binary log.
Note that binlog_cache_use is incremented for both types of cache, transactional
and non-transactional and that the behavior presented in this patch also applies
to the binlog_cache_disk_use.
Finally, we re-organized the code around the functions binlog_flush_trx_cache and
binlog_flush_stmt_cache.
@ mysql-test/extra/binlog_tests/binlog_cache_stat.test
Updated the test case with comments and additional tests to check both
transactional and non-transactional changes and what happens when a
is transaction either committed or aborted.
@ mysql-test/suite/binlog/r/binlog_innodb.result
Updated the result file.
@ mysql-test/suite/binlog/r/binlog_mixed_cache_stat.result
Updated the result file.
@ mysql-test/suite/binlog/r/binlog_row_cache_stat.result
Updated the result file.
@ mysql-test/suite/binlog/r/binlog_stm_cache_stat.result
Updated the result file.
@ mysql-test/suite/binlog/t/binlog_mixed_cache_stat.test
Updated the test case with a new source file.
@ mysql-test/suite/binlog/t/binlog_row_cache_stat.test
Updated the test case with a new source file.
@ mysql-test/suite/binlog/t/binlog_stm_cache_stat.test
Updated the test case with a new source file.
@ sql/log_event.cc
Introduced debug information to check if Query_log_event("BEGIN"),
Query_log_event("COMMIT") and Query_log_event("ROLLBACK").
@ sql/log_event.h
Guaranteed Xid_log_event is always classified as a transactional event.
renamed:
mysql-test/extra/binlog_tests/innodb_stat.test => mysql-test/extra/binlog_tests/binlog_cache_stat.test
mysql-test/suite/binlog/r/binlog_mix_innodb_stat.result => mysql-test/suite/binlog/r/binlog_mixed_cache_stat.result
mysql-test/suite/binlog/r/binlog_row_innodb_stat.result => mysql-test/suite/binlog/r/binlog_row_cache_stat.result
mysql-test/suite/binlog/r/binlog_stm_innodb_stat.result => mysql-test/suite/binlog/r/binlog_stm_cache_stat.result
mysql-test/suite/binlog/t/binlog_mix_innodb_stat.test => mysql-test/suite/binlog/t/binlog_mixed_cache_stat.test
mysql-test/suite/binlog/t/binlog_row_innodb_stat.test => mysql-test/suite/binlog/t/binlog_row_cache_stat.test
mysql-test/suite/binlog/t/binlog_stm_innodb_stat.test => mysql-test/suite/binlog/t/binlog_stm_cache_stat.test
modified:
mysql-test/suite/binlog/r/binlog_innodb.result
sql/log.cc
sql/log_event.cc
sql/log_event.h
mysql-test/extra/binlog_tests/binlog_cache_stat.test
mysql-test/suite/binlog/r/binlog_mixed_cache_stat.result
mysql-test/suite/binlog/r/binlog_row_cache_stat.result
mysql-test/suite/binlog/r/binlog_stm_cache_stat.result
mysql-test/suite/binlog/t/binlog_mixed_cache_stat.test
mysql-test/suite/binlog/t/binlog_row_cache_stat.test
mysql-test/suite/binlog/t/binlog_stm_cache_stat.test
=== renamed file 'mysql-test/extra/binlog_tests/innodb_stat.test' => 'mysql-test/extra/binlog_tests/binlog_cache_stat.test'
--- a/mysql-test/extra/binlog_tests/innodb_stat.test 2008-09-22 19:15:52 +0000
+++ b/mysql-test/extra/binlog_tests/binlog_cache_stat.test 2010-10-06 08:34:49 +0000
@@ -2,22 +2,36 @@
-- source include/not_embedded.inc
-- source include/have_innodb.inc
+# Creating tables
+--disable_warnings
+drop table if exists t1, t2;
+--enable_warnings
+
+create table t1 (a int) engine=innodb;
+create table t2 (a int) engine=myisam;
+
#
# Let us test binlog_cache_use and binlog_cache_disk_use status vars.
-# Actually this test has nothing to do with innodb per se, it just requires
-# transactional table.
+# Actually this test has nothing to do with innodb per se, it just
+# requires transactional table.
+#
+# This test checks binlog_cache_use and binlog_cache_disk_use when
+# transactions are committed and after when they are aborted.
+#
+
+#
+# Checking commit.
#
+--echo **** Preparing the enviroment to check commit and its effect on
+--echo **** the binlog_cache_use and binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
flush status;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
---disable_warnings
-drop table if exists t1;
---enable_warnings
-create table t1 (a int) engine=innodb;
-
-# Now we are going to create transaction which is long enough so its
-# transaction binlog will be flushed to disk...
+--echo **** Now we are going to create transactional changes which are long enough so
+--echo **** they will be flushed to disk...
+--echo **** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
let $1=2000;
disable_query_log;
begin;
@@ -31,11 +45,85 @@ enable_query_log;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
-# Transaction which should not be flushed to disk and so should not
-# increase binlog_cache_disk_use.
+--echo **** Transactional changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
begin;
-delete from t1;
+insert into t1 values( 1 );
commit;
show status like "binlog_cache_use";
show status like "binlog_cache_disk_use";
-drop table t1;
+
+--echo **** Non-Transactional changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+commit;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+--echo **** Mixed changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
+commit;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+#
+# Checking abort.
+#
+--echo **** Preparing the enviroment to check abort and its effect on
+--echo **** the binlog_cache_use and binlog_cache_disk_use
+--echo **** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
+flush status;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+--echo **** Now we are going to create transactional changes which are long enough so
+--echo **** they will be flushed to disk...
+--echo **** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+let $1=2000;
+disable_query_log;
+begin;
+while ($1)
+{
+ eval insert into t1 values( $1 );
+ dec $1;
+}
+rollback;
+enable_query_log;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+--echo **** Transactional changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+--echo **** Non-Transactional changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+
+--echo **** Mixed changes which should not be flushed to disk and so should not
+--echo **** increase binlog_cache_disk_use.
+--echo **** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+drop table t1, t2;
=== modified file 'mysql-test/suite/binlog/r/binlog_innodb.result'
--- a/mysql-test/suite/binlog/r/binlog_innodb.result 2010-06-17 13:31:51 +0000
+++ b/mysql-test/suite/binlog/r/binlog_innodb.result 2010-10-06 08:34:49 +0000
@@ -123,7 +123,7 @@ Binlog_cache_disk_use 0
create table t1 (a int) engine=innodb;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 2
+Binlog_cache_use 1
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
@@ -132,7 +132,7 @@ delete from t1;
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 4
+Binlog_cache_use 2
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
=== renamed file 'mysql-test/suite/binlog/r/binlog_mix_innodb_stat.result' => 'mysql-test/suite/binlog/r/binlog_mixed_cache_stat.result'
--- a/mysql-test/suite/binlog/r/binlog_mix_innodb_stat.result 2010-01-05 16:55:23 +0000
+++ b/mysql-test/suite/binlog/r/binlog_mixed_cache_stat.result 2010-10-06 08:34:49 +0000
@@ -1,3 +1,9 @@
+drop table if exists t1, t2;
+create table t1 (a int) engine=innodb;
+create table t2 (a int) engine=myisam;
+**** Preparing the enviroment to check commit and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
flush status;
show status like "binlog_cache_use";
Variable_name Value
@@ -5,21 +11,110 @@ Binlog_cache_use 0
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
-drop table if exists t1;
-create table t1 (a int) engine=innodb;
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 2
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+commit;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
begin;
-delete from t1;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 4
+Binlog_cache_use 5
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Preparing the enviroment to check abort and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
+flush status;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 0
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 0
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 2
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 5
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
-drop table t1;
+drop table t1, t2;
=== renamed file 'mysql-test/suite/binlog/r/binlog_row_innodb_stat.result' => 'mysql-test/suite/binlog/r/binlog_row_cache_stat.result'
--- a/mysql-test/suite/binlog/r/binlog_row_innodb_stat.result 2010-01-05 16:55:23 +0000
+++ b/mysql-test/suite/binlog/r/binlog_row_cache_stat.result 2010-10-06 08:34:49 +0000
@@ -1,3 +1,9 @@
+drop table if exists t1, t2;
+create table t1 (a int) engine=innodb;
+create table t2 (a int) engine=myisam;
+**** Preparing the enviroment to check commit and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
flush status;
show status like "binlog_cache_use";
Variable_name Value
@@ -5,21 +11,110 @@ Binlog_cache_use 0
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
-drop table if exists t1;
-create table t1 (a int) engine=innodb;
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 2
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+commit;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
begin;
-delete from t1;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 4
+Binlog_cache_use 5
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Preparing the enviroment to check abort and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
+flush status;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 0
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 0
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 2
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 5
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
-drop table t1;
+drop table t1, t2;
=== renamed file 'mysql-test/suite/binlog/r/binlog_stm_innodb_stat.result' => 'mysql-test/suite/binlog/r/binlog_stm_cache_stat.result'
--- a/mysql-test/suite/binlog/r/binlog_stm_innodb_stat.result 2010-01-05 16:55:23 +0000
+++ b/mysql-test/suite/binlog/r/binlog_stm_cache_stat.result 2010-10-06 08:34:49 +0000
@@ -1,3 +1,9 @@
+drop table if exists t1, t2;
+create table t1 (a int) engine=innodb;
+create table t2 (a int) engine=myisam;
+**** Preparing the enviroment to check commit and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
flush status;
show status like "binlog_cache_use";
Variable_name Value
@@ -5,21 +11,110 @@ Binlog_cache_use 0
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 0
-drop table if exists t1;
-create table t1 (a int) engine=innodb;
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+commit;
show status like "binlog_cache_use";
Variable_name Value
Binlog_cache_use 2
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+commit;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
begin;
-delete from t1;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
commit;
show status like "binlog_cache_use";
Variable_name Value
-Binlog_cache_use 4
+Binlog_cache_use 5
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Preparing the enviroment to check abort and its effect on
+**** the binlog_cache_use and binlog_cache_disk_use
+**** Expected: binlog_cache_use = 0, binlog_cache_disk_use = 0.
+flush status;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 0
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 0
+**** Now we are going to create transactional changes which are long enough so
+**** they will be flushed to disk...
+**** Expected: binlog_cache_use = 1, binlog_cache_disk_use = 1.
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 1
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 2, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+rollback;
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 2
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Non-Transactional changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 3, binlog_cache_disk_use = 1.
+begin;
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 3
+show status like "binlog_cache_disk_use";
+Variable_name Value
+Binlog_cache_disk_use 1
+**** Mixed changes which should not be flushed to disk and so should not
+**** increase binlog_cache_disk_use.
+**** Expected: binlog_cache_use = 5, binlog_cache_disk_use = 1.
+begin;
+insert into t1 values( 1 );
+insert into t2 values( 1 );
+rollback;
+Warnings:
+Warning 1196 Some non-transactional changed tables couldn't be rolled back
+show status like "binlog_cache_use";
+Variable_name Value
+Binlog_cache_use 5
show status like "binlog_cache_disk_use";
Variable_name Value
Binlog_cache_disk_use 1
-drop table t1;
+drop table t1, t2;
=== renamed file 'mysql-test/suite/binlog/t/binlog_mix_innodb_stat.test' => 'mysql-test/suite/binlog/t/binlog_mixed_cache_stat.test'
--- a/mysql-test/suite/binlog/t/binlog_mix_innodb_stat.test 2008-09-08 20:23:55 +0000
+++ b/mysql-test/suite/binlog/t/binlog_mixed_cache_stat.test 2010-10-06 08:34:49 +0000
@@ -2,4 +2,4 @@
# For both statement and row based bin logs 9/19/2005 [jbm]
-- source include/have_binlog_format_mixed.inc
--- source extra/binlog_tests/innodb_stat.test
+-- source extra/binlog_tests/binlog_cache_stat.test
=== renamed file 'mysql-test/suite/binlog/t/binlog_row_innodb_stat.test' => 'mysql-test/suite/binlog/t/binlog_row_cache_stat.test'
--- a/mysql-test/suite/binlog/t/binlog_row_innodb_stat.test 2007-06-27 12:28:02 +0000
+++ b/mysql-test/suite/binlog/t/binlog_row_cache_stat.test 2010-10-06 08:34:49 +0000
@@ -2,4 +2,4 @@
# For both statement and row based bin logs 9/19/2005 [jbm]
-- source include/have_binlog_format_row.inc
--- source extra/binlog_tests/innodb_stat.test
+-- source extra/binlog_tests/binlog_cache_stat.test
=== renamed file 'mysql-test/suite/binlog/t/binlog_stm_innodb_stat.test' => 'mysql-test/suite/binlog/t/binlog_stm_cache_stat.test'
--- a/mysql-test/suite/binlog/t/binlog_stm_innodb_stat.test 2008-09-08 20:23:55 +0000
+++ b/mysql-test/suite/binlog/t/binlog_stm_cache_stat.test 2010-10-06 08:34:49 +0000
@@ -2,4 +2,4 @@
# For both statement and row based bin logs 9/19/2005 [jbm]
-- source include/have_binlog_format_statement.inc
--- source extra/binlog_tests/innodb_stat.test
+-- source extra/binlog_tests/binlog_cache_stat.test
=== modified file 'sql/log.cc'
--- a/sql/log.cc 2010-09-06 17:18:44 +0000
+++ b/sql/log.cc 2010-10-06 08:34:49 +0000
@@ -210,6 +210,9 @@ class binlog_cache_data
public:
binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
incident(FALSE), changes_to_non_trans_temp_table_flag(FALSE)
+#ifndef DBUG_OFF
+ , has_trans(FALSE)
+#endif
{
cache_log.end_of_file= max_binlog_cache_size;
}
@@ -262,6 +265,14 @@ public:
incident= FALSE;
before_stmt_pos= MY_OFF_T_UNDEF;
cache_log.end_of_file= max_binlog_cache_size;
+ /*
+ When a truncate is called there may be write activity and by consequence
+ "disk_writes" is increased. This breaks the "disk_writes"' use by the
+ binary log which aims to compute the ratio between in-memory cache usage
+ and disk cache usage. To avoid this undesirable behavior, we reset the
+ variable after truncating the cache.
+ */
+ cache_log.disk_writes= 0;
DBUG_ASSERT(empty());
}
@@ -292,6 +303,18 @@ public:
before_stmt_pos= MY_OFF_T_UNDEF;
}
+#ifndef DBUG_OFF
+ bool is_transactional()
+ {
+ return(has_trans);
+ }
+
+ void set_transactional(bool is_transactional)
+ {
+ has_trans= is_transactional;
+ }
+#endif
+
/*
Cache to store data before copying it to the binary log.
*/
@@ -321,6 +344,13 @@ private:
*/
bool changes_to_non_trans_temp_table_flag;
+#ifndef DBUG_OFF
+ /*
+ Defines the type of the cache either: transactional or non-transactional.
+ */
+ bool has_trans;
+#endif
+
/*
It truncates the cache to a certain position. This includes deleting the
pending event.
@@ -1506,57 +1536,147 @@ static int binlog_close_connection(handl
}
/**
- This function flushes a transactional cache upon commit/rollback.
-
- @param thd The thread whose transaction should be flushed
- @param cache_mngr Pointer to the cache data to be flushed
- @param end_ev The end event either commit/rollback.
+ This function computes binlog cache and disk usage.
- @return
- nonzero if an error pops up when flushing the transactional cache.
+ @param cache_data Pointer to the cache where data is
+ stored.
*/
-static int
-binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
- Log_event *end_ev)
+static inline void
+binlog_compute_statistics(binlog_cache_data* cache_data)
{
- DBUG_ENTER("binlog_flush_trx_cache");
- int error=0;
- IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log;
+ if (!cache_data->empty())
+ {
+ statistic_increment(binlog_cache_use, &LOCK_status);
+ if (cache_data->cache_log.disk_writes != 0)
+ statistic_increment(binlog_cache_disk_use, &LOCK_status);
+ }
+}
- /*
- This function handles transactional changes and as such
- this flag equals to true.
- */
- bool const is_transactional= TRUE;
+/**
+ This function flushes a cache upon commit/rollback.
- if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
- DBUG_RETURN(1);
- /*
- Doing a commit or a rollback including non-transactional tables,
- i.e., ending a transaction where we might write the transaction
- cache to the binary log.
+ @param thd The thread whose transaction should be flushed
+ @param cache_data Pointer to the cache
+ @param end_ev The end event either commit/rollback
+ @param is_transactional The type of the cache: transactional or
+ non-transactional
- We can always end the statement when ending a transaction since
- transactions are not allowed inside stored functions. If they
- were, we would have to ensure that we're not ending a statement
- inside a stored function.
- */
- error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev,
- cache_mngr->trx_cache.has_incident());
- cache_mngr->reset_cache(&cache_mngr->trx_cache);
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_flush_cache(THD *thd, binlog_cache_data* cache_data, Log_event *end_evt,
+ bool is_transactional)
+{
+ DBUG_ENTER("binlog_flush_cache");
+ int error= 0;
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (cache_log->disk_writes != 0)
+ if (!cache_data->empty())
{
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- cache_log->disk_writes= 0;
+#ifndef DBUG_OFF
+ DBUG_PRINT("info", ("is_transactional(%d), event(%d), cache_data(%d)",
+ is_transactional, end_evt->use_trans_cache(),
+ cache_data->is_transactional()));
+ DBUG_ASSERT(is_transactional == end_evt->use_trans_cache() &&
+ is_transactional == cache_data->is_transactional());
+#endif
+ if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
+ DBUG_RETURN(1);
+ /*
+ Doing a commit or a rollback including non-transactional tables,
+ i.e., ending a transaction where we might write the transaction
+ cache to the binary log.
+
+ We can always end the statement when ending a transaction since
+ transactions are not allowed inside stored functions. If they
+ were, we would have to ensure that we're not ending a statement
+ inside a stored function.
+ */
+ error= mysql_bin_log.write(thd, &cache_data->cache_log, end_evt,
+ cache_data->has_incident());
}
+ binlog_compute_statistics(cache_data);
+ cache_data->reset();
- DBUG_ASSERT(cache_mngr->trx_cache.empty());
+ DBUG_ASSERT(cache_data->empty());
DBUG_RETURN(error);
}
/**
+ This function flushes the stmt-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_stmt_cache(THD *thd,
+ binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
+ FALSE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->stmt_cache, &end_evt,
+ FALSE));
+}
+
+/**
+ This function flushes the trx-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("COMMIT"),
+ TRUE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
+ This function flushes the trx-cache upon rollback.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_rollback_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+ Query_log_event end_evt(thd, STRING_WITH_LEN("ROLLBACK"),
+ TRUE, FALSE, TRUE, 0);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
+ This function flushes the trx-cache upon commit.
+
+ @param thd The thread whose transaction should be flushed
+ @param cache_mngr Pointer to the cache manager
+ @param xid Transaction Id
+
+ @return
+ nonzero if an error pops up when flushing the cache.
+*/
+static inline int
+binlog_commit_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
+ my_xid xid)
+{
+ Xid_log_event end_evt(thd, xid);
+ return (binlog_flush_cache(thd, &cache_mngr->trx_cache, &end_evt,
+ TRUE));
+}
+
+/**
This function truncates the transactional cache upon committing or rolling
back either a transaction or a statement.
@@ -1579,23 +1699,26 @@ binlog_truncate_trx_cache(THD *thd, binl
*/
bool const is_transactional= TRUE;
- DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s",
+ DBUG_PRINT("info", ("thd->options={ %s %s}, transaction: %s",
FLAGSTR(thd->variables.option_bits, OPTION_NOT_AUTOCOMMIT),
FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
all ? "all" : "stmt"));
+
+ thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
/*
If rolling back an entire transaction or a single statement not
inside a transaction, we reset the transaction cache.
*/
- thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
if (ending_trans(thd, all))
{
if (cache_mngr->trx_cache.has_incident())
error= mysql_bin_log.write_incident(thd, TRUE);
- cache_mngr->reset_cache(&cache_mngr->trx_cache);
-
thd->clear_binlog_table_maps();
+
+ binlog_compute_statistics(&cache_mngr->trx_cache);
+
+ cache_mngr->reset_cache(&cache_mngr->trx_cache);
}
/*
If rolling back a statement in a transaction, we truncate the
@@ -1620,51 +1743,6 @@ static int binlog_prepare(handlerton *ht
}
/**
- This function flushes the non-transactional to the binary log upon
- committing or rolling back a statement.
-
- @param thd The thread whose transaction should be flushed
- @param cache_mngr Pointer to the cache data to be flushed
-
- @return
- nonzero if an error pops up when flushing the non-transactional cache.
-*/
-static int
-binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
-{
- int error= 0;
- DBUG_ENTER("binlog_flush_stmt_cache");
- /*
- If we are flushing the statement cache, it means that the changes get
- through otherwise the cache is empty and this routine should not be called.
- */
- DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE);
- /*
- This function handles non-transactional changes and as such this flag equals
- to false.
- */
- bool const is_transactional= FALSE;
- IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
-
- if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
- DBUG_RETURN(1);
-
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
- if ((error= mysql_bin_log.write(thd, cache_log, &qev,
- cache_mngr->stmt_cache.has_incident())))
- DBUG_RETURN(error);
- cache_mngr->reset_cache(&cache_mngr->stmt_cache);
-
- statistic_increment(binlog_cache_use, &LOCK_status);
- if (cache_log->disk_writes != 0)
- {
- statistic_increment(binlog_cache_disk_use, &LOCK_status);
- cache_log->disk_writes= 0;
- }
- DBUG_RETURN(error);
-}
-
-/**
This function is called once after each statement.
It has the responsibility to flush the caches to the binary log on commits.
@@ -1690,19 +1768,7 @@ static int binlog_commit(handlerton *hto
YESNO(thd->transaction.all.modified_non_trans_table),
YESNO(thd->transaction.stmt.modified_non_trans_table)));
- if (!cache_mngr->stmt_cache.empty())
- {
- binlog_flush_stmt_cache(thd, cache_mngr);
- }
-
- if (cache_mngr->trx_cache.empty())
- {
- /*
- we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
- */
- cache_mngr->reset_cache(&cache_mngr->trx_cache);
- DBUG_RETURN(0);
- }
+ binlog_commit_flush_stmt_cache(thd, cache_mngr);
/*
We commit the transaction if:
@@ -1711,16 +1777,14 @@ static int binlog_commit(handlerton *hto
Otherwise, we accumulate the changes.
*/
if (ending_trans(thd, all))
- {
- Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
- error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
- }
+ error= binlog_commit_flush_trx_cache(thd, cache_mngr);
/*
This is part of the stmt rollback.
*/
if (!all)
cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
+
DBUG_RETURN(error);
}
@@ -1755,19 +1819,8 @@ static int binlog_rollback(handlerton *h
error= mysql_bin_log.write_incident(thd, TRUE);
cache_mngr->reset_cache(&cache_mngr->stmt_cache);
}
- else if (!cache_mngr->stmt_cache.empty())
- {
- binlog_flush_stmt_cache(thd, cache_mngr);
- }
-
- if (cache_mngr->trx_cache.empty())
- {
- /*
- we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
- */
- cache_mngr->reset_cache(&cache_mngr->trx_cache);
- DBUG_RETURN(0);
- }
+ else
+ binlog_commit_flush_stmt_cache(thd, cache_mngr);
if (mysql_bin_log.check_write_error(thd))
{
@@ -1796,7 +1849,6 @@ static int binlog_rollback(handlerton *h
. the format is MIXED, non-trans table was updated and
aborting a single statement transaction;
*/
-
if (ending_trans(thd, all) &&
((thd->variables.option_bits & OPTION_KEEP_LOG) ||
(trans_has_updated_non_trans_table(thd) &&
@@ -1806,10 +1858,7 @@ static int binlog_rollback(handlerton *h
(trans_has_updated_non_trans_table(thd) &&
ending_single_stmt_trans(thd,all) &&
thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
- {
- Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
- error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
- }
+ error= binlog_rollback_flush_trx_cache(thd, cache_mngr);
/*
Truncate the cache if:
. aborting a single or multi-statement transaction or;
@@ -1832,7 +1881,8 @@ static int binlog_rollback(handlerton *h
This is part of the stmt rollback.
*/
if (!all)
- cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
+ cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
+
DBUG_RETURN(error);
}
@@ -4364,6 +4414,11 @@ int THD::binlog_setup_trx_data()
cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
+#ifndef DBUG_OFF
+ cache_mngr->trx_cache.set_transactional(TRUE);
+ cache_mngr->stmt_cache.set_transactional(FALSE);
+#endif
+
DBUG_RETURN(0);
}
@@ -6291,15 +6346,14 @@ void TC_LOG_BINLOG::close()
int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
{
DBUG_ENTER("TC_LOG_BINLOG::log");
- Xid_log_event xle(thd, xid);
binlog_cache_mngr *cache_mngr=
(binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
/*
We always commit the entire transaction when writing an XID. Also
note that the return value is inverted.
*/
- DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) &&
- !binlog_flush_trx_cache(thd, cache_mngr, &xle));
+ DBUG_RETURN(!binlog_commit_flush_stmt_cache(thd, cache_mngr) &&
+ !binlog_commit_flush_trx_cache(thd, cache_mngr, xid));
}
void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc 2010-08-23 22:31:12 +0000
+++ b/sql/log_event.cc 2010-10-06 08:34:49 +0000
@@ -2537,6 +2537,22 @@ Query_log_event::Query_log_event(THD* th
bool trx_cache= FALSE;
cache_type= Log_event::EVENT_INVALID_CACHE;
+#ifndef DBUG_OFF
+ /*
+ If debug is enabled, we make sure that begin, commit and rollback
+ have the cache_type exclusively defined by the param using_trans.
+ as this is important while checking if the correct cache is used.
+
+ Note this is the only way to accurately set the type of the cache
+ when a begin, commit or rollback event is created because such
+ events may be artificially produced to compose the binary log.
+ */
+ if (strncmp("BEGIN", query_arg, query_length) &&
+ strncmp("COMMIT", query_arg, query_length) &&
+ strncmp("ROLLBACK", query_arg, query_length))
+ {
+#endif
+
switch (lex->sql_command)
{
case SQLCOM_DROP_TABLE:
@@ -2574,6 +2590,15 @@ Query_log_event::Query_log_event(THD* th
cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
else
cache_type= Log_event::EVENT_STMT_CACHE;
+
+#ifndef DBUG_OFF
+ }
+ else if (using_trans)
+ cache_type= Log_event::EVENT_TRANSACTIONAL_CACHE;
+ else
+ cache_type= Log_event::EVENT_STMT_CACHE;
+#endif
+
DBUG_ASSERT(cache_type != Log_event::EVENT_INVALID_CACHE);
DBUG_PRINT("info",("Query_log_event has flags2: %lu sql_mode: %lu",
(ulong) flags2, sql_mode));
=== modified file 'sql/log_event.h'
--- a/sql/log_event.h 2010-07-15 13:47:50 +0000
+++ b/sql/log_event.h 2010-10-06 08:34:49 +0000
@@ -2504,7 +2504,7 @@ class Xid_log_event: public Log_event
my_xid xid;
#ifdef MYSQL_SERVER
- Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg,0,0), xid(x) {}
+ Xid_log_event(THD* thd_arg, my_xid x): Log_event(thd_arg, 0, TRUE), xid(x) {}
#ifdef HAVE_REPLICATION
void pack_info(Protocol* protocol);
#endif /* HAVE_REPLICATION */
Attachment: [text/bzr-bundle] bzr/alfranio.correia@oracle.com-20101006083449-9p236n0arpkrx1sq.bundle