Hi Alfranio,
Good work. Thanks for the nice online discussion about this.
I have posted some comments inline.
On Wed, 2009-05-27 at 09:37 +0000, Alfranio Correia wrote:
> #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-27
> 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 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
>
> 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-27 09:37:34 +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-27 09:37:34 +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-27 09:37:34 +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-27 09:37:34
> +0000
> @@ -0,0 +1,133 @@
> +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;
>
> +########################################################################################
> +# SINGLE STATEMENT
>
> +########################################################################################
> +BEGIN;
> +Got one of the listed errors
> +Got one of the listed errors
> +source include/diff_master_slave.inc;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +2
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +2
> +TRUNCATE TABLE t1;
> +BEGIN;
> +Got one of the listed errors
> +Got one of the listed errors
> +Got one of the listed errors
> +BEGIN;
> +INSERT INTO t1(a, data) VALUES (17, 's');
> +INSERT INTO t1(a, data) VALUES (18, 's');
> +COMMIT;
> +source include/diff_master_slave.inc;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7203
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7203
>
> +########################################################################################
> +# BEGIN - COMMIT
>
> +########################################################################################
> +TRUNCATE TABLE t1;
> +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;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7201
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7201
>
> +########################################################################################
> +# BEGIN - ROLLBACK
>
> +########################################################################################
> +TRUNCATE TABLE t1;
> +BEGIN;
> +Got one of the listed errors
> +Got one of the listed errors
> +Got one of the listed errors
> +ROLLBACK;
> +source include/diff_master_slave.inc;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +NULL
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +NULL
>
> +########################################################################################
> +# PROCEDURE
>
> +########################################################################################
> +TRUNCATE TABLE t1;
> +CREATE PROCEDURE p1(pd VARCHAR(2500))
> +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;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +NULL
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +NULL
>
> +########################################################################################
> +# XID
>
> +########################################################################################
> +TRUNCATE TABLE t1;
> +BEGIN;
> +Got one of the listed errors
> +Got one of the listed errors
> +Got one of the listed errors
> +ROLLBACK TO sv;
> +COMMIT;
> +source include/diff_master_slave.inc;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7200
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +7200
>
> +########################################################################################
> +# NON-TRANS TABLE
>
> +########################################################################################
> +TRUNCATE TABLE t1;
> +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;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +SUM(LENGTH(data))
> +4801
> +BEGIN;
> +Got one of the listed errors
>
> +########################################################################################
> +# CLEAN
>
> +########################################################################################
>
> === 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-27 09:37:34
> +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-27 09:37:34
> +0000
> @@ -0,0 +1,272 @@
>
> +########################################################################################
> +# This test verifies if the binlog is not corrupted when the cache buffer is not
> +# big enough to accomodate the updates.
>
> +########################################################################################
Please, add a brief summary for each of the test cases below.
I would also suggest that some extra tests with: 1. temporary tables and
2. autocommit with multiple tables (some non-transactional).
>
> +########################################################################################
> +# Configuring the environment
>
> +########################################################################################
> +-- source include/have_innodb.inc
> +--source include/master-slave.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;
> +
> +--source suite/rpl/include/bug43929_binlog.sql
> +
> +--echo
> ########################################################################################
> +--echo # SINGLE STATEMENT
> +--echo
> ########################################################################################
> +
> +connection master;
> +
> +BEGIN;
> +--disable_query_log
> +eval INSERT INTO t1 (a, data) VALUES (0,'a');
> +--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
> +eval INSERT INTO t1 (a, data) VALUES (1,
> + CONCAT($data, $data, $data, $data, $data));
> +--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
> +eval INSERT INTO t1 (a, data) VALUES (2,
> + CONCAT($data, $data, $data, $data, $data));
> +eval INSERT INTO t1 (a, data) VALUES (4,'a');
> +--disable_query_log
> +COMMIT;
> +
> +let $diff_statement= SELECT * FROM t1;
> +--source include/diff_master_slave.inc
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +#--echo
> ########################################################################################
> +#--echo # BEGIN - BEGIN
> +#--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +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');
> +--enable_query_log
> +
> +BEGIN;
> +INSERT INTO t1(a, data) VALUES (17, 's');
> +INSERT INTO t1(a, data) VALUES (18, 's');
> +COMMIT;
> +
> +let $diff_statement= SELECT * FROM t1;
> +--source include/diff_master_slave.inc
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +--echo
> ########################################################################################
> +--echo # BEGIN - COMMIT
> +--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +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');
> +--enable_query_log
> +COMMIT;
> +
> +let $diff_statement= SELECT * FROM t1;
> +--source include/diff_master_slave.inc
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +--echo
> ########################################################################################
> +--echo # BEGIN - ROLLBACK
> +--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +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');
> +--enable_query_log
> +ROLLBACK;
> +
> +let $diff_statement= SELECT * FROM t1;
> +--source include/diff_master_slave.inc
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +--echo
> ########################################################################################
> +--echo # PROCEDURE
> +--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +DELIMITER //;
> +
> +CREATE PROCEDURE p1(pd VARCHAR(2500))
> +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
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +--echo
> ########################################################################################
> +--echo # XID
> +--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +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);
> +SAVEPOINT sv;
> +--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');
> +--enable_query_log
> +ROLLBACK TO sv;
> +COMMIT;
> +
> +let $diff_statement= SELECT * FROM t1;
> +--source include/diff_master_slave.inc
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +connection slave;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +--echo
> ########################################################################################
> +--echo # NON-TRANS TABLE
> +--echo
> ########################################################################################
> +
> +connection master;
> +TRUNCATE TABLE t1;
> +
> +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');
> +--enable_query_log
> +COMMIT;
> +
> +connection master;
> +SELECT SUM(LENGTH(data)) FROM t1;
> +
> +BEGIN;
> +--disable_query_log
> +--eval INSERT INTO t1 (a, data) VALUES (12, $data);
> +--eval INSERT INTO t1 (a, data) VALUES (13, $data);
> +--eval INSERT INTO t2 (a, data) VALUES (14, $data);
> +--error ER_TRANS_CACHE_FULL, ER_BINLOG_LOGGING_IMPOSSIBLE
> +--eval INSERT INTO t1 (a, data) VALUES (15, $data);
> +COMMIT;
> +
> +connection slave;
> +--source include/wait_for_slave_sql_to_stop.inc
> +
> +--echo
> ########################################################################################
> +--echo # CLEAN
> +--echo
> ########################################################################################
> +
> +connection master;
> +DROP TABLE t1;
> +DROP TABLE t2;
> +DROP PROCEDURE p1;
> +connection slave;
> +DROP TABLE t1;
> +DROP TABLE t2;
> +DROP PROCEDURE p1;
>
> === modified file 'sql/log.cc'
> --- a/sql/log.cc 2009-04-09 15:25:25 +0000
> +++ b/sql/log.cc 2009-05-27 09:37:34 +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,8 +1568,9 @@ 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 ||
> + 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))
> {
Check that OPTION_KEEP_LOG does not have side effects on this patch.
> /*
> @@ -1561,8 +1585,7 @@ 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
This comment is a bit ambiguous now. Please make it more clear.
> @@ -1570,12 +1593,57 @@ static int binlog_rollback(handlerton *h
> log.
> */
> error= binlog_end_trans(thd, trx_data, 0, all);
> + if (thd->transaction.all.modified_non_trans_table &&
> + !trx_data->has_incident() &&
> mysql_bin_log.check_write_error(thd))
> + {
>From handler.cc:
" In autocommit mode thd->transaction.all is empty.
Instead, data of thd->transaction.stmt is
used to commit/rollback the normal transaction. "
Probably you are missing another condition in the if above:
if (( thd->transaction.all.modified_non_trans_table ||
thd->transaction.stmt.modified_non_trans_table ) && ...
> + 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);
> + }
> }
> 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 +3919,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 +3994,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 +4046,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;
> }
> /*
> @@ -4071,10 +4140,10 @@ 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_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
> + 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-27 09:37:34 +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-27 09:37:34 +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-27 09:37:34 +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-27 09:37:34 +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
> }
>
Regards,
Luís