List:Commits« Previous MessageNext Message »
From:Alfranio Correia Date:May 29 2009 10:30am
Subject:bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2912)
Bug#43929
View as plain text  
#At file:///home/acorreia/workspace.sun/repository.mysql/bzrwork/bug-43929/mysql-5.1-bugteam/ based on revid:bjorn.munch@stripped

 2912 Alfranio Correia	2009-05-29
      BUG#43929 binlog corruption when max_binlog_cache_size is exceeded
      
      Large transactions and statements may corrupt the binary log if the size of the
      cache, which is set by the max_binlog_cache_size, is not enough to store the
      the changes.
      
      In a nutshell, to fix the bug, we save the position of the next character in the
      cache before starting processing a statement. If there is a problem, we simply
      restore the position thus removing any effect of the statement from the cache.
      Unfortunately, to avoid corrupting the binary log, we may end up loosing changes
      on non-transactional tables if they do not fit in the cache. In such cases, we
      store an Incident_log_event in order to stop the slave and alert users that some
      changes were not logged.
      
      Precisely, for every non-transactional changes that cannot fit into the cache, we
      do the following:
        a) its respective statement gives an error
        b) the statement is *not* logged
        c) an incident event is logged
      
      For transactional changes that cannot fit into the cache, we do the following:
        a) its respective statement gives an error
        b) the statement is *not* logged
      
      To work properly, this patch requires that callers to MYSQL_BIN_LOG::write and
      THD::binlog_query handle any error returned and take the appropriate actions
      such as undoing the effects of a statement. We already changed some calls from
      the sql_insert.cc, sql_update.cc and sql_insert.cc modules but the remaining
      calls spread all over the code should be handled in BUG#37148.

    added:
      mysql-test/suite/rpl/include/bug43929_binlog.sql
      mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result
      mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt
      mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test
    modified:
      mysql-test/include/commit.inc
      mysql-test/r/commit_1innodb.result
      sql/log.cc
      sql/log.h
      sql/sql_delete.cc
      sql/sql_insert.cc
      sql/sql_update.cc
=== modified file 'mysql-test/include/commit.inc'
--- a/mysql-test/include/commit.inc	2009-01-23 12:22:05 +0000
+++ b/mysql-test/include/commit.inc	2009-05-29 10:20:18 +0000
@@ -669,13 +669,9 @@ call p_verify_status_increment(1, 0, 1, 
 insert t1 set a=3;
 call p_verify_status_increment(2, 2, 2, 2);
 savepoint a;
-call p_verify_status_increment(0, 0, 0, 0);
+call p_verify_status_increment(1, 0, 0, 0);
 insert t1 set a=4;
---echo # Binlog does not register itself this time for other than the 1st
---echo # statement of the transaction with MIXED/STATEMENT binlog_format.
---echo # It needs registering with the ROW format. Therefore 1,0,2,2 are 
---echo # the correct arguments to this test after bug#40221 fixed.
-call p_verify_status_increment(1, 0, 2, 2);
+call p_verify_status_increment(2, 2, 2, 2);
 release savepoint a;
 rollback;
 call p_verify_status_increment(0, 0, 0, 0);

=== modified file 'mysql-test/r/commit_1innodb.result'
--- a/mysql-test/r/commit_1innodb.result	2009-02-10 14:44:58 +0000
+++ b/mysql-test/r/commit_1innodb.result	2009-05-29 10:20:18 +0000
@@ -766,15 +766,11 @@ call p_verify_status_increment(2, 2, 2, 
 SUCCESS
 
 savepoint a;
-call p_verify_status_increment(0, 0, 0, 0);
+call p_verify_status_increment(1, 0, 0, 0);
 SUCCESS
 
 insert t1 set a=4;
-# Binlog does not register itself this time for other than the 1st
-# statement of the transaction with MIXED/STATEMENT binlog_format.
-# It needs registering with the ROW format. Therefore 1,0,2,2 are 
-# the correct arguments to this test after bug#40221 fixed.
-call p_verify_status_increment(1, 0, 2, 2);
+call p_verify_status_increment(2, 2, 2, 2);
 SUCCESS
 
 release savepoint a;

=== added file 'mysql-test/suite/rpl/include/bug43929_binlog.sql'
--- a/mysql-test/suite/rpl/include/bug43929_binlog.sql	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/include/bug43929_binlog.sql	2009-05-29 10:20:18 +0000
@@ -0,0 +1,36 @@
+let $data='vb
+alxxMCC5o X3dAkvHXY,WhFV72Z6;oNHpL,WfTAOYKMdb8OQ tUfYXjlNcois8V7hcnk5;.ixojWOcBpMGOVQl9,p3	v313eQ3j6mbGH7nh3sQeJn,
+G aEbB8 :YorJ1 wPzDerR8kLazeliXwxedpxhNUel0XpBO.KLdjNW MGlkaNSbtQVpfcmR wZPeyLWK0avXphFRd:5c4dCEMC XHsZvEZy Q1CrNIGTaJuKIkH5UEaDuacHzICkRugIn	nW1Z MHYV7w d ZYA:U;V4Kku99ioob4TQHlLlanD RH	vUq64phzC77pPIhf3PWxlB	dLhimAG ;l0UMCqxV2alAHV  iW,uIfp2,UH2	7Kf
+dJHeh4VmzxmAP6lG6ih2uIwfl;KwcLN	qGrF70W , :QxfiB	X7	dhEMEP: r3RllCaS.CTCCBaMQa;87vvEZnO6NmLsoEeoQx:zG6UTKvHRSyWcYC7bcWDF,jngS7QNZQwyoY H7ZC0ocebLf NpTy42NJ cupL	LYQ7Xg2X16h2T
+csX,sqT B	hRDsocDBBuu9j Iz9k EL1VuamulUc3zsFHI.dKWQRyCPTE0NEiy4eMNhBT4 L1Klqey YmWYuXZkrFUV89c:AONXIg
+ DsvgkPgNwZOTi; 9DGec F2XHLWH1yY R1Cjh	5PmE60jAl3B4SOz.coG:Oy.G boG 4;kZRTpIBda3eG3S6
+s2;	Y.a	vEV:MZKvOf6
+U3jkTX49wafxd;i:gJ
+sxTpvLa2B2jj 4cBG Bazi5  XpKqfTcBW0iUhKDlD6KamzWUk
+R9i
+n,STLTyG6DP:WH1fmw5:N wmQU3kpSJsGeXwxJ	.BnmaMdcfqqinSpryqgTBvQ	,B:feTao.xkF.:l tY	pW3u;D CbU
+8ahKp4rteHuaX
+, zXZ4kT 9DX;8Rwwi6JNaDWkSO6JHtjczuZat.NxW,UM0w2s5gCOgbx:jlfEeq4XDe1xsFHORNa 0RTT	ftMPj7eqP OkqUteCtOyfweMZ;LdvYwGFjM7xOfa9jSQv6Ypmhd;MIZ.rBb,p7Ce3aPDra8eoKy6YxLsqxPIzAO  pZPVTrmmj7Jyc.QVmF57gdRMv3X8kXcvTz TArOZ wZr4acAu8eJjr
+7Z;.Sy3p9nGivSprQjVR:X0,Af4iYk,WAoXRyT tu09b6c:v.Ci 7EMjstiR7,f	L653d hfswxvY;IB.gWXEVFn3EhhxoYCcL0fftXcf Ec3ZW9 A2hYMa;F9GWeCvshNZc2:Bwa5VzwaarfVpf
+HSA4iREIbgg		a,;61.
+
+5 rnGNC	CsaoRevNeDjhN80 wB.bS7oL ,ioctAQWi9gQS 6pV .pgLtnbPA:gEz:Mq:DkAtpulNoziTWitVAoMu;zwrKibXoQEHU0ji4CJ4GSUuzZ,yrmPe1Tx	2n8mJ15Aa7f
+abtu
+rgaf
+yWY2m8pM2Ps gmiMdJXiYQkU0Girlk;OhB;mdClF.dWhvl:NhkIUoWEO0b6b13pxB3XXa3V Kr3l.edsfoX950p:cmPPlNrOiAl.Oat934PC
+dM	hBgUUk:RCgi.uGTu.tG0Umia7	9.2u1L.yE6ToYn7sB;aF9mups.v3XJYJh3gkaOojNU7:;Q2OpiIrnee1VRn 6q DY9nFwe9zjZ8ciJ 	oUQLaEooVFhuner;ZFRO2
+lHu:w0Lu
+dajd2lZ3FBw
+j
+X
+aaUARW xmaccUvRc3b6V5nrVHnOTQFpWYCoqvat1dtNl8aY
+KEa6YzWL8,Le53mjfK
+FQp8r4RFOj7:xVSWr1GQbKKXiKd4C7tblGaSy8VU9w7Wkr6 SVKaJn6Nd1hWymraIH0K13bb3 K,0ersTE.hX2
+Z xS1lC98j,g9V:4kU1E ZR;Fhpa2Jfr3MY:Vsz
+T1c2aV8q5b4;NCEnu5;M5S.i9	tI1EIK;Lban	Z
+06nyfms94A7ukJ2h8utxZSa6PX52k81L1VR 6Z TXlVfLa;18bSy;LhHpOY,B3Z0 e5N0WXgVqh,1AV25CHLJ;yFtz;Pr011 Mqhya.phYDvzzJYrPY6;Znji
+cYC2kIv;FqS otKpKQ:hOThDkwU2AnGZs848aF6kH1rgyRJWGcihB
+kXhjBfb0zM2bL,Jmpb3K3GEIMNzc35V	THnO495KjefyL.Lvfmt  nk saDs qo;hHpOW,;12
+ZTXRWxxt
+qKIfVus3D:mvPd8wq4Vw0cItYLeta2E6MP78kdJlBPxGbtSRyPtG6MD4GNYIroTNohSWwiy5v0iXeFzeaDkdb:qfK9eICd LD	GStfa
+mOe,Uhs ul;Ziev3 mleNCPku8aDKovqPd,OX:JN	3,Sb 9WwS:gprHC	 n6E1';

=== added file 'mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result'
--- a/mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_binlog_max_cache_size.result	2009-05-29 10:20:18 +0000
@@ -0,0 +1,137 @@
+stop slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+reset master;
+reset slave;
+drop table if exists t1,t2,t3,t4,t5,t6,t7,t8,t9;
+start slave;
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MyIsam;
+CREATE TABLE t3(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+########################################################################################
+#                                   1 - SINGLE STATEMENT
+########################################################################################
+*** Single statment on transactional table ***
+Got one of the listed errors
+*** Single statment on non-transactional table ***
+*** After WL#2687 the difference between STATEMENT/MIXED and ROW will not exist. ***
+Got one of the listed errors
+*** Single statment on both transactional and non-transactional tables. ***
+*** After WL#2687 we will be able to change the order of the tables. ***
+Got one of the listed errors
+RESET MASTER;
+STOP SLAVE;
+RESET SLAVE;
+START SLAVE;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+source include/diff_master_slave.inc;
+########################################################################################
+#                                     3 - BEGIN - COMMIT
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+COMMIT;
+source include/diff_master_slave.inc;
+########################################################################################
+#                                      4 - BEGIN - ROLLBACK
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+ROLLBACK;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+source include/diff_master_slave.inc;
+########################################################################################
+#                                         5 - PROCEDURE 
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+CREATE PROCEDURE p1(pd VARCHAR(30000))
+BEGIN
+INSERT INTO t1 (a, data) VALUES (1, pd);
+INSERT INTO t1 (a, data) VALUES (2, pd);
+INSERT INTO t1 (a, data) VALUES (3, pd);
+INSERT INTO t1 (a, data) VALUES (4, pd);
+INSERT INTO t1 (a, data) VALUES (5, 's');
+END//
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t1;
+BEGIN;
+Got one of the listed errors
+COMMIT;
+TRUNCATE TABLE t1;
+BEGIN;
+Got one of the listed errors
+ROLLBACK;
+source include/diff_master_slave.inc;
+########################################################################################
+#                                           6 - XID
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+ROLLBACK TO sv;
+Warnings:
+Warning	1196	Some non-transactional changed tables couldn't be rolled back
+COMMIT;
+source include/diff_master_slave.inc;
+########################################################################################
+#                                        7 - NON-TRANS TABLE
+########################################################################################
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+BEGIN;
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+Got one of the listed errors
+COMMIT;
+BEGIN;
+Got one of the listed errors
+COMMIT;
+########################################################################################
+#                                        CLEAN
+########################################################################################
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;

=== added file 'mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt'
--- a/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size-master.opt	2009-05-29 10:20:18 +0000
@@ -0,0 +1 @@
+--binlog_cache_size=4096 --max_binlog_cache_size=8192

=== added file 'mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test'
--- a/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_binlog_max_cache_size.test	2009-05-29 10:20:18 +0000
@@ -0,0 +1,404 @@
+########################################################################################
+#    This test verifies if the binlog is not corrupted when the cache buffer is not
+#    big enough to accommodate the updates.
+#
+#    1 - Single Statements:
+#    1.1 - Single statement on transactional table.
+#    1.2 - Single statement on non-transactional table. 
+#    1.3 - Single statement on both transactional and non-transactional tables.
+#    In both 1.2 and 1.3, an incident event is logged to notify the user that the
+#    master and slave are diverging.
+#
+#    2 - Transactions ended by an implicit commit.
+#
+#    3 - Transactions ended by a COMMIT.
+#
+#    4 - Transactions ended by a ROLLBACK.
+#
+#    5 - Transactions with a failing statement that updates a non-transactional
+#    table. In this case, a failure means that the statement does not get into
+#    the cache and an incident event is logged to notify the user that the master
+#    and slave are diverging.
+#    
+########################################################################################
+
+########################################################################################
+#                                Configuring the environment
+########################################################################################
+--source include/have_innodb.inc
+--source include/master-slave.inc
+--source include/not_embedded.inc
+--source include/not_windows.inc
+
+CREATE TABLE t1(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+CREATE TABLE t2(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=MyIsam;
+CREATE TABLE t3(a INT PRIMARY KEY, data VARCHAR(30000)) ENGINE=Innodb;
+
+--source suite/rpl/include/bug43929_binlog.sql
+
+--echo ########################################################################################
+--echo #                                   1 - SINGLE STATEMENT
+--echo ########################################################################################
+
+connection master;
+
+--echo *** Single statment on transactional table ***
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+eval INSERT INTO t1 (a, data) VALUES (1,
+     CONCAT($data, $data, $data, $data, $data));
+--enable_query_log
+
+--echo *** Single statment on non-transactional table ***
+--echo *** After WL#2687 the difference between STATEMENT/MIXED and ROW will not exist. ***
+--disable_query_log
+--disable_warnings
+if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
+{
+  eval INSERT INTO t2 (a, data) VALUES (2,
+       CONCAT($data, $data, $data, $data, $data, $data));
+  --echo Got one of the listed errors
+}
+if (`SELECT @@binlog_format = 'ROW'`)
+{
+  --error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+  eval INSERT INTO t2 (a, data) VALUES (2,
+       CONCAT($data, $data, $data, $data, $data, $data));
+
+  RESET MASTER;
+  connection slave;
+  --source include/wait_for_slave_sql_to_stop.inc
+  STOP SLAVE;
+  --source include/wait_for_slave_to_stop.inc
+  RESET SLAVE;
+  START SLAVE;
+  --source include/wait_for_slave_to_start.inc
+}
+--enable_warnings
+--enable_query_log
+
+connection master;
+
+--disable_query_log
+eval INSERT INTO t1 (a, data) VALUES (3, $data);
+eval INSERT INTO t1 (a, data) VALUES (4, $data);
+eval INSERT INTO t1 (a, data) VALUES (5, $data);
+eval INSERT INTO t2 (a, data) VALUES (3, $data);
+eval INSERT INTO t2 (a, data) VALUES (4, $data);
+eval INSERT INTO t2 (a, data) VALUES (5, $data);
+--enable_query_log
+
+--echo *** Single statment on both transactional and non-transactional tables. ***
+--echo *** After WL#2687 we will be able to change the order of the tables. ***
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+eval UPDATE t2, t1 SET t2.data = CONCAT($data, $data, $data, $data),
+                       t1.data = CONCAT($data, $data, $data, $data);
+--enable_query_log
+
+RESET MASTER;
+connection slave;
+--source include/wait_for_slave_sql_to_stop.inc
+STOP SLAVE;
+--source include/wait_for_slave_to_stop.inc
+RESET SLAVE;
+START SLAVE;
+--source include/wait_for_slave_to_start.inc
+
+#--echo ########################################################################################
+#--echo #                             2 - BEGIN - IMPLICIT COMMIT by DDL
+#--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+
+--disable_query_log
+ALTER TABLE t3 ADD COLUMN d int;
+--enable_query_log
+
+--disable_query_log
+--eval INSERT INTO t2 (a, data) VALUES (10, $data);
+--eval INSERT INTO t2 (a, data) VALUES (11, $data);
+--eval INSERT INTO t2 (a, data) VALUES (12, $data);
+--eval INSERT INTO t2 (a, data) VALUES (13, $data);
+--enable_query_log
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (14, $data);
+--eval INSERT INTO t1 (a, data) VALUES (15, $data);
+--eval INSERT INTO t1 (a, data) VALUES (16, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (17, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (18, $data);
+--eval INSERT INTO t1 (a, data) VALUES (19, 's');
+--eval INSERT INTO t2 (a, data) VALUES (20, 's');
+--eval INSERT INTO t1 (a, data) VALUES (21, 's');
+--enable_query_log
+
+if (`SELECT @@binlog_format = 'STATEMENT' || @@binlog_format = 'MIXED'`)
+{
+  --disable_query_log
+  CREATE TABLE t4 SELECT * FROM t1;
+  --enable_query_log
+  --echo Got one of the listed errors
+}
+if (`SELECT @@binlog_format = 'ROW'`)
+{
+  --disable_query_log
+  --error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+  CREATE TABLE t4 SELECT * FROM t1;
+  --enable_query_log
+}
+
+--disable_query_log
+--eval INSERT INTO t2 (a, data) VALUES (15, $data);
+--enable_query_log
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (22, $data);
+--eval INSERT INTO t1 (a, data) VALUES (23, $data);
+--eval INSERT INTO t1 (a, data) VALUES (24, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (25, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (26, $data);
+--eval INSERT INTO t1 (a, data) VALUES (27, 's');
+--eval INSERT INTO t2 (a, data) VALUES (28, 's');
+--eval INSERT INTO t1 (a, data) VALUES (29, 's');
+--enable_query_log
+
+--disable_query_log
+CREATE TABLE t5 (a int);
+--enable_query_log
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo #                                     3 - BEGIN - COMMIT
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+COMMIT;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo #                                      4 - BEGIN - ROLLBACK
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+ROLLBACK;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo #                                         5 - PROCEDURE 
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+DELIMITER //;
+
+CREATE PROCEDURE p1(pd VARCHAR(30000))
+BEGIN
+  INSERT INTO t1 (a, data) VALUES (1, pd);
+  INSERT INTO t1 (a, data) VALUES (2, pd);
+  INSERT INTO t1 (a, data) VALUES (3, pd);
+  INSERT INTO t1 (a, data) VALUES (4, pd);
+  INSERT INTO t1 (a, data) VALUES (5, 's');
+END//
+
+DELIMITER ;//
+
+TRUNCATE TABLE t1;
+
+--disable_query_log
+eval CALL p1($data);
+--enable_query_log
+
+TRUNCATE TABLE t1;
+
+BEGIN;
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+eval CALL p1($data);
+--enable_query_log
+COMMIT;
+
+TRUNCATE TABLE t1;
+
+BEGIN;
+--disable_query_log
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+eval CALL p1($data);
+--enable_query_log
+ROLLBACK;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo #                                           6 - XID
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t1 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+SAVEPOINT sv;
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (5, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (6, $data);
+--eval INSERT INTO t1 (a, data) VALUES (7, 's');
+--eval INSERT INTO t2 (a, data) VALUES (8, 's');
+--eval INSERT INTO t1 (a, data) VALUES (9, 's');
+--enable_query_log
+ROLLBACK TO sv;
+COMMIT;
+
+let $diff_statement= SELECT * FROM t1;
+--source include/diff_master_slave.inc
+
+--echo ########################################################################################
+--echo #                                        7 - NON-TRANS TABLE
+--echo ########################################################################################
+
+connection master;
+TRUNCATE TABLE t1;
+TRUNCATE TABLE t2;
+TRUNCATE TABLE t3;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (1, $data);
+--eval INSERT INTO t1 (a, data) VALUES (2, $data);
+--eval INSERT INTO t2 (a, data) VALUES (3, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (4, $data);
+--eval INSERT INTO t2 (a, data) VALUES (5, $data);
+--eval INSERT INTO t2 (a, data) VALUES (6, $data);
+--eval INSERT INTO t2 (a, data) VALUES (7, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (8, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (9, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (10, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval UPDATE t2 SET data= CONCAT($data, $data);
+--eval INSERT INTO t1 (a, data) VALUES (11, 's');
+--eval INSERT INTO t1 (a, data) VALUES (12, 's');
+--eval INSERT INTO t2 (a, data) VALUES (13, 's');
+--eval INSERT INTO t1 (a, data) VALUES (14, 's');
+--enable_query_log
+COMMIT;
+
+BEGIN;
+--disable_query_log
+--eval INSERT INTO t1 (a, data) VALUES (15, $data);
+--eval INSERT INTO t1 (a, data) VALUES (16, $data);
+--eval INSERT INTO t2 (a, data) VALUES (17, $data);
+--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
+--eval INSERT INTO t1 (a, data) VALUES (18, $data);
+--enable_query_log
+COMMIT;
+
+connection slave;
+--source include/wait_for_slave_sql_to_stop.inc
+
+--echo ########################################################################################
+--echo #                                        CLEAN
+--echo ########################################################################################
+
+--disable_warnings
+connection master;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+connection slave;
+DROP TABLE t1;
+DROP TABLE t2;
+DROP TABLE t3;
+DROP TABLE IF EXISTS t4;
+DROP TABLE IF EXISTS t5;
+DROP TABLE IF EXISTS t6;
+DROP PROCEDURE p1;
+--enable_warnings

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2009-04-09 15:25:25 +0000
+++ b/sql/log.cc	2009-05-29 10:20:18 +0000
@@ -153,9 +153,10 @@ private:
 class binlog_trx_data {
 public:
   binlog_trx_data()
-    : at_least_one_stmt(0), m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF)
+    : at_least_one_stmt(0), incident(FALSE), m_pending(0),
+    before_stmt_pos(MY_OFF_T_UNDEF)
   {
-    trans_log.end_of_file= max_binlog_cache_size;
+    calculate_cache_size();
   }
 
   ~binlog_trx_data()
@@ -184,6 +185,7 @@ public:
     delete pending();
     set_pending(0);
     reinit_io_cache(&trans_log, WRITE_CACHE, pos, 0, 0);
+    calculate_cache_size();
     if (pos < before_stmt_pos)
       before_stmt_pos= MY_OFF_T_UNDEF;
 
@@ -206,7 +208,8 @@ public:
     if (!empty())
       truncate(0);
     before_stmt_pos= MY_OFF_T_UNDEF;
-    trans_log.end_of_file= max_binlog_cache_size;
+    incident= FALSE;
+    calculate_cache_size();
     DBUG_ASSERT(empty());
   }
 
@@ -222,11 +225,29 @@ public:
 
   IO_CACHE trans_log;                         // The transaction cache
 
+  void set_incident(void)
+  {
+    incident= TRUE;
+  }
+  
+  bool has_incident(void)
+  {
+    return(incident);
+  }
+
+  my_off_t calculate_cache_size(void)
+  {
+    my_off_t diff= (incident ? 0 : reserved_cache_size);
+    trans_log.end_of_file= (((max_binlog_cache_size - diff) < IO_SIZE) ?
+                            IO_SIZE : (max_binlog_cache_size - diff));
+    return trans_log.end_of_file;
+  }
   /**
     Boolean that is true if there is at least one statement in the
     transaction cache.
   */
   bool at_least_one_stmt;
+  bool incident;
 
 private:
   /*
@@ -240,6 +261,7 @@ public:
     Binlog position before the start of the current statement.
   */
   my_off_t before_stmt_pos;
+  static const my_off_t reserved_cache_size= 512;
 };
 
 handlerton *binlog_hton;
@@ -1391,7 +1413,8 @@ binlog_end_trans(THD *thd, binlog_trx_da
   */
   if (end_ev != NULL)
   {
-    thd->binlog_flush_pending_rows_event(TRUE);
+    if (thd->binlog_flush_pending_rows_event(TRUE))
+      DBUG_RETURN(1);
     /*
       Doing a commit or a rollback including non-transactional tables,
       i.e., ending a transaction where we might write the transaction
@@ -1545,9 +1568,11 @@ static int binlog_rollback(handlerton *h
                        YESNO(all),
                        YESNO(thd->transaction.all.modified_non_trans_table),
                        YESNO(thd->transaction.stmt.modified_non_trans_table)));
-  if (all && thd->transaction.all.modified_non_trans_table ||
-      !all && thd->transaction.stmt.modified_non_trans_table ||
-      (thd->options & OPTION_KEEP_LOG))
+  if ((all && thd->transaction.all.modified_non_trans_table) ||
+      (!all && thd->transaction.stmt.modified_non_trans_table &&
+       !mysql_bin_log.check_write_error(thd)) ||
+      ((thd->options & OPTION_KEEP_LOG) &&
+        !mysql_bin_log.check_write_error(thd)))
   {
     /*
       We write the transaction cache with a rollback last if we have
@@ -1561,21 +1586,82 @@ static int binlog_rollback(handlerton *h
     qev.error_code= 0; // see comment in MYSQL_LOG::write(THD, IO_CACHE)
     error= binlog_end_trans(thd, trx_data, &qev, all);
   }
-  else if (all && !thd->transaction.all.modified_non_trans_table ||
-           !all && !thd->transaction.stmt.modified_non_trans_table)
+  else
   {
     /*
-      If we have modified only transactional tables, we can truncate
-      the transaction cache without writing anything to the binary
-      log.
+      We reach this point if either only transactional tables were modified or
+      the effect of a statement that did not get into the binlog needs to be
+      rolled back. In the later case, if the statement changed non-transactional
+      tables or had the OPTION_KEEP_LOG associated, we write an incident event
+      to the binlog in order to stop the slave and notify users that some
+      changes on the master did not get into the binlog and the slave will be
+      inconsistent. On the other hand, if the statement is transactional is
+      safe to roll it back.
      */
     error= binlog_end_trans(thd, trx_data, 0, all);
+    if ((thd->transaction.all.modified_non_trans_table ||
+         thd->transaction.stmt.modified_non_trans_table ||
+         (thd->options & OPTION_KEEP_LOG)) &&
+        !trx_data->has_incident() && mysql_bin_log.check_write_error(thd))
+    {
+      /* 
+        We need to allocate extra space to write the incident event.
+      */  
+      trx_data->set_incident();
+      trx_data->calculate_cache_size();
+      LEX_STRING const write_error_msg= 
+        { C_STRING_WITH_LEN("error writing to the binary log") };
+      Incident incident= INCIDENT_LOST_EVENTS;
+      Incident_log_event ev(thd, incident, write_error_msg);
+      mysql_bin_log.write(&ev);
+      /* 
+        We need to reset the cache if not in a transaction as there will be no
+        call to commit or rollback a transaction in order to unset the incident
+        flag and the extra space allocated.
+      */  
+      if (!(thd->options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN)))
+        trx_data->reset();    
+    }
   }
   if (!all)
     trx_data->before_stmt_pos = MY_OFF_T_UNDEF; // part of the stmt rollback
   DBUG_RETURN(error);
 }
 
+void MYSQL_BIN_LOG::set_write_error(THD *thd)
+{
+  DBUG_ENTER("set_write_error");
+
+  if (check_write_error(thd))
+    DBUG_VOID_RETURN;
+
+  my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(MY_WME),
+           "Error writing events");
+
+  DBUG_VOID_RETURN;
+}
+
+bool MYSQL_BIN_LOG::check_write_error(THD *thd)
+{
+  DBUG_ENTER("check_write_error");
+
+  bool checked= FALSE;
+
+  if (!thd->is_error())
+    DBUG_RETURN(checked);
+
+  switch (thd->main_da.sql_errno())
+  {
+    case ER_TRANS_CACHE_FULL:
+    case ER_ERROR_ON_WRITE:
+    case ER_BINLOG_LOGGING_IMPOSSIBLE:
+      checked= TRUE;
+    break;
+  }
+
+  DBUG_RETURN(checked);
+}
+
 /**
   @note
   How do we handle this (unlikely but legal) case:
@@ -3851,6 +3937,7 @@ MYSQL_BIN_LOG::flush_and_set_pending_row
     if (pending->write(file))
     {
       pthread_mutex_unlock(&LOCK_log);
+      set_write_error(thd);
       DBUG_RETURN(1);
     }
 
@@ -3925,7 +4012,8 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
   */
   bool const end_stmt=
     thd->prelocked_mode && thd->lex->requires_prelocking();
-  thd->binlog_flush_pending_rows_event(end_stmt);
+  if (thd->binlog_flush_pending_rows_event(end_stmt))
+    DBUG_RETURN(error);
 
   pthread_mutex_lock(&LOCK_log);
 
@@ -3976,8 +4064,7 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
         DBUG_PRINT("info", ("Using trans_log: cache: %d, trans_log_pos: %lu",
                             event_info->get_cache_stmt(),
                             (ulong) trans_log_pos));
-        if (trans_log_pos == 0)
-          thd->binlog_start_trans_and_stmt();
+        thd->binlog_start_trans_and_stmt();
         file= trans_log;
       }
       /*
@@ -4055,7 +4142,8 @@ bool MYSQL_BIN_LOG::write(Log_event *eve
        Write the SQL command
      */
 
-    if (event_info->write(file))
+    if (event_info->write(file) || 
+        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
       goto err;
 
     if (file == &log_file) // we are writing to the real log (disk)
@@ -4071,10 +4159,11 @@ err:
     if (error)
     {
       if (my_errno == EFBIG)
-	my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(0));
+        my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
       else
-	my_error(ER_ERROR_ON_WRITE, MYF(0), name, errno);
-      write_error=1;
+        my_error(ER_BINLOG_LOGGING_IMPOSSIBLE, MYF(MY_WME),
+                 "Error writing events");
+      write_error= 1;
     }
   }
 

=== modified file 'sql/log.h'
--- a/sql/log.h	2009-01-23 12:22:05 +0000
+++ b/sql/log.h	2009-05-29 10:20:18 +0000
@@ -359,6 +359,8 @@ public:
   bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event);
 
   int  write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
+  void set_write_error(THD *thd);
+  bool check_write_error(THD *thd);
 
   void start_union_events(THD *thd, query_id_t query_id_param);
   void stop_union_events(THD *thd);

=== modified file 'sql/sql_delete.cc'
--- a/sql/sql_delete.cc	2009-05-15 13:25:29 +0000
+++ b/sql/sql_delete.cc	2009-05-29 10:20:18 +0000
@@ -404,7 +404,7 @@ cleanup:
                                         thd->query, thd->query_length,
                                         is_trans, FALSE, killed_status);
 
-      if (log_result && transactional_table)
+      if (log_result)
       {
 	error=1;
       }

=== modified file 'sql/sql_insert.cc'
--- a/sql/sql_insert.cc	2009-05-15 12:57:51 +0000
+++ b/sql/sql_insert.cc	2009-05-29 10:20:18 +0000
@@ -893,8 +893,7 @@ bool mysql_insert(THD *thd,TABLE_LIST *t
 	if (thd->binlog_query(THD::ROW_QUERY_TYPE,
 			      thd->query, thd->query_length,
 			      transactional_table, FALSE,
-			      (error>0) ? thd->killed : THD::NOT_KILLED) &&
-	    transactional_table)
+			      (error>0) ? thd->killed : THD::NOT_KILLED))
         {
 	  error=1;
 	}

=== modified file 'sql/sql_update.cc'
--- a/sql/sql_update.cc	2009-05-15 13:03:22 +0000
+++ b/sql/sql_update.cc	2009-05-29 10:20:18 +0000
@@ -799,8 +799,7 @@ int mysql_update(THD *thd,
         thd->clear_error();
       if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                             thd->query, thd->query_length,
-                            transactional_table, FALSE, killed_status) &&
-          transactional_table)
+                            transactional_table, FALSE, killed_status))
       {
         error=1;				// Rollback update
       }
@@ -2079,8 +2078,7 @@ bool multi_update::send_eof()
         thd->clear_error();
       if (thd->binlog_query(THD::ROW_QUERY_TYPE,
                             thd->query, thd->query_length,
-                            transactional_tables, FALSE, killed_status) &&
-          trans_safe)
+                            transactional_tables, FALSE, killed_status))
       {
 	local_error= 1;				// Rollback update
       }


Attachment: [text/bzr-bundle]
Thread
bzr commit into mysql-5.1-bugteam branch (alfranio.correia:2912)Bug#43929Alfranio Correia29 May