List:Commits« Previous MessageNext Message »
From:Andrei Elkin Date:May 3 2010 9:52am
Subject:bzr commit into mysql-5.1-rep+2 branch (aelkin:3146) WL#2540
View as plain text  
#At file:///home/andrei/MySQL/BZR/FIXES/rep2-wl2540-checksum/ based on revid:luis.soares@stripped

 3146 Andrei Elkin	2010-05-03
      wl#2540 replication events checksum
      
      Took over Luis' patch.
      Improved at some points, corrected at some others. That include making
      checksum generating and its verification optional in run time.
      
      Notes:
      
      0. SQL thread has gained a new option to avoid CRC check at reading from
         relay log via the new server flag slave-sql-verify-checksum (ON by default);
         (todo/fixme) a new param to Change_master might fit better.
      2. crc check can be done in recovery, binlog init depending on 
         the server new flag opt_master_verify_binlog_crc (OFF by default).
         The new flag is OFF means the burned fo CRC check is entirely on the client/slave
         side. The slave conducts mandatory check by IO thread if an event has
         marked with CRC flag. 
      
      Side effects:
      
      making the show_binlog_events{,2}.inc macros to reset the input paramaters even though those 
      are of the global scope.
      
      aligning HB init failure handling at the slave side with the existing policy of 
      get_master_().
      
      *Open issue*:  
      
      A. sql/rpl_rli.cc - how to control enable/disable CRC for the FD
         of the relay-log, put disabled at the moment.
      
      B. Improving tests to be log-pos agnostic appeared to be previously
         not-scheduled and huge work.
         Some tests still require work on, incl:
      
      main.flush_block_commit_notembedded 
      main.mysqlbinlog 
      main.ctype_cp932_binlog_stm
      main.multi_update 
      main.mysqlbinlog2
      
         That means mtr does not succeed with any from the list if
         master started with --binlog-crc.
         This patch relies on that fixes for BUG@49741 will take care of the explicit
         values and after merging with the fixes all test will pass with either value
         of opt_binlog_checksum.
     @ client/Makefile.am
        Added checksum.c to Makefile.
     @ client/mysqlbinlog.cc
        A new flag option to verify the possible checksum in event. Is set to ON by default;
        connecting to the online server is done with notifying the server that the client
        is checksum-aware.
     @ mysql-test/include/show_binlog_events.inc
        augmenting binlog_start to account 4 bytes of crc + 1 byte of the checksum alg (crc);
        making the macro to reset the input paramaters after they have been used.
        Another macro invocation is supposed to set the parameters anew.
     @ mysql-test/include/show_binlog_events2.inc
        augmenting binlog_start to account 4 bytes of crc + 1 byte of the checksum alg (crc);
        making the macro to reset the input paramaters even though those are of the global scope.
     @ mysql-test/suite/binlog/r/binlog_checksum.result
        new results file
     @ mysql-test/suite/binlog/t/binlog_checksum.test
        the new tests file to demo binlog file is parsable via mysqlbinlog with the new
        -c option as well as with show binlog events that verifies checksum while processing
        the events.
     @ mysql-test/suite/rpl/r/rpl_checksum.result
        new results file
     @ mysql-test/suite/rpl/t/rpl_checksum-master.opt
        the new option is put to test it as well.
     @ mysql-test/suite/rpl/t/rpl_checksum.test
        New tests file to demo checksum control via the user variables.
        Their default values and possible values are checked.
        Simulation section shows reaction on a possible checksum verification failure
        in three possible cases.
     @ mysql-test/suite/rpl/t/rpl_checksum_cache.test
        checksumming of the trans cache alg is tested here.
     @ sql/log.cc
        Added a new helper function to identify whether the logging target is
        the trans cache;
        Raising the checksum flag for FD of the relay log according to
        slave_sql_verify_checksum option;
        Implementing opt_binlog_checksum changes to force binlog rotation
        so that a particular file contains all event either with checksum or w/o it;
        closing the binlog file to ensure the correct value of checksum flag is stored;
        Changed write_cache so that it fixes the checksum when relative
        positions are set to absolute;
        Master side invocations of Log_event::read_log_event() are augmented with
        the new option master_verify_checksum into the arg list;
     @ sql/log.h
        Adding a bool member to MYSQL_BIN_LOG class to mark the fact of opt_binlog_checksum
        is being changed. The value helps to achive that the being closed and the new 
        opened file will contain the right values of FD's checksum flags in their headers;
        A possible future use item binlog_checksum_alg_id to represent the algorith in use
        is added as an extern.
     @ sql/log_event.cc
        Additionally to Luis' changes
        
                Changed log events write procedure and added code relative to checksum
                checking.  Major changes include:
                
                   i) write_header turns on CRC flags and changes length
                      conditionally, whether the binlog crc flag is on or not;
                
                  ii) ::write(...) is implemented as write_header && write_body &&
                      write_footer.  write_header and write_body functions, compute
                      aggregated checksums. The write_footer function appends the
                      computed checksum to the file.
                
                 iii) Calls to my_b_safe_write are intercepted
                      (Log_event::wrapper_my_b_safe_write) and before writing with
                      my_b_safe_write, crc computation takes place (if binlog crc
                      option is set);
                
                  iv) static write_str function gets an IN/OUT parameter (ha_checksum
                      *crc), so that it computes the CRC inside;
                
                   v) Changed write_data so that it takes an IN/OUT parameter
                      (ha_checksum *crc), so that it hands the aggregated CRC to
                      write_str inside;
                
                  vi) Added conditional checksum check to
                      Log_event::read_log_event. The check only takes place if event
                      being read is marked with checksum flag.
                
                 vii) Log_event::read_log_event truncates event length to
                      event_length-BINLOG_CRC_LEN before instanciating new events;
                
                viii) crc field of log event read is set to the value read from the
                      buffer. This is useful for mysqlbinlog printing the "CRC" and
                      its hex-value line.
                
                  iv) Added printing of "CRC"-and-its-hex-value for mysqlbinlog.
         
        the following are done:
        
        1. crc_check arg is added to  Log_event::read_log_event(FD) method.
        The new arg is set to 
             opt_master_verify_binlog_checksum value
        for invocations that are done on the "master" side that include recovery,   binlog initialization (init_server_components()), init_relay_log_info(), few others annotated separately pre file.
        
        2. my_checksum is invoked with caution when the len arg not to be zero, as the latter is specified to reset the accumulated so far value passed through the 1st arg.
        
        3. FD is checksumed with the hot binlog flag set OFF.
        
        4. support for HB and Incident events.
        
        5. old events, that current master can not generate are not crc-ed.
        
        6. The trans cache events are checksummed only one time thanks to 
           a new need_checksum() is invoked at time of diciding whether to
           conduct it or not.
        
        7. opt_binlog_checksum is changeable in run time to force binlog rotation
           once modified.
        
        8. Events cant, and FD event in particular receives the checksumming instruction
           via the event's flag prepared by the caller of Log_event::write().
     @ sql/log_event.h
        Signature for Log_event::read_log_event(FD) methods is changed to pass
        crc_check boolean;
        Defined size constant for the checksum alg;
        Added interface of Log_event::need_checksum() to help at deciding
        whether to checksum or not;
        
        The former changes:
                Changes related to log events and CRCs. These include:
                
                  i) Added binlog crc length macro (BINLOG_CHECKSUM_LEN);
                
                 ii) Added event header CRC flag (LOG_EVENT_CHECKSUM_F);
                
                iii) Added field crc to log events;
                
                 iv) Added declaration of Log_event::write_footer and
                     Log_event::wrapper_my_b_safe_write;
                
                  v) Changed implementation of Log_event::write so that it includes
                     the write_footer.
                
                 vi) Exported the function event_checksum_test so that it is used on
                     another module, slave.cc (queue_event).
     @ sql/mysql_priv.h
        Added declarations of external variables (options) for activating binlog
        crc, controling of checking on the master and the slave sides.
     @ sql/mysqld.cc
        added declarations of external variables and the command line options 
        for activating binlog checksum, controling of checking on the master and the slave sides.
     @ sql/repl_failsafe.cc
        Disabling crc_check at reading from a binary/relay log at this file particular invocations.
     @ sql/rpl_rli.cc
        shifting rli->relay_log.is_relay_log= TRUE to make sure
        is_relay_log is known inside open();
        crc_check is optional at relay log initialization.
     @ sql/set_var.cc
        Implementing a new sys_var class to match opt_sql_slave_verify_checksum and opt_master_verify_checksum needs.
     @ sql/set_var.h
        A new class declaration for checksum verification options is added.
     @ sql/share/errmsg.txt
        Error messages for different CRC failures are added.
     @ sql/slave.cc
        Additional to Luis' changes
        
                Added checksum verification to queue_event. This provides means to
                detect network checksum failures. Log_event::read_log_event will catch
                disk I/O failures.
                
                Strip CRC length (if event has CRC flag on) while creating an instance
                from the network received buffer for the Rotate_log_event.
        
        are:
        
        disabling crc check for events from old masters;
        making crc check optional for SQL thread (exploiting opt_sql_slave_verify_checksum);
        support for HB;
     @ sql/sql_binlog.cc
        disabling crc check at handling BINLOG event sent via client/server communication.
     @ sql/sql_class.h
        A new binlog rotation time flag is added to designate rotation is due to
        changing of opt_binlog_checksum.
     @ sql/sql_repl.cc
        Other to Luis'
        
                Three changes in this file:
                
                  i) Checksum fixing on mysql_binlog_send because, some flags in the
                     header file for some events are update on the fly here;
        
        (/me adds: that relates to only CREATED timestamp and not the hot-binlog flag)
                
                 ii) Added calculation of CRC for fake rotate events
                     (fake_rotate_event).
                
                iii) Added sys_opt_binlog_crc.
        
        include:
        
        deploying crc check on the master side, and optionally (exploiting opt_master_verify_) for
        two cases: show binlog events and reading in the dump thread;
        
        Implementing a new sys_var class to match opt_binlog_checksum needs.
        In particular changes to the global sys variable are done under protection
        of mysql_bin_log.get_log_lock().
        
        adding two more system variables to control crc check in run time on the master side and for the SQL slave thread;
        
        handling of error != LOG_READ_MEM when binlog_can_be_corrupted is true
        is improved.
        
        A new function is added to notify master that the client is checksum-aware.
        
        Instanciation of the new three global system variables is added.

    added:
      mysql-test/suite/binlog/r/binlog_checksum.result
      mysql-test/suite/binlog/t/binlog_checksum.test
      mysql-test/suite/rpl/r/rpl_checksum.result
      mysql-test/suite/rpl/t/rpl_checksum-master.opt
      mysql-test/suite/rpl/t/rpl_checksum.test
      mysql-test/suite/rpl/t/rpl_checksum_cache.test
    modified:
      client/Makefile.am
      client/mysqlbinlog.cc
      mysql-test/include/show_binlog_events.inc
      mysql-test/include/show_binlog_events2.inc
      sql/log.cc
      sql/log.h
      sql/log_event.cc
      sql/log_event.h
      sql/mysql_priv.h
      sql/mysqld.cc
      sql/repl_failsafe.cc
      sql/rpl_rli.cc
      sql/set_var.cc
      sql/set_var.h
      sql/share/errmsg.txt
      sql/slave.cc
      sql/sql_binlog.cc
      sql/sql_class.h
      sql/sql_repl.cc
=== modified file 'client/Makefile.am'
--- a/client/Makefile.am	2009-11-13 12:14:38 +0000
+++ b/client/Makefile.am	2010-05-03 09:52:27 +0000
@@ -63,7 +63,8 @@ mysqlbinlog_SOURCES =		mysqlbinlog.cc \
 				$(top_srcdir)/mysys/my_bit.c \
 				$(top_srcdir)/mysys/my_bitmap.c \
 				$(top_srcdir)/mysys/my_vle.c \
-				$(top_srcdir)/mysys/base64.c
+				$(top_srcdir)/mysys/base64.c \
+                                $(top_srcdir)/mysys/checksum.c
 mysqlbinlog_LDADD =		$(LDADD) $(CXXLDFLAGS)
 
 mysqldump_SOURCES=              mysqldump.c \

=== modified file 'client/mysqlbinlog.cc'
--- a/client/mysqlbinlog.cc	2009-11-20 13:30:35 +0000
+++ b/client/mysqlbinlog.cc	2010-05-03 09:52:27 +0000
@@ -73,6 +73,7 @@ static const char* database= 0;
 static my_bool force_opt= 0, short_form= 0, remote_opt= 0;
 static my_bool debug_info_flag, debug_check_flag;
 static my_bool force_if_open_opt= 1;
+static my_bool opt_verify_binlog_checksum= 1;
 static ulonglong offset = 0;
 static const char* host = 0;
 static int port= 0;
@@ -1150,6 +1151,9 @@ that may lead to an endless loop.",
    "Used to reserve file descriptors for usage by this program",
    (uchar**) &open_files_limit, (uchar**) &open_files_limit, 0, GET_ULONG,
    REQUIRED_ARG, MY_NFILE, 8, OS_FILE_LIMIT, 0, 1, 0},
+  {"verify-binlog-crc", 'c', "Verify checksum binlog events.",
+   (uchar**) &opt_verify_binlog_checksum, (uchar**) &opt_verify_binlog_checksum,
+   0, GET_BOOL, NO_ARG, 0, 0, 0, 0, 0, 0},
   {0, 0, 0, 0, 0, 0, GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0}
 };
 
@@ -1481,6 +1485,12 @@ static Exit_status check_master_version(
     goto err;
   }
 
+  if (mysql_query(mysql, "SET @slave_is_checksum_aware= 1"))
+  {
+    error("Could not notify master about checksum awareness."
+          "Master returned '%s'", mysql_error(mysql));
+    goto err;
+  }
   delete glob_description_event;
   switch (*version) {
   case '3':
@@ -1596,7 +1606,8 @@ static Exit_status dump_remote_log_entri
 			len, net->read_pos[5]));
     if (!(ev= Log_event::read_log_event((const char*) net->read_pos + 1 ,
                                         len - 1, &error_msg,
-                                        glob_description_event)))
+                                        glob_description_event,
+                                        opt_verify_binlog_checksum)))
     {
       error("Could not construct log event object: %s", error_msg);
       DBUG_RETURN(ERROR_STOP);
@@ -1823,7 +1834,8 @@ static Exit_status check_header(IO_CACHE
         Format_description_log_event *new_description_event;
         my_b_seek(file, tmp_pos); /* seek back to event's start */
         if (!(new_description_event= (Format_description_log_event*) 
-              Log_event::read_log_event(file, glob_description_event)))
+              Log_event::read_log_event(file, glob_description_event,
+                                        opt_verify_binlog_checksum)))
           /* EOF can't be hit here normally, so it's a real error */
         {
           error("Could not read a Format_description_log_event event at "
@@ -1856,7 +1868,8 @@ static Exit_status check_header(IO_CACHE
       {
         Log_event *ev;
         my_b_seek(file, tmp_pos); /* seek back to event's start */
-        if (!(ev= Log_event::read_log_event(file, glob_description_event)))
+        if (!(ev= Log_event::read_log_event(file, glob_description_event,
+                                            opt_verify_binlog_checksum)))
         {
           /* EOF can't be hit here normally, so it's a real error */
           error("Could not read a Rotate_log_event event at offset %llu;"
@@ -1969,7 +1982,8 @@ static Exit_status dump_local_log_entrie
     char llbuff[21];
     my_off_t old_off = my_b_tell(file);
 
-    Log_event* ev = Log_event::read_log_event(file, glob_description_event);
+    Log_event* ev = Log_event::read_log_event(file, glob_description_event,
+                                              opt_verify_binlog_checksum);
     if (!ev)
     {
       /*

=== modified file 'mysql-test/include/show_binlog_events.inc'
--- a/mysql-test/include/show_binlog_events.inc	2009-10-01 17:22:44 +0000
+++ b/mysql-test/include/show_binlog_events.inc	2010-05-03 09:52:27 +0000
@@ -1,20 +1,37 @@
+#
 # $binlog_start can be set by caller or take a default value
 # $binary_log_file the name of the log file show
 # $binary_log_limit_row - sets the number of binlog rows to be returned
 # $binary_log_limit_offset - sets the offset where to start returning events
+# $verbose
+#
+# Notice, the parameters to the macro are reset at the end of it
+# to avoid their values to substitute default arguments in show slave status
+# at following invocation of the macro.
 
 let $show_binlog_events= show binlog events;
 
 if (!$binlog_start)
 {
+  let $binlog_checksum= `select variable_value='ON' from information_schema.GLOBAL_VARIABLES where variable_name='binlog_checksum';`;
+
   # defaults to chop the first event in the binary log
-  let $binlog_start=107;
+  if($binlog_checksum)
+  {
+    let $binlog_start=112;
+  }
+
+  if(!$binlog_checksum)
+  {
+    let $binlog_start=107;
+  }
 }
 
 if (!`SELECT '$binary_log_file' = ''`)
 {
     let $show_binlog_events= $show_binlog_events in '$binary_log_file';
 }
+
 let $show_binlog_events= $show_binlog_events from $binlog_start;
 
 if ($binary_log_limit_row)
@@ -29,7 +46,19 @@ if ($binary_log_limit_row)
   let $show_binlog_events= $show_binlog_events $limit;
 }
 
+if ($verbose)
+{
+  --echo *** $show_binlog_events ***
+}
+
 --replace_result $MYSQLTEST_VARDIR MYSQLTEST_VARDIR $binlog_start <binlog_start>
 --replace_column 2 # 4 # 5 #
 --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/ /file_id=[0-9]+/file_id=#/ /block_len=[0-9]+/block_len=#/
 --eval $show_binlog_events
+
+#
+# reset of the global scope parameters
+#
+let $binary_log_file= ;
+let $binary_log_limit_row= ;
+let $binary_log_limit_offset= ;

=== modified file 'mysql-test/include/show_binlog_events2.inc'
--- a/mysql-test/include/show_binlog_events2.inc	2009-09-29 11:16:23 +0000
+++ b/mysql-test/include/show_binlog_events2.inc	2010-05-03 09:52:27 +0000
@@ -1,4 +1,18 @@
---let $binlog_start=107
+if (!$binlog_start)
+{
+  let $binlog_checksum= `select variable_value='ON' from information_schema.GLOBAL_VARIABLES where variable_name='binlog_checksum';`;
+
+  if($binlog_checksum)
+  {
+    let $binlog_start=112;
+  }
+
+  if(!$binlog_checksum)
+  {
+    let $binlog_start=107;
+  }
+}
+
 --replace_result $binlog_start <binlog_start>
 --replace_column 2 # 5 #
 --replace_regex /\/\* xid=.* \*\//\/* XID *\// /table_id: [0-9]+/table_id: #/

=== added file 'mysql-test/suite/binlog/r/binlog_checksum.result'
--- a/mysql-test/suite/binlog/r/binlog_checksum.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/r/binlog_checksum.result	2010-05-03 09:52:27 +0000
@@ -0,0 +1,19 @@
+set @@global.binlog_checksum=1;
+set @@global.master_verify_checksum = 1;
+reset master;
+must be master-bin.000001 
+show binary logs;
+Log_name	File_size
+master-bin.000001	#
+create table t1 (a int);
+flush logs;
+drop table t1;
+show binlog events from <binlog_start>;
+Log_name	Pos	Event_type	Server_id	End_log_pos	Info
+master-bin.000001	#	Query	#	#	use `test`; create table t1 (a int)
+master-bin.000001	#	Rotate	#	#	master-bin.000002;pos=4
+show tables;
+Tables_in_test
+t1
+drop table t1;
+End of the tests

=== added file 'mysql-test/suite/binlog/t/binlog_checksum.test'
--- a/mysql-test/suite/binlog/t/binlog_checksum.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/binlog/t/binlog_checksum.test	2010-05-03 09:52:27 +0000
@@ -0,0 +1,33 @@
+source include/have_innodb.inc;
+source include/have_log_bin.inc;
+
+#
+# WL#2540 replication event checksum
+#
+# Objectives of the test are:
+# to demo binlog events with CRC32 checksum in them and 
+# to prove show binlog events and mysqlbinlog are capable to handle 
+# the checksum.
+#
+
+set @@global.binlog_checksum=1;
+set @@global.master_verify_checksum = 1;
+let $MYSQLD_DATADIR= `select @@datadir`;
+
+reset master; 
+--echo must be master-bin.000001 
+--source include/show_binary_logs.inc
+
+create table t1 (a int);
+flush logs;
+drop table t1;
+
+--source include/show_binlog_events.inc
+--exec $MYSQL_BINLOG -c $MYSQLD_DATADIR/master-bin.000001 | $MYSQL
+show tables;
+
+# clean-up 
+
+drop table t1;
+
+--echo End of the tests

=== added file 'mysql-test/suite/rpl/r/rpl_checksum.result'
--- a/mysql-test/suite/rpl/r/rpl_checksum.result	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/r/rpl_checksum.result	2010-05-03 09:52:27 +0000
@@ -0,0 +1,91 @@
+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;
+call mtr.add_suppression('Slave can not handle replication events with the checksum that master is configured to log');
+call mtr.add_suppression('Replication event checksum verification failed');
+call mtr.add_suppression('Relay log write failure: could not queue event from master');
+set @save_binlog_checksum= @@global.binlog_checksum;
+set @save_master_verify_checksum =  @@global.master_verify_checksum;
+select @@global.binlog_checksum as 'must be one because of the command line option';
+must be one because of the command line option
+1
+select @@session.binlog_checksum as 'no session var';
+ERROR HY000: Variable 'binlog_checksum' is a GLOBAL variable
+select @@global.master_verify_checksum  as 'must be zero because of default';
+must be zero because of default
+0
+select @@session.master_verify_checksum  as 'no session var';
+ERROR HY000: Variable 'master_verify_checksum' is a GLOBAL variable
+set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
+select @@global.slave_sql_verify_checksum  as 'must be one because of default';
+must be one because of default
+1
+select @@session.slave_sql_verify_checksum  as 'no session var';
+ERROR HY000: Variable 'slave_sql_verify_checksum' is a GLOBAL variable
+show binary logs;
+Log_name	File_size
+master-bin.000001	#
+set @@global.binlog_checksum = 0;
+*** must be rotations seen ***
+show binary logs;
+Log_name	File_size
+master-bin.000001	#
+master-bin.000002	#
+set @@global.binlog_checksum = default;
+set @@global.binlog_checksum = 1;
+set @@global.binlog_checksum = 1;
+set @@global.master_verify_checksum = 0;
+set @@global.master_verify_checksum = default;
+set @@global.binlog_checksum = 2;
+ERROR 42000: Variable 'binlog_checksum' can't be set to the value of '2'
+set @@global.master_verify_checksum = 2;
+ERROR 42000: Variable 'master_verify_checksum' can't be set to the value of '2'
+set @@global.slave_sql_verify_checksum = 0;
+set @@global.slave_sql_verify_checksum = default;
+set @@global.slave_sql_verify_checksum = 2;
+ERROR 42000: Variable 'slave_sql_verify_checksum' can't be set to the value of '2'
+set @@global.binlog_checksum = 0;
+create table t1 (a int);
+flush logs;
+select count(*) as zero from t1;
+zero
+0
+include/stop_slave.inc
+set @@global.binlog_checksum = 1;
+insert into t1 values (1) /* will not be applied on slave due to simulation */;
+set @@global.debug='d,simulate_slave_unaware_checksum';
+start slave;
+*** Got IO thread error code: 1644, text: Slave can not handle replication events with the checksum that master is configured to log. ***
+select count(*) as zero from t1;
+zero
+0
+set @@global.debug='';
+include/start_slave.inc
+set @@global.master_verify_checksum = 1;
+set @@session.debug='d,simulate_checksum_test_failure';
+show binlog events;
+ERROR HY000: Error when executing command SHOW BINLOG EVENTS: Wrong offset or I/O error
+set @@session.debug='';
+set @@global.master_verify_checksum = default;
+include/stop_slave.inc
+create table t2 (a int);
+set @@global.debug='d,simulate_checksum_test_failure';
+start slave io_thread;
+*** Got IO thread error code: 1595, text: Relay log write failure: could not queue event from master ***
+set @@global.debug='';
+start slave io_thread;
+set @@global.slave_sql_verify_checksum = 1;
+set @@global.debug='d,simulate_checksum_test_failure';
+start slave sql_thread;
+*** Got SQL thread error code: 1594, text: Relay log read failure: Could not parse relay log event entry. The possible reasons are: the master's binary log is corrupted (you can check this by running 'mysqlbinlog' on the binary log), the slave's relay log is corrupted (you can check this by running 'mysqlbinlog' on the relay log), a network problem, or a bug in the master's or slave's MySQL code. If you want to check the master's binary log or slave's relay log, you will be able to know their names by issuing 'SHOW SLAVE STATUS' on this slave. ***
+set @@global.debug='';
+stop slave;
+include/start_slave.inc
+drop table t1, t2;
+set @@global.binlog_checksum = @save_binlog_checksum;
+set @@global.master_verify_checksum = @save_master_verify_checksum;
+set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
+End of tests

=== added file 'mysql-test/suite/rpl/t/rpl_checksum-master.opt'
--- a/mysql-test/suite/rpl/t/rpl_checksum-master.opt	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_checksum-master.opt	2010-05-03 09:52:27 +0000
@@ -0,0 +1 @@
+--binlog-checksum

=== added file 'mysql-test/suite/rpl/t/rpl_checksum.test'
--- a/mysql-test/suite/rpl/t/rpl_checksum.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_checksum.test	2010-05-03 09:52:27 +0000
@@ -0,0 +1,176 @@
+# WL2540 replication events checksum
+# Testing configuration parameters
+
+--source include/master-slave.inc
+--source include/have_debug.inc
+--source include/have_binlog_format_mixed.inc
+
+call mtr.add_suppression('Slave can not handle replication events with the checksum that master is configured to log');
+call mtr.add_suppression('Replication event checksum verification failed');
+# due to C failure simulation
+call mtr.add_suppression('Relay log write failure: could not queue event from master');
+
+# A. read/write access to the global vars:
+# binlog_checksum master_verify_checksum slave_sql_verify_checksum
+
+connection master;
+
+set @save_binlog_checksum= @@global.binlog_checksum;
+set @save_master_verify_checksum =  @@global.master_verify_checksum;
+
+select @@global.binlog_checksum as 'must be one because of the command line option';
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@session.binlog_checksum as 'no session var';
+
+select @@global.master_verify_checksum  as 'must be zero because of default';
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@session.master_verify_checksum  as 'no session var';
+
+connection slave;
+
+set @save_slave_sql_verify_checksum = @@global.slave_sql_verify_checksum;
+
+select @@global.slave_sql_verify_checksum  as 'must be one because of default';
+--error ER_INCORRECT_GLOBAL_LOCAL_VAR
+select @@session.slave_sql_verify_checksum  as 'no session var';
+
+connection master;
+
+source include/show_binary_logs.inc;
+set @@global.binlog_checksum = 0;
+--echo  *** must be rotations seen ***
+source include/show_binary_logs.inc;
+
+set @@global.binlog_checksum = default;
+
+# testing lack of side-effects in non-effective update of binlog_checksum:
+set @@global.binlog_checksum = 1;
+set @@global.binlog_checksum = 1; 
+
+set @@global.master_verify_checksum = 0;
+set @@global.master_verify_checksum = default;
+
+--error ER_WRONG_VALUE_FOR_VAR
+set @@global.binlog_checksum = 2; # the var is of bool type
+--error ER_WRONG_VALUE_FOR_VAR
+set @@global.master_verify_checksum = 2; # the var is of bool type
+
+connection slave;
+
+set @@global.slave_sql_verify_checksum = 0;
+set @@global.slave_sql_verify_checksum = default;
+--error ER_WRONG_VALUE_FOR_VAR
+set @@global.slave_sql_verify_checksum = 2; # the var is of bool type
+
+#
+# B. Old Slave to New master conditions
+#
+# while master does not send a checksum-ed binlog the Old Slave can
+# work with the New Master
+
+connection master;
+
+set @@global.binlog_checksum = 0;
+create table t1 (a int);
+
+# testing that binlog rotation preserves opt_binlog_checksum value
+flush logs;
+
+sync_slave_with_master;
+#connection slave;
+select count(*) as zero from t1;
+source include/stop_slave.inc;
+
+connection master;
+set @@global.binlog_checksum = 1;
+insert into t1 values (1) /* will not be applied on slave due to simulation */;
+
+# instruction to the dump thread
+set @@global.debug='d,simulate_slave_unaware_checksum'; # merge todo: +/- d syntax fails in my clone
+
+connection slave;
+start slave;
+source include/wait_for_slave_io_to_stop.inc;
+
+let $errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+let $error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
+--echo *** Got IO thread error code: $errno, text: $error ***
+
+select count(*) as zero from t1;
+
+connection master;
+set @@global.debug=''; # merge todo: +/- d syntax fails in my clone
+
+connection slave;
+source include/start_slave.inc;
+
+# 
+# C. checksum failure simulations
+#
+
+# C1. Failure by a client thread
+connection master;
+set @@global.master_verify_checksum = 1;
+set @@session.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
+--error ER_ERROR_WHEN_EXECUTING_COMMAND
+show binlog events;
+set @@session.debug=''; # merge todo: +/- d syntax fails in my clone
+set @@global.master_verify_checksum = default;
+
+#connection master;
+sync_slave_with_master;
+
+connection slave;
+source include/stop_slave.inc;
+
+connection master;
+create table t2 (a int);
+let $pos_master= query_get_value(SHOW MASTER STATUS, Position, 1);
+
+connection slave;
+
+# C2. Failure by IO thread
+# instruction to io thread
+set @@global.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
+start slave io_thread;
+source include/wait_for_slave_io_to_stop.inc;
+let $errno= query_get_value(SHOW SLAVE STATUS, Last_IO_Errno, 1);
+let $error= query_get_value(SHOW SLAVE STATUS, Last_IO_Error, 1);
+--echo *** Got IO thread error code: $errno, text: $error ***
+set @@global.debug=''; # todo: merge
+
+# to make IO thread re-read it again w/o the failure
+start slave io_thread;
+let $slave_param= Read_Master_Log_Pos;
+let $slave_param_value= $pos_master;
+source include/wait_for_slave_param.inc;
+
+# C3. Failure by SQL thread
+# instruction to sql thread;
+set @@global.slave_sql_verify_checksum = 1;
+set @@global.debug='d,simulate_checksum_test_failure'; # merge todo deploy +/- syntax
+start slave sql_thread;
+source include/wait_for_slave_sql_to_stop.inc;
+let $errno= query_get_value(SHOW SLAVE STATUS, Last_SQL_Errno, 1);
+let $error= query_get_value(SHOW SLAVE STATUS, Last_SQL_Error, 1);
+--echo *** Got SQL thread error code: $errno, text: $error ***
+
+# resuming SQL thread to parse out the event w/o the failure
+
+set @@global.debug=''; 
+stop slave;
+source include/start_slave.inc;
+
+#clean-up
+
+connection master;
+drop table t1, t2;
+set @@global.binlog_checksum = @save_binlog_checksum;
+set @@global.master_verify_checksum = @save_master_verify_checksum;
+
+#connection slave;
+sync_slave_with_master;
+
+set @@global.slave_sql_verify_checksum = @save_slave_sql_verify_checksum;
+
+--echo End of tests

=== added file 'mysql-test/suite/rpl/t/rpl_checksum_cache.test'
--- a/mysql-test/suite/rpl/t/rpl_checksum_cache.test	1970-01-01 00:00:00 +0000
+++ b/mysql-test/suite/rpl/t/rpl_checksum_cache.test	2010-05-03 09:52:27 +0000
@@ -0,0 +1,222 @@
+-- source include/have_innodb.inc
+-- source include/master-slave.inc
+
+connection master;
+set @@global.binlog_cache_size=4096;
+set @@global.binlog_checksum=1;
+
+#
+# Testing a critical part of checksum handling dealing with transaction cache.
+# The cache's buffer size is set to be less than the transaction's footprint
+# in binlog.
+#
+# To verify combined buffer-by-buffer read out of the file and fixing crc per event
+# there are the following parts:
+#
+# 1. the event size is much less than the cache's buffer
+# 2. the event size is bigger than the cache's buffer
+# 3. the event size if approximately the same as the cache's buffer
+# 4. all in above
+
+#
+# 1. the event size is much less than the cache's buffer
+#
+
+flush status;
+show status like "binlog_cache_use";
+show status like "binlog_cache_disk_use";
+--disable_warnings
+drop table if exists t1;
+--enable_warnings
+
+#
+# parameter to ensure the test slightly varies binlog content
+# between different invocations
+#
+let $deviation_size=32;
+eval create table t1 (a int, b CHAR($deviation_size)) engine=innodb;
+
+# Now we are going to create transaction which is long enough so its 
+# transaction binlog will be flushed to disk...
+let $1 = 4000;
+--disable_query_log
+begin;
+while ($1)
+{
+ eval select round(RAND() * $deviation_size) into @act_size;
+ set @data = repeat('a', @act_size);
+ eval insert into t1 values( $1, @data );
+ dec $1;
+}
+commit;
+--enable_query_log
+show status like "binlog_cache_use";
+--echo *** binlog_cache_disk_use must be non-zero ***
+show status like "binlog_cache_disk_use";
+
+sync_slave_with_master;
+
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+# undoing changes with verifying the above once again
+
+begin;
+delete from t1;
+commit;
+
+sync_slave_with_master;
+
+
+#
+# 2. the event size is bigger than the cache's buffer
+#
+connection master;
+
+flush status;
+let $t2_data_size= `select 3 * @@global.binlog_cache_size`;
+let $t2_aver_size= `select 2 * @@global.binlog_cache_size`;
+let $t2_max_rand=  `select 1 * @@global.binlog_cache_size`;
+
+eval create table t2(a int auto_increment primary key, data VARCHAR($t2_data_size)) ENGINE=Innodb;
+let $1=100;
+--disable_query_log
+begin;
+while ($1)
+{
+ eval select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size;
+ set @data = repeat('a', @act_size);
+ insert into t2 set data = @data;
+ dec $1;
+}
+commit;
+--enable_query_log
+show status like "binlog_cache_use";
+--echo *** binlog_cache_disk_use must be non-zero ***
+show status like "binlog_cache_disk_use";
+
+sync_slave_with_master;
+
+let $diff_table_1=master:test.t2;
+let $diff_table_2=slave:test.t2;
+source include/diff_tables.inc;
+
+# undoing changes with verifying the above once again
+
+begin;
+delete from t2;
+commit;
+
+sync_slave_with_master;
+
+#
+# 3. the event size if approximately the same as the cache's buffer
+#
+
+connection master;
+
+flush status;
+let $t3_data_size= `select 2 * @@global.binlog_cache_size`;
+let $t3_aver_size= `select (9 * @@global.binlog_cache_size) / 10`;
+let $t3_max_rand=  `select (2 * @@global.binlog_cache_size) / 10`;
+
+eval create table t3(a int auto_increment primary key, data VARCHAR($t3_data_size)) engine=innodb;
+
+let $1= 300;
+--disable_query_log
+begin;
+while ($1)
+{
+ eval select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size;
+ insert into t3 set data= repeat('a', @act_size);
+ dec $1;
+}
+commit;
+--enable_query_log
+show status like "binlog_cache_use";
+--echo *** binlog_cache_disk_use must be non-zero ***
+show status like "binlog_cache_disk_use";
+
+sync_slave_with_master;
+
+let $diff_table_1=master:test.t3;
+let $diff_table_2=slave:test.t3;
+source include/diff_tables.inc;
+
+# undoing changes with verifying the above once again
+
+begin;
+delete from t3;
+commit;
+
+sync_slave_with_master;
+
+
+#
+# 4. all in above
+#
+
+connection master;
+flush status;
+
+delimiter |;
+eval create procedure test.p1 (n int) 
+begin
+  while n > 0 do
+    case (select (round(rand()*100) % 3) + 1)
+    when 1 then
+      select round(RAND() * $deviation_size) into @act_size;
+      set @data = repeat('a', @act_size);
+      insert into t1 values(n, @data);
+    when 2 then
+      begin
+        select round($t2_aver_size + RAND() * $t2_max_rand) into @act_size;
+	insert into t2 set data=repeat('a', @act_size);
+      end;
+    when 3 then
+      begin
+        select round($t3_aver_size + RAND() * $t3_max_rand) into @act_size;
+	insert into t3 set data= repeat('a', @act_size);
+      end;
+    end case;
+    set n= n-1;
+  end while;
+end|
+delimiter ;|
+
+let $1= 1000;
+set autocommit= 0;
+eval call test.p1($1);
+commit;
+
+show status like "binlog_cache_use";
+--echo *** binlog_cache_disk_use must be non-zero ***
+show status like "binlog_cache_disk_use";
+
+sync_slave_with_master;
+
+let $diff_table_1=master:test.t1;
+let $diff_table_2=slave:test.t1;
+source include/diff_tables.inc;
+
+let $diff_table_1=master:test.t2;
+let $diff_table_2=slave:test.t2;
+source include/diff_tables.inc;
+
+let $diff_table_1=master:test.t3;
+let $diff_table_2=slave:test.t3;
+source include/diff_tables.inc;
+
+
+connection master;
+
+begin;
+delete from t1;
+delete from t2;
+delete from t3;
+commit;
+
+drop table t1, t2, t3;
+
+sync_slave_with_master;

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2009-11-22 03:59:48 +0000
+++ b/sql/log.cc	2010-05-03 09:52:27 +0000
@@ -290,6 +290,12 @@ public:
 
 handlerton *binlog_hton;
 
+IO_CACHE * get_thd_trans_cache(THD * thd)
+{
+  return &((class binlog_trx_data*)
+           thd_get_ha_data(thd, binlog_hton))->trans_log;
+}
+
 bool LOGGER::is_log_table_enabled(uint log_table_type)
 {
   switch (log_table_type) {
@@ -2498,6 +2504,7 @@ MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_
    need_start_event(TRUE), m_table_map_version(0),
    sync_period_ptr(sync_period),
    is_relay_log(0), signal_cnt(0),
+   checksum_flip(FALSE),
    description_event_for_exec(0), description_event_for_queue(0)
 {
   /*
@@ -2663,7 +2670,9 @@ bool MYSQL_BIN_LOG::open(const char *log
         as we won't be able to reset it later
       */
       if (io_cache_type == WRITE_CACHE)
-        s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
+        s.flags |= LOG_EVENT_BINLOG_IN_USE_F;
+      if (is_relay_log && opt_slave_sql_verify_checksum)
+        s.flags |= LOG_EVENT_CHECKSUM_F;
       if (!s.is_valid())
         goto err;
       s.dont_set_created= null_created_arg;
@@ -3690,7 +3699,11 @@ void MYSQL_BIN_LOG::new_file_impl(bool n
   old_name=name;
   name=0;				// Don't free name
   close(LOG_CLOSE_TO_BE_OPENED);
-
+  if (log_type == LOG_BIN && checksum_flip)
+  {
+    DBUG_ASSERT(!is_relay_log);
+    opt_binlog_checksum= !opt_binlog_checksum;
+  }
   /*
      Note that at this point, log_state != LOG_CLOSED (important for is_open()).
   */
@@ -4373,6 +4386,8 @@ void MYSQL_BIN_LOG::rotate_and_purge(uin
   if ((flags & RP_FORCE_ROTATE) ||
       (my_b_tell(&log_file) >= (my_off_t) max_size))
   {
+    if (flags & RP_BINLOG_CHECKSUM_ON_OFF)
+      checksum_flip= TRUE;
     new_file_without_locking();
 #ifdef HAVE_REPLICATION
     if (expire_logs_days)
@@ -4382,6 +4397,8 @@ void MYSQL_BIN_LOG::rotate_and_purge(uin
         purge_logs_before_date(purge_time);
     }
 #endif
+    if (flags & RP_BINLOG_CHECKSUM_ON_OFF)
+      checksum_flip= FALSE;
   }
   if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
     pthread_mutex_unlock(&LOCK_log);
@@ -4397,6 +4414,38 @@ uint MYSQL_BIN_LOG::next_file_id()
 }
 
 
+/**
+  Calculate checksum of possibly a part of an event containing at least
+  the whole common header.
+
+  @param    buf       the pointer to trans cache's buffer
+  @param    off       the offset of the beginning of the event in the buffer
+  @param    event_len no-checksum length of the event
+  @param    length    the current size of the buffer
+
+  @param    crc       [in-out] the checksum
+
+  Event is getting flagged-up with @c LOG_EVENT_CHECKSUM_F.
+
+  @return 0 or number of unprocessed yet bytes of the event excluding 
+            the checksum part.
+*/
+  static ulong fix_log_event_crc(uchar *buf, uint off, uint event_len,
+                                 uint length, ha_checksum *crc)
+{
+  ulong ret;
+  uchar *event_begin= buf + off;
+  uint16 flags= uint2korr(event_begin + FLAGS_OFFSET);
+
+  DBUG_ASSERT(length >= off + LOG_EVENT_HEADER_LEN); //at least common header in
+  DBUG_ASSERT(!(flags & LOG_EVENT_CHECKSUM_F));
+  flags|= LOG_EVENT_CHECKSUM_F;
+  int2store(event_begin + FLAGS_OFFSET, flags);
+  ret= length >= off + event_len ? 0 : off + event_len - length;
+  *crc= my_checksum(*crc, event_begin, event_len - ret); 
+  return ret;
+}
+
 /*
   Write the contents of a cache to the binary log.
 
@@ -4409,7 +4458,13 @@ uint MYSQL_BIN_LOG::next_file_id()
   DESCRIPTION
     Write the contents of the cache to the binary log. The cache will
     be reset as a READ_CACHE to be able to read the contents from it.
- */
+
+    While reading from the trans cache is always by filling in 
+    the cache's buffer, the following write to the binlog cache is
+    done differently depending on @c opt_binlog_checksum flag option.
+    When the flag is OFF the entire buf is written, otherwise writting
+    happens event by event.
+*/
 
 int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
 {
@@ -4418,8 +4473,10 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
   if (reinit_io_cache(cache, READ_CACHE, 0, 0, 0))
     return ER_ERROR_ON_WRITE;
   uint length= my_b_bytes_in_cache(cache), group, carry, hdr_offs;
+  ulong remains= 0; // part of unprocessed yet netto length of the event
   long val;
   uchar header[LOG_EVENT_HEADER_LEN];
+  ha_checksum crc, crc_0;
 
   /*
     The events in the buffer have incorrect end_log_pos data
@@ -4437,6 +4494,8 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
 
   group= (uint)my_b_tell(&log_file);
   hdr_offs= carry= 0;
+  if  (opt_binlog_checksum)
+    crc= crc_0= my_checksum(0L, NULL, 0);
 
   do
   {
@@ -4447,15 +4506,30 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
     */
     if (unlikely(carry > 0))
     {
+      uint16 flags;
       DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN);
 
       /* assemble both halves */
-      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
+      memcpy(&header[carry], (char *)cache->read_pos,
+             LOG_EVENT_HEADER_LEN - carry);
 
       /* fix end_log_pos */
-      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
+      val= uint4korr(&header[LOG_POS_OFFSET]) + group +
+        (opt_binlog_checksum ? BINLOG_CHECKSUM_LEN : 0);
       int4store(&header[LOG_POS_OFFSET], val);
 
+      if (opt_binlog_checksum)
+      {
+        /* fix len */
+        int4store(&header[EVENT_LEN_OFFSET],
+                  uint4korr(&header[EVENT_LEN_OFFSET]) + BINLOG_CHECKSUM_LEN);
+        /* fix flags */
+        flags= uint2korr(&header[FLAGS_OFFSET]);
+        DBUG_ASSERT(!(flags & LOG_EVENT_CHECKSUM_F));
+        flags |= LOG_EVENT_CHECKSUM_F;
+        int2store(&header[FLAGS_OFFSET], flags);
+      }
+
       /* write the first half of the split header */
       if (my_b_write(&log_file, header, carry))
         return ER_ERROR_ON_WRITE;
@@ -4464,11 +4538,20 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
         copy fixed second half of header to cache so the correct
         version will be written later.
       */
-      memcpy((char *)cache->read_pos, &header[carry], LOG_EVENT_HEADER_LEN - carry);
+      memcpy((char *)cache->read_pos, &header[carry],
+             LOG_EVENT_HEADER_LEN - carry);
 
       /* next event header at ... */
-      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
+      hdr_offs= uint4korr(&header[EVENT_LEN_OFFSET]) - carry -
+        (opt_binlog_checksum ? BINLOG_CHECKSUM_LEN : 0);
 
+      if (opt_binlog_checksum)
+      {
+        DBUG_ASSERT(crc == crc_0 && remains == 0);
+        crc= my_checksum(crc, header, carry);
+        remains= uint4korr(header + EVENT_LEN_OFFSET) - carry -
+          BINLOG_CHECKSUM_LEN;
+      }
       carry= 0;
     }
 
@@ -4483,6 +4566,24 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
         very next iteration, just "eventually").
       */
 
+      /* crc-calc the whole buffer */
+      if (opt_binlog_checksum && hdr_offs >= length)
+      {
+
+        DBUG_ASSERT(remains != 0 && crc != crc_0);
+
+        crc= my_checksum(crc, cache->read_pos, length); 
+        remains -= length;
+        if (my_b_write(&log_file, cache->read_pos, length))
+          return ER_ERROR_ON_WRITE;
+        if (remains == 0)
+        {
+          if (my_b_write(&log_file, &crc, BINLOG_CHECKSUM_LEN))
+            return ER_ERROR_ON_WRITE;
+          crc= crc_0;
+        }
+      }
+
       while (hdr_offs < length)
       {
         /*
@@ -4490,6 +4591,25 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
           we get the rest.
         */
 
+        if (opt_binlog_checksum)
+        {
+          if (remains != 0)
+          {
+            /*
+              finish off with remains of the last event that crawls
+              from previous into the current buffer
+            */
+            DBUG_ASSERT(crc != crc_0);
+            crc= my_checksum(crc, cache->read_pos, hdr_offs);
+            remains -= hdr_offs;
+            DBUG_ASSERT(remains == 0);
+            if (my_b_write(&log_file, cache->read_pos, hdr_offs) ||
+                my_b_write(&log_file, &crc, BINLOG_CHECKSUM_LEN))
+              return ER_ERROR_ON_WRITE;
+            crc= crc_0;
+          }
+        }
+
         if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
         {
           carry= length - hdr_offs;
@@ -4499,17 +4619,37 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
         else
         {
           /* we've got a full event-header, and it came in one piece */
-
-          uchar *log_pos= (uchar *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
+          uchar *ev= (uchar *)cache->read_pos + hdr_offs;
+          uint event_len= uint4korr(ev + EVENT_LEN_OFFSET); // netto len
+          uchar *log_pos= ev + LOG_POS_OFFSET;
 
           /* fix end_log_pos */
-          val= uint4korr(log_pos) + group;
+          val= uint4korr(log_pos) + group +
+            (opt_binlog_checksum ? BINLOG_CHECKSUM_LEN : 0);
           int4store(log_pos, val);
 
+	  /* fix CRC */
+	  if (opt_binlog_checksum)
+          {
+            /* fix length */
+            int4store(ev + EVENT_LEN_OFFSET, event_len + BINLOG_CHECKSUM_LEN);
+            remains= fix_log_event_crc(cache->read_pos, hdr_offs, event_len,
+                                       length, &crc);
+            if (my_b_write(&log_file, ev, 
+                           remains == 0 ? event_len : length - hdr_offs))
+              return ER_ERROR_ON_WRITE;
+            if (remains == 0)
+            {
+              if (my_b_write(&log_file, &crc, BINLOG_CHECKSUM_LEN))
+                return ER_ERROR_ON_WRITE;
+              crc= crc_0; // crc is complete
+            }
+          }
+
           /* next event header at ... */
-          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
-          hdr_offs += uint4korr(log_pos);
+          hdr_offs += event_len; // incr by the netto len
 
+          DBUG_ASSERT(!opt_binlog_checksum || remains == 0 || hdr_offs >= length);
         }
       }
 
@@ -4524,20 +4664,24 @@ int MYSQL_BIN_LOG::write_cache(IO_CACHE 
       hdr_offs -= length;
     }
 
-    /* Write data to the binary log file */
-    if (my_b_write(&log_file, cache->read_pos, length))
-      return ER_ERROR_ON_WRITE;
+    /* Write the entire buf to the binary log file */
+    if (!opt_binlog_checksum)
+      if (my_b_write(&log_file, cache->read_pos, length))
+        return ER_ERROR_ON_WRITE;
     cache->read_pos=cache->read_end;		// Mark buffer used up
   } while ((length= my_b_fill(cache)));
 
-  DBUG_ASSERT(carry == 0);
-
   if (sync_log)
     return flush_and_sync(0);
 
+  DBUG_ASSERT(carry == 0);
+  DBUG_ASSERT(!opt_binlog_checksum || remains == 0);
+  DBUG_ASSERT(!opt_binlog_checksum || crc == crc_0);
+
   return 0;                                     // All OK
 }
 
+
 /*
   Helper function to get the error code of the query to be binlogged.
  */
@@ -4815,10 +4959,11 @@ void MYSQL_BIN_LOG::close(uint exiting)
     /* don't pwrite in a file opened with O_APPEND - it doesn't work */
     if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
     {
-      my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
+      my_off_t flags_offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
       my_off_t org_position= my_tell(log_file.file, MYF(0));
-      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
-      my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+      uchar flags= !opt_binlog_checksum? 0 : LOG_EVENT_CHECKSUM_F;
+
+      my_pwrite(log_file.file, &flags, 1, flags_offset, MYF(0));
       /*
         Restore position so that anything we have in the IO_cache is written
         to the correct position.
@@ -5704,7 +5849,8 @@ int TC_LOG_BINLOG::open(const char *opt_
       goto err;
     }
 
-    if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
+    if ((ev= Log_event::read_log_event(&log, 0, &fdle,
+                                       opt_master_verify_checksum)) &&
         ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
         ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
     {
@@ -5783,7 +5929,9 @@ int TC_LOG_BINLOG::recover(IO_CACHE *log
 
   fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
 
-  while ((ev= Log_event::read_log_event(log,0,fdle)) && ev->is_valid())
+  while ((ev= Log_event::read_log_event(log, 0, fdle,
+                                        opt_master_verify_checksum))
+         && ev->is_valid())
   {
     if (ev->get_type_code() == XID_EVENT)
     {

=== modified file 'sql/log.h'
--- a/sql/log.h	2009-11-22 03:59:48 +0000
+++ b/sql/log.h	2010-05-03 09:52:27 +0000
@@ -310,6 +310,7 @@ public:
   /* This is relay log */
   bool is_relay_log;
   ulong signal_cnt;  // update of the counter is checked by heartbeat
+  bool checksum_flip; // sets to true at time opt_binlog_checksum is changing
   /*
     These describe the log's format. This is used only for relay logs.
     _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
@@ -623,6 +624,12 @@ enum enum_binlog_format {
 };
 extern TYPELIB binlog_format_typelib;
 
+/*
+  if more alg will be added in future, binlog_checksum_alg_id should be
+  turned into an option
+*/
+extern const uint8 binlog_checksum_alg_id;
+
 int query_error_code(THD *thd, bool not_killed);
 uint purge_log_get_error_code(int res);
 

=== modified file 'sql/log_event.cc'
--- a/sql/log_event.cc	2009-11-06 16:35:04 +0000
+++ b/sql/log_event.cc	2010-05-03 09:52:27 +0000
@@ -51,6 +51,24 @@
 */
 #define FMT_G_BUFSIZE(PREC) (3 + (PREC) + 5 + 1)
 
+enum enum_binlog_checksum_alg {
+  BINLOG_CHECKSUM_ALG_CRC32= 1,  // to be indexed by opt_binlog_checksum_alg_id
+  BINLOG_CHECKSUM_ALG_ENUM_END
+};
+/* 
+   the text names of checksum alg:s vector to be indexed
+   by  FD post_header checksum part enum value
+*/
+const char* binlog_checksum_alg_names[]= {"CRC32", NullS};
+/*
+  if more alg will be added in future, binlog_checksum_alg_id should be
+  turned into an option of the server startup
+*/
+const uint8 binlog_checksum_alg_id= BINLOG_CHECKSUM_ALG_CRC32;
+
+#if !defined(MYSQL_CLIENT)
+IO_CACHE *  get_thd_trans_cache(THD *);
+#endif
 
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
 static int rows_event_stmt_cleanup(Relay_log_info const *rli, THD* thd);
@@ -606,6 +624,59 @@ static void print_set_option(IO_CACHE* f
 }
 #endif
 
+inline bool event_checksum_test(uchar *event_buf, ulong event_len)
+{
+  uint16 flags= uint2korr(event_buf + FLAGS_OFFSET);
+  bool res= FALSE;
+
+  if ((flags & LOG_EVENT_CHECKSUM_F) == LOG_EVENT_CHECKSUM_F)
+  {
+    ha_checksum incoming;
+    ha_checksum computed;
+    /*
+      FD event is to be CRC-ed and therefore verified w/o the binlog-in-use flag
+    */
+    if (event_buf[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT)
+    {
+      /* crc is to be computed w/o IN_USE flag */
+      DBUG_ASSERT(!(flags & LOG_EVENT_BINLOG_IN_USE_F));
+      /*
+        The complile time guards to watch that
+        the max number of alg is bound to
+          number of bits combination of checksum postheader, and
+
+          - FD checksum header and the variable holding alg value
+          - the enum and the vector of names 
+
+          are size-compatible
+      */
+      compile_time_assert(sizeof(enum enum_binlog_checksum_alg)
+                          <
+                          (1 << sizeof(binlog_checksum_alg_id) * 8));
+      
+      compile_time_assert(sizeof(binlog_checksum_alg_id) 
+                          == 
+                          BINLOG_CHECKSUM_HEADER_SIZE);
+
+      compile_time_assert(sizeof(binlog_checksum_alg_names)/sizeof(char*)
+                          ==
+                          BINLOG_CHECKSUM_ALG_ENUM_END);
+    }
+    incoming= uint4korr(event_buf + event_len - BINLOG_CHECKSUM_LEN);
+    computed= my_checksum(0L, NULL, 0);
+    /* checksum the event content but the checksum part itself */
+    computed= my_checksum(computed, (const uchar*) event_buf,
+                          event_len - BINLOG_CHECKSUM_LEN);
+    res= !(computed == incoming);
+
+    /* The only algorithm currently is CRC32 */
+    DBUG_ASSERT(res || event_buf[EVENT_TYPE_OFFSET] != FORMAT_DESCRIPTION_EVENT
+                || BINLOG_CHECKSUM_ALG_CRC32 == * (uint8 *) 
+                (event_buf +
+                 Format_description_log_event::checksum_flag_offset()));
+  }
+  return DBUG_EVALUATE_IF("simulate_checksum_test_failure", TRUE, res);
+}
 /**************************************************************************
 	Log_event methods (= the parent class of all events)
 **************************************************************************/
@@ -660,7 +731,7 @@ const char* Log_event::get_type_str()
 
 #ifndef MYSQL_CLIENT
 Log_event::Log_event(THD* thd_arg, uint16 flags_arg, bool using_trans)
-  :log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg), thd(thd_arg)
+  :log_pos(0), temp_buf(0), exec_time(0), flags(flags_arg), crc(0), thd(thd_arg)
 {
   server_id=	thd->server_id;
   when=		thd->start_time;
@@ -676,7 +747,7 @@ Log_event::Log_event(THD* thd_arg, uint1
 */
 
 Log_event::Log_event()
-  :temp_buf(0), exec_time(0), flags(0), cache_stmt(0),
+  :temp_buf(0), exec_time(0), flags(0), cache_stmt(0), crc(0),
    thd(0)
 {
   server_id=	::server_id;
@@ -696,7 +767,7 @@ Log_event::Log_event()
 
 Log_event::Log_event(const char* buf,
                      const Format_description_log_event* description_event)
-  :temp_buf(0), cache_stmt(0)
+  :temp_buf(0), cache_stmt(0), crc(0)
 {
 #ifndef MYSQL_CLIENT
   thd = 0;
@@ -882,6 +953,54 @@ void Log_event::init_show_field_list(Lis
   field_list->push_back(new Item_empty_string("Info", 20));
 }
 
+/**
+   Decision helper whether to trigger checksum computation or not.
+   To be invoked in Log_event::write().
+   The decision is positive when the event instance got already
+   @c LOG_EVENT_CHECKSUM_F flagged (e.g via
+   Log_event::write the caller or Log_event::write_header() 
+   set it after the first invocation of Log_event::need_checksum)
+   or 
+   global.binlog_checksum is ON and events is 
+   directly written to the binlog file.
+   Otherwise the decision is negative.
+
+   @return true (positive) or false (negative)
+*/
+my_bool Log_event::need_checksum(IO_CACHE* file)
+{
+  return  
+    /* 
+       some callers of Log_event::write can pre-set the flag on 
+       to force checksum incapsulation into the event 
+    */
+    (flags & LOG_EVENT_CHECKSUM_F) || 
+    (opt_binlog_checksum && (!thd  /* bootstrap */
+                             || /* the main branch */
+                             get_thd_trans_cache(thd) != file));
+}
+
+bool Log_event::wrapper_my_b_safe_write(IO_CACHE* file, const uchar* buf, ulong size)
+{
+  if (need_checksum(file) && size != 0)
+    crc= my_checksum(crc, buf, size);
+
+  return my_b_safe_write(file, buf, size);
+}
+
+bool Log_event::write_footer(IO_CACHE* file) 
+{
+  /* footer contains: i) CRC */
+  if (need_checksum(file))
+  {
+    uchar buf[BINLOG_CHECKSUM_LEN];
+    int4store(buf, crc);
+
+    return my_b_safe_write(file, (uchar*) buf, sizeof(buf));
+  }
+
+  return 0;
+}
 
 /*
   Log_event::write()
@@ -896,6 +1015,13 @@ bool Log_event::write_header(IO_CACHE* f
   /* Store number of bytes that will be written by this event */
   data_written= event_data_length + sizeof(header);
 
+  if (need_checksum(file))
+  {
+    crc= my_checksum(0L, NULL, 0);
+    data_written += BINLOG_CHECKSUM_LEN;
+    flags = flags | LOG_EVENT_CHECKSUM_F;
+  }
+
   /*
     log_pos != 0 if this is relay-log event. In this case we should not
     change the position
@@ -954,9 +1080,18 @@ bool Log_event::write_header(IO_CACHE* f
   int4store(header+ SERVER_ID_OFFSET, server_id);
   int4store(header+ EVENT_LEN_OFFSET, data_written);
   int4store(header+ LOG_POS_OFFSET, log_pos);
-  int2store(header+ FLAGS_OFFSET, flags);
+  /*
+    recording the FD event's CRC w/o the binlog-in-use flag.
+    The flag needs dropping before checksum calculation.
+  */
+  int2store(header+ FLAGS_OFFSET,
+            (need_checksum(file) &&
+             header[EVENT_TYPE_OFFSET] == FORMAT_DESCRIPTION_EVENT) ?
+            flags & ~LOG_EVENT_BINLOG_IN_USE_F : flags);  
+  
+  /* writing to the binlog, we must crc it */
+  DBUG_RETURN(wrapper_my_b_safe_write(file, header, sizeof(header)) != 0);
 
-  DBUG_RETURN(my_b_safe_write(file, header, sizeof(header)) != 0);
 }
 
 
@@ -971,6 +1106,7 @@ int Log_event::read_log_event(IO_CACHE* 
   ulong data_len;
   int result=0;
   char buf[LOG_EVENT_MINIMAL_HEADER_LEN];
+  uchar ev_offset= packet->length();
   DBUG_ENTER("Log_event::read_log_event");
 
   if (log_lock)
@@ -1028,6 +1164,19 @@ int Log_event::read_log_event(IO_CACHE* 
                (file->error >= 0 ? LOG_READ_TRUNC: LOG_READ_IO));
       /* Implicit goto end; */
     }
+    else
+    {
+      /*
+        CRC verification.
+      */
+      if (opt_master_verify_checksum && 
+          event_checksum_test((uchar*) packet->ptr() + ev_offset,
+          data_len + sizeof(buf)))
+      {
+        result= LOG_READ_CHECKSUM_FAILURE;
+        goto end;
+      }
+    }
   }
 
 end:
@@ -1053,11 +1202,13 @@ end:
 Log_event* Log_event::read_log_event(IO_CACHE* file,
 				     pthread_mutex_t* log_lock,
                                      const Format_description_log_event
-                                     *description_event)
+                                     *description_event,
+                                     my_bool crc_check)
 #else
 Log_event* Log_event::read_log_event(IO_CACHE* file,
                                      const Format_description_log_event
-                                     *description_event)
+                                     *description_event,
+                                     my_bool crc_check)
 #endif
 {
   DBUG_ENTER("Log_event::read_log_event");
@@ -1121,7 +1272,7 @@ failed my_b_read"));
     error = "read error";
     goto err;
   }
-  if ((res= read_log_event(buf, data_len, &error, description_event)))
+  if ((res= read_log_event(buf, data_len, &error, description_event, crc_check)))
     res->register_temp_buf(buf);
 
 err:
@@ -1154,9 +1305,11 @@ err:
 
 Log_event* Log_event::read_log_event(const char* buf, uint event_len,
 				     const char **error,
-                                     const Format_description_log_event *description_event)
+                                     const Format_description_log_event *description_event,
+                                     my_bool crc_check)
 {
   Log_event* ev;
+  uint16 flags= uint2korr(buf + FLAGS_OFFSET);
   DBUG_ENTER("Log_event::read_log_event(char*,...)");
   DBUG_ASSERT(description_event != 0);
   DBUG_PRINT("info", ("binlog_version: %d", description_event->binlog_version));
@@ -1172,6 +1325,28 @@ Log_event* Log_event::read_log_event(con
   }
 
   uint event_type= buf[EVENT_TYPE_OFFSET];
+
+  /*
+    CRC verification.
+  */
+  if (crc_check && event_checksum_test((uchar *) buf, event_len))
+  {
+#ifdef MYSQL_CLIENT
+    *error= "Event crc check failed! Most likely there is event corruption.";
+    if (force_opt)
+    {
+      ev= new Unknown_log_event(buf, description_event);
+      DBUG_RETURN(ev);
+    }
+    else
+      DBUG_RETURN(NULL);
+#else
+    *error= ER(ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE);
+    sql_print_error("%s", ER(ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE));
+    DBUG_RETURN(NULL);
+#endif
+  }
+
   if (event_type > description_event->number_of_event_types &&
       event_type != FORMAT_DESCRIPTION_EVENT)
   {
@@ -1210,6 +1385,9 @@ Log_event* Log_event::read_log_event(con
       event_type= description_event->event_type_permutation[event_type];
     }
 
+    if ((flags & LOG_EVENT_CHECKSUM_F) == LOG_EVENT_CHECKSUM_F)
+      event_len= event_len - BINLOG_CHECKSUM_LEN;
+
     switch(event_type) {
     case QUERY_EVENT:
       ev  = new Query_log_event(buf, event_len, description_event, QUERY_EVENT);
@@ -1301,6 +1479,9 @@ Log_event* Log_event::read_log_event(con
     }
   }
 
+  if (flags & LOG_EVENT_CHECKSUM_F)
+    ev->crc= uint4korr(buf + (event_len));
+
   DBUG_PRINT("read_event", ("%s(type_code: %d; event_len: %d)",
                             ev ? ev->get_type_str() : "<unknown>",
                             buf[EVENT_TYPE_OFFSET],
@@ -1353,6 +1534,17 @@ void Log_event::print_header(IO_CACHE* f
   my_b_printf(file, " server id %lu  end_log_pos %s ", (ulong) server_id,
               llstr(log_pos,llbuff));
 
+  /* print the checksum */
+  if (uint2korr(temp_buf+FLAGS_OFFSET) & LOG_EVENT_CHECKSUM_F)
+  {
+    char checksum_buf[BINLOG_CHECKSUM_LEN * 2 + 4]; // to fit to "0x%lx "
+    size_t const bytes_written=
+      my_snprintf(checksum_buf, sizeof(checksum_buf), "0x%08lx ", crc);
+    my_b_printf(file, "%s ",
+                binlog_checksum_alg_names[binlog_checksum_alg_id - 1]);
+    my_b_printf(file, checksum_buf, bytes_written);
+  }
+
   /* mysqlbinlog --hexdump */
   if (print_event_info->hexdump_from)
   {
@@ -2321,12 +2513,13 @@ bool Query_log_event::write(IO_CACHE* fi
   event_length= (uint) (start-buf) + get_post_header_size_for_derived() + db_len + 1 + q_len;
 
   return (write_header(file, event_length) ||
-          my_b_safe_write(file, (uchar*) buf, QUERY_HEADER_LEN) ||
+          wrapper_my_b_safe_write(file, (uchar*) buf, QUERY_HEADER_LEN) ||
           write_post_header_for_derived(file) ||
-          my_b_safe_write(file, (uchar*) start_of_status,
+          wrapper_my_b_safe_write(file, (uchar*) start_of_status,
                           (uint) (start-start_of_status)) ||
-          my_b_safe_write(file, (db) ? (uchar*) db : (uchar*)"", db_len + 1) ||
-          my_b_safe_write(file, (uchar*) query, q_len)) ? 1 : 0;
+          wrapper_my_b_safe_write(file, (db) ? (uchar*) db : (uchar*)"", db_len + 1) ||
+          wrapper_my_b_safe_write(file, (uchar*) query, q_len) ||
+	  write_footer(file)) ? 1 : 0;
 }
 
 /**
@@ -3481,7 +3674,8 @@ bool Start_log_event_v3::write(IO_CACHE*
     created= when= get_time();
   int4store(buff + ST_CREATED_OFFSET,created);
   return (write_header(file, sizeof(buff)) ||
-          my_b_safe_write(file, (uchar*) buff, sizeof(buff)));
+          wrapper_my_b_safe_write(file, (uchar*) buff, sizeof(buff)) ||
+	  write_footer(file));
 }
 #endif
 
@@ -3874,17 +4068,32 @@ bool Format_description_log_event::write
     We don't call Start_log_event_v3::write() because this would make 2
     my_b_safe_write().
   */
-  uchar buff[FORMAT_DESCRIPTION_HEADER_LEN];
+  uchar buff[FORMAT_DESCRIPTION_HEADER_LEN + BINLOG_CHECKSUM_HEADER_SIZE];
+  size_t rec_size= sizeof(buff) - BINLOG_CHECKSUM_HEADER_SIZE;
   int2store(buff + ST_BINLOG_VER_OFFSET,binlog_version);
   memcpy((char*) buff + ST_SERVER_VER_OFFSET,server_version,ST_SERVER_VER_LEN);
   if (!dont_set_created)
     created= when= get_time();
   int4store(buff + ST_CREATED_OFFSET,created);
   buff[ST_COMMON_HEADER_LEN_OFFSET]= LOG_EVENT_HEADER_LEN;
-  memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET+1, (uchar*) post_header_len,
+  memcpy((char*) buff+ST_COMMON_HEADER_LEN_OFFSET + 1, (uchar*) post_header_len,
          LOG_EVENT_TYPES);
-  return (write_header(file, sizeof(buff)) ||
-          my_b_safe_write(file, buff, sizeof(buff)));
+  /*
+    if checksum is requested
+    record the checksum-algorithm descriptor next to
+    post_header_len vector which will be followed by the checksum value.
+    Master is supposed to trigger checksumming with opt_binlog_checksum
+    Slave does it via marking the event with the flag.
+  */
+  if (need_checksum(file))
+  {
+    compile_time_assert(sizeof(BINLOG_CHECKSUM_HEADER_SIZE == 1));
+    buff[FORMAT_DESCRIPTION_HEADER_LEN]= binlog_checksum_alg_id;
+    rec_size += BINLOG_CHECKSUM_HEADER_SIZE;
+  }
+  return (write_header(file, rec_size) ||
+          wrapper_my_b_safe_write(file, buff, rec_size) ||
+	  write_footer(file));
 }
 #endif
 
@@ -4890,8 +5099,9 @@ bool Rotate_log_event::write(IO_CACHE* f
   char buf[ROTATE_HEADER_LEN];
   int8store(buf + R_POS_OFFSET, pos);
   return (write_header(file, ROTATE_HEADER_LEN + ident_len) ||
-          my_b_safe_write(file, (uchar*)buf, ROTATE_HEADER_LEN) ||
-          my_b_safe_write(file, (uchar*)new_log_ident, (uint) ident_len));
+          wrapper_my_b_safe_write(file, (uchar*)buf, ROTATE_HEADER_LEN) ||
+          wrapper_my_b_safe_write(file, (uchar*)new_log_ident, (uint) ident_len)||
+	  write_footer(file));
 }
 #endif
 
@@ -5060,7 +5270,8 @@ bool Intvar_log_event::write(IO_CACHE* f
   buf[I_TYPE_OFFSET]= (uchar) type;
   int8store(buf + I_VAL_OFFSET, val);
   return (write_header(file, sizeof(buf)) ||
-          my_b_safe_write(file, buf, sizeof(buf)));
+          wrapper_my_b_safe_write(file, buf, sizeof(buf)) ||
+	  write_footer(file));
 }
 #endif
 
@@ -5188,7 +5399,8 @@ bool Rand_log_event::write(IO_CACHE* fil
   int8store(buf + RAND_SEED1_OFFSET, seed1);
   int8store(buf + RAND_SEED2_OFFSET, seed2);
   return (write_header(file, sizeof(buf)) ||
-          my_b_safe_write(file, buf, sizeof(buf)));
+          wrapper_my_b_safe_write(file, buf, sizeof(buf)) ||
+	  write_footer(file));
 }
 #endif
 
@@ -5290,8 +5502,9 @@ Xid_log_event(const char* buf,
 bool Xid_log_event::write(IO_CACHE* file)
 {
   DBUG_EXECUTE_IF("do_not_write_xid", return 0;);
-  return write_header(file, sizeof(xid)) ||
-         my_b_safe_write(file, (uchar*) &xid, sizeof(xid));
+  return (write_header(file, sizeof(xid)) ||
+	  wrapper_my_b_safe_write(file, (uchar*) &xid, sizeof(xid)) ||
+	  write_footer(file));
 }
 #endif
 
@@ -5508,10 +5721,11 @@ bool User_var_log_event::write(IO_CACHE*
   event_length= sizeof(buf)+ name_len + buf1_length + val_len;
 
   return (write_header(file, event_length) ||
-          my_b_safe_write(file, (uchar*) buf, sizeof(buf))   ||
-	  my_b_safe_write(file, (uchar*) name, name_len)     ||
-	  my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
-	  my_b_safe_write(file, pos, val_len));
+          wrapper_my_b_safe_write(file, (uchar*) buf, sizeof(buf))   ||
+	  wrapper_my_b_safe_write(file, (uchar*) name, name_len)     ||
+	  wrapper_my_b_safe_write(file, (uchar*) buf1, buf1_length) ||
+	  wrapper_my_b_safe_write(file, pos, val_len) ||
+	  write_footer(file));
 }
 #endif
 
@@ -6264,8 +6478,9 @@ bool Append_block_log_event::write(IO_CA
   uchar buf[APPEND_BLOCK_HEADER_LEN];
   int4store(buf + AB_FILE_ID_OFFSET, file_id);
   return (write_header(file, APPEND_BLOCK_HEADER_LEN + block_len) ||
-          my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
-	  my_b_safe_write(file, (uchar*) block, block_len));
+          wrapper_my_b_safe_write(file, buf, APPEND_BLOCK_HEADER_LEN) ||
+	  wrapper_my_b_safe_write(file, (uchar*) block, block_len) ||
+	  write_footer(file));
 }
 #endif
 
@@ -6419,7 +6634,8 @@ bool Delete_file_log_event::write(IO_CAC
  uchar buf[DELETE_FILE_HEADER_LEN];
  int4store(buf + DF_FILE_ID_OFFSET, file_id);
  return (write_header(file, sizeof(buf)) ||
-         my_b_safe_write(file, buf, sizeof(buf)));
+         wrapper_my_b_safe_write(file, buf, sizeof(buf)) ||
+	 write_footer(file));
 }
 #endif
 
@@ -6516,7 +6732,8 @@ bool Execute_load_log_event::write(IO_CA
   uchar buf[EXEC_LOAD_HEADER_LEN];
   int4store(buf + EL_FILE_ID_OFFSET, file_id);
   return (write_header(file, sizeof(buf)) || 
-          my_b_safe_write(file, buf, sizeof(buf)));
+          wrapper_my_b_safe_write(file, buf, sizeof(buf)) ||
+	  write_footer(file));
 }
 #endif
 
@@ -6577,9 +6794,11 @@ int Execute_load_log_event::do_apply_eve
                 fname);
     goto err;
   }
-  if (!(lev = (Load_log_event*)Log_event::read_log_event(&file,
-                                                         (pthread_mutex_t*)0,
-                                                         rli->relay_log.description_event_for_exec)) ||
+  if (!(lev = (Load_log_event*)
+        Log_event::read_log_event(&file,
+                                  (pthread_mutex_t*) 0,
+                                  rli->relay_log.description_event_for_exec,
+                                  opt_slave_sql_verify_checksum)) ||
       lev->get_type_code() != NEW_LOAD_EVENT)
   {
     rli->report(ERROR_LEVEL, 0, "Error in Exec_load event: "
@@ -6749,7 +6968,7 @@ Execute_load_query_log_event::write_post
   int4store(buf + 4, fn_pos_start);
   int4store(buf + 4 + 4, fn_pos_end);
   *(buf + 4 + 4 + 4)= (uchar) dup_handling;
-  return my_b_safe_write(file, buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
+  return wrapper_my_b_safe_write(file, buf, EXECUTE_LOAD_QUERY_EXTRA_HEADER_LEN);
 }
 #endif
 
@@ -7693,11 +7912,11 @@ bool Rows_log_event::write_data_header(I
                   {
                     int4store(buf + 0, m_table_id);
                     int2store(buf + 4, m_flags);
-                    return (my_b_safe_write(file, buf, 6));
+                    return (wrapper_my_b_safe_write(file, buf, 6));
                   });
   int6store(buf + RW_MAPID_OFFSET, (ulonglong)m_table_id);
   int2store(buf + RW_FLAGS_OFFSET, m_flags);
-  return (my_b_safe_write(file, buf, ROWS_HEADER_LEN));
+  return (wrapper_my_b_safe_write(file, buf, ROWS_HEADER_LEN));
 }
 
 bool Rows_log_event::write_data_body(IO_CACHE*file)
@@ -7713,10 +7932,10 @@ bool Rows_log_event::write_data_body(IO_
   DBUG_ASSERT(static_cast<size_t>(sbuf_end - sbuf) <= sizeof(sbuf));
 
   DBUG_DUMP("m_width", sbuf, (size_t) (sbuf_end - sbuf));
-  res= res || my_b_safe_write(file, sbuf, (size_t) (sbuf_end - sbuf));
+  res= res || wrapper_my_b_safe_write(file, sbuf, (size_t) (sbuf_end - sbuf));
 
   DBUG_DUMP("m_cols", (uchar*) m_cols.bitmap, no_bytes_in_map(&m_cols));
-  res= res || my_b_safe_write(file, (uchar*) m_cols.bitmap,
+  res= res || wrapper_my_b_safe_write(file, (uchar*) m_cols.bitmap,
                               no_bytes_in_map(&m_cols));
   /*
     TODO[refactor write]: Remove the "down cast" here (and elsewhere).
@@ -7725,11 +7944,11 @@ bool Rows_log_event::write_data_body(IO_
   {
     DBUG_DUMP("m_cols_ai", (uchar*) m_cols_ai.bitmap,
               no_bytes_in_map(&m_cols_ai));
-    res= res || my_b_safe_write(file, (uchar*) m_cols_ai.bitmap,
+    res= res || wrapper_my_b_safe_write(file, (uchar*) m_cols_ai.bitmap,
                                 no_bytes_in_map(&m_cols_ai));
   }
   DBUG_DUMP("rows", m_rows_buf, data_size);
-  res= res || my_b_safe_write(file, m_rows_buf, (size_t) data_size);
+  res= res || wrapper_my_b_safe_write(file, m_rows_buf, (size_t) data_size);
 
   return res;
 
@@ -8163,11 +8382,11 @@ bool Table_map_log_event::write_data_hea
                   {
                     int4store(buf + 0, m_table_id);
                     int2store(buf + 4, m_flags);
-                    return (my_b_safe_write(file, buf, 6));
+                    return (wrapper_my_b_safe_write(file, buf, 6));
                   });
   int6store(buf + TM_MAPID_OFFSET, (ulonglong)m_table_id);
   int2store(buf + TM_FLAGS_OFFSET, m_flags);
-  return (my_b_safe_write(file, buf, TABLE_MAP_HEADER_LEN));
+  return (wrapper_my_b_safe_write(file, buf, TABLE_MAP_HEADER_LEN));
 }
 
 bool Table_map_log_event::write_data_body(IO_CACHE *file)
@@ -8191,15 +8410,15 @@ bool Table_map_log_event::write_data_bod
   uchar mbuf[sizeof(m_field_metadata_size)];
   uchar *const mbuf_end= net_store_length(mbuf, m_field_metadata_size);
 
-  return (my_b_safe_write(file, dbuf,      sizeof(dbuf)) ||
-          my_b_safe_write(file, (const uchar*)m_dbnam,   m_dblen+1) ||
-          my_b_safe_write(file, tbuf,      sizeof(tbuf)) ||
-          my_b_safe_write(file, (const uchar*)m_tblnam,  m_tbllen+1) ||
-          my_b_safe_write(file, cbuf, (size_t) (cbuf_end - cbuf)) ||
-          my_b_safe_write(file, m_coltype, m_colcnt) ||
-          my_b_safe_write(file, mbuf, (size_t) (mbuf_end - mbuf)) ||
-          my_b_safe_write(file, m_field_metadata, m_field_metadata_size),
-          my_b_safe_write(file, m_null_bits, (m_colcnt + 7) / 8));
+  return (wrapper_my_b_safe_write(file, dbuf,      sizeof(dbuf)) ||
+          wrapper_my_b_safe_write(file, (const uchar*)m_dbnam,   m_dblen+1) ||
+          wrapper_my_b_safe_write(file, tbuf,      sizeof(tbuf)) ||
+          wrapper_my_b_safe_write(file, (const uchar*)m_tblnam,  m_tbllen+1) ||
+          wrapper_my_b_safe_write(file, cbuf, (size_t) (cbuf_end - cbuf)) ||
+          wrapper_my_b_safe_write(file, m_coltype, m_colcnt) ||
+          wrapper_my_b_safe_write(file, mbuf, (size_t) (mbuf_end - mbuf)) ||
+          wrapper_my_b_safe_write(file, m_field_metadata, m_field_metadata_size),
+          wrapper_my_b_safe_write(file, m_null_bits, (m_colcnt + 7) / 8));
  }
 #endif
 
@@ -9415,13 +9634,25 @@ Incident_log_event::write_data_header(IO
   DBUG_PRINT("enter", ("m_incident: %d", m_incident));
   uchar buf[sizeof(int16)];
   int2store(buf, (int16) m_incident);
-  DBUG_RETURN(my_b_safe_write(file, buf, sizeof(buf)));
+#ifndef MYSQL_CLIENT
+  DBUG_RETURN(wrapper_my_b_safe_write(file, buf, sizeof(buf)));
+#else
+   DBUG_RETURN(my_b_safe_write(file, buf, sizeof(buf)));
+#endif
 }
 
 bool
 Incident_log_event::write_data_body(IO_CACHE *file)
 {
+  uchar tmp[1];
   DBUG_ENTER("Incident_log_event::write_data_body");
+  tmp[0]= (uchar) m_message.length;
+  crc= my_checksum(crc, (uchar*) tmp, 1);
+  if (m_message.length > 0)
+  {
+    crc= my_checksum(crc, (uchar*) m_message.str, m_message.length);
+    // todo: report a bug on write_str accepts uint but treats it as uchar
+  }
   DBUG_RETURN(write_str(file, m_message.str, (uint) m_message.length));
 }
 

=== modified file 'sql/log_event.h'
--- a/sql/log_event.h	2009-11-06 16:35:04 +0000
+++ b/sql/log_event.h	2010-05-03 09:52:27 +0000
@@ -72,6 +72,7 @@
 #define LOG_READ_MEM    -5
 #define LOG_READ_TRUNC  -6
 #define LOG_READ_TOO_LARGE -7
+#define LOG_READ_CHECKSUM_FAILURE -8
 
 #define LOG_EVENT_OFFSET 4
 
@@ -272,6 +273,9 @@ struct sql_ex_info
   MAX_SIZE_LOG_EVENT_STATUS + /* status */ \
   NAME_LEN + 1)
 
+#define BINLOG_CHECKSUM_LEN         4  /* 4 bytes in CRC32 the only current alg  */
+#define BINLOG_CHECKSUM_HEADER_SIZE 1  /* 1 byte contribution to FD post_header */
+
 /* 
    Event header offsets; 
    these point to places inside the fixed header.
@@ -484,6 +488,13 @@ struct sql_ex_info
 #define LOG_EVENT_RELAY_LOG_F 0x40
 
 /**
+   @def LOG_EVENT_CHECKSUM_F
+   
+   Events with CRC32 checksum
+*/
+#define LOG_EVENT_CHECKSUM_F 0x80
+
+/**
   @def OPTIONS_WRITTEN_TO_BIN_LOG
 
   OPTIONS_WRITTEN_TO_BIN_LOG are the bits of thd->options which must
@@ -929,6 +940,10 @@ public:
   */
   ulong slave_exec_mode;
 
+  /**
+    Placeholder for event checksum while writing to binlog.
+   */
+  ha_checksum crc;
 #ifndef MYSQL_CLIENT
   THD* thd;
 
@@ -948,7 +963,8 @@ public:
   static Log_event* read_log_event(IO_CACHE* file,
 				   pthread_mutex_t* log_lock,
                                    const Format_description_log_event
-                                   *description_event);
+                                   *description_event,
+                                   my_bool crc_check);
   static int read_log_event(IO_CACHE* file, String* packet,
 			    pthread_mutex_t* log_lock);
   /*
@@ -977,7 +993,7 @@ public:
     /* avoid having to link mysqlbinlog against libpthread */
   static Log_event* read_log_event(IO_CACHE* file,
                                    const Format_description_log_event
-                                   *description_event);
+                                   *description_event, my_bool crc_check);
   /* print*() functions are used by mysqlbinlog */
   virtual void print(FILE* file, PRINT_EVENT_INFO* print_event_info) = 0;
   void print_timestamp(IO_CACHE* file, time_t *ts = 0);
@@ -1001,13 +1017,19 @@ public:
   static void *operator new(size_t, void* ptr) { return ptr; }
   static void operator delete(void*, void*) { }
 
+
 #ifndef MYSQL_CLIENT
+  bool wrapper_my_b_safe_write(IO_CACHE* file, const uchar* buf, ulong data_length);
   bool write_header(IO_CACHE* file, ulong data_length);
+  bool write_footer(IO_CACHE* file);
+  my_bool need_checksum(IO_CACHE* file);
+
   virtual bool write(IO_CACHE* file)
   {
-    return (write_header(file, get_data_size()) ||
-            write_data_header(file) ||
-            write_data_body(file));
+    return(write_header(file, get_data_size()) ||
+	   write_data_header(file) ||
+	   write_data_body(file) ||
+	   write_footer(file));
   }
   virtual bool write_data_header(IO_CACHE* file)
   { return 0; }
@@ -1052,7 +1074,7 @@ public:
   static Log_event* read_log_event(const char* buf, uint event_len,
 				   const char **error,
                                    const Format_description_log_event
-                                   *description_event);
+                                   *description_event, my_bool crc_check);
   /**
     Returns the human readable name of the given event type.
   */
@@ -2229,6 +2251,13 @@ public:
   }
 
   void calc_server_version_split();
+  /*
+    returns relative to the start of the event position of checksum alg:s flags
+  */
+  static my_off_t checksum_flag_offset()
+  {
+    return (LOG_EVENT_MINIMAL_HEADER_LEN + FORMAT_DESCRIPTION_HEADER_LEN); 
+  }
 
 protected:
 #if !defined(MYSQL_CLIENT) && defined(HAVE_REPLICATION)
@@ -2454,7 +2483,7 @@ public:
   User_var_log_event(THD* thd_arg, char *name_arg, uint name_len_arg,
                      char *val_arg, ulong val_len_arg, Item_result type_arg,
 		     uint charset_number_arg)
-    :Log_event(), name(name_arg), name_len(name_len_arg), val(val_arg),
+    :Log_event(thd_arg, 0, 0), name(name_arg), name_len(name_len_arg), val(val_arg),
     val_len(val_len_arg), type(type_arg), charset_number(charset_number_arg)
     { is_null= !val; }
   void pack_info(Protocol* protocol);
@@ -3981,4 +4010,6 @@ private:
   @} (end of group Replication)
 */
 
+bool
+event_checksum_test(uchar *buf, ulong event_len);
 #endif /* _log_event_h */

=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h	2009-11-13 10:17:53 +0000
+++ b/sql/mysql_priv.h	2010-05-03 09:52:27 +0000
@@ -1879,6 +1879,9 @@ extern ulong binlog_cache_size, open_fil
 extern ulonglong max_binlog_cache_size;
 extern ulong max_binlog_size, max_relay_log_size;
 extern ulong opt_binlog_rows_event_max_size;
+extern volatile my_bool opt_binlog_checksum;
+extern my_bool opt_master_verify_checksum;
+extern my_bool opt_slave_sql_verify_checksum;
 extern ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
 extern ulong back_log;
 #endif /* MYSQL_SERVER */

=== modified file 'sql/mysqld.cc'
--- a/sql/mysqld.cc	2009-11-13 10:17:53 +0000
+++ b/sql/mysqld.cc	2010-05-03 09:52:27 +0000
@@ -503,6 +503,9 @@ my_bool opt_noacl;
 my_bool sp_automatic_privileges= 1;
 
 ulong opt_binlog_rows_event_max_size;
+volatile my_bool opt_binlog_checksum;
+my_bool opt_master_verify_checksum= 0;
+my_bool opt_slave_sql_verify_checksum= 1;
 const char *binlog_format_names[]= {"MIXED", "STATEMENT", "ROW", NullS};
 TYPELIB binlog_format_typelib=
   { array_elements(binlog_format_names) - 1, "",
@@ -5555,7 +5558,10 @@ enum options_mysqld
 #ifndef DBUG_OFF
   OPT_BINLOG_SHOW_XID,
 #endif
-  OPT_BINLOG_ROWS_EVENT_MAX_SIZE, 
+  OPT_BINLOG_ROWS_EVENT_MAX_SIZE,
+  OPT_BINLOG_CHECKSUM,
+  OPT_MASTER_VERIFY_CHECKSUM,
+  OPT_SLAVE_SQL_VERIFY_CHECKSUM,
   OPT_WANT_CORE,               OPT_CONCURRENT_INSERT,
   OPT_MEMLOCK,                 OPT_MYISAM_RECOVER,
   OPT_REPLICATE_REWRITE_DB,    OPT_SERVER_ID,
@@ -5771,9 +5777,29 @@ struct my_option my_long_options[] =
    (uchar**) &opt_binlog_rows_event_max_size, 0, 
    GET_ULONG, REQUIRED_ARG, 
    /* def_value */ 1024, /* min_value */  256, /* max_value */ ULONG_MAX, 
-   /* sub_size */     0, /* block_size */ 256, 
+   /* sub_size */     0, /* block_size */ 256,
    /* app_type */ 0
   },
+  {"binlog-checksum", OPT_BINLOG_CHECKSUM,
+   "Adding checksum (CRC32 only algorithm currently) for binlogged events. "
+   "Disabled by default.",
+   (uchar**) &opt_binlog_checksum, (uchar**) &opt_binlog_checksum, 0, GET_BOOL,
+   NO_ARG, 0, 0, 1, 0, 0, 0},
+  {"master-verify-checksum", OPT_MASTER_VERIFY_CHECKSUM,
+   "Forcing verification of binlogged events checksum before sending them "
+   "to slaves and in show binlog event. "
+   "Enabled by default.",
+   (uchar**) &opt_master_verify_checksum,
+   (uchar**) &opt_master_verify_checksum,
+   0, GET_BOOL, NO_ARG, 0, 0, 1, 0, 0, 0},
+  {"slave-sql-verify-checksum", OPT_SLAVE_SQL_VERIFY_CHECKSUM,
+   "Forcing verification of CRC-checksum of replication events after reading "
+   "them from the relay log. Notice, CRC-ed events are always verified by slave at "
+   "receiving from the network before to be written to the relay log. "
+   "Enabled by default.",
+   (uchar**) &opt_slave_sql_verify_checksum,
+   (uchar**) &opt_slave_sql_verify_checksum,
+   0, GET_BOOL, NO_ARG, 1, 0, 1, 0, 0, 0},
 #ifndef DISABLE_GRANT_OPTIONS
   {"bootstrap", OPT_BOOTSTRAP, "Used by mysql installation scripts.", 0, 0, 0,
    GET_NO_ARG, NO_ARG, 0, 0, 0, 0, 0, 0},

=== modified file 'sql/repl_failsafe.cc'
--- a/sql/repl_failsafe.cc	2009-11-13 10:17:53 +0000
+++ b/sql/repl_failsafe.cc	2010-05-03 09:52:27 +0000
@@ -243,7 +243,7 @@ static int find_target_pos(LEX_MASTER_IN
   for (;;)
   {
     Log_event* ev;
-    if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0)))
+    if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0, 0)))
     {
       if (log->error > 0)
 	strmov(errmsg, "Binary log truncated in the middle of event");
@@ -417,7 +417,7 @@ static Slave_log_event* find_slave_event
 
   for (i = 0; i < 2; i++)
   {
-    if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*)0, 0)))
+    if (!(ev = Log_event::read_log_event(log, (pthread_mutex_t*) 0, 0, 0)))
     {
       my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
 		  "Error reading event in log '%s'",

=== modified file 'sql/rpl_rli.cc'
--- a/sql/rpl_rli.cc	2009-11-06 16:35:04 +0000
+++ b/sql/rpl_rli.cc	2010-05-03 09:52:27 +0000
@@ -155,6 +155,7 @@ int init_relay_log_info(Relay_log_info* 
                         "use '--relay-log=%s' to avoid this problem.", ln);
       name_warning_sent= 1;
     }
+    rli->relay_log.is_relay_log= TRUE;
     /*
       note, that if open() fails, we'll still have index file open
       but a destructor will take care of that
@@ -168,7 +169,6 @@ int init_relay_log_info(Relay_log_info* 
       sql_print_error("Failed in open_log() called from init_relay_log_info()");
       DBUG_RETURN(1);
     }
-    rli->relay_log.is_relay_log= TRUE;
   }
 
   /* if file does not exist */
@@ -520,8 +520,9 @@ int init_relay_log_pos(Relay_log_info* r
         Because of we have rli->data_lock and log_lock, we can safely read an
         event
       */
-      if (!(ev=Log_event::read_log_event(rli->cur_log,0,
-                                         rli->relay_log.description_event_for_exec)))
+      if (!(ev= Log_event::read_log_event(rli->cur_log, 0,
+                                          rli->relay_log.description_event_for_exec,
+                                          opt_slave_sql_verify_checksum)))
       {
         DBUG_PRINT("info",("could not read event, rli->cur_log->error=%d",
                            rli->cur_log->error));

=== modified file 'sql/set_var.cc'
--- a/sql/set_var.cc	2009-11-13 10:17:53 +0000
+++ b/sql/set_var.cc	2010-05-03 09:52:27 +0000
@@ -1560,6 +1560,30 @@ sys_var_long_ptr(sys_var_chain *chain, c
                            &LOCK_global_system_variables, after_update_arg)
 {}
 
+sys_var_bool_ptr_global::sys_var_bool_ptr_global(sys_var_chain *chain,
+                                                 const char *name_arg,
+                                                 my_bool *value_arg,
+                                                 pthread_mutex_t *guard_arg,
+                                                 sys_after_update_func after_update_arg)
+  :sys_var_global(name_arg, after_update_arg, guard_arg), value(value_arg)	
+{ 
+  chain_sys_var(chain);
+}
+
+bool sys_var_bool_ptr_global::update(THD *thd, set_var *var)
+{
+  pthread_mutex_lock(guard);
+  *value= (my_bool) var->save_result.ulong_value;
+  pthread_mutex_unlock(guard);
+  return 0;
+}
+
+void sys_var_bool_ptr_global::set_default(THD *thd, enum_var_type type)
+{
+  pthread_mutex_lock(guard);
+  *value= (my_bool) option_limits->def_value;
+  pthread_mutex_unlock(guard);
+}
 
 bool sys_var_long_ptr_global::check(THD *thd, set_var *var)
 {

=== modified file 'sql/set_var.h'
--- a/sql/set_var.h	2009-11-13 10:17:53 +0000
+++ b/sql/set_var.h	2010-05-03 09:52:27 +0000
@@ -258,6 +258,27 @@ public:
   bool is_readonly() const { return 1; }
 };
 
+class sys_var_bool_ptr_global: public sys_var_global
+{
+  public:
+  enum_var_type var_type;
+  my_bool *value;
+  sys_var_bool_ptr_global(sys_var_chain *chain, const char *name_arg, my_bool *value_arg,
+                          pthread_mutex_t *guard_arg,
+                          sys_after_update_func after_update_arg= NULL);
+  bool check(THD *thd, set_var *var)
+  {
+    return check_enum(thd, var, &bool_typelib);
+  }
+  bool update(THD *thd, set_var *var);
+  void set_default(THD *thd, enum_var_type type);
+  SHOW_TYPE show_type() { return SHOW_MY_BOOL; }
+  uchar *value_ptr(THD *thd, enum_var_type type, LEX_STRING *base)
+  { return (uchar*) value; }
+  bool check_update_type(Item_result type) { return 0; }
+  bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
+};
+
 
 class sys_var_str :public sys_var
 {

=== modified file 'sql/share/errmsg.txt'
--- a/sql/share/errmsg.txt	2009-11-13 10:17:53 +0000
+++ b/sql/share/errmsg.txt	2010-05-03 09:52:27 +0000
@@ -6216,3 +6216,10 @@ ER_DEBUG_SYNC_TIMEOUT
 ER_DEBUG_SYNC_HIT_LIMIT
   eng "debug sync point hit limit reached"
   ger "Debug Sync Point Hit Limit erreicht"
+
+ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE
+  eng "Replication event checksum verification failed while reading from network."
+ER_BINLOG_READ_EVENT_CHECKSUM_FAILURE
+  eng "Replication event checksum verification failed while reading from a log file."
+ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE
+  eng "Slave can not handle replication events with the checksum that master is configured to log."

=== modified file 'sql/slave.cc'
--- a/sql/slave.cc	2009-11-20 13:30:35 +0000
+++ b/sql/slave.cc	2010-05-03 09:52:27 +0000
@@ -1426,19 +1426,59 @@ when it try to get the value of TIME_ZON
     llstr((ulonglong) (mi->heartbeat_period*1000000000UL), llbuf);
     my_sprintf(query, (query, query_format, llbuf));
 
-    if (mysql_real_query(mysql, query, strlen(query))
-        && !check_io_slave_killed(mi->io_thd, mi, NULL))
+    if (mysql_real_query(mysql, query, strlen(query)))
     {
-      errmsg= "The slave I/O thread stops because SET @master_heartbeat_period "
-        "on master failed.";
-      err_code= ER_SLAVE_FATAL_ERROR;
-      sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
-      mysql_free_result(mysql_store_result(mysql));
-      goto err;
+      if (is_network_error(mysql_errno(mysql)))
+      {
+        mi->report(WARNING_LEVEL, mysql_errno(mysql),
+                   "SET @master_heartbeat_period to master failed with error: %s",
+                   mysql_error(mysql));
+        mysql_free_result(mysql_store_result(mysql));
+        goto network_err;
+      }
+      else
+      {
+        /* Fatal error */
+        errmsg= "The slave I/O thread stops because a fatal error is encountered "
+          " when it tries to SET @master_heartbeat_period on master.";
+        err_code= ER_SLAVE_FATAL_ERROR;
+        sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
+        mysql_free_result(mysql_store_result(mysql));
+        goto err;
+      }
     }
     mysql_free_result(mysql_store_result(mysql));
   }
- 
+  
+  /*
+    Notifying the master about CRC-awareness of this slave
+  */
+  {
+    int rc;
+    const char query[]= "SET @slave_is_checksum_aware= 1";
+    rc= mysql_real_query(mysql, query, strlen(query));
+    if (rc == 0)
+      mysql_free_result(mysql_store_result(mysql));
+    else 
+      if (is_network_error(mysql_errno(mysql)))
+      {
+        mi->report(WARNING_LEVEL, mysql_errno(mysql),
+                   "Notifying master by SET @slave_is_checksum_aware failed with "
+                   "error: %s", mysql_error(mysql));
+        mysql_free_result(mysql_store_result(mysql));
+        goto network_err;
+      }
+      else
+      {
+        errmsg= "The slave I/O thread stops because a fatal error is encountered "
+          "when it tried to SET @slave_is_checksum on master.";
+        err_code= ER_SLAVE_FATAL_ERROR;
+        sprintf(err_buff, "%s Error: %s", errmsg, mysql_error(mysql));
+        mysql_free_result(mysql_store_result(mysql));
+        goto err;
+      }
+    mysql_free_result(mysql_store_result(mysql));
+  }
 
 err:
   if (errmsg)
@@ -2803,6 +2843,11 @@ Stopping slave I/O thread due to out-of-
           mi->report(ERROR_LEVEL, ER_OUT_OF_RESOURCES,
                      "%s", ER(ER_OUT_OF_RESOURCES));
           goto err;
+        case ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE:
+          mi->report(ERROR_LEVEL, ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE,
+                     ER(ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE),
+                     mysql_error_number, mysql_error(mysql));
+          goto err;
         }
         if (try_to_reconnect(thd, mysql, mi, &retry_count, suppress_warnings,
                              reconnect_messages[SLAVE_RECON_ACT_EVENT]))
@@ -3521,8 +3566,9 @@ static int queue_binlog_ver_1_event(Mast
     Append_block/Exec_load (the SQL thread needs the data, as that thread is not
     connected to the master).
   */
-  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
-                                            mi->rli.relay_log.description_event_for_queue);
+  Log_event *ev=
+    Log_event::read_log_event(buf,event_len, &errmsg,
+                              mi->rli.relay_log.description_event_for_queue, 0);
   if (unlikely(!ev))
   {
     sql_print_error("Read invalid event from master: '%s',\
@@ -3609,8 +3655,9 @@ static int queue_binlog_ver_3_event(Mast
   DBUG_ENTER("queue_binlog_ver_3_event");
 
   /* read_log_event() will adjust log_pos to be end_log_pos */
-  Log_event *ev = Log_event::read_log_event(buf,event_len, &errmsg,
-                                            mi->rli.relay_log.description_event_for_queue);
+  Log_event *ev=
+    Log_event::read_log_event(buf, event_len, &errmsg,
+                              mi->rli.relay_log.description_event_for_queue, 0);
   if (unlikely(!ev))
   {
     sql_print_error("Read invalid event from master: '%s',\
@@ -3636,6 +3683,7 @@ static int queue_binlog_ver_3_event(Mast
     inc_pos= event_len;
     break;
   }
+
   if (unlikely(rli->relay_log.append(ev)))
   {
     delete ev;
@@ -3699,8 +3747,17 @@ static int queue_event(Master_info* mi,c
   Relay_log_info *rli= &mi->rli;
   pthread_mutex_t *log_lock= rli->relay_log.get_log_lock();
   ulong s_id;
+  bool unlock_data_lock= TRUE;
+  uint16 flags= uint2korr(buf + FLAGS_OFFSET);
   DBUG_ENTER("queue_event");
 
+  if (event_checksum_test((uchar *) buf, event_len))
+  {
+    error= ER_NETWORK_READ_EVENT_CHECKSUM_FAILURE;
+    unlock_data_lock= FALSE;
+    goto err;
+  }
+
   LINT_INIT(inc_pos);
 
   if (mi->rli.relay_log.description_event_for_queue->binlog_version<4 &&
@@ -3727,7 +3784,11 @@ static int queue_event(Master_info* mi,c
     goto err;
   case ROTATE_EVENT:
   {
-    Rotate_log_event rev(buf,event_len,mi->rli.relay_log.description_event_for_queue);
+    Rotate_log_event rev(buf,
+			 (flags & LOG_EVENT_CHECKSUM_F) ?
+                         event_len - BINLOG_CHECKSUM_LEN : event_len,
+                         mi->rli.relay_log.description_event_for_queue);
+
     if (unlikely(process_io_rotate(mi,&rev)))
     {
       error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
@@ -3755,7 +3816,8 @@ static int queue_event(Master_info* mi,c
     const char* errmsg;
     if (!(tmp= (Format_description_log_event*)
           Log_event::read_log_event(buf, event_len, &errmsg,
-                                    mi->rli.relay_log.description_event_for_queue)))
+                                    mi->rli.relay_log.description_event_for_queue,
+                                    0)))
     {
       error= ER_SLAVE_RELAY_LOG_WRITE_FAILURE;
       goto err;
@@ -3783,7 +3845,10 @@ static int queue_event(Master_info* mi,c
       HB (heartbeat) cannot come before RL (Relay)
     */
     char  llbuf[22];
-    Heartbeat_log_event hb(buf, event_len, mi->rli.relay_log.description_event_for_queue);
+    Heartbeat_log_event hb(buf,
+                           ((flags & LOG_EVENT_CHECKSUM_F) == LOG_EVENT_CHECKSUM_F) ?
+                           event_len - BINLOG_CHECKSUM_LEN : event_len,
+                           mi->rli.relay_log.description_event_for_queue);
     if (!hb.is_valid())
     {
       error= ER_SLAVE_HEARTBEAT_FAILURE;
@@ -3911,7 +3976,8 @@ static int queue_event(Master_info* mi,c
 skip_relay_logging:
   
 err:
-  pthread_mutex_unlock(&mi->data_lock);
+  if (unlock_data_lock)
+    pthread_mutex_unlock(&mi->data_lock);
   DBUG_PRINT("info", ("error: %d", error));
   if (error)
     mi->report(ERROR_LEVEL, error, ER(error), 
@@ -4377,8 +4443,9 @@ static Log_event* next_event(Relay_log_i
       But if the relay log is created by new_file(): then the solution is:
       MYSQL_BIN_LOG::open() will write the buffered description event.
     */
-    if ((ev=Log_event::read_log_event(cur_log,0,
-                                      rli->relay_log.description_event_for_exec)))
+    if ((ev=Log_event::read_log_event(cur_log, 0,
+                                      rli->relay_log.description_event_for_exec,
+                                      opt_slave_sql_verify_checksum)))
 
     {
       DBUG_ASSERT(thd==rli->sql_thd);

=== modified file 'sql/sql_binlog.cc'
--- a/sql/sql_binlog.cc	2009-11-06 16:35:04 +0000
+++ b/sql/sql_binlog.cc	2010-05-03 09:52:27 +0000
@@ -173,7 +173,8 @@ void mysql_client_binlog_statement(THD* 
       }
 
       ev= Log_event::read_log_event(bufptr, event_len, &error,
-                                    rli->relay_log.description_event_for_exec);
+                                    rli->relay_log.description_event_for_exec,
+                                    0);
 
       DBUG_PRINT("info",("binlog base64 err=%s", error));
       if (!ev)

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2009-11-06 16:35:04 +0000
+++ b/sql/sql_class.h	2010-05-03 09:52:27 +0000
@@ -115,7 +115,7 @@ typedef struct st_user_var_events
 
 #define RP_LOCK_LOG_IS_ALREADY_LOCKED 1
 #define RP_FORCE_ROTATE               2
-
+#define RP_BINLOG_CHECKSUM_ON_OFF     4
 /*
   The COPY_INFO structure is used by INSERT/REPLACE code.
   The schema of the row counting by the INSERT/INSERT ... ON DUPLICATE KEY
@@ -1477,6 +1477,7 @@ public:
   uint get_binlog_table_maps() const {
     return binlog_table_maps;
   }
+
 #endif /* MYSQL_CLIENT */
 
 public:

=== modified file 'sql/sql_repl.cc'
--- a/sql/sql_repl.cc	2009-11-20 13:30:35 +0000
+++ b/sql/sql_repl.cc	2010-05-03 09:52:27 +0000
@@ -29,6 +29,28 @@ my_bool opt_sporadic_binlog_dump_fail = 
 static int binlog_dump_count = 0;
 #endif
 
+/**
+   Internal to mysql_binlog_send() routine that recalculates checksum for
+   a FD event (asserted) that needs additional arranment prior sending to slave.
+*/
+static void fix_checksum(String *packet, ulong ev_offset)
+{
+  uint16 flags= uint2korr(packet->ptr() + ev_offset + FLAGS_OFFSET);
+
+  /* recalculate the crc for this event */
+  if (flags & LOG_EVENT_CHECKSUM_F)
+  {
+    uint data_len = uint4korr(packet->ptr() + ev_offset + EVENT_LEN_OFFSET);
+    ha_checksum crc= my_checksum(0L, NULL, 0);
+    DBUG_ASSERT(data_len == 
+                LOG_EVENT_MINIMAL_HEADER_LEN + FORMAT_DESCRIPTION_HEADER_LEN +
+                BINLOG_CHECKSUM_HEADER_SIZE +  BINLOG_CHECKSUM_LEN);
+    crc= my_checksum(crc, (uchar *)packet->ptr() + ev_offset, data_len -
+                     BINLOG_CHECKSUM_LEN);
+    int4store(packet->ptr() + ev_offset + data_len - BINLOG_CHECKSUM_LEN, crc);
+  }
+}
+
 /*
     fake_rotate_event() builds a fake (=which does not exist physically in any
     binlog) Rotate event, which contains the name of the binlog we are going to
@@ -52,27 +74,42 @@ static int fake_rotate_event(NET* net, S
 {
   DBUG_ENTER("fake_rotate_event");
   char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN+100];
+  my_bool do_checksum= opt_binlog_checksum;
   /*
     'when' (the timestamp) is set to 0 so that slave could distinguish between
     real and fake Rotate events (if necessary)
   */
   memset(header, 0, 4);
-  header[EVENT_TYPE_OFFSET] = ROTATE_EVENT;
+  header[EVENT_TYPE_OFFSET]= ROTATE_EVENT;
 
   char* p = log_file_name+dirname_length(log_file_name);
   uint ident_len = (uint) strlen(p);
-  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN + ROTATE_HEADER_LEN;
+  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN + ROTATE_HEADER_LEN + (do_checksum ? BINLOG_CHECKSUM_LEN : 0);
+  uint16 flags= LOG_EVENT_ARTIFICIAL_F | (do_checksum ? LOG_EVENT_CHECKSUM_F : 0);
+
   int4store(header + SERVER_ID_OFFSET, server_id);
   int4store(header + EVENT_LEN_OFFSET, event_len);
-  int2store(header + FLAGS_OFFSET, LOG_EVENT_ARTIFICIAL_F);
+  int2store(header + FLAGS_OFFSET, flags);
 
   // TODO: check what problems this may cause and fix them
   int4store(header + LOG_POS_OFFSET, 0);
 
   packet->append(header, sizeof(header));
-  int8store(buf+R_POS_OFFSET,position);
+  int8store(buf+R_POS_OFFSET, position);
   packet->append(buf, ROTATE_HEADER_LEN);
-  packet->append(p,ident_len);
+  packet->append(p, ident_len);
+
+  if (do_checksum)
+  {
+    char b[BINLOG_CHECKSUM_LEN];
+    ha_checksum crc= my_checksum(0L, NULL, 0);
+    crc= my_checksum(crc, (uchar*)header, sizeof(header));
+    crc= my_checksum(crc, (uchar*)buf, ROTATE_HEADER_LEN);
+    crc= my_checksum(crc, (uchar*)p, ident_len);
+    int4store(b, crc);
+    packet->append(b, sizeof(b));
+  }
+
   if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
   {
     *errmsg = "failed on my_net_write()";
@@ -342,6 +379,9 @@ Increase max_allowed_packet on master";
   case LOG_READ_TRUNC:
     *errmsg = "binlog truncated in the middle of event";
     break;
+  case LOG_READ_CHECKSUM_FAILURE:
+    *errmsg = "event read from binlog did not pass crc check";
+    break;
   default:
     *errmsg = "unknown error reading log event on the master";
     break;
@@ -388,6 +428,7 @@ static int send_heartbeat_event(NET* net
 {
   DBUG_ENTER("send_heartbeat_event");
   char header[LOG_EVENT_HEADER_LEN];
+  my_bool do_checksum= opt_binlog_checksum;
   /*
     'when' (the timestamp) is set to 0 so that slave could distinguish between
     real and fake Rotate events (if necessary)
@@ -399,16 +440,27 @@ static int send_heartbeat_event(NET* net
   char* p= coord->file_name + dirname_length(coord->file_name);
 
   uint ident_len = strlen(p);
-  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN;
+  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN +
+    (do_checksum ? BINLOG_CHECKSUM_LEN : 0);
   int4store(header + SERVER_ID_OFFSET, server_id);
   int4store(header + EVENT_LEN_OFFSET, event_len);
-  int2store(header + FLAGS_OFFSET, 0);
+  int2store(header + FLAGS_OFFSET, do_checksum ? LOG_EVENT_CHECKSUM_F : 0);
 
   int4store(header + LOG_POS_OFFSET, coord->pos);  // log_pos
 
   packet->append(header, sizeof(header));
   packet->append(p, ident_len);             // log_file_name
 
+  if (do_checksum)
+  {
+    char b[BINLOG_CHECKSUM_LEN];
+    ha_checksum crc= my_checksum(0L, NULL, 0);
+    crc= my_checksum(crc, (uchar*) header, sizeof(header));
+    crc= my_checksum(crc, (uchar*) p, ident_len);
+    int4store(b, crc);
+    packet->append(b, sizeof(b));
+  }
+
   if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) ||
       net_flush(net))
   {
@@ -417,6 +469,29 @@ static int send_heartbeat_event(NET* net
   DBUG_RETURN(0);
 }
 
+/**
+  An auxiliary function for calling in mysql_binlog_send
+  to check if slave passed crc-handshake.
+
+  @param[in]    thd  THD to access a user variable
+
+  @return        heartbeat period an ulonglong of nanoseconds
+                 or zero if heartbeat was not demanded by slave
+*/ 
+static bool is_slave_crc_aware(THD * thd)
+{
+  DBUG_ENTER("is_slave_crc_aware");
+  my_bool null_value;
+  LEX_STRING name=  { C_STRING_WITH_LEN("slave_is_checksum_aware")};
+  user_var_entry *entry= 
+    (user_var_entry*) hash_search(&thd->user_vars, (uchar*) name.str,
+                                  name.length);
+
+  DBUG_EXECUTE_IF("simulate_slave_unaware_checksum", entry= NULL;);
+  DBUG_ASSERT(!entry || entry->val_int(&null_value) == 1);
+  DBUG_RETURN(entry? true  : false);
+}
+
 /*
   TODO: Clean up loop to only have one call to send_file()
 */
@@ -463,6 +538,7 @@ void mysql_binlog_send(THD* thd, char* l
   }
   sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)",
                         thd->server_id, log_ident, (ulong)pos);
+  
   if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
   {
     errmsg= "Failed to run hook 'transmit_start'";
@@ -591,8 +667,8 @@ impossible position";
        Try to find a Format_description_log_event at the beginning of
        the binlog
      */
-     if (!(error = Log_event::read_log_event(&log, packet, log_lock)))
-     {
+    if (!(error = Log_event::read_log_event(&log, packet, log_lock)))
+    { 
        /*
          The packet has offsets equal to the normal offsets in a
          binlog event + ev_offset (the first ev_offset characters are
@@ -603,6 +679,13 @@ impossible position";
                    (*packet)[EVENT_TYPE_OFFSET+ev_offset]));
        if ((*packet)[EVENT_TYPE_OFFSET+ev_offset] == FORMAT_DESCRIPTION_EVENT)
        {
+         if (!is_slave_crc_aware(thd) &&
+             (*packet)[ev_offset + FLAGS_OFFSET] & LOG_EVENT_CHECKSUM_F)
+         {
+           my_errno= ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE;
+           errmsg= ER(my_errno);
+           goto err;
+         }
          binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] &
                                        LOG_EVENT_BINLOG_IN_USE_F);
          (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
@@ -618,6 +701,10 @@ impossible position";
           */
          int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
                    ST_CREATED_OFFSET+ev_offset, (ulong) 0);
+
+	 /* fix the checksum due to latest changes in header */
+	 fix_checksum(packet, ev_offset);
+
          /* send it */
          if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
          {
@@ -680,6 +767,13 @@ impossible position";
       event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
       if (event_type == FORMAT_DESCRIPTION_EVENT)
       {
+        if (!is_slave_crc_aware(thd) &&
+            (*packet)[ev_offset + FLAGS_OFFSET] & LOG_EVENT_CHECKSUM_F)
+        {
+          my_errno= ER_SLAVE_IS_NOT_CHECKSUM_CAPABLE;
+          errmsg= ER(my_errno);
+           goto err;
+        }
         binlog_can_be_corrupted= test((*packet)[FLAGS_OFFSET+ev_offset] &
                                       LOG_EVENT_BINLOG_IN_USE_F);
         (*packet)[FLAGS_OFFSET+ev_offset] &= ~LOG_EVENT_BINLOG_IN_USE_F;
@@ -730,7 +824,8 @@ impossible position";
       here we were reading binlog that was not closed properly (as a result
       of a crash ?). treat any corruption as EOF
     */
-    if (binlog_can_be_corrupted && error != LOG_READ_MEM)
+    if (binlog_can_be_corrupted &&
+        (error != LOG_READ_MEM && error != LOG_READ_CHECKSUM_FAILURE))
       error=LOG_READ_EOF;
     /*
       TODO: now that we are logging the offset, check to make sure
@@ -798,6 +893,7 @@ impossible position";
           if (coord)
             coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
           event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
+          DBUG_ASSERT(event_type != FORMAT_DESCRIPTION_EVENT);
 	  break;
 
 	case LOG_READ_EOF:
@@ -1735,7 +1831,8 @@ bool mysql_show_binlog_events(THD* thd)
       This code will fail on a mixed relay log (one which has Format_desc then
       Rotate then Format_desc).
     */
-    ev = Log_event::read_log_event(&log,(pthread_mutex_t*)0,description_event);
+    ev = Log_event::read_log_event(&log, (pthread_mutex_t*) 0, description_event,
+                                   opt_master_verify_checksum);
     if (ev)
     {
       if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
@@ -1757,7 +1854,8 @@ bool mysql_show_binlog_events(THD* thd)
 
     for (event_count = 0;
 	 (ev = Log_event::read_log_event(&log,(pthread_mutex_t*) 0,
-                                         description_event)); )
+                                         description_event,
+                                         opt_master_verify_checksum));)
     {
       if (event_count >= limit_start &&
 	  ev->net_send(protocol, linfo.log_file_name, pos))
@@ -2030,8 +2128,40 @@ static void fix_slave_net_timeout(THD *t
   DBUG_VOID_RETURN;
 }
 
+class sys_var_binlog_checksum :public sys_var_bool_ptr
+{
+public:
+  sys_var_binlog_checksum(sys_var_chain *chain, const char *name_arg,
+                          my_bool *value_arg) 
+    :sys_var_bool_ptr(chain, name_arg, value_arg) {}
+  bool check(THD *thd, set_var *var);
+  bool update(THD *thd, set_var *var);
+  bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
+  /*
+    We can't retrieve the value of this, so we don't have to define
+    type() or value_ptr()
+  */
+};
+
 static sys_var_chain vars = { NULL, NULL };
 
+static sys_var_binlog_checksum
+sys_binlog_checksum(&vars,
+                    "binlog_checksum",
+                    (my_bool *) &opt_binlog_checksum);
+
+static sys_var_bool_ptr_global
+sys_slave_sql_verify_checksum(&vars,
+                        "slave_sql_verify_checksum",
+                        (my_bool *) &opt_slave_sql_verify_checksum,
+                        &LOCK_global_system_variables);
+
+static sys_var_bool_ptr_global
+sys_master_verify_checksum(&vars,
+                        "master_verify_checksum",
+                        (my_bool *) &opt_master_verify_checksum,
+                        &LOCK_global_system_variables);
+
 static sys_var_const    sys_log_slave_updates(&vars, "log_slave_updates",
                                               OPT_GLOBAL, SHOW_MY_BOOL,
                                               (uchar*) &opt_log_slave_updates);
@@ -2112,6 +2242,26 @@ bool sys_var_slave_skip_counter::update(
   return 0;
 }
 
+bool sys_var_binlog_checksum::update(THD *thd, set_var *var)
+{
+  pthread_mutex_lock(mysql_bin_log.get_log_lock());
+  if(mysql_bin_log.is_open())
+  {
+    mysql_bin_log.rotate_and_purge(RP_FORCE_ROTATE |
+                                   RP_LOCK_LOG_IS_ALREADY_LOCKED |
+                                   (opt_binlog_checksum !=
+                                    (my_bool) var->save_result.ulong_value?
+                                    RP_BINLOG_CHECKSUM_ON_OFF : 0));
+  }
+  DBUG_ASSERT(opt_binlog_checksum == (ulong) var->save_result.ulong_value);
+  pthread_mutex_unlock(mysql_bin_log.get_log_lock());
+  return 0;
+}
+
+bool sys_var_binlog_checksum::check(THD *thd, set_var *var)
+{
+  return check_enum(thd, var, &bool_typelib);
+}
 
 int init_replication_sys_vars()
 {


Attachment: [text/bzr-bundle] bzr/aelkin@mysql.com-20100503095227-jcfa2oz1eax21kth.bundle
Thread
bzr commit into mysql-5.1-rep+2 branch (aelkin:3146) WL#2540Andrei Elkin3 May
  • Re: bzr commit into mysql-5.1-rep+2 branch (aelkin:3146) WL#2540Luís Soares11 May
  • Re: bzr commit into mysql-5.1-rep+2 branch (aelkin:3146) WL#2540Alfranio Correia17 May