List:Commits« Previous MessageNext Message »
From:Luís Soares Date:June 21 2010 10:25am
Subject:Re: bzr commit into mysql-next-mr-rpl-merge branch (zhenxing.he:2981)
View as plain text  
Hi Zhenxing,

  I have found some conflicts when merging the bundle. I guess
these are due to some recent merge from main into mysql-next-mr-rpl-merge.

  Otherwise, the changes requested by Kostja (prefixing files with rpl_
and removing repl_failsafe.cc) seem good.

  Approved.

Regards,
Luís

On 21/06/10 07:02, He Zhenxing wrote:
> #At file:///media/sdb2/hezx/work/mysql/bzr/w5385/next-mr-rpl-merge-new/ based on
> revid:zhenxing.he@stripped
> 
>  2981 He Zhenxing	2010-06-21 [merge]
>       Test commit
> 
>     removed:
>       sql/repl_failsafe.cc
>       sql/repl_failsafe.h
>       sql/sql_repl.cc
>       sql/sql_repl.h
>     added:
>       sql/binlog.cc
>       sql/binlog.h
>       sql/rpl_master.cc
>       sql/rpl_master.h
>     renamed:
>       sql/slave.cc => sql/rpl_slave.cc
>       sql/slave.h => sql/rpl_slave.h
>     modified:
>       libmysqld/CMakeLists.txt
>       libmysqld/Makefile.am
>       mysql-test/lib/v1/mysql-test-run.pl
>       mysql-test/suite/rpl/rpl_1slave_base.cnf
>       mysql-test/suite/rpl/t/rpl_ip_mix.cnf
>       mysql-test/suite/rpl/t/rpl_ip_mix2.cnf
>       mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf
>       mysql-test/suite/rpl/t/rpl_ipv6.cnf
>       mysql-test/suite/rpl_ndb/my.cnf
>       mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_2ch.cnf
>       sql/CMakeLists.txt
>       sql/Makefile.am
>       sql/field.cc
>       sql/ha_ndbcluster_binlog.cc
>       sql/ha_partition.cc
>       sql/item_func.cc
>       sql/log.cc
>       sql/log.h
>       sql/log_event.cc
>       sql/log_event.h
>       sql/mysqld.cc
>       sql/mysqld.h
>       sql/rpl_handler.cc
>       sql/rpl_injector.cc
>       sql/rpl_mi.cc
>       sql/rpl_record.cc
>       sql/rpl_rli.cc
>       sql/rpl_rli.h
>       sql/set_var.h
>       sql/sql_binlog.cc
>       sql/sql_class.cc
>       sql/sql_db.cc
>       sql/sql_insert.cc
>       sql/sql_load.cc
>       sql/sql_parse.cc
>       sql/sql_servers.h
>       sql/sql_show.cc
>       sql/sql_yacc.yy
>       sql/structs.h
>       sql/sys_vars.cc
>       sql/rpl_slave.cc
>       sql/rpl_slave.h
> === modified file 'libmysqld/CMakeLists.txt'
> --- a/libmysqld/CMakeLists.txt	2010-05-12 11:51:23 +0000
> +++ b/libmysqld/CMakeLists.txt	2010-06-21 06:01:50 +0000
> @@ -54,7 +54,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
>             ../sql/log_event.cc ../sql/mf_iocache.cc ../sql/my_decimal.cc 
>             ../sql/net_serv.cc ../sql/opt_range.cc ../sql/opt_sum.cc 
>             ../sql/parse_file.cc ../sql/procedure.cc ../sql/protocol.cc 
> -           ../sql/records.cc ../sql/repl_failsafe.cc ../sql/rpl_filter.cc
> +           ../sql/records.cc ../sql/rpl_filter.cc
>             ../sql/rpl_record.cc ../sql/sha2.cc ../sql/des_key_file.cc
>             ../sql/rpl_injector.cc ../sql/set_var.cc ../sql/spatial.cc 
>             ../sql/sp_cache.cc ../sql/sp.cc ../sql/sp_head.cc 
> @@ -69,7 +69,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
>             ../sql/sql_binlog.cc ../sql/sql_manager.cc ../sql/sql_map.cc 
>             ../sql/sql_parse.cc ../sql/sql_partition.cc ../sql/sql_plugin.cc 
>             ../sql/debug_sync.cc
> -           ../sql/sql_prepare.cc ../sql/sql_rename.cc ../sql/sql_repl.cc 
> +           ../sql/sql_prepare.cc ../sql/sql_rename.cc
>             ../sql/sql_select.cc ../sql/sql_servers.cc
>             ../sql/sql_show.cc ../sql/sql_state.c ../sql/sql_string.cc
>             ../sql/sql_tablespace.cc ../sql/sql_table.cc ../sql/sql_test.cc
> @@ -81,7 +81,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
>             ../sql/scheduler.cc ../sql/sql_audit.cc
>             ../sql/event_parse_data.cc
>             ../sql/sql_signal.cc ../sql/rpl_handler.cc
> -	       ../sql/rpl_utility.cc
> +	       ../sql/rpl_utility.cc ../sql/binlog.cc
>             ../sql/sys_vars.cc
>             ${CMAKE_BINARY_DIR}/sql/sql_builtin.cc
>             ../sql/mdl.cc ../sql/transaction.cc
> 
> === modified file 'libmysqld/Makefile.am'
> --- a/libmysqld/Makefile.am	2010-05-19 13:00:23 +0000
> +++ b/libmysqld/Makefile.am	2010-06-21 06:01:50 +0000
> @@ -80,7 +80,7 @@ sqlsources = derror.cc field.cc field_co
>  	debug_sync.cc sql_tablespace.cc transaction.cc \
>  	rpl_injector.cc my_user.c partition_info.cc \
>  	sql_servers.cc event_parse_data.cc sql_signal.cc \
> -	rpl_handler.cc mdl.cc keycaches.cc sql_audit.cc
> +	binlog.cc rpl_handler.cc mdl.cc keycaches.cc sql_audit.cc
>  
>  libmysqld_int_a_SOURCES= $(libmysqld_sources)
>  nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)
> 
> === modified file 'mysql-test/lib/v1/mysql-test-run.pl'
> --- a/mysql-test/lib/v1/mysql-test-run.pl	2010-03-22 10:36:23 +0000
> +++ b/mysql-test/lib/v1/mysql-test-run.pl	2010-06-21 06:01:50 +0000
> @@ -3959,7 +3959,6 @@ sub mysqld_arguments ($$$$) {
>      mtr_error("unknown mysqld type")
>        unless $mysqld->{'type'} eq 'slave';
>  
> -    mtr_add_arg($args, "%s--init-rpl-role=slave", $prefix);
>      if (! ( $opt_skip_slave_binlog || $skip_binlog ))
>      {
>        mtr_add_arg($args, "%s--log-bin=%s/log/slave%s-bin", $prefix,
> @@ -4016,9 +4015,7 @@ sub mysqld_arguments ($$$$) {
>  #    	            $master->[0]->{'port'}); # First master
>  #      }
>        my $slave_server_id=  2 + $idx;
> -      my $slave_rpl_rank= $slave_server_id;
>        mtr_add_arg($args, "%s--server-id=%d", $prefix, $slave_server_id);
> -      mtr_add_arg($args, "%s--rpl-recovery-rank=%d", $prefix, $slave_rpl_rank);
>      }
>  
>      my $cluster= $clusters->[$mysqld->{'cluster'}];
> @@ -4094,12 +4091,7 @@ sub mysqld_arguments ($$$$) {
>      mtr_add_arg($args, "%s%s", $prefix, "--core-file");
>    }
>  
> -  if ( $opt_bench )
> -  {
> -    mtr_add_arg($args, "%s--rpl-recovery-rank=1", $prefix);
> -    mtr_add_arg($args, "%s--init-rpl-role=master", $prefix);
> -  }
> -  elsif ( $mysqld->{'type'} eq 'master' )
> +  if ( !$opt_bench and $mysqld->{'type'} eq 'master' )
>    {
>      mtr_add_arg($args, "%s--open-files-limit=1024", $prefix);
>    }
> 
> === modified file 'mysql-test/suite/rpl/rpl_1slave_base.cnf'
> --- a/mysql-test/suite/rpl/rpl_1slave_base.cnf	2009-10-21 12:59:47 +0000
> +++ b/mysql-test/suite/rpl/rpl_1slave_base.cnf	2010-06-21 05:56:56 +0000
> @@ -22,7 +22,6 @@ loose-innodb
>  log-bin=                    slave-bin
>  relay-log=                  slave-relay-bin
>  
> -init-rpl-role=              slave
>  log-slave-updates
>  master-retry-count=         10
>  
> 
> === modified file 'mysql-test/suite/rpl/t/rpl_ip_mix.cnf'
> --- a/mysql-test/suite/rpl/t/rpl_ip_mix.cnf	2009-11-23 16:38:42 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_ip_mix.cnf	2010-06-21 05:56:56 +0000
> @@ -26,7 +26,6 @@ bind-address=               ::
>  log-bin=                    slave-bin
>  relay-log=                  slave-relay-bin
>  
> -init-rpl-role=              slave
>  log-slave-updates
>  master-retry-count=         10
>  
> 
> === modified file 'mysql-test/suite/rpl/t/rpl_ip_mix2.cnf'
> --- a/mysql-test/suite/rpl/t/rpl_ip_mix2.cnf	2009-11-23 16:38:42 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_ip_mix2.cnf	2010-06-21 05:56:56 +0000
> @@ -26,7 +26,6 @@ bind-address=               0.0.0.0
>  log-bin=                    slave-bin
>  relay-log=                  slave-relay-bin
>  
> -init-rpl-role=              slave
>  log-slave-updates
>  master-retry-count=         10
>  
> 
> === modified file 'mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf'
> --- a/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf	2009-11-23 16:38:42 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_ipv4_as_ipv6.cnf	2010-06-21 05:56:56 +0000
> @@ -26,7 +26,6 @@ bind-address=               0.0.0.0
>  log-bin=                    slave-bin
>  relay-log=                  slave-relay-bin
>  
> -init-rpl-role=              slave
>  log-slave-updates
>  master-retry-count=         10
>  
> 
> === modified file 'mysql-test/suite/rpl/t/rpl_ipv6.cnf'
> --- a/mysql-test/suite/rpl/t/rpl_ipv6.cnf	2009-11-23 16:38:42 +0000
> +++ b/mysql-test/suite/rpl/t/rpl_ipv6.cnf	2010-06-21 05:56:56 +0000
> @@ -26,7 +26,6 @@ bind-address=               ::
>  log-bin=                    slave-bin
>  relay-log=                  slave-relay-bin
>  
> -init-rpl-role=              slave
>  log-slave-updates
>  master-retry-count=         10
>  
> 
> === modified file 'mysql-test/suite/rpl_ndb/my.cnf'
> --- a/mysql-test/suite/rpl_ndb/my.cnf	2009-12-01 19:07:18 +0000
> +++ b/mysql-test/suite/rpl_ndb/my.cnf	2010-06-21 05:56:56 +0000
> @@ -33,7 +33,6 @@ log-bin=                       master-bi
>  log-bin=                      slave-bin
>  relay-log=                    slave-relay-bin
>  
> -init-rpl-role=                slave
>  log-slave-updates
>  master-retry-count=           10
>  
> 
> === modified file 'mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_2ch.cnf'
> --- a/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_2ch.cnf	2009-11-04 12:28:20 +0000
> +++ b/mysql-test/suite/rpl_ndb/t/rpl_ndb_circular_2ch.cnf	2010-06-21 05:56:56 +0000
> @@ -15,7 +15,6 @@ skip-slave-start
>  
>  [mysqld.2.slave]
>  server-id= 2
> -init-rpl-role=		slave
>  log-bin
>  skip-slave-start
>  ndb_connectstring=	@mysql_cluster.slave.ndb_connectstring
> 
> === modified file 'sql/CMakeLists.txt'
> --- a/sql/CMakeLists.txt	2010-05-12 21:20:24 +0000
> +++ b/sql/CMakeLists.txt	2010-06-21 06:01:50 +0000
> @@ -48,14 +48,12 @@ SET (SQL_SOURCE
>                 item_create.cc item_func.cc item_geofunc.cc item_row.cc 
>                 item_strfunc.cc item_subselect.cc item_sum.cc item_timefunc.cc 
>                 key.cc log.cc lock.cc
> -               log_event.cc rpl_record.cc rpl_reporting.cc
> -               log_event_old.cc rpl_record_old.cc
>                 message.h mf_iocache.cc my_decimal.cc ../sql-common/my_time.c
>                 mysqld.cc net_serv.cc  keycaches.cc
>                 opt_range.cc opt_range.h opt_sum.cc 
>                 ../sql-common/pack.c parse_file.cc password.c procedure.cc 
> -               protocol.cc records.cc repl_failsafe.cc rpl_filter.cc set_var.cc 
> -               slave.cc sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc 
> +               protocol.cc records.cc set_var.cc 
> +               sp.cc sp_cache.cc sp_head.cc sp_pcontext.cc 
>                 sp_rcontext.cc spatial.cc sql_acl.cc sql_analyse.cc sql_base.cc 
>                 sql_cache.cc sql_class.cc sql_client.cc sql_crypt.cc sql_crypt.h 
>                 sql_cursor.cc sql_db.cc sql_delete.cc sql_derived.cc sql_do.cc 
> @@ -63,18 +61,18 @@ SET (SQL_SOURCE
>                 sql_list.cc sql_load.cc sql_manager.cc sql_map.cc sql_parse.cc 
>                 sql_partition.cc sql_plugin.cc sql_prepare.cc sql_rename.cc 
>                 debug_sync.cc debug_sync.h
> -               sql_repl.cc sql_select.cc sql_show.cc sql_state.c sql_string.cc 
> +               sql_select.cc sql_show.cc sql_state.c sql_string.cc 
>                 sql_table.cc sql_test.cc sql_trigger.cc sql_udf.cc sql_union.cc
>                 sql_update.cc sql_view.cc strfunc.cc table.cc thr_malloc.cc 
>                 sql_time.cc tztime.cc uniques.cc unireg.cc item_xmlfunc.cc 
> -               rpl_tblmap.cc sql_binlog.cc event_scheduler.cc event_data_objects.cc
> +               event_scheduler.cc event_data_objects.cc
>                 event_queue.cc event_db_repository.cc 
>                 sql_tablespace.cc events.cc ../sql-common/my_user.c 
> -               partition_info.cc rpl_utility.cc rpl_injector.cc sql_locale.cc
> -               rpl_rli.cc rpl_mi.cc sql_servers.cc sql_audit.cc
> +               partition_info.cc sql_locale.cc
> +               sql_servers.cc sql_audit.cc
>                 sql_connect.cc scheduler.cc 
>                 sql_profile.cc event_parse_data.cc
> -               sql_signal.cc rpl_handler.cc mdl.cc
> +               sql_signal.cc mdl.cc
>                 transaction.cc sys_vars.cc
>                 ${GEN_SOURCES}
>                 ${MYSYS_LIBWRAP_SOURCE})
> @@ -89,7 +87,16 @@ TARGET_LINK_LIBRARIES(sql ${MYSQLD_STATI
>    ${LIBWRAP} ${LIBCRYPT} ${LIBDL}
>    ${SSL_LIBRARIES})
>  
> - 
> +SET (BINLOG_SOURCE log_event.cc log_event_old.cc binlog.cc sql_binlog.cc
> +		   rpl_filter.cc rpl_record.cc rpl_record_old.cc rpl_utility.cc
> +		   sql_binlog.cc rpl_injector.cc)
> +ADD_LIBRARY(binlog ${BINLOG_SOURCE})
> +SET (RPL_SOURCE rpl_handler.cc rpl_tblmap.cc)
> +ADD_LIBRARY(rpl ${RPL_SOURCE})
> +SET (MASTER_SOURCE rpl_master.cc)
> +ADD_LIBRARY(master ${MASTER_SOURCE})
> +SET (SLAVE_SOURCE rpl_slave.cc rpl_reporting.cc rpl_mi.cc rpl_rli.cc)
> +ADD_LIBRARY(slave ${SLAVE_SOURCE})
>  
>  IF(WIN32)
>    SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h  message.rc)
> @@ -131,7 +138,7 @@ IF(NOT WITHOUT_DYNAMIC_PLUGINS)
>  ENDIF()
>  
>  SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE) 
> -TARGET_LINK_LIBRARIES(mysqld sql)
> +TARGET_LINK_LIBRARIES(mysqld sql binlog rpl master slave)
>  
>  # Provide plugins with minimal set of libraries
>  SET(INTERFACE_LIBS ${LIBRT})
> 
> === modified file 'sql/Makefile.am'
> --- a/sql/Makefile.am	2010-05-19 13:00:23 +0000
> +++ b/sql/Makefile.am	2010-06-21 06:01:50 +0000
> @@ -62,6 +62,8 @@ DTRACEFILES_DEPEND =    filesort.o \
>                          sql_select.o \
>                          sql_update.o
>  
> +RPL_LIBS = 		libbinlog.la librpl.la libmaster.la libslave.la
> +pkglib_LTLIBRARIES=	$(RPL_LIBS)
>  
>  noinst_LTLIBRARIES=	libndb.la \
>  			udf_example.la
> @@ -71,9 +73,11 @@ SUPPORTING_LIBS =	$(top_builddir)/vio/li
>  			$(top_builddir)/dbug/libdbug.a \
>  			$(top_builddir)/regex/libregex.a \
>  			$(top_builddir)/strings/libmystrings.a
> -mysqld_DEPENDENCIES=	@mysql_plugin_libs@ $(SUPPORTING_LIBS) libndb.la
> +mysqld_DEPENDENCIES=	@mysql_plugin_libs@ $(SUPPORTING_LIBS) libndb.la \
> +			$(RPL_LIBS)
>  LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@
>  mysqld_LDADD =		libndb.la \
> +			$(RPL_LIBS) \
>  			@MYSQLD_EXTRA_LDFLAGS@ \
>  			@pstack_libs@ \
>  			@mysql_plugin_libs@ \
> @@ -105,7 +109,7 @@ noinst_HEADERS =	item.h item_func.h item
>  			sql_derived.h sql_load.h sql_handler.h init.h \
>  			derror.h sql_union.h des_key_file.h sql_binlog.h \
>  			discover.h sql_manager.h sql_do.h \
> -			sql_repl.h slave.h rpl_filter.h rpl_injector.h \
> +			rpl_slave.h rpl_master.h  rpl_filter.h rpl_injector.h \
>  			log_event.h rpl_record.h sql_const.h \
>  			log_event_old.h rpl_record_old.h \
>  			sql_sort.h sql_cache.h set_var.h sys_vars_shared.h \
> @@ -142,8 +146,6 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
>  			procedure.cc sql_test.cc \
>  			log.cc init.cc derror.cc sql_acl.cc \
>  			unireg.cc des_key_file.cc \
> -			log_event.cc rpl_record.cc \
> -			log_event_old.cc rpl_record_old.cc \
>  			discover.cc sql_time.cc opt_range.cc opt_sum.cc \
>  		   	records.cc filesort.cc handler.cc \
>  		        ha_partition.cc \
> @@ -151,12 +153,8 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
>  			sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
>  			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
>  			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
> -			slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
> -			rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \
> -			rpl_reporting.cc \
>                          sql_union.cc sql_derived.cc \
>  			sql_client.cc \
> -			repl_failsafe.h repl_failsafe.cc \
>  			sql_olap.cc sql_view.cc \
>  			gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
>  			tztime.cc my_decimal.cc\
> @@ -164,14 +162,21 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
>  			sp_cache.cc parse_file.cc sql_trigger.cc \
>                          event_scheduler.cc event_data_objects.cc \
>                          event_queue.cc event_db_repository.cc events.cc \
> -			sql_plugin.cc sql_binlog.cc \
> +			sql_plugin.cc \
>  			sql_builtin.cc sql_tablespace.cc partition_info.cc \
>  			sql_servers.cc event_parse_data.cc sql_signal.cc \
> -			rpl_handler.cc mdl.cc transaction.cc sql_audit.cc  \
> +			mdl.cc transaction.cc sql_audit.cc  \
>  			sha2.cc
>  
>  nodist_mysqld_SOURCES =	mini_client_errors.c pack.c client.c my_time.c my_user.c 
>  
> +libbinlog_la_SOURCES =	log_event.cc log_event_old.cc binlog.cc \
> +			rpl_filter.cc rpl_record.cc rpl_record_old.cc \
> +			rpl_utility.cc sql_binlog.cc rpl_injector.cc
> +librpl_la_SOURCES    =  rpl_handler.cc rpl_tblmap.cc
> +libmaster_la_SOURCES =	rpl_master.cc
> +libslave_la_SOURCES = 	rpl_slave.cc rpl_reporting.cc rpl_rli.cc rpl_mi.cc
> +
>  libndb_la_CPPFLAGS=	@ndbcluster_includes@
>  libndb_la_SOURCES=	ha_ndbcluster.cc \
>  			ha_ndbcluster_binlog.cc \
> 
> === added file 'sql/binlog.cc'
> --- a/sql/binlog.cc	1970-01-01 00:00:00 +0000
> +++ b/sql/binlog.cc	2010-06-21 05:56:56 +0000
> @@ -0,0 +1,5135 @@
> +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +
> +#include "my_global.h"
> +#include "log.h"
> +#include "binlog.h"
> +#include "log_event.h"
> +#include "rpl_filter.h"
> +#include "rpl_rli.h"
> +#include "sql_plugin.h"
> +#include "rpl_handler.h"
> +
> +#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
> +#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
> +
> +handlerton *binlog_hton;
> +
> +MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
> +
> +static bool purge_error_message(THD* thd, int res);
> +static void adjust_linfo_offsets(my_off_t purge_offset);
> +static bool log_in_use(const char* log_name);
> +
> +static int binlog_init(void *p);
> +static int binlog_close_connection(handlerton *hton, THD *thd);
> +static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
> +static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
> +static int binlog_commit(handlerton *hton, THD *thd, bool all);
> +static int binlog_rollback(handlerton *hton, THD *thd, bool all);
> +static int binlog_prepare(handlerton *hton, THD *thd, bool all);
> +
> +/*
> +  Helper class to hold a mutex for the duration of the
> +  block.
> +
> +  Eliminates the need for explicit unlocking of mutexes on, e.g.,
> +  error returns.  On passing a null pointer, the sentry will not do
> +  anything.
> + */
> +class Mutex_sentry
> +{
> +public:
> +  Mutex_sentry(mysql_mutex_t *mutex)
> +    : m_mutex(mutex)
> +  {
> +    if (m_mutex)
> +      mysql_mutex_lock(mutex);
> +  }
> +
> +  ~Mutex_sentry()
> +  {
> +    if (m_mutex)
> +      mysql_mutex_unlock(m_mutex);
> +#ifndef DBUG_OFF
> +    m_mutex= 0;
> +#endif
> +  }
> +
> +private:
> +  mysql_mutex_t *m_mutex;
> +
> +  // It's not allowed to copy this object in any way
> +  Mutex_sentry(Mutex_sentry const&);
> +  void operator=(Mutex_sentry const&);
> +};
> +
> +/*
> +  Helper classes to store non-transactional and transactional data
> +  before copying it to the binary log.
> +*/
> +class binlog_cache_data
> +{
> +public:
> +  binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
> +  incident(FALSE)
> +  {
> +    cache_log.end_of_file= max_binlog_cache_size;
> +  }
> +
> +  ~binlog_cache_data()
> +  {
> +    DBUG_ASSERT(empty());
> +    close_cached_file(&cache_log);
> +  }
> +
> +  bool empty() const
> +  {
> +    return pending() == NULL && my_b_tell(&cache_log) == 0;
> +  }
> +
> +  Rows_log_event *pending() const
> +  {
> +    return m_pending;
> +  }
> +
> +  void set_pending(Rows_log_event *const pending)
> +  {
> +    m_pending= pending;
> +  }
> +
> +  void set_incident(void)
> +  {
> +    incident= TRUE;
> +  }
> +  
> +  bool has_incident(void)
> +  {
> +    return(incident);
> +  }
> +
> +  void reset()
> +  {
> +    truncate(0);
> +    incident= FALSE;
> +    before_stmt_pos= MY_OFF_T_UNDEF;
> +    cache_log.end_of_file= max_binlog_cache_size;
> +    DBUG_ASSERT(empty());
> +  }
> +
> +  my_off_t get_byte_position() const
> +  {
> +    return my_b_tell(&cache_log);
> +  }
> +
> +  my_off_t get_prev_position()
> +  {
> +     return(before_stmt_pos);
> +  }
> +
> +  void set_prev_position(my_off_t pos)
> +  {
> +     before_stmt_pos= pos;
> +  }
> +  
> +  void restore_prev_position()
> +  {
> +    truncate(before_stmt_pos);
> +  }
> +
> +  void restore_savepoint(my_off_t pos)
> +  {
> +    truncate(pos);
> +    if (pos < before_stmt_pos)
> +      before_stmt_pos= MY_OFF_T_UNDEF;
> +  }
> +
> +  /*
> +    Cache to store data before copying it to the binary log.
> +  */
> +  IO_CACHE cache_log;
> +
> +private:
> +  /*
> +    Pending binrows event. This event is the event where the rows are currently
> +    written.
> +   */
> +  Rows_log_event *m_pending;
> +
> +  /*
> +    Binlog position before the start of the current statement.
> +  */
> +  my_off_t before_stmt_pos;
> + 
> +  /*
> +    This indicates that some events did not get into the cache and most likely
> +    it is corrupted.
> +  */ 
> +  bool incident;
> +
> +  /*
> +    It truncates the cache to a certain position. This includes deleting the
> +    pending event.
> +   */
> +  void truncate(my_off_t pos)
> +  {
> +    DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
> +    if (pending())
> +    {
> +      delete pending();
> +      set_pending(0);
> +    }
> +    reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
> +    cache_log.end_of_file= max_binlog_cache_size;
> +  }
> + 
> +  binlog_cache_data& operator=(const binlog_cache_data& info);
> +  binlog_cache_data(const binlog_cache_data& info);
> +};
> +
> +class binlog_cache_mngr {
> +public:
> +  binlog_cache_mngr() {}
> +
> +  void reset_cache(binlog_cache_data* cache_data)
> +  {
> +    cache_data->reset();
> +  }
> +
> +  binlog_cache_data* get_binlog_cache_data(bool is_transactional)
> +  {
> +    return (is_transactional ? &trx_cache : &stmt_cache);
> +  }
> +
> +  IO_CACHE* get_binlog_cache_log(bool is_transactional)
> +  {
> +    return (is_transactional ? &trx_cache.cache_log :
> &stmt_cache.cache_log);
> +  }
> +
> +  binlog_cache_data stmt_cache;
> +
> +  binlog_cache_data trx_cache;
> +
> +private:
> +
> +  binlog_cache_mngr& operator=(const binlog_cache_mngr& info);
> +  binlog_cache_mngr(const binlog_cache_mngr& info);
> +};
> +
> + /*
> +  Save position of binary log transaction cache.
> +
> +  SYNPOSIS
> +    binlog_trans_log_savepos()
> +
> +    thd      The thread to take the binlog data from
> +    pos      Pointer to variable where the position will be stored
> +
> +  DESCRIPTION
> +
> +    Save the current position in the binary log transaction cache into
> +    the variable pointed to by 'pos'
> + */
> +
> +static void
> +binlog_trans_log_savepos(THD *thd, my_off_t *pos)
> +{
> +  DBUG_ENTER("binlog_trans_log_savepos");
> +  DBUG_ASSERT(pos != NULL);
> +  if (thd_get_ha_data(thd, binlog_hton) == NULL)
> +    thd->binlog_setup_trx_data();
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  DBUG_ASSERT(mysql_bin_log.is_open());
> +  *pos= cache_mngr->trx_cache.get_byte_position();
> +  DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos));
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/*
> +  Truncate the binary log transaction cache.
> +
> +  SYNPOSIS
> +    binlog_trans_log_truncate()
> +
> +    thd      The thread to take the binlog data from
> +    pos      Position to truncate to
> +
> +  DESCRIPTION
> +
> +    Truncate the binary log to the given position. Will not change
> +    anything else.
> +
> + */
> +static void
> +binlog_trans_log_truncate(THD *thd, my_off_t pos)
> +{
> +  DBUG_ENTER("binlog_trans_log_truncate");
> +  DBUG_PRINT("enter", ("pos: %lu", (ulong) pos));
> +
> +  DBUG_ASSERT(thd_get_ha_data(thd, binlog_hton) != NULL);
> +  /* Only true if binlog_trans_log_savepos() wasn't called before */
> +  DBUG_ASSERT(pos != ~(my_off_t) 0);
> +
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  cache_mngr->trx_cache.restore_savepoint(pos);
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/*
> +  this function is mostly a placeholder.
> +  conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
> +  should be moved here.
> +*/
> +
> +static int binlog_init(void *p)
> +{
> +  binlog_hton= (handlerton *)p;
> +  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
> +  binlog_hton->db_type=DB_TYPE_BINLOG;
> +  binlog_hton->savepoint_offset= sizeof(my_off_t);
> +  binlog_hton->close_connection= binlog_close_connection;
> +  binlog_hton->savepoint_set= binlog_savepoint_set;
> +  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
> +  binlog_hton->commit= binlog_commit;
> +  binlog_hton->rollback= binlog_rollback;
> +  binlog_hton->prepare= binlog_prepare;
> +  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
> +  return 0;
> +}
> +
> +static int binlog_close_connection(handlerton *hton, THD *thd)
> +{
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  DBUG_ASSERT(cache_mngr->trx_cache.empty() &&
> cache_mngr->stmt_cache.empty());
> +  thd_set_ha_data(thd, binlog_hton, NULL);
> +  cache_mngr->~binlog_cache_mngr();
> +  my_free((uchar*)cache_mngr, MYF(0));
> +  return 0;
> +}
> +
> +/**
> +  This function flushes a transactional cache upon commit/rollback.
> +
> +  @param thd        The thread whose transaction should be flushed
> +  @param cache_mngr Pointer to the cache data to be flushed
> +  @param end_ev     The end event either commit/rollback.
> +
> +  @return
> +    nonzero if an error pops up when flushing the transactional cache.
> +*/
> +static int
> +binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
> +                       Log_event *end_ev)
> +{
> +  DBUG_ENTER("binlog_flush_trx_cache");
> +  int error=0;
> +  IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log;
> +
> +  /*
> +    This function handles transactional changes and as such
> +    this flag equals to true.
> +  */
> +  bool const is_transactional= TRUE;
> +
> +  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
> +    DBUG_RETURN(1);
> +  /*
> +    Doing a commit or a rollback including non-transactional tables,
> +    i.e., ending a transaction where we might write the transaction
> +    cache to the binary log.
> +
> +    We can always end the statement when ending a transaction since
> +    transactions are not allowed inside stored functions. If they
> +    were, we would have to ensure that we're not ending a statement
> +    inside a stored function.
> +  */
> +  error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev,
> +                             cache_mngr->trx_cache.has_incident());
> +  cache_mngr->reset_cache(&cache_mngr->trx_cache);
> +
> +  /*
> +    We need to step the table map version after writing the
> +    transaction cache to disk.
> +  */
> +  mysql_bin_log.update_table_map_version();
> +  statistic_increment(binlog_cache_use, &LOCK_status);
> +  if (cache_log->disk_writes != 0)
> +  {
> +    statistic_increment(binlog_cache_disk_use, &LOCK_status);
> +    cache_log->disk_writes= 0;
> +  }
> +
> +  DBUG_ASSERT(cache_mngr->trx_cache.empty());
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  This function truncates the transactional cache upon committing or rolling
> +  back either a transaction or a statement.
> +
> +  @param thd        The thread whose transaction should be flushed
> +  @param cache_mngr Pointer to the cache data to be flushed
> +  @param all        @c true means truncate the transaction, otherwise the
> +                    statement must be truncated.
> +
> +  @return
> +    nonzero if an error pops up when truncating the transactional cache.
> +*/
> +static int
> +binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
> +{
> +  DBUG_ENTER("binlog_truncate_trx_cache");
> +  int error=0;
> +  /*
> +    This function handles transactional changes and as such this flag
> +    equals to true.
> +  */
> +  bool const is_transactional= TRUE;
> +
> +  DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s",
> +                      FLAGSTR(thd->variables.option_bits,
> OPTION_NOT_AUTOCOMMIT),
> +                      FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
> +                      all ? "all" : "stmt"));
> +  /*
> +    If rolling back an entire transaction or a single statement not
> +    inside a transaction, we reset the transaction cache.
> +  */
> +  thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
> +  if (ending_trans(thd, all))
> +  {
> +    if (cache_mngr->trx_cache.has_incident())
> +      error= mysql_bin_log.write_incident(thd, TRUE);
> +
> +    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> +
> +    thd->clear_binlog_table_maps();
> +  }
> +  /*
> +    If rolling back a statement in a transaction, we truncate the
> +    transaction cache to remove the statement.
> +  */
> +  else
> +    cache_mngr->trx_cache.restore_prev_position();
> +
> +  /*
> +    We need to step the table map version on a rollback to ensure that a new
> +    table map event is generated instead of the one that was written to the
> +    thrown-away transaction cache.
> +  */
> +  mysql_bin_log.update_table_map_version();
> +
> +  DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL);
> +  DBUG_RETURN(error);
> +}
> +
> +static int binlog_prepare(handlerton *hton, THD *thd, bool all)
> +{
> +  /*
> +    do nothing.
> +    just pretend we can do 2pc, so that MySQL won't
> +    switch to 1pc.
> +    real work will be done in MYSQL_BIN_LOG::log_xid()
> +  */
> +  return 0;
> +}
> +
> +/**
> +  This function flushes the non-transactional to the binary log upon
> +  committing or rolling back a statement.
> +
> +  @param thd        The thread whose transaction should be flushed
> +  @param cache_mngr Pointer to the cache data to be flushed
> +
> +  @return
> +    nonzero if an error pops up when flushing the non-transactional cache.
> +*/
> +static int
> +binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
> +{
> +  int error= 0;
> +  DBUG_ENTER("binlog_flush_stmt_cache");
> +  /*
> +    If we are flushing the statement cache, it means that the changes get
> +    through otherwise the cache is empty and this routine should not be called.
> +  */
> +  DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE);
> +  /*
> +    This function handles non-transactional changes and as such this flag equals
> +    to false.
> +  */
> +  bool const is_transactional= FALSE;
> +  IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
> +
> +  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
> +    DBUG_RETURN(1);
> +
> +  Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
> +  if ((error= mysql_bin_log.write(thd, cache_log, &qev,
> +                                  cache_mngr->stmt_cache.has_incident())))
> +    DBUG_RETURN(error);
> +  cache_mngr->reset_cache(&cache_mngr->stmt_cache);
> +
> +  /*
> +    We need to step the table map version after writing the
> +    transaction cache to disk.
> +  */
> +  mysql_bin_log.update_table_map_version();
> +  statistic_increment(binlog_cache_use, &LOCK_status);
> +  if (cache_log->disk_writes != 0)
> +  {
> +    statistic_increment(binlog_cache_disk_use, &LOCK_status);
> +    cache_log->disk_writes= 0;
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  This function is called once after each statement.
> +
> +  It has the responsibility to flush the caches to the binary log on commits.
> +
> +  @param hton  The binlog handlerton.
> +  @param thd   The client thread that executes the transaction.
> +  @param all   This is @c true if this is a real transaction commit, and
> +               @false otherwise.
> +
> +  @see handlerton::commit
> +*/
> +static int binlog_commit(handlerton *hton, THD *thd, bool all)
> +{
> +  int error= 0;
> +  DBUG_ENTER("binlog_commit");
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  DBUG_PRINT("debug",
> +             ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s,
> stmt.modified_non_trans_table: %s",
> +              all,
> +              YESNO(thd->in_multi_stmt_transaction()),
> +              YESNO(thd->transaction.all.modified_non_trans_table),
> +              YESNO(thd->transaction.stmt.modified_non_trans_table)));
> +
> +  if (!cache_mngr->stmt_cache.empty())
> +  {
> +    binlog_flush_stmt_cache(thd, cache_mngr);
> +  }
> +
> +  if (cache_mngr->trx_cache.empty())
> +  {
> +    /*
> +      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
> +    */
> +    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> +    DBUG_RETURN(0);
> +  }
> +
> +  /*
> +    We commit the transaction if:
> +     - We are not in a transaction and committing a statement, or
> +     - We are in a transaction and a full transaction is committed.
> +    Otherwise, we accumulate the changes.
> +  */
> +  if (ending_trans(thd, all))
> +  {
> +    Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
> +    error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
> +  }
> +
> +  /*
> +    This is part of the stmt rollback.
> +  */
> +  if (!all)
> +    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  This function is called when a transaction or a statement is rolled back.
> +
> +  @param hton  The binlog handlerton.
> +  @param thd   The client thread that executes the transaction.
> +  @param all   This is @c true if this is a real transaction rollback, and
> +               @false otherwise.
> +
> +  @see handlerton::rollback
> +*/
> +static int binlog_rollback(handlerton *hton, THD *thd, bool all)
> +{
> +  DBUG_ENTER("binlog_rollback");
> +  int error=0;
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s,
> stmt.modified_non_trans_table: %s",
> +                       YESNO(all),
> +                       YESNO(thd->transaction.all.modified_non_trans_table),
> +                       YESNO(thd->transaction.stmt.modified_non_trans_table)));
> +
> +  /*
> +    If an incident event is set we do not flush the content of the statement
> +    cache because it may be corrupted.
> +  */
> +  if (cache_mngr->stmt_cache.has_incident())
> +  {
> +    error= mysql_bin_log.write_incident(thd, TRUE);
> +    cache_mngr->reset_cache(&cache_mngr->stmt_cache);
> +  }
> +  else if (!cache_mngr->stmt_cache.empty())
> +  {
> +    binlog_flush_stmt_cache(thd, cache_mngr);
> +  }
> +
> +  if (cache_mngr->trx_cache.empty())
> +  {
> +    /* 
> +      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
> +    */
> +    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> +    DBUG_RETURN(0);
> +  }
> +
> +  if (mysql_bin_log.check_write_error(thd))
> +  {
> +    /*
> +      "all == true" means that a "rollback statement" triggered the error and
> +      this function was called. However, this must not happen as a rollback
> +      is written directly to the binary log. And in auto-commit mode, a single
> +      statement that is rolled back has the flag all == false.
> +    */
> +    DBUG_ASSERT(!all);
> +    /*
> +      We reach this point if the effect of a statement did not properly get into
> +      a cache and need to be rolled back.
> +    */
> +    error= binlog_truncate_trx_cache(thd, cache_mngr, all);
> +  }
> +  else
> +  {  
> +    /*
> +      We flush the cache wrapped in a beging/rollback if:
> +        . aborting a single or multi-statement transaction and;
> +        . the format is STMT and non-trans engines were updated or;
> +        . the OPTION_KEEP_LOG is activate.
> +    */
> +    if (ending_trans(thd, all) &&
> +        ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
> +         (trans_has_updated_non_trans_table(thd) &&
> +          thd->variables.binlog_format == BINLOG_FORMAT_STMT)))
> +    {
> +      Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
> +      error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
> +    }
> +    /*
> +      Truncate the cache if:
> +        . aborting a single or multi-statement transaction or;
> +        . the OPTION_KEEP_LOG is not activate and;
> +        . the format is not STMT or no non-trans were updated.
> +    */
> +    else if (ending_trans(thd, all) ||
> +             (!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
> +              ((!stmt_has_updated_non_trans_table(thd) ||
> +               thd->variables.binlog_format != BINLOG_FORMAT_STMT))))
> +      error= binlog_truncate_trx_cache(thd, cache_mngr, all);
> +  }
> +
> +  /* 
> +    This is part of the stmt rollback.
> +  */
> +  if (!all)
> +    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); 
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  @note
> +  How do we handle this (unlikely but legal) case:
> +  @verbatim
> +    [transaction] + [update to non-trans table] + [rollback to savepoint] ?
> +  @endverbatim
> +  The problem occurs when a savepoint is before the update to the
> +  non-transactional table. Then when there's a rollback to the savepoint, if we
> +  simply truncate the binlog cache, we lose the part of the binlog cache where
> +  the update is. If we want to not lose it, we need to write the SAVEPOINT
> +  command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
> +  is easy: it's just write at the end of the binlog cache, but the former
> +  should be *inserted* to the place where the user called SAVEPOINT. The
> +  solution is that when the user calls SAVEPOINT, we write it to the binlog
> +  cache (so no need to later insert it). As transactions are never intermixed
> +  in the binary log (i.e. they are serialized), we won't have conflicts with
> +  savepoint names when using mysqlbinlog or in the slave SQL thread.
> +  Then when ROLLBACK TO SAVEPOINT is called, if we updated some
> +  non-transactional table, we don't truncate the binlog cache but instead write
> +  ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
> +  will chop the SAVEPOINT command from the binlog cache, which is good as in
> +  that case there is no need to have it in the binlog).
> +*/
> +
> +static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
> +{
> +  DBUG_ENTER("binlog_savepoint_set");
> +
> +  binlog_trans_log_savepos(thd, (my_off_t*) sv);
> +  /* Write it to the binary log */
> +
> +  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
> +  int const error=
> +    thd->binlog_query(THD::STMT_QUERY_TYPE,
> +                      thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
> +                      errcode);
> +  DBUG_RETURN(error);
> +}
> +
> +static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
> +{
> +  DBUG_ENTER("binlog_savepoint_rollback");
> +
> +  /*
> +    Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
> +    non-transactional table. Otherwise, truncate the binlog cache starting
> +    from the SAVEPOINT command.
> +  */
> +  if (unlikely(trans_has_updated_non_trans_table(thd) ||
> +               (thd->variables.option_bits & OPTION_KEEP_LOG)))
> +  {
> +    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
> +    int error=
> +      thd->binlog_query(THD::STMT_QUERY_TYPE,
> +                        thd->query(), thd->query_length(), TRUE, FALSE,
> FALSE,
> +                        errcode);
> +    DBUG_RETURN(error);
> +  }
> +  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
> +  DBUG_RETURN(0);
> +}
> +
> +
> +/*
> +  Adjust the position pointer in the binary log file for all running slaves
> +
> +  SYNOPSIS
> +    adjust_linfo_offsets()
> +    purge_offset	Number of bytes removed from start of log index file
> +
> +  NOTES
> +    - This is called when doing a PURGE when we delete lines from the
> +      index log file
> +
> +  REQUIREMENTS
> +    - Before calling this function, we have to ensure that no threads are
> +      using any binary log file before purge_offset.a
> +
> +  TODO
> +    - Inform the slave threads that they should sync the position
> +      in the binary log file with flush_relay_log_info.
> +      Now they sync is done for next read.
> +*/
> +
> +static void adjust_linfo_offsets(my_off_t purge_offset)
> +{
> +  THD *tmp;
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  I_List_iterator<THD> it(threads);
> +
> +  while ((tmp=it++))
> +  {
> +    LOG_INFO* linfo;
> +    if ((linfo = tmp->current_linfo))
> +    {
> +      mysql_mutex_lock(&linfo->lock);
> +      /*
> +	Index file offset can be less that purge offset only if
> +	we just started reading the index file. In that case
> +	we have nothing to adjust
> +      */
> +      if (linfo->index_file_offset < purge_offset)
> +	linfo->fatal = (linfo->index_file_offset != 0);
> +      else
> +	linfo->index_file_offset -= purge_offset;
> +      mysql_mutex_unlock(&linfo->lock);
> +    }
> +  }
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +}
> +
> +
> +static bool log_in_use(const char* log_name)
> +{
> +  size_t log_name_len = strlen(log_name) + 1;
> +  THD *tmp;
> +  bool result = 0;
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  I_List_iterator<THD> it(threads);
> +
> +  while ((tmp=it++))
> +  {
> +    LOG_INFO* linfo;
> +    if ((linfo = tmp->current_linfo))
> +    {
> +      mysql_mutex_lock(&linfo->lock);
> +      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
> +                     log_name_len);
> +      mysql_mutex_unlock(&linfo->lock);
> +      if (result)
> +	break;
> +    }
> +  }
> +
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  return result;
> +}
> +
> +static bool purge_error_message(THD* thd, int res)
> +{
> +  uint errcode;
> +
> +  if ((errcode= purge_log_get_error_code(res)) != 0)
> +  {
> +    my_message(errcode, ER(errcode), MYF(0));
> +    return TRUE;
> +  }
> +  my_ok(thd);
> +  return FALSE;
> +}
> +
> +
> +int check_binlog_magic(IO_CACHE* log, const char** errmsg)
> +{
> +  char magic[4];
> +  DBUG_ASSERT(my_b_tell(log) == 0);
> +
> +  if (my_b_read(log, (uchar*) magic, sizeof(magic)))
> +  {
> +    *errmsg = "I/O error reading the header from the binary log";
> +    sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
> +		    log->error);
> +    return 1;
> +  }
> +  if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
> +  {
> +    *errmsg = "Binlog has bad magic number;  It's not a binary log file that can be
> used by this version of MySQL";
> +    return 1;
> +  }
> +  return 0;
> +}
> +
> +
> +File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
> +{
> +  File file;
> +  DBUG_ENTER("open_binlog");
> +
> +  if ((file= mysql_file_open(key_file_binlog,
> +                             log_file_name, O_RDONLY | O_BINARY | O_SHARE,
> +                             MYF(MY_WME))) < 0)
> +  {
> +    sql_print_error("Failed to open log (file '%s', errno %d)",
> +                    log_file_name, my_errno);
> +    *errmsg = "Could not open log file";
> +    goto err;
> +  }
> +  if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
> +                    MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
> +  {
> +    sql_print_error("Failed to create a cache on log (file '%s')",
> +                    log_file_name);
> +    *errmsg = "Could not open log file";
> +    goto err;
> +  }
> +  if (check_binlog_magic(log,errmsg))
> +    goto err;
> +  DBUG_RETURN(file);
> +
> +err:
> +  if (file >= 0)
> +  {
> +    mysql_file_close(file, MYF(0));
> +    end_io_cache(log);
> +  }
> +  DBUG_RETURN(-1);
> +}
> +
> +/** 
> +  This function checks if a transactional table was updated by the
> +  current transaction.
> +
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a transactional table was updated, @c false otherwise.
> +*/
> +bool
> +trans_has_updated_trans_table(const THD* thd)
> +{
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
> +}
> +
> +/** 
> +  This function checks if a transactional table was updated by the
> +  current statement.
> +
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a transactional table was updated, @c false otherwise.
> +*/
> +bool
> +stmt_has_updated_trans_table(const THD *thd)
> +{
> +  Ha_trx_info *ha_info;
> +
> +  for (ha_info= thd->transaction.stmt.ha_list; ha_info;
> +       ha_info= ha_info->next())
> +  {
> +    if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
> +      return (TRUE);
> +  }
> +  return (FALSE);
> +}
> +
> +/** 
> +  This function checks if either a trx-cache or a non-trx-cache should
> +  be used. If @c bin_log_direct_non_trans_update is active or the format
> +  is either MIXED or ROW, the cache to be used depends on the flag @c
> +  is_transactional. 
> +
> +  On the other hand, if binlog_format is STMT or direct option is
> +  OFF, the trx-cache should be used if and only if the statement is
> +  transactional or the trx-cache is not empty. Otherwise, the
> +  non-trx-cache should be used.
> +
> +  @param thd              The client thread.
> +  @param is_transactional The changes are related to a trx-table.
> +  @return
> +    @c true if a trx-cache should be used, @c false otherwise.
> +*/
> +bool use_trans_cache(const THD* thd, bool is_transactional)
> +{
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  return
> +    ((thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
> +     thd->variables.binlog_direct_non_trans_update) ? is_transactional :
> +     (is_transactional || !cache_mngr->trx_cache.empty()));
> +}
> +
> +/**
> +  This function checks if a transaction, either a multi-statement
> +  or a single statement transaction is about to commit or not.
> +
> +  @param thd The client thread that executed the current statement.
> +  @param all Committing a transaction (i.e. TRUE) or a statement
> +             (i.e. FALSE).
> +  @return
> +    @c true if committing a transaction, otherwise @c false.
> +*/
> +bool ending_trans(THD* thd, const bool all)
> +{
> +  return (all || (!all && !thd->in_multi_stmt_transaction()));
> +}
> +
> +/**
> +  This function checks if a non-transactional table was updated by
> +  the current transaction.
> +
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a non-transactional table was updated, @c false
> +    otherwise.
> +*/
> +bool trans_has_updated_non_trans_table(const THD* thd)
> +{
> +  return (thd->transaction.all.modified_non_trans_table ||
> +          thd->transaction.stmt.modified_non_trans_table);
> +}
> +
> +/**
> +  This function checks if a non-transactional table was updated by the
> +  current statement.
> +
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a non-transactional table was updated, @c false otherwise.
> +*/
> +bool stmt_has_updated_non_trans_table(const THD* thd)
> +{
> +  return (thd->transaction.stmt.modified_non_trans_table);
> +}
> +
> +#ifndef EMBEDDED_LIBRARY
> +/**
> +  Execute a PURGE BINARY LOGS TO <log> command.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param to_log Name of the last log to purge.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool purge_master_logs(THD* thd, const char* to_log)
> +{
> +  char search_file_name[FN_REFLEN];
> +  if (!mysql_bin_log.is_open())
> +  {
> +    my_ok(thd);
> +    return FALSE;
> +  }
> +
> +  mysql_bin_log.make_log_name(search_file_name, to_log);
> +  return purge_error_message(thd,
> +			     mysql_bin_log.purge_logs(search_file_name, 0, 1,
> +						      1, NULL));
> +}
> +
> +
> +/**
> +  Execute a PURGE BINARY LOGS BEFORE <date> command.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param purge_time Date before which logs should be purged.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool purge_master_logs_before_date(THD* thd, time_t purge_time)
> +{
> +  if (!mysql_bin_log.is_open())
> +  {
> +    my_ok(thd);
> +    return 0;
> +  }
> +  return purge_error_message(thd,
> +                             mysql_bin_log.purge_logs_before_date(purge_time));
> +}
> +#endif /* EMBEDDED_LIBRARY */
> +
> +/*
> +  Helper function to get the error code of the query to be binlogged.
> + */
> +int query_error_code(THD *thd, bool not_killed)
> +{
> +  int error;
> +  
> +  if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
> +  {
> +    error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
> +
> +    /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or
> +       ER_QUERY_INTERRUPTED, So here we need to make sure that error
> +       is not set to these errors when specified not_killed by the
> +       caller.
> +    */
> +    if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED)
> +      error= 0;
> +  }
> +  else
> +  {
> +    /* killed status for DELAYED INSERT thread should never be used */
> +    DBUG_ASSERT(!(thd->system_thread & SYSTEM_THREAD_DELAYED_INSERT));
> +    error= thd->killed_errno();
> +  }
> +
> +  return error;
> +}
> +
> +
> +/**
> +  Move all data up in a file in an filename index file.
> +
> +    We do the copy outside of the IO_CACHE as the cache buffers would just
> +    make things slower and more complicated.
> +    In most cases the copy loop should only do one read.
> +
> +  @param index_file			File to move
> +  @param offset			Move everything from here to beginning
> +
> +  @note
> +    File will be truncated to be 'offset' shorter or filled up with newlines
> +
> +  @retval
> +    0	ok
> +*/
> +
> +#ifdef HAVE_REPLICATION
> +
> +static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
> +{
> +  int bytes_read;
> +  my_off_t init_offset= offset;
> +  File file= index_file->file;
> +  uchar io_buf[IO_SIZE*2];
> +  DBUG_ENTER("copy_up_file_and_fill");
> +
> +  for (;; offset+= bytes_read)
> +  {
> +    mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0));
> +    if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf),
> +                                           MYF(MY_WME)))
> +	< 0)
> +      goto err;
> +    if (!bytes_read)
> +      break;					// end of file
> +    mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
> +    if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
> +      goto err;
> +  }
> +  /* The following will either truncate the file or fill the end with \n' */
> +  if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
> +      mysql_file_sync(file, MYF(MY_WME)))
> +    goto err;
> +
> +  /* Reset data in old index cache */
> +  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
> +  DBUG_RETURN(0);
> +
> +err:
> +  DBUG_RETURN(1);
> +}
> +
> +/**
> +   Load data's io cache specific hook to be executed
> +   before a chunk of data is being read into the cache's buffer
> +   The fuction instantianates and writes into the binlog
> +   replication events along LOAD DATA processing.
> +   
> +   @param file  pointer to io-cache
> +   @retval 0 success
> +   @retval 1 failure
> +*/
> +int log_loaded_block(IO_CACHE* file)
> +{
> +  DBUG_ENTER("log_loaded_block");
> +  LOAD_FILE_INFO *lf_info;
> +  uint block_len;
> +  /* buffer contains position where we started last read */
> +  uchar* buffer= (uchar*) my_b_get_buffer_start(file);
> +  uint max_event_size= current_thd->variables.max_allowed_packet;
> +  lf_info= (LOAD_FILE_INFO*) file->arg;
> +  if (lf_info->thd->is_current_stmt_binlog_format_row())
> +    DBUG_RETURN(0);
> +  if (lf_info->last_pos_in_file != HA_POS_ERROR &&
> +      lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
> +    DBUG_RETURN(0);
> +  
> +  for (block_len= (uint) (my_b_get_bytes_in_buffer(file)); block_len > 0;
> +       buffer += min(block_len, max_event_size),
> +       block_len -= min(block_len, max_event_size))
> +  {
> +    lf_info->last_pos_in_file= my_b_get_pos_in_file(file);
> +    if (lf_info->wrote_create_file)
> +    {
> +      Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
> +                               min(block_len, max_event_size),
> +                               lf_info->log_delayed);
> +      if (mysql_bin_log.write(&a))
> +        DBUG_RETURN(1);
> +    }
> +    else
> +    {
> +      Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
> +                                   buffer,
> +                                   min(block_len, max_event_size),
> +                                   lf_info->log_delayed);
> +      if (mysql_bin_log.write(&b))
> +        DBUG_RETURN(1);
> +      lf_info->wrote_create_file= 1;
> +    }
> +  }
> +  DBUG_RETURN(0);
> +}
> +
> +/* Helper function for SHOW BINLOG/RELAYLOG EVENTS */
> +bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log)
> +{
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  const char *errmsg = 0;
> +  bool ret = TRUE;
> +  IO_CACHE log;
> +  File file = -1;
> +  DBUG_ENTER("show_binlog_events");
> +
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
> +              thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
> +
> +  Format_description_log_event *description_event= new
> +    Format_description_log_event(3); /* MySQL 4.0 by default */
> +
> +  if (binary_log->is_open())
> +  {
> +    LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
> +    SELECT_LEX_UNIT *unit= &thd->lex->unit;
> +    ha_rows event_count, limit_start, limit_end;
> +    my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
> +    char search_file_name[FN_REFLEN], *name;
> +    const char *log_file_name = lex_mi->log_file_name;
> +    mysql_mutex_t *log_lock = binary_log->get_log_lock();
> +    LOG_INFO linfo;
> +    Log_event* ev;
> +
> +    unit->set_limit(thd->lex->current_select);
> +    limit_start= unit->offset_limit_cnt;
> +    limit_end= unit->select_limit_cnt;
> +
> +    name= search_file_name;
> +    if (log_file_name)
> +      binary_log->make_log_name(search_file_name, log_file_name);
> +    else
> +      name=0;					// Find first log
> +
> +    linfo.index_file_offset = 0;
> +
> +    if (binary_log->find_log_pos(&linfo, name, 1))
> +    {
> +      errmsg = "Could not find target log";
> +      goto err;
> +    }
> +
> +    mysql_mutex_lock(&LOCK_thread_count);
> +    thd->current_linfo = &linfo;
> +    mysql_mutex_unlock(&LOCK_thread_count);
> +
> +    if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
> +      goto err;
> +
> +    /*
> +      to account binlog event header size
> +    */
> +    thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER;
> +
> +    mysql_mutex_lock(log_lock);
> +
> +    /*
> +      open_binlog() sought to position 4.
> +      Read the first event in case it's a Format_description_log_event, to
> +      know the format. If there's no such event, we are 3.23 or 4.x. This
> +      code, like before, can't read 3.23 binlogs.
> +      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, (mysql_mutex_t*)0, description_event);
> +    if (ev)
> +    {
> +      if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
> +      {
> +        delete description_event;
> +        description_event= (Format_description_log_event*) ev;
> +      }
> +      else
> +        delete ev;
> +    }
> +
> +    my_b_seek(&log, pos);
> +
> +    if (!description_event->is_valid())
> +    {
> +      errmsg="Invalid Format_description event; could be out of memory";
> +      goto err;
> +    }
> +
> +    for (event_count = 0;
> +         (ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
> +                                         description_event)); )
> +    {
> +      if (event_count >= limit_start &&
> +	  ev->net_send(protocol, linfo.log_file_name, pos))
> +      {
> +	errmsg = "Net error";
> +	delete ev;
> +        mysql_mutex_unlock(log_lock);
> +	goto err;
> +      }
> +
> +      pos = my_b_tell(&log);
> +      delete ev;
> +
> +      if (++event_count >= limit_end)
> +	break;
> +    }
> +
> +    if (event_count < limit_end && log.error)
> +    {
> +      errmsg = "Wrong offset or I/O error";
> +      mysql_mutex_unlock(log_lock);
> +      goto err;
> +    }
> +
> +    mysql_mutex_unlock(log_lock);
> +  }
> +
> +  ret= FALSE;
> +
> +err:
> +  delete description_event;
> +  if (file >= 0)
> +  {
> +    end_io_cache(&log);
> +    mysql_file_close(file, MYF(MY_WME));
> +  }
> +
> +  if (errmsg)
> +    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
> +             "SHOW BINLOG EVENTS", errmsg);
> +  else
> +    my_eof(thd);
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  thd->current_linfo = 0;
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  DBUG_RETURN(ret);
> +}
> +
> +/**
> +  Execute a SHOW BINLOG EVENTS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool mysql_show_binlog_events(THD* thd)
> +{
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  DBUG_ENTER("mysql_show_binlog_events");
> +
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS);
> +
> +  Log_event::init_show_field_list(&field_list);
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +
> +  /*
> +    Wait for handlers to insert any pending information
> +    into the binlog.  For e.g. ndb which updates the binlog asynchronously
> +    this is needed so that the uses sees all its own commands in the binlog
> +  */
> +  ha_binlog_wait(thd);
> +  
> +  DBUG_RETURN(show_binlog_events(thd, &mysql_bin_log));
> +}
> +
> +#endif /* HAVE_REPLICATION */
> +
> +
> +MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
> +  :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
> +   need_start_event(TRUE), m_table_map_version(0),
> +   sync_period_ptr(sync_period),
> +   is_relay_log(0), signal_cnt(0),
> +   description_event_for_exec(0), description_event_for_queue(0)
> +{
> +  /*
> +    We don't want to initialize locks here as such initialization depends on
> +    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
> +    called only in main(). Doing initialization here would make it happen
> +    before main().
> +  */
> +  index_file_name[0] = 0;
> +  bzero((char*) &index_file, sizeof(index_file));
> +  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> +}
> +
> +/* this is called only once */
> +
> +void MYSQL_BIN_LOG::cleanup()
> +{
> +  DBUG_ENTER("cleanup");
> +  if (inited)
> +  {
> +    inited= 0;
> +    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
> +    delete description_event_for_queue;
> +    delete description_event_for_exec;
> +    mysql_mutex_destroy(&LOCK_log);
> +    mysql_mutex_destroy(&LOCK_index);
> +    mysql_cond_destroy(&update_cond);
> +  }
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/* Init binlog-specific vars */
> +void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::init");
> +  no_auto_events= no_auto_events_arg;
> +  max_size= max_size_arg;
> +  DBUG_PRINT("info",("max_size: %lu", max_size));
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +void MYSQL_BIN_LOG::init_pthread_objects()
> +{
> +  DBUG_ASSERT(inited == 0);
> +  inited= 1;
> +  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> +  mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
> +  mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0);
> +}
> +
> +
> +bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
> +                                    const char *log_name, bool need_mutex)
> +{
> +  File index_file_nr= -1;
> +  DBUG_ASSERT(!my_b_inited(&index_file));
> +
> +  /*
> +    First open of this class instance
> +    Create an index file that will hold all file names uses for logging.
> +    Add new entries to the end of it.
> +  */
> +  myf opt= MY_UNPACK_FILENAME;
> +  if (!index_file_name_arg)
> +  {
> +    index_file_name_arg= log_name;    // Use same basename for index file
> +    opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
> +  }
> +  fn_format(index_file_name, index_file_name_arg, mysql_data_home,
> +            ".index", opt);
> +  if ((index_file_nr= mysql_file_open(key_file_binlog_index,
> +                                      index_file_name,
> +                                      O_RDWR | O_CREAT | O_BINARY,
> +                                      MYF(MY_WME))) < 0 ||
> +       mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
> +       init_io_cache(&index_file, index_file_nr,
> +                     IO_SIZE, WRITE_CACHE,
> +                     mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
> +                                     0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
> +      DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
> +  {
> +    /*
> +      TODO: all operations creating/deleting the index file or a log, should
> +      call my_sync_dir() or my_sync_dir_by_file() to be durable.
> +      TODO: file creation should be done with mysql_file_create()
> +      not mysql_file_open().
> +    */
> +    if (index_file_nr >= 0)
> +      mysql_file_close(index_file_nr, MYF(0));
> +    return TRUE;
> +  }
> +
> +#ifdef HAVE_REPLICATION
> +  /*
> +    Sync the index by purging any binary log file that is not registered.
> +    In other words, either purge binary log files that were removed from
> +    the index but not purged from the file system due to a crash or purge
> +    any binary log file that was created but not register in the index
> +    due to a crash.
> +  */
> +
> +  if (set_purge_index_file_name(index_file_name_arg) ||
> +      open_purge_index_file(FALSE) ||
> +      purge_index_entry(NULL, NULL, need_mutex) ||
> +      close_purge_index_file() ||
> +      DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
> +  {
> +    sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
> +                    "file.");
> +    return TRUE;
> +  }
> +#endif
> +
> +  return FALSE;
> +}
> +
> +
> +/**
> +  Open a (new) binlog file.
> +
> +  - Open the log file and the index file. Register the new
> +  file name in it
> +  - When calling this when the file is in use, you must have a locks
> +  on LOCK_log and LOCK_index.
> +
> +  @retval
> +    0	ok
> +  @retval
> +    1	error
> +*/
> +
> +bool MYSQL_BIN_LOG::open(const char *log_name,
> +                         enum_log_type log_type_arg,
> +                         const char *new_name,
> +                         enum cache_type io_cache_type_arg,
> +                         bool no_auto_events_arg,
> +                         ulong max_size_arg,
> +                         bool null_created_arg,
> +                         bool need_mutex)
> +{
> +  File file= -1;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::open");
> +  DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
> +
> +  if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
> +                                 io_cache_type_arg))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
> +    DBUG_RETURN(1);
> +  }
> +
> +#ifdef HAVE_REPLICATION
> +  if (open_purge_index_file(TRUE) ||
> +      register_create_index_entry(log_file_name) ||
> +      sync_purge_index_file() ||
> +      DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
> +    DBUG_RETURN(1);
> +  }
> +  DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_ABORT(););
> +#endif
> +
> +  write_error= 0;
> +
> +  /* open the main log file */
> +  if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
> +                      io_cache_type_arg))
> +  {
> +#ifdef HAVE_REPLICATION
> +    close_purge_index_file();
> +#endif
> +    DBUG_RETURN(1);                            /* all warnings issued */
> +  }
> +
> +  init(no_auto_events_arg, max_size_arg);
> +
> +  open_count++;
> +
> +  DBUG_ASSERT(log_type == LOG_BIN);
> +
> +  {
> +    bool write_file_name_to_index_file=0;
> +
> +    if (!my_b_filelength(&log_file))
> +    {
> +      /*
> +	The binary log file was empty (probably newly created)
> +	This is the normal case and happens when the user doesn't specify
> +	an extension for the binary log files.
> +	In this case we write a standard header to it.
> +      */
> +      if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC,
> +			  BIN_LOG_HEADER_SIZE))
> +        goto err;
> +      bytes_written+= BIN_LOG_HEADER_SIZE;
> +      write_file_name_to_index_file= 1;
> +    }
> +
> +    if (need_start_event && !no_auto_events)
> +    {
> +      /*
> +        In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
> +        even if this is not the very first binlog.
> +      */
> +      Format_description_log_event s(BINLOG_VERSION);
> +      /*
> +        don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
> +        as we won't be able to reset it later
> +      */
> +      if (io_cache_type == WRITE_CACHE)
> +        s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
> +      if (!s.is_valid())
> +        goto err;
> +      s.dont_set_created= null_created_arg;
> +      if (s.write(&log_file))
> +        goto err;
> +      bytes_written+= s.data_written;
> +    }
> +    if (description_event_for_queue &&
> +        description_event_for_queue->binlog_version>=4)
> +    {
> +      /*
> +        This is a relay log written to by the I/O slave thread.
> +        Write the event so that others can later know the format of this relay
> +        log.
> +        Note that this event is very close to the original event from the
> +        master (it has binlog version of the master, event types of the
> +        master), so this is suitable to parse the next relay log's event. It
> +        has been produced by
> +        Format_description_log_event::Format_description_log_event(char* buf,).
> +        Why don't we want to write the description_event_for_queue if this
> +        event is for format<4 (3.23 or 4.x): this is because in that case, the
> +        description_event_for_queue describes the data received from the
> +        master, but not the data written to the relay log (*conversion*),
> +        which is in format 4 (slave's).
> +      */
> +      /*
> +        Set 'created' to 0, so that in next relay logs this event does not
> +        trigger cleaning actions on the slave in
> +        Format_description_log_event::apply_event_impl().
> +      */
> +      description_event_for_queue->created= 0;
> +      /* Don't set log_pos in event header */
> +      description_event_for_queue->set_artificial_event();
> +
> +      if (description_event_for_queue->write(&log_file))
> +        goto err;
> +      bytes_written+= description_event_for_queue->data_written;
> +    }
> +    if (flush_io_cache(&log_file) ||
> +        mysql_file_sync(log_file.file, MYF(MY_WME)))
> +      goto err;
> +
> +    if (write_file_name_to_index_file)
> +    {
> +#ifdef HAVE_REPLICATION
> +      DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_ABORT(););
> +#endif
> +
> +      DBUG_ASSERT(my_b_inited(&index_file) != 0);
> +      reinit_io_cache(&index_file, WRITE_CACHE,
> +                      my_b_filelength(&index_file), 0, 0);
> +      /*
> +        As this is a new log file, we write the file name to the index
> +        file. As every time we write to the index file, we sync it.
> +      */
> +      if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
> +          my_b_write(&index_file, (uchar*) log_file_name,
> +                     strlen(log_file_name)) ||
> +          my_b_write(&index_file, (uchar*) "\n", 1) ||
> +          flush_io_cache(&index_file) ||
> +          mysql_file_sync(index_file.file, MYF(MY_WME)))
> +        goto err;
> +
> +#ifdef HAVE_REPLICATION
> +      DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_ABORT(););
> +#endif
> +    }
> +  }
> +  log_state= LOG_OPENED;
> +
> +#ifdef HAVE_REPLICATION
> +  close_purge_index_file();
> +#endif
> +
> +  DBUG_RETURN(0);
> +
> +err:
> +#ifdef HAVE_REPLICATION
> +  if (is_inited_purge_index_file())
> +    purge_index_entry(NULL, NULL, need_mutex);
> +  close_purge_index_file();
> +#endif
> +  sql_print_error("Could not use %s for logging (error %d). \
> +Turning logging off for the whole duration of the MySQL server process. \
> +To turn it on again: fix the cause, \
> +shutdown the MySQL server and restart it.", name, errno);
> +  if (file >= 0)
> +    mysql_file_close(file, MYF(0));
> +  end_io_cache(&log_file);
> +  end_io_cache(&index_file);
> +  safeFree(name);
> +  log_state= LOG_CLOSED;
> +  DBUG_RETURN(1);
> +}
> +
> +
> +int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
> +{
> +  mysql_mutex_lock(&LOCK_log);
> +  int ret = raw_get_current_log(linfo);
> +  mysql_mutex_unlock(&LOCK_log);
> +  return ret;
> +}
> +
> +int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
> +{
> +  strmake(linfo->log_file_name, log_file_name,
> sizeof(linfo->log_file_name)-1);
> +  linfo->pos = my_b_tell(&log_file);
> +  return 0;
> +}
> +
> +bool MYSQL_BIN_LOG::check_write_error(THD *thd)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::check_write_error");
> +
> +  bool checked= FALSE;
> +
> +  if (!thd->is_error())
> +    DBUG_RETURN(checked);
> +
> +  switch (thd->stmt_da->sql_errno())
> +  {
> +    case ER_TRANS_CACHE_FULL:
> +    case ER_ERROR_ON_WRITE:
> +    case ER_BINLOG_LOGGING_IMPOSSIBLE:
> +      checked= TRUE;
> +    break;
> +  }
> +
> +  DBUG_RETURN(checked);
> +}
> +
> +void MYSQL_BIN_LOG::set_write_error(THD *thd)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
> +
> +  write_error= 1;
> +
> +  if (check_write_error(thd))
> +    DBUG_VOID_RETURN;
> +
> +  if (my_errno == EFBIG)
> +    my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
> +  else
> +    my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +/**
> +  Find the position in the log-index-file for the given log name.
> +
> +  @param linfo		Store here the found log file name and position to
> +                       the NEXT log file name in the index file.
> +  @param log_name	Filename to find in the index file.
> +                       Is a null pointer if we want to read the first entry
> +  @param need_lock	Set this to 1 if the parent doesn't already have a
> +                       lock on LOCK_index
> +
> +  @note
> +    On systems without the truncate function the file will end with one or
> +    more empty lines.  These will be ignored when reading the file.
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF	        End of log-index-file found
> +  @retval
> +    LOG_INFO_IO		Got IO error while reading file
> +*/
> +
> +int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
> +			    bool need_lock)
> +{
> +  int error= 0;
> +  char *fname= linfo->log_file_name;
> +  uint log_name_len= log_name ? (uint) strlen(log_name) : 0;
> +  DBUG_ENTER("find_log_pos");
> +  DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL"));
> +
> +  /*
> +    Mutex needed because we need to make sure the file pointer does not
> +    move from under our feet
> +  */
> +  if (need_lock)
> +    mysql_mutex_lock(&LOCK_index);
> +  mysql_mutex_assert_owner(&LOCK_index);
> +
> +  /* As the file is flushed, we can't get an error here */
> +  (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0);
> +
> +  for (;;)
> +  {
> +    uint length;
> +    my_off_t offset= my_b_tell(&index_file);
> +
> +    DBUG_EXECUTE_IF("simulate_find_log_pos_error",
> +                    error=  LOG_INFO_EOF; break;);
> +    /* If we get 0 or 1 characters, this is the end of the file */
> +    if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
> +    {
> +      /* Did not find the given entry; Return not found or error */
> +      error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
> +      break;
> +    }
> +
> +    // if the log entry matches, null string matching anything
> +    if (!log_name ||
> +	(log_name_len == length-1 && fname[log_name_len] == '\n' &&
> +	 !memcmp(fname, log_name, log_name_len)))
> +    {
> +      DBUG_PRINT("info",("Found log file entry"));
> +      fname[length-1]=0;			// remove last \n
> +      linfo->index_file_start_offset= offset;
> +      linfo->index_file_offset = my_b_tell(&index_file);
> +      break;
> +    }
> +  }
> +
> +  if (need_lock)
> +    mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +
> +
> +/**
> +  Find the position in the log-index-file for the given log name.
> +
> +  @param
> +    linfo		Store here the next log file name and position to
> +			the file name after that.
> +  @param
> +    need_lock		Set this to 1 if the parent doesn't already have a
> +			lock on LOCK_index
> +
> +  @note
> +    - Before calling this function, one has to call find_log_pos()
> +    to set up 'linfo'
> +    - Mutex needed because we need to make sure the file pointer does not move
> +    from under our feet
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF	        End of log-index-file found
> +  @retval
> +    LOG_INFO_IO		Got IO error while reading file
> +*/
> +
> +int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
> +{
> +  int error= 0;
> +  uint length;
> +  char *fname= linfo->log_file_name;
> +
> +  if (need_lock)
> +    mysql_mutex_lock(&LOCK_index);
> +  mysql_mutex_assert_owner(&LOCK_index);
> +
> +  /* As the file is flushed, we can't get an error here */
> +  (void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset,
> 0,
> +			 0);
> +
> +  linfo->index_file_start_offset= linfo->index_file_offset;
> +  if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
> +  {
> +    error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
> +    goto err;
> +  }
> +  fname[length-1]=0;				// kill \n
> +  linfo->index_file_offset = my_b_tell(&index_file);
> +
> +err:
> +  if (need_lock)
> +    mysql_mutex_unlock(&LOCK_index);
> +  return error;
> +}
> +
> +
> +/**
> +  Delete all logs refered to in the index file.
> +  Start writing to a new log file.
> +
> +  The new index file will only contain this file.
> +
> +  @param thd		Thread
> +
> +  @note
> +    If not called from slave thread, write start event to new log
> +
> +  @retval
> +    0	ok
> +  @retval
> +    1   error
> +*/
> +
> +bool MYSQL_BIN_LOG::reset_logs(THD* thd)
> +{
> +  LOG_INFO linfo;
> +  bool error=0;
> +  int err;
> +  const char* save_name;
> +  DBUG_ENTER("reset_logs");
> +
> +  ha_reset_logs(thd);
> +  /*
> +    We need to get both locks to be sure that no one is trying to
> +    write to the index log file.
> +  */
> +  mysql_mutex_lock(&LOCK_log);
> +  mysql_mutex_lock(&LOCK_index);
> +
> +  /*
> +    The following mutex is needed to ensure that no threads call
> +    'delete thd' as we would then risk missing a 'rollback' from this
> +    thread. If the transaction involved MyISAM tables, it should go
> +    into binlog even on rollback.
> +  */
> +  mysql_mutex_lock(&LOCK_thread_count);
> +
> +  /* Save variables so that we can reopen the log */
> +  save_name=name;
> +  name=0;					// Protect against free
> +  close(LOG_CLOSE_TO_BE_OPENED);
> +
> +  /*
> +    First delete all old log files and then update the index file.
> +    As we first delete the log files and do not use sort of logging,
> +    a crash may lead to an inconsistent state where the index has
> +    references to non-existent files.
> +
> +    We need to invert the steps and use the purge_index_file methods
> +    in order to make the operation safe.
> +  */
> +
> +  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
> +  {
> +    uint errcode= purge_log_get_error_code(err);
> +    sql_print_error("Failed to locate old binlog or relay log files");
> +    my_message(errcode, ER(errcode), MYF(0));
> +    error= 1;
> +    goto err;
> +  }
> +
> +  for (;;)
> +  {
> +    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                            linfo.log_file_name);
> +        sql_print_information("Failed to delete file '%s'",
> +                              linfo.log_file_name);
> +        my_errno= 0;
> +        error= 0;
> +      }
> +      else
> +      {
> +        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                            ER_BINLOG_PURGE_FATAL_ERR,
> +                            "a problem with deleting %s; "
> +                            "consider examining correspondence "
> +                            "of your binlog index file "
> +                            "to the actual binlog files",
> +                            linfo.log_file_name);
> +        error= 1;
> +        goto err;
> +      }
> +    }
> +    if (find_next_log(&linfo, 0))
> +      break;
> +  }
> +
> +  /* Start logging with a new file */
> +  close(LOG_CLOSE_INDEX);
> +  if ((error= my_delete_allow_opened(index_file_name, MYF(0))))	// Reset (open will
> update)
> +  {
> +    if (my_errno == ENOENT) 
> +    {
> +      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                          index_file_name);
> +      sql_print_information("Failed to delete file '%s'",
> +                            index_file_name);
> +      my_errno= 0;
> +      error= 0;
> +    }
> +    else
> +    {
> +      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                          ER_BINLOG_PURGE_FATAL_ERR,
> +                          "a problem with deleting %s; "
> +                          "consider examining correspondence "
> +                          "of your binlog index file "
> +                          "to the actual binlog files",
> +                          index_file_name);
> +      error= 1;
> +      goto err;
> +    }
> +  }
> +  if (!thd->slave_thread)
> +    need_start_event=1;
> +  if (!open_index_file(index_file_name, 0, FALSE))
> +    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0,
> FALSE);
> +  my_free((uchar*) save_name, MYF(0));
> +
> +err:
> +  if (error == 1)
> +    name= const_cast<char*>(save_name);
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  mysql_mutex_unlock(&LOCK_index);
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_RETURN(error);
> +}
> +
> +
> +/**
> +  Delete relay log files prior to rli->group_relay_log_name
> +  (i.e. all logs which are not involved in a non-finished group
> +  (transaction)), remove them from the index file and start on next
> +  relay log.
> +
> +  IMPLEMENTATION
> +  - Protects index file with LOCK_index
> +  - Delete relevant relay log files
> +  - Copy all file names after these ones to the front of the index file
> +  - If the OS has truncate, truncate the file, else fill it with \n'
> +  - Read the next file name from the index file and store in rli->linfo
> +
> +  @param rli	       Relay log information
> +  @param included     If false, all relay logs that are strictly before
> +                      rli->group_relay_log_name are deleted ; if true, the
> +                      latter is deleted too (i.e. all relay logs
> +                      read by the SQL slave thread are deleted).
> +
> +  @note
> +    - This is only called from the slave-execute thread when it has read
> +    all commands from a relay log and want to switch to a new relay log.
> +    - When this happens, we can be in an active transaction as
> +    a transaction can span over two relay logs
> +    (although it is always written as a single block to the master's binary
> +    log, hence cannot span over two master's binary logs).
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF	        End of log-index-file found
> +  @retval
> +    LOG_INFO_SEEK	Could not allocate IO cache
> +  @retval
> +    LOG_INFO_IO		Got IO error while reading file
> +*/
> +
> +#ifdef HAVE_REPLICATION
> +
> +int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
> +{
> +  int error;
> +  char *to_purge_if_included= NULL;
> +  DBUG_ENTER("purge_first_log");
> +
> +  DBUG_ASSERT(is_open());
> +  DBUG_ASSERT(rli->slave_running == 1);
> +  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
> +
> +  mysql_mutex_lock(&LOCK_index);
> +  to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
> +
> +  /*
> +    Read the next log file name from the index file and pass it back to
> +    the caller.
> +  */
> +  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) || 
> +     (error=find_next_log(&rli->linfo, 0)))
> +  {
> +    char buff[22];
> +    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> +                    error,
> +                    llstr(rli->linfo.index_file_offset,buff),
> +                    rli->event_relay_log_name,
> +                    included);
> +    goto err;
> +  }
> +
> +  /*
> +    Reset rli's coordinates to the current log.
> +  */
> +  rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
> +  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
> +	  sizeof(rli->event_relay_log_name)-1);
> +
> +  /*
> +    If we removed the rli->group_relay_log_name file,
> +    we must update the rli->group* coordinates, otherwise do not touch it as the
> +    group's execution is not finished (e.g. COMMIT not executed)
> +  */
> +  if (included)
> +  {
> +    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
> +    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
> +            sizeof(rli->group_relay_log_name)-1);
> +    rli->notify_group_relay_log_name_update();
> +  }
> +
> +  /* Store where we are in the new file for the execution thread */
> +  flush_relay_log_info(rli);
> +
> +  DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_ABORT(););
> +
> +  mysql_mutex_lock(&rli->log_space_lock);
> +  rli->relay_log.purge_logs(to_purge_if_included, included,
> +                            0, 0, &rli->log_space_total);
> +  // Tell the I/O thread to take the relay_log_space_limit into account
> +  rli->ignore_log_space_limit= 0;
> +  mysql_mutex_unlock(&rli->log_space_lock);
> +
> +  /*
> +    Ok to broadcast after the critical region as there is no risk of
> +    the mutex being destroyed by this thread later - this helps save
> +    context switches
> +  */
> +  mysql_cond_broadcast(&rli->log_space_cond);
> +
> +  /*
> +   * Need to update the log pos because purge logs has been called 
> +   * after fetching initially the log pos at the begining of the method.
> +   */
> +  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
> +  {
> +    char buff[22];
> +    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> +                    error,
> +                    llstr(rli->linfo.index_file_offset,buff),
> +                    rli->group_relay_log_name,
> +                    included);
> +    goto err;
> +  }
> +
> +  /* If included was passed, rli->linfo should be the first entry. */
> +  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
> +
> +err:
> +  my_free(to_purge_if_included, MYF(0));
> +  mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Update log index_file.
> +*/
> +
> +int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
> +{
> +  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
> +    return LOG_INFO_IO;
> +
> +  // now update offsets in index file for running threads
> +  if (need_update_threads)
> +    adjust_linfo_offsets(log_info->index_file_start_offset);
> +  return 0;
> +}
> +
> +/**
> +  Remove all logs before the given log from disk and from the index file.
> +
> +  @param to_log	      Delete all log file name before this file.
> +  @param included            If true, to_log is deleted too.
> +  @param need_mutex
> +  @param need_update_threads If we want to update the log coordinates of
> +                             all threads. False for relay logs, true otherwise.
> +  @param freed_log_space     If not null, decrement this variable of
> +                             the amount of log space freed
> +
> +  @note
> +    If any of the logs before the deleted one is in use,
> +    only purge logs up to this one.
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF		to_log not found
> +    LOG_INFO_EMFILE             too many files opened
> +    LOG_INFO_FATAL              if any other than ENOENT error from
> +                                mysql_file_stat() or mysql_file_delete()
> +*/
> +
> +int MYSQL_BIN_LOG::purge_logs(const char *to_log, 
> +                          bool included,
> +                          bool need_mutex, 
> +                          bool need_update_threads, 
> +                          ulonglong *decrease_log_space)
> +{
> +  int error= 0;
> +  bool exit_loop= 0;
> +  LOG_INFO log_info;
> +  THD *thd= current_thd;
> +  DBUG_ENTER("purge_logs");
> +  DBUG_PRINT("info",("to_log= %s",to_log));
> +
> +  if (need_mutex)
> +    mysql_mutex_lock(&LOCK_index);
> +  if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) 
> +  {
> +    sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
> +                    "listed in the index.", to_log);
> +    goto err;
> +  }
> +
> +  if ((error= open_purge_index_file(TRUE)))
> +  {
> +    sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
> +    goto err;
> +  }
> +
> +  /*
> +    File name exists in index file; delete until we find this file
> +    or a file that is used.
> +  */
> +  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> +    goto err;
> +  while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
> +         !is_active(log_info.log_file_name) &&
> +         !log_in_use(log_info.log_file_name))
> +  {
> +    if ((error= register_purge_index_entry(log_info.log_file_name)))
> +    {
> +      sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register
> file.",
> +                      log_info.log_file_name);
> +      goto err;
> +    }
> +
> +    if (find_next_log(&log_info, 0) || exit_loop)
> +      break;
> +  }
> +
> +  DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_ABORT(););
> +
> +  if ((error= sync_purge_index_file()))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
> +    goto err;
> +  }
> +
> +  /* We know how many files to delete. Update index file. */
> +  if ((error=update_log_index(&log_info, need_update_threads)))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
> +    goto err;
> +  }
> +
> +  DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_ABORT(););
> +
> +err:
> +  /* Read each entry from purge_index_file and delete the file. */
> +  if (is_inited_purge_index_file() &&
> +      (error= purge_index_entry(thd, decrease_log_space, FALSE)))
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
> +                    " that would be purged.");
> +  close_purge_index_file();
> +
> +  DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_ABORT(););
> +
> +  if (need_mutex)
> +    mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
> +  if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
> +                ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
> +                              MY_REPLACE_EXT)) == NULL)
> +  {
> +    error= 1;
> +    sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
> +                      "file name.");
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
> +{
> +  int error= 0;
> +  File file= -1;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
> +
> +  if (destroy)
> +    close_purge_index_file();
> +
> +  if (!my_b_inited(&purge_index_file))
> +  {
> +    if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
> +                       MYF(MY_WME | ME_WAITTANG))) < 0  ||
> +        init_io_cache(&purge_index_file, file, IO_SIZE,
> +                      (destroy ? WRITE_CACHE : READ_CACHE),
> +                      0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
> +    {
> +      error= 1;
> +      sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register
> "
> +                      " file.");
> +    }
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::close_purge_index_file()
> +{
> +  int error= 0;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
> +
> +  if (my_b_inited(&purge_index_file))
> +  {
> +    end_io_cache(&purge_index_file);
> +    error= my_close(purge_index_file.file, MYF(0));
> +  }
> +  my_delete(purge_index_file_name, MYF(0));
> +  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> +
> +  DBUG_RETURN(error);
> +}
> +
> +bool MYSQL_BIN_LOG::is_inited_purge_index_file()
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
> +  DBUG_RETURN (my_b_inited(&purge_index_file));
> +}
> +
> +int MYSQL_BIN_LOG::sync_purge_index_file()
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
> +
> +  if ((error= flush_io_cache(&purge_index_file)) ||
> +      (error= my_sync(purge_index_file.file, MYF(MY_WME))))
> +    DBUG_RETURN(error);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
> +
> +  if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry)))
> ||
> +      (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
> +    DBUG_RETURN (error);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
> +  DBUG_RETURN(register_purge_index_entry(entry));
> +}
> +
> +int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> +                                     bool need_mutex)
> +{
> +  MY_STAT s;
> +  int error= 0;
> +  LOG_INFO log_info;
> +  LOG_INFO check_log_info;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
> +
> +  DBUG_ASSERT(my_b_inited(&purge_index_file));
> +
> +  if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file
> "
> +                    "for read");
> +    goto err;
> +  }
> +
> +  for (;;)
> +  {
> +    uint length;
> +
> +    if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
> +                          FN_REFLEN)) <= 1)
> +    {
> +      if (purge_index_file.error)
> +      {
> +        error= purge_index_file.error;
> +        sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
> +                        "register file.", error);
> +        goto err;
> +      }
> +
> +      /* Reached EOF */
> +      break;
> +    }
> +
> +    /* Get rid of the trailing '\n' */
> +    log_info.log_file_name[length-1]= 0;
> +
> +    if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0)))
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        /*
> +          It's not fatal if we can't stat a log file that does not exist;
> +          If we could not stat, we won't delete.
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                              log_info.log_file_name);
> +        }
> +        sql_print_information("Failed to execute mysql_file_stat on file '%s'",
> +			      log_info.log_file_name);
> +        my_errno= 0;
> +      }
> +      else
> +      {
> +        /*
> +          Other than ENOENT are fatal
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_BINLOG_PURGE_FATAL_ERR,
> +                              "a problem with getting info on being purged %s; "
> +                              "consider examining correspondence "
> +                              "of your binlog index file "
> +                              "to the actual binlog files",
> +                              log_info.log_file_name);
> +        }
> +        else
> +        {
> +          sql_print_information("Failed to delete log file '%s'; "
> +                                "consider examining correspondence "
> +                                "of your binlog index file "
> +                                "to the actual binlog files",
> +                                log_info.log_file_name);
> +        }
> +        error= LOG_INFO_FATAL;
> +        goto err;
> +      }
> +    }
> +    else
> +    {
> +      if ((error= find_log_pos(&check_log_info, log_info.log_file_name,
> need_mutex)))
> +      {
> +        if (error != LOG_INFO_EOF)
> +        {
> +          if (thd)
> +          {
> +            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                ER_BINLOG_PURGE_FATAL_ERR,
> +                                "a problem with deleting %s and "
> +                                "reading the binlog index file",
> +                                log_info.log_file_name);
> +          }
> +          else
> +          {
> +            sql_print_information("Failed to delete file '%s' and "
> +                                  "read the binlog index file",
> +                                  log_info.log_file_name);
> +          }
> +          goto err;
> +        }
> +           
> +        error= 0;
> +        if (!need_mutex)
> +        {
> +          /*
> +            This is to avoid triggering an error in NDB.
> +          */
> +          ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
> +        }
> +
> +        DBUG_PRINT("info",("purging %s",log_info.log_file_name));
> +        if (!my_delete(log_info.log_file_name, MYF(0)))
> +        {
> +          if (decrease_log_space)
> +            *decrease_log_space-= s.st_size;
> +        }
> +        else
> +        {
> +          if (my_errno == ENOENT)
> +          {
> +            if (thd)
> +            {
> +              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                  ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                                  log_info.log_file_name);
> +            }
> +            sql_print_information("Failed to delete file '%s'",
> +                                  log_info.log_file_name);
> +            my_errno= 0;
> +          }
> +          else
> +          {
> +            if (thd)
> +            {
> +              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                  ER_BINLOG_PURGE_FATAL_ERR,
> +                                  "a problem with deleting %s; "
> +                                  "consider examining correspondence "
> +                                  "of your binlog index file "
> +                                  "to the actual binlog files",
> +                                  log_info.log_file_name);
> +            }
> +            else
> +            {
> +              sql_print_information("Failed to delete file '%s'; "
> +                                    "consider examining correspondence "
> +                                    "of your binlog index file "
> +                                    "to the actual binlog files",
> +                                    log_info.log_file_name);
> +            }
> +            if (my_errno == EMFILE)
> +            {
> +              DBUG_PRINT("info",
> +                         ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
> +              error= LOG_INFO_EMFILE;
> +              goto err;
> +            }
> +            error= LOG_INFO_FATAL;
> +            goto err;
> +          }
> +        }
> +      }
> +    }
> +  }
> +
> +err:
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Remove all logs before the given file date from disk and from the
> +  index file.
> +
> +  @param thd		Thread pointer
> +  @param purge_time	Delete all log files before given date.
> +
> +  @note
> +    If any of the logs before the deleted one is in use,
> +    only purge logs up to this one.
> +
> +  @retval
> +    0				ok
> +  @retval
> +    LOG_INFO_PURGE_NO_ROTATE	Binary file that can't be rotated
> +    LOG_INFO_FATAL              if any other than ENOENT error from
> +                                mysql_file_stat() or mysql_file_delete()
> +*/
> +
> +int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
> +{
> +  int error;
> +  char to_log[FN_REFLEN];
> +  LOG_INFO log_info;
> +  MY_STAT stat_area;
> +  THD *thd= current_thd;
> +  
> +  DBUG_ENTER("purge_logs_before_date");
> +
> +  mysql_mutex_lock(&LOCK_index);
> +  to_log[0]= 0;
> +
> +  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> +    goto err;
> +
> +  while (strcmp(log_file_name, log_info.log_file_name) &&
> +	 !is_active(log_info.log_file_name) &&
> +         !log_in_use(log_info.log_file_name))
> +  {
> +    if (!mysql_file_stat(key_file_binlog,
> +                         log_info.log_file_name, &stat_area, MYF(0)))
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        /*
> +          It's not fatal if we can't stat a log file that does not exist.
> +        */
> +        my_errno= 0;
> +      }
> +      else
> +      {
> +        /*
> +          Other than ENOENT are fatal
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_BINLOG_PURGE_FATAL_ERR,
> +                              "a problem with getting info on being purged %s; "
> +                              "consider examining correspondence "
> +                              "of your binlog index file "
> +                              "to the actual binlog files",
> +                              log_info.log_file_name);
> +        }
> +        else
> +        {
> +          sql_print_information("Failed to delete log file '%s'",
> +                                log_info.log_file_name);
> +        }
> +        error= LOG_INFO_FATAL;
> +        goto err;
> +      }
> +    }
> +    else
> +    {
> +      if (stat_area.st_mtime < purge_time) 
> +        strmake(to_log, 
> +                log_info.log_file_name, 
> +                sizeof(log_info.log_file_name) - 1);
> +      else
> +        break;
> +    }
> +    if (find_next_log(&log_info, 0))
> +      break;
> +  }
> +
> +  error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
> +
> +err:
> +  mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +#endif /* HAVE_REPLICATION */
> +
> +
> +/**
> +  Create a new log file name.
> +
> +  @param buf		buf of at least FN_REFLEN where new name is stored
> +
> +  @note
> +    If file name will be longer then FN_REFLEN it will be truncated
> +*/
> +
> +void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
> +{
> +  uint dir_len = dirname_length(log_file_name); 
> +  if (dir_len >= FN_REFLEN)
> +    dir_len=FN_REFLEN-1;
> +  strnmov(buf, log_file_name, dir_len);
> +  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
> +}
> +
> +
> +/**
> +  Check if we are writing/reading to the given log file.
> +*/
> +
> +bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
> +{
> +  return !strcmp(log_file_name, log_file_name_arg);
> +}
> +
> +
> +/*
> +  Wrappers around new_file_impl to avoid using argument
> +  to control locking. The argument 1) less readable 2) breaks
> +  incapsulation 3) allows external access to the class without
> +  a lock (which is not possible with private new_file_without_locking
> +  method).
> +*/
> +
> +void MYSQL_BIN_LOG::new_file()
> +{
> +  new_file_impl(1);
> +}
> +
> +
> +void MYSQL_BIN_LOG::new_file_without_locking()
> +{
> +  new_file_impl(0);
> +}
> +
> +
> +/**
> +  Start writing to a new log file or reopen the old file.
> +
> +  @param need_lock		Set to 1 if caller has not locked LOCK_log
> +
> +  @note
> +    The new file name is stored last in the index file
> +*/
> +
> +void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
> +{
> +  char new_name[FN_REFLEN], *new_name_ptr, *old_name;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
> +  if (!is_open())
> +  {
> +    DBUG_PRINT("info",("log is closed"));
> +    DBUG_VOID_RETURN;
> +  }
> +
> +  if (need_lock)
> +    mysql_mutex_lock(&LOCK_log);
> +  mysql_mutex_lock(&LOCK_index);
> +
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  mysql_mutex_assert_owner(&LOCK_index);
> +
> +  /*
> +    if binlog is used as tc log, be sure all xids are "unlogged",
> +    so that on recover we only need to scan one - latest - binlog file
> +    for prepared xids. As this is expected to be a rare event,
> +    simple wait strategy is enough. We're locking LOCK_log to be sure no
> +    new Xid_log_event's are added to the log (and prepared_xids is not
> +    increased), and waiting on COND_prep_xids for late threads to
> +    catch up.
> +  */
> +  if (prepared_xids)
> +  {
> +    tc_log_page_waits++;
> +    mysql_mutex_lock(&LOCK_prep_xids);
> +    while (prepared_xids) {
> +      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> +      mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
> +    }
> +    mysql_mutex_unlock(&LOCK_prep_xids);
> +  }
> +
> +  /* Reuse old name if not binlog and not update log */
> +  new_name_ptr= name;
> +
> +  /*
> +    If user hasn't specified an extension, generate a new log name
> +    We have to do this here and not in open as we want to store the
> +    new file name in the current binary log file.
> +  */
> +  if (generate_new_name(new_name, name))
> +    goto end;
> +  new_name_ptr=new_name;
> +
> +  if (log_type == LOG_BIN)
> +  {
> +    if (!no_auto_events)
> +    {
> +      /*
> +        We log the whole file name for log file as the user may decide
> +        to change base names at some point.
> +      */
> +      Rotate_log_event r(new_name+dirname_length(new_name),
> +                         0, LOG_EVENT_OFFSET, is_relay_log ?
> Rotate_log_event::RELAY_LOG : 0);
> +      r.write(&log_file);
> +      bytes_written += r.data_written;
> +    }
> +    /*
> +      Update needs to be signalled even if there is no rotate event
> +      log rotation should give the waiting thread a signal to
> +      discover EOF and move on to the next log.
> +    */
> +    signal_update();
> +  }
> +  old_name=name;
> +  name=0;				// Don't free name
> +  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
> +
> +  /*
> +     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
> +  */
> +
> +  /*
> +     new_file() is only used for rotation (in FLUSH LOGS or because size >
> +     max_binlog_size or max_relay_log_size).
> +     If this is a binary log, the Format_description_log_event at the beginning of
> +     the new file should have created=0 (to distinguish with the
> +     Format_description_log_event written at server startup, which should
> +     trigger temp tables deletion on slaves.
> +  */
> +
> +  /* reopen index binlog file, BUG#34582 */
> +  if (!open_index_file(index_file_name, 0, FALSE))
> +    open(old_name, log_type, new_name_ptr,
> +         io_cache_type, no_auto_events, max_size, 1, FALSE);
> +  my_free(old_name,MYF(0));
> +
> +end:
> +  if (need_lock)
> +    mysql_mutex_unlock(&LOCK_log);
> +  mysql_mutex_unlock(&LOCK_index);
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +bool MYSQL_BIN_LOG::append(Log_event* ev)
> +{
> +  bool error = 0;
> +  mysql_mutex_lock(&LOCK_log);
> +  DBUG_ENTER("MYSQL_BIN_LOG::append");
> +
> +  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> +  /*
> +    Log_event::write() is smart enough to use my_b_write() or
> +    my_b_append() depending on the kind of cache we have.
> +  */
> +  if (ev->write(&log_file))
> +  {
> +    error=1;
> +    goto err;
> +  }
> +  bytes_written+= ev->data_written;
> +  DBUG_PRINT("info",("max_size: %lu",max_size));
> +  if (flush_and_sync(0))
> +    goto err;
> +  if ((uint) my_b_append_tell(&log_file) > max_size)
> +    new_file_without_locking();
> +
> +err:
> +  mysql_mutex_unlock(&LOCK_log);
> +  signal_update();				// Safe as we don't call close
> +  DBUG_RETURN(error);
> +}
> +
> +
> +bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
> +{
> +  bool error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::appendv");
> +  va_list(args);
> +  va_start(args,len);
> +
> +  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> +
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  do
> +  {
> +    if (my_b_append(&log_file,(uchar*) buf,len))
> +    {
> +      error= 1;
> +      goto err;
> +    }
> +    bytes_written += len;
> +  } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
> +  DBUG_PRINT("info",("max_size: %lu",max_size));
> +  if (flush_and_sync(0))
> +    goto err;
> +  if ((uint) my_b_append_tell(&log_file) > max_size)
> +    new_file_without_locking();
> +
> +err:
> +  if (!error)
> +    signal_update();
> +  DBUG_RETURN(error);
> +}
> +
> +bool MYSQL_BIN_LOG::flush_and_sync(bool *synced)
> +{
> +  int err=0, fd=log_file.file;
> +  if (synced)
> +    *synced= 0;
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  if (flush_io_cache(&log_file))
> +    return 1;
> +  uint sync_period= get_sync_period();
> +  if (sync_period && ++sync_counter >= sync_period)
> +  {
> +    sync_counter= 0;
> +    err= mysql_file_sync(fd, MYF(MY_WME));
> +    if (synced)
> +      *synced= 1;
> +  }
> +  return err;
> +}
> +
> +void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
> +{
> +  DBUG_ASSERT(!thd->binlog_evt_union.do_union);
> +  thd->binlog_evt_union.do_union= TRUE;
> +  thd->binlog_evt_union.unioned_events= FALSE;
> +  thd->binlog_evt_union.unioned_events_trans= FALSE;
> +  thd->binlog_evt_union.first_query_id= query_id_param;
> +}
> +
> +void MYSQL_BIN_LOG::stop_union_events(THD *thd)
> +{
> +  DBUG_ASSERT(thd->binlog_evt_union.do_union);
> +  thd->binlog_evt_union.do_union= FALSE;
> +}
> +
> +bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
> +{
> +  return (thd->binlog_evt_union.do_union && 
> +          query_id_param >= thd->binlog_evt_union.first_query_id);
> +}
> +
> +
> +/**
> +  This function removes the pending rows event, discarding any outstanding
> +  rows. If there is no pending rows event available, this is effectively a
> +  no-op.
> +
> +  @param thd               a pointer to the user thread.
> +  @param is_transactional  @c true indicates a transactional cache,
> +                           otherwise @c false a non-transactional.
> +*/
> +int
> +MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, bool is_transactional)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event");
> +
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  DBUG_ASSERT(cache_mngr);
> +
> +  binlog_cache_data *cache_data=
> +    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> +
> +  if (Rows_log_event* pending= cache_data->pending())
> +  {
> +    delete pending;
> +    cache_data->set_pending(NULL);
> +  }
> +
> +  DBUG_RETURN(0);
> +}
> +
> +/*
> +  Moves the last bunch of rows from the pending Rows event to a cache (either
> +  transactional cache if is_transaction is @c true, or the non-transactional
> +  cache otherwise. Sets a new pending event.
> +
> +  @param thd               a pointer to the user thread.
> +  @param evt               a pointer to the row event.
> +  @param is_transactional  @c true indicates a transactional cache,
> +                           otherwise @c false a non-transactional.
> +*/
> +int
> +MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
> +                                                Rows_log_event* event,
> +                                                bool is_transactional)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
> +  DBUG_ASSERT(mysql_bin_log.is_open());
> +  DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
> +
> +  int error= 0;
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  DBUG_ASSERT(cache_mngr);
> +
> +  binlog_cache_data *cache_data=
> +    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> +
> +  DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long)
> cache_data->pending()));
> +
> +  if (Rows_log_event* pending= cache_data->pending())
> +  {
> +    IO_CACHE *file= &cache_data->cache_log;
> +
> +    /*
> +      Write pending event to the cache.
> +    */
> +    if (pending->write(file))
> +    {
> +      set_write_error(thd);
> +      if (check_write_error(thd) && cache_data &&
> +          stmt_has_updated_non_trans_table(thd))
> +        cache_data->set_incident();
> +      DBUG_RETURN(1);
> +    }
> +
> +    /*
> +      We step the table map version if we are writing an event
> +      representing the end of a statement.
> +
> +      In an ideal world, we could avoid stepping the table map version,
> +      since we could then reuse the table map that was written earlier
> +      in the cache. This does not work since STMT_END_F implies closing
> +      all table mappings on the slave side.
> +    
> +      TODO: Find a solution so that table maps does not have to be
> +      written several times within a transaction.
> +    */
> +    if (pending->get_flags(Rows_log_event::STMT_END_F))
> +      ++m_table_map_version;
> +
> +    delete pending;
> +  }
> +
> +  thd->binlog_set_pending_rows_event(event, is_transactional);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Write an event to the binary log.
> +*/
> +
> +bool MYSQL_BIN_LOG::write(Log_event *event_info)
> +{
> +  THD *thd= event_info->thd;
> +  bool error= 1;
> +  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
> +  binlog_cache_data *cache_data= 0;
> +
> +  if (thd->binlog_evt_union.do_union)
> +  {
> +    /*
> +      In Stored function; Remember that function call caused an update.
> +      We will log the function call to the binary log on function exit
> +    */
> +    thd->binlog_evt_union.unioned_events= TRUE;
> +    thd->binlog_evt_union.unioned_events_trans |=
> +      event_info->use_trans_cache();
> +    DBUG_RETURN(0);
> +  }
> +
> +  /*
> +    We only end the statement if we are in a top-level statement.  If
> +    we are inside a stored function, we do not end the statement since
> +    this will close all tables on the slave.
> +  */
> +  bool const end_stmt=
> +    thd->locked_tables_mode && thd->lex->requires_prelocking();
> +  if (thd->binlog_flush_pending_rows_event(end_stmt,
> +                                           event_info->use_trans_cache()))
> +    DBUG_RETURN(error);
> +
> +  /*
> +     In most cases this is only called if 'is_open()' is true; in fact this is
> +     mostly called if is_open() *was* true a few instructions before, but it
> +     could have changed since.
> +  */
> +  if (likely(is_open()))
> +  {
> +#ifdef HAVE_REPLICATION
> +    /*
> +      In the future we need to add to the following if tests like
> +      "do the involved tables match (to be implemented)
> +      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
> +    */
> +    const char *local_db= event_info->get_db();
> +    if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
> +	!binlog_filter->db_ok(local_db))
> +      DBUG_RETURN(0);
> +#endif /* HAVE_REPLICATION */
> +
> +    IO_CACHE *file= NULL;
> +
> +    if (event_info->use_direct_logging())
> +    {
> +      file= &log_file;
> +      mysql_mutex_lock(&LOCK_log);
> +    }
> +    else
> +    {
> +      if (thd->binlog_setup_trx_data())
> +        goto err;
> +
> +      binlog_cache_mngr *const cache_mngr=
> +        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +      bool is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
> +      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
> +      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
> +
> +      thd->binlog_start_trans_and_stmt();
> +    }
> +    DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
> +
> +    /*
> +       No check for auto events flag here - this write method should
> +       never be called if auto-events are enabled.
> +
> +       Write first log events which describe the 'run environment'
> +       of the SQL command. If row-based binlogging, Insert_id, Rand
> +       and other kind of "setting context" events are not needed.
> +    */
> +    if (thd)
> +    {
> +      if (!thd->is_current_stmt_binlog_format_row())
> +      {
> +        if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
> +        {
> +          Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
> +                            
> thd->first_successful_insert_id_in_prev_stmt_for_binlog);
> +          if (e.write(file))
> +            goto err;
> +        }
> +        if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
> +        {
> +          DBUG_PRINT("info",("number of auto_inc intervals: %u",
> +                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
> +                             nb_elements()));
> +          Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
> +                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
> +                             minimum());
> +          if (e.write(file))
> +            goto err;
> +        }
> +        if (thd->rand_used)
> +        {
> +          Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
> +          if (e.write(file))
> +            goto err;
> +        }
> +        if (thd->user_var_events.elements)
> +        {
> +          for (uint i= 0; i < thd->user_var_events.elements; i++)
> +          {
> +            BINLOG_USER_VAR_EVENT *user_var_event;
> +            get_dynamic(&thd->user_var_events,(uchar*) &user_var_event,
> i);
> +
> +            /* setting flags for user var log event */
> +            uchar flags= User_var_log_event::UNDEF_F;
> +            if (user_var_event->unsigned_flag)
> +              flags|= User_var_log_event::UNSIGNED_F;
> +
> +            User_var_log_event e(thd,
> user_var_event->user_var_event->name.str,
> +                                 user_var_event->user_var_event->name.length,
> +                                 user_var_event->value,
> +                                 user_var_event->length,
> +                                 user_var_event->type,
> +                                 user_var_event->charset_number,
> +                                 flags);
> +            if (e.write(file))
> +              goto err;
> +          }
> +        }
> +      }
> +    }
> +
> +    /*
> +      Write the event.
> +    */
> +    if (event_info->write(file) ||
> +        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
> +      goto err;
> +
> +    error= 0;
> +
> +err:
> +    if (event_info->use_direct_logging())
> +    {
> +      if (!error)
> +      {
> +        bool synced;
> +        if ((error= flush_and_sync(&synced)))
> +          goto unlock;
> +
> +        if ((error= RUN_HOOK(binlog_storage, after_flush,
> +                 (thd, log_file_name, file->pos_in_file, synced))))
> +        {
> +          sql_print_error("Failed to run 'after_flush' hooks");
> +          goto unlock;
> +        }
> +        signal_update();
> +        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> +      }
> +unlock:
> +      mysql_mutex_unlock(&LOCK_log);
> +    }
> +
> +    if (error)
> +    {
> +      set_write_error(thd);
> +      if (check_write_error(thd) && cache_data &&
> +          stmt_has_updated_non_trans_table(thd))
> +        cache_data->set_incident();
> +    }
> +  }
> +
> +  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
> +    ++m_table_map_version;
> +
> +  DBUG_RETURN(error);
> +}
> +
> +
> +void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
> +{
> +#ifdef HAVE_REPLICATION
> +  bool check_purge= false;
> +#endif
> +  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> +    mysql_mutex_lock(&LOCK_log);
> +  if ((flags & RP_FORCE_ROTATE) ||
> +      (my_b_tell(&log_file) >= (my_off_t) max_size))
> +  {
> +    new_file_without_locking();
> +#ifdef HAVE_REPLICATION
> +    check_purge= true;
> +#endif
> +  }
> +  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> +    mysql_mutex_unlock(&LOCK_log);
> +
> +#ifdef HAVE_REPLICATION
> +  /*
> +    NOTE: Run purge_logs wo/ holding LOCK_log
> +          as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
> +  */
> +  if (check_purge && expire_logs_days)
> +  {
> +    time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
> +    if (purge_time >= 0)
> +      purge_logs_before_date(purge_time);
> +  }
> +#endif
> +}
> +
> +uint MYSQL_BIN_LOG::next_file_id()
> +{
> +  uint res;
> +  mysql_mutex_lock(&LOCK_log);
> +  res = file_id++;
> +  mysql_mutex_unlock(&LOCK_log);
> +  return res;
> +}
> +
> +
> +/*
> +  Write the contents of a cache to the binary log.
> +
> +  SYNOPSIS
> +    write_cache()
> +    cache    Cache to write to the binary log
> +    lock_log True if the LOCK_log mutex should be aquired, false otherwise
> +    sync_log True if the log should be flushed and synced
> +
> +  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.
> + */
> +
> +int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
> +{
> +  Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
> +
> +  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;
> +  long val;
> +  uchar header[LOG_EVENT_HEADER_LEN];
> +
> +  /*
> +    The events in the buffer have incorrect end_log_pos data
> +    (relative to beginning of group rather than absolute),
> +    so we'll recalculate them in situ so the binlog is always
> +    correct, even in the middle of a group. This is possible
> +    because we now know the start position of the group (the
> +    offset of this cache in the log, if you will); all we need
> +    to do is to find all event-headers, and add the position of
> +    the group to the end_log_pos of each event.  This is pretty
> +    straight forward, except that we read the cache in segments,
> +    so an event-header might end up on the cache-border and get
> +    split.
> +  */
> +
> +  group= (uint)my_b_tell(&log_file);
> +  hdr_offs= carry= 0;
> +
> +  do
> +  {
> +    /*
> +      if we only got a partial header in the last iteration,
> +      get the other half now and process a full header.
> +    */
> +    if (unlikely(carry > 0))
> +    {
> +      DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN);
> +
> +      /* assemble both halves */
> +      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN -
> carry);
> +
> +      /* fix end_log_pos */
> +      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
> +      int4store(&header[LOG_POS_OFFSET], val);
> +
> +      /* write the first half of the split header */
> +      if (my_b_write(&log_file, header, carry))
> +        return ER_ERROR_ON_WRITE;
> +
> +      /*
> +        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);
> +
> +      /* next event header at ... */
> +      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
> +
> +      carry= 0;
> +    }
> +
> +    /* if there is anything to write, process it. */
> +
> +    if (likely(length > 0))
> +    {
> +      /*
> +        process all event-headers in this (partial) cache.
> +        if next header is beyond current read-buffer,
> +        we'll get it later (though not necessarily in the
> +        very next iteration, just "eventually").
> +      */
> +
> +      while (hdr_offs < length)
> +      {
> +        /*
> +          partial header only? save what we can get, process once
> +          we get the rest.
> +        */
> +
> +        if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
> +        {
> +          carry= length - hdr_offs;
> +          memcpy(header, (char *)cache->read_pos + hdr_offs, carry);
> +          length= hdr_offs;
> +        }
> +        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;
> +
> +          /* fix end_log_pos */
> +          val= uint4korr(log_pos) + group;
> +          int4store(log_pos, val);
> +
> +          /* next event header at ... */
> +          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
> +          hdr_offs += uint4korr(log_pos);
> +
> +        }
> +      }
> +
> +      /*
> +        Adjust hdr_offs. Note that it may still point beyond the segment
> +        read in the next iteration; if the current event is very long,
> +        it may take a couple of read-iterations (and subsequent adjustments
> +        of hdr_offs) for it to point into the then-current segment.
> +        If we have a split header (!carry), hdr_offs will be set at the
> +        beginning of the next iteration, overwriting the value we set here:
> +      */
> +      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;
> +    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);
> +
> +  return 0;                                     // All OK
> +}
> +
> +bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
> +{
> +  uint error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
> +  LEX_STRING const write_error_msg=
> +    { C_STRING_WITH_LEN("error writing to the binary log") };
> +  Incident incident= INCIDENT_LOST_EVENTS;
> +  Incident_log_event ev(thd, incident, write_error_msg);
> +  if (lock)
> +    mysql_mutex_lock(&LOCK_log);
> +  error= ev.write(&log_file);
> +  if (lock)
> +  {
> +    if (!error && !(error= flush_and_sync(0)))
> +    {
> +      signal_update();
> +      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> +    }
> +    mysql_mutex_unlock(&LOCK_log);
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Write a cached log entry to the binary log.
> +  - To support transaction over replication, we wrap the transaction
> +  with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
> +  We want to write a BEGIN/ROLLBACK block when a non-transactional table
> +  was updated in a transaction which was rolled back. This is to ensure
> +  that the same updates are run on the slave.
> +
> +  @param thd
> +  @param cache		The cache to copy to the binlog
> +  @param commit_event   The commit event to print after writing the
> +                        contents of the cache.
> +  @param incident       Defines if an incident event should be created to
> +                        notify that some non-transactional changes did
> +                        not get into the binlog.
> +
> +  @note
> +    We only come here if there is something in the cache.
> +  @note
> +    The thing in the cache is always a complete transaction.
> +  @note
> +    'cache' needs to be reinitialized after this functions returns.
> +*/
> +
> +bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
> +                          bool incident)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
> +  mysql_mutex_lock(&LOCK_log);
> +
> +  DBUG_ASSERT(is_open());
> +  if (likely(is_open()))                       // Should always be true
> +  {
> +    /*
> +      We only bother to write to the binary log if there is anything
> +      to write.
> +     */
> +    if (my_b_tell(cache) > 0)
> +    {
> +      /*
> +        Log "BEGIN" at the beginning of every transaction.  Here, a
> +        transaction is either a BEGIN..COMMIT block or a single
> +        statement in autocommit mode.
> +      */
> +      Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
> +      if (qinfo.write(&log_file))
> +        goto err;
> +      DBUG_EXECUTE_IF("crash_before_writing_xid",
> +                      {
> +                        if ((write_error= write_cache(cache, false, true)))
> +                          DBUG_PRINT("info", ("error writing binlog cache: %d",
> +                                               write_error));
> +                        DBUG_PRINT("info", ("crashing before writing xid"));
> +                        DBUG_ABORT();
> +                      });
> +
> +      if ((write_error= write_cache(cache, false, false)))
> +        goto err;
> +
> +      if (commit_event && commit_event->write(&log_file))
> +        goto err;
> +
> +      if (incident && write_incident(thd, FALSE))
> +        goto err;
> +
> +      bool synced= 0;
> +      if (flush_and_sync(&synced))
> +        goto err;
> +      DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
> +      if (cache->error)				// Error on read
> +      {
> +        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
> +        write_error=1;				// Don't give more errors
> +        goto err;
> +      }
> +
> +      if (RUN_HOOK(binlog_storage, after_flush,
> +                   (thd, log_file_name, log_file.pos_in_file, synced)))
> +      {
> +        sql_print_error("Failed to run 'after_flush' hooks");
> +        write_error=1;
> +        goto err;
> +      }
> +
> +      signal_update();
> +    }
> +
> +    /*
> +      if commit_event is Xid_log_event, increase the number of
> +      prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
> +      if there're prepared xids in it - see the comment in new_file() for
> +      an explanation.
> +      If the commit_event is not Xid_log_event (then it's a Query_log_event)
> +      rotate binlog, if necessary.
> +    */
> +    if (commit_event && commit_event->get_type_code() == XID_EVENT)
> +    {
> +      mysql_mutex_lock(&LOCK_prep_xids);
> +      prepared_xids++;
> +      mysql_mutex_unlock(&LOCK_prep_xids);
> +    }
> +    else
> +      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> +  }
> +  mysql_mutex_unlock(&LOCK_log);
> +
> +  DBUG_RETURN(0);
> +
> +err:
> +  if (!write_error)
> +  {
> +    write_error= 1;
> +    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> +  }
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_RETURN(1);
> +}
> +
> +
> +/**
> +  Wait until we get a signal that the relay log has been updated.
> +
> +  @param thd		Thread variable
> +
> +  @note
> +    One must have a lock on LOCK_log before calling this function.
> +    This lock will be released before return! That's required by
> +    THD::enter_cond() (see NOTES in sql_class.h).
> +*/
> +
> +void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
> +{
> +  const char *old_msg;
> +  DBUG_ENTER("wait_for_update_relay_log");
> +
> +  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> +                           "Slave has read all relay log; "
> +                           "waiting for the slave I/O "
> +                           "thread to update it" );
> +  mysql_cond_wait(&update_cond, &LOCK_log);
> +  thd->exit_cond(old_msg);
> +  DBUG_VOID_RETURN;
> +}
> +
> +/**
> +  Wait until we get a signal that the binary log has been updated.
> +  Applies to master only.
> +     
> +  NOTES
> +  @param[in] thd        a THD struct
> +  @param[in] timeout    a pointer to a timespec;
> +                        NULL means to wait w/o timeout.
> +  @retval    0          if got signalled on update
> +  @retval    non-0      if wait timeout elapsed
> +  @note
> +    LOCK_log must be taken before calling this function.
> +    LOCK_log is being released while the thread is waiting.
> +    LOCK_log is released by the caller.
> +*/
> +
> +int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
> +                                           const struct timespec *timeout)
> +{
> +  int ret= 0;
> +  const char* old_msg = thd->proc_info;
> +  DBUG_ENTER("wait_for_update_bin_log");
> +  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> +                           "Master has sent all binlog to slave; "
> +                           "waiting for binlog to be updated");
> +  if (!timeout)
> +    mysql_cond_wait(&update_cond, &LOCK_log);
> +  else
> +    ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
> +                              const_cast<struct timespec *>(timeout));
> +  DBUG_RETURN(ret);
> +}
> +
> +
> +/**
> +  Close the log file.
> +
> +  @param exiting     Bitmask for one or more of the following bits:
> +          - LOG_CLOSE_INDEX : if we should close the index file
> +          - LOG_CLOSE_TO_BE_OPENED : if we intend to call open
> +                                     at once after close.
> +          - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
> +
> +  @note
> +    One can do an open on the object at once after doing a close.
> +    The internal structures are not freed until cleanup() is called
> +*/
> +
> +void MYSQL_BIN_LOG::close(uint exiting)
> +{					// One can't set log_type here!
> +  DBUG_ENTER("MYSQL_BIN_LOG::close");
> +  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
> +  if (log_state == LOG_OPENED)
> +  {
> +#ifdef HAVE_REPLICATION
> +    if (log_type == LOG_BIN && !no_auto_events &&
> +	(exiting & LOG_CLOSE_STOP_EVENT))
> +    {
> +      Stop_log_event s;
> +      s.write(&log_file);
> +      bytes_written+= s.data_written;
> +      signal_update();
> +    }
> +#endif /* HAVE_REPLICATION */
> +
> +    /* 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 org_position= mysql_file_tell(log_file.file, MYF(0));
> +      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
> +      mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
> +      /*
> +        Restore position so that anything we have in the IO_cache is written
> +        to the correct position.
> +        We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the
> +        original position on system that doesn't support pwrite().
> +      */
> +      mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
> +    }
> +
> +    /* this will cleanup IO_CACHE, sync and close the file */
> +    MYSQL_LOG::close(exiting);
> +  }
> +
> +  /*
> +    The following test is needed even if is_open() is not set, as we may have
> +    called a not complete close earlier and the index file is still open.
> +  */
> +
> +  if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
> +  {
> +    end_io_cache(&index_file);
> +    if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error)
> +    {
> +      write_error= 1;
> +      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
> +    }
> +  }
> +  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> +  safeFree(name);
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
> +{
> +  /*
> +    We need to take locks, otherwise this may happen:
> +    new_file() is called, calls open(old_max_size), then before open() starts,
> +    set_max_size() sets max_size to max_size_arg, then open() starts and
> +    uses the old_max_size argument, so max_size_arg has been overwritten and
> +    it's like if the SET command was never run.
> +  */
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
> +  mysql_mutex_lock(&LOCK_log);
> +  if (is_open())
> +    max_size= max_size_arg;
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +void MYSQL_BIN_LOG::signal_update()
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
> +  signal_cnt++;
> +  mysql_cond_broadcast(&update_cond);
> +  DBUG_VOID_RETURN;
> +}
> +
> +/****** transaction coordinator log for 2pc - binlog() based solution ******/
> +
> +/**
> +  @todo
> +  keep in-memory list of prepared transactions
> +  (add to list in log(), remove on unlog())
> +  and copy it to the new binlog if rotated
> +  but let's check the behaviour of tc_log_page_waits first!
> +*/
> +
> +int MYSQL_BIN_LOG::open(const char *opt_name)
> +{
> +  LOG_INFO log_info;
> +  int      error= 1;
> +
> +  DBUG_ASSERT(total_ha_2pc > 1);
> +  DBUG_ASSERT(opt_name && opt_name[0]);
> +
> +  mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
> +                   &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
> +  mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
> +
> +  if (!my_b_inited(&index_file))
> +  {
> +    /* There was a failure to open the index file, can't open the binlog */
> +    cleanup();
> +    return 1;
> +  }
> +
> +  if (using_heuristic_recover())
> +  {
> +    /* generate a new binlog to mask a corrupted one */
> +    open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE);
> +    cleanup();
> +    return 1;
> +  }
> +
> +  if ((error= find_log_pos(&log_info, NullS, 1)))
> +  {
> +    if (error != LOG_INFO_EOF)
> +      sql_print_error("find_log_pos() failed (error: %d)", error);
> +    else
> +      error= 0;
> +    goto err;
> +  }
> +
> +  {
> +    const char *errmsg;
> +    IO_CACHE    log;
> +    File        file;
> +    Log_event  *ev=0;
> +    Format_description_log_event fdle(BINLOG_VERSION);
> +    char        log_name[FN_REFLEN];
> +
> +    if (! fdle.is_valid())
> +      goto err;
> +
> +    do
> +    {
> +      strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
> +    } while (!(error= find_next_log(&log_info, 1)));
> +
> +    if (error !=  LOG_INFO_EOF)
> +    {
> +      sql_print_error("find_log_pos() failed (error: %d)", error);
> +      goto err;
> +    }
> +
> +    if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
> +    {
> +      sql_print_error("%s", errmsg);
> +      goto err;
> +    }
> +
> +    if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
> +        ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
> +        ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
> +    {
> +      sql_print_information("Recovering after a crash using %s", opt_name);
> +      error= recover(&log, (Format_description_log_event *)ev);
> +    }
> +    else
> +      error=0;
> +
> +    delete ev;
> +    end_io_cache(&log);
> +    mysql_file_close(file, MYF(MY_WME));
> +
> +    if (error)
> +      goto err;
> +  }
> +
> +err:
> +  return error;
> +}
> +
> +/** This is called on shutdown, after ha_panic. */
> +void MYSQL_BIN_LOG::close()
> +{
> +  DBUG_ASSERT(prepared_xids==0);
> +  mysql_mutex_destroy(&LOCK_prep_xids);
> +  mysql_cond_destroy(&COND_prep_xids);
> +}
> +
> +/**
> +  @todo
> +  group commit
> +
> +  @retval
> +    0    error
> +  @retval
> +    1    success
> +*/
> +int MYSQL_BIN_LOG::log_xid(THD *thd, my_xid xid)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::log_xid");
> +  Xid_log_event xle(thd, xid);
> +  binlog_cache_mngr *cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  /*
> +    We always commit the entire transaction when writing an XID. Also
> +    note that the return value is inverted.
> +   */
> +  DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) &&
> +              !binlog_flush_trx_cache(thd, cache_mngr, &xle));
> +}
> +
> +void MYSQL_BIN_LOG::unlog(ulong cookie, my_xid xid)
> +{
> +  mysql_mutex_lock(&LOCK_prep_xids);
> +  DBUG_ASSERT(prepared_xids > 0);
> +  if (--prepared_xids == 0) {
> +    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> +    mysql_cond_signal(&COND_prep_xids);
> +  }
> +  mysql_mutex_unlock(&LOCK_prep_xids);
> +  rotate_and_purge(0);     // as ::write() did not rotate
> +}
> +
> +int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
> +{
> +  Log_event  *ev;
> +  HASH xids;
> +  MEM_ROOT mem_root;
> +
> +  if (! fdle->is_valid() ||
> +      my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
> +                   sizeof(my_xid), 0, 0, MYF(0)))
> +    goto err1;
> +
> +  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
> +
> +  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())
> +  {
> +    if (ev->get_type_code() == XID_EVENT)
> +    {
> +      Xid_log_event *xev=(Xid_log_event *)ev;
> +      uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
> +                                      sizeof(xev->xid));
> +      if (!x || my_hash_insert(&xids, x))
> +        goto err2;
> +    }
> +    delete ev;
> +  }
> +
> +  if (ha_recover(&xids))
> +    goto err2;
> +
> +  free_root(&mem_root, MYF(0));
> +  my_hash_free(&xids);
> +  return 0;
> +
> +err2:
> +  free_root(&mem_root, MYF(0));
> +  my_hash_free(&xids);
> +err1:
> +  sql_print_error("Crash recovery failed. Either correct the problem "
> +                  "(if it's, for example, out of memory error) and restart, "
> +                  "or delete (or rename) binary log and start mysqld with "
> +                  "--tc-heuristic-recover={commit|rollback}");
> +  return 1;
> +}
> +
> +
> +/*
> +  These functions are placed in this file since they need access to
> +  binlog_hton, which has internal linkage.
> +*/
> +
> +int THD::binlog_setup_trx_data()
> +{
> +  DBUG_ENTER("THD::binlog_setup_trx_data");
> +  binlog_cache_mngr *cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +
> +  if (cache_mngr)
> +    DBUG_RETURN(0);                             // Already set up
> +
> +  cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr),
> MYF(MY_ZEROFILL));
> +  if (!cache_mngr ||
> +      open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
> +                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)) ||
> +      open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir,
> +                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
> +  {
> +    my_free((uchar*)cache_mngr, MYF(MY_ALLOW_ZERO_PTR));
> +    DBUG_RETURN(1);                      // Didn't manage to set it up
> +  }
> +  thd_set_ha_data(this, binlog_hton, cache_mngr);
> +
> +  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
> +
> +  DBUG_RETURN(0);
> +}
> +
> +/*
> +  Function to start a statement and optionally a transaction for the
> +  binary log.
> +
> +  SYNOPSIS
> +    binlog_start_trans_and_stmt()
> +
> +  DESCRIPTION
> +
> +    This function does three things:
> +    - Start a transaction if not in autocommit mode or if a BEGIN
> +      statement has been seen.
> +
> +    - Start a statement transaction to allow us to truncate the cache.
> +
> +    - Save the currrent binlog position so that we can roll back the
> +      statement by truncating the cache.
> +
> +      We only update the saved position if the old one was undefined,
> +      the reason is that there are some cases (e.g., for CREATE-SELECT)
> +      where the position is saved twice (e.g., both in
> +      select_create::prepare() and THD::binlog_write_table_map()) , but
> +      we should use the first. This means that calls to this function
> +      can be used to start the statement before the first table map
> +      event, to include some extra events.
> + */
> +
> +void
> +THD::binlog_start_trans_and_stmt()
> +{
> +  binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this,
> binlog_hton);
> +  DBUG_ENTER("binlog_start_trans_and_stmt");
> +  DBUG_PRINT("enter", ("cache_mngr: %p 
> cache_mngr->trx_cache.get_prev_position(): %lu",
> +                       cache_mngr,
> +                       (cache_mngr ? (ulong)
> cache_mngr->trx_cache.get_prev_position() :
> +                        (ulong) 0)));
> +
> +  if (cache_mngr == NULL ||
> +      cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
> +  {
> +    this->binlog_set_stmt_begin();
> +    if (in_multi_stmt_transaction())
> +      trans_register_ha(this, TRUE, binlog_hton);
> +    trans_register_ha(this, FALSE, binlog_hton);
> +    /*
> +      Mark statement transaction as read/write. We never start
> +      a binary log transaction and keep it read-only,
> +      therefore it's best to mark the transaction read/write just
> +      at the same time we start it.
> +      Not necessary to mark the normal transaction read/write
> +      since the statement-level flag will be propagated automatically
> +      inside ha_commit_trans.
> +    */
> +    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
> +  }
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::binlog_set_stmt_begin() {
> +  binlog_cache_mngr *cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +
> +  /*
> +    The call to binlog_trans_log_savepos() might create the cache_mngr
> +    structure, if it didn't exist before, so we save the position
> +    into an auto variable and then write it into the transaction
> +    data for the binary log (i.e., cache_mngr).
> +  */
> +  my_off_t pos= 0;
> +  binlog_trans_log_savepos(this, &pos);
> +  cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +  cache_mngr->trx_cache.set_prev_position(pos);
> +}
> +
> +
> +/**
> +  This function writes a table map to the binary log. 
> +  Note that in order to keep the signature uniform with related methods,
> +  we use a redundant parameter to indicate whether a transactional table
> +  was changed or not.
> + 
> +  @param table             a pointer to the table.
> +  @param is_transactional  @c true indicates a transactional table,
> +                           otherwise @c false a non-transactional.
> +  @return
> +    nonzero if an error pops up when writing the table map event.
> +*/
> +int THD::binlog_write_table_map(TABLE *table, bool is_transactional)
> +{
> +  int error;
> +  DBUG_ENTER("THD::binlog_write_table_map");
> +  DBUG_PRINT("enter", ("table: 0x%lx  (%s: #%lu)",
> +                       (long) table, table->s->table_name.str,
> +                       table->s->table_map_id));
> +
> +  /* Pre-conditions */
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
> +
> +  Table_map_log_event
> +    the_event(this, table, table->s->table_map_id, is_transactional);
> +
> +  if (binlog_table_maps == 0)
> +    binlog_start_trans_and_stmt();
> +
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +
> +  IO_CACHE *file=
> +    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
> +  if ((error= the_event.write(file)))
> +    DBUG_RETURN(error);
> +
> +  binlog_table_maps++;
> +  table->s->table_map_version= mysql_bin_log.table_map_version();
> +  DBUG_RETURN(0);
> +}
> +
> +/**
> +  This function retrieves a pending row event from a cache which is
> +  specified through the parameter @c is_transactional. Respectively, when it
> +  is @c true, the pending event is returned from the transactional cache.
> +  Otherwise from the non-transactional cache.
> +
> +  @param is_transactional  @c true indicates a transactional cache,
> +                           otherwise @c false a non-transactional.
> +  @return
> +    The row event if any. 
> +*/
> +Rows_log_event*
> +THD::binlog_get_pending_rows_event(bool is_transactional) const
> +{
> +  Rows_log_event* rows= NULL;
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +
> +  /*
> +    This is less than ideal, but here's the story: If there is no cache_mngr,
> +    prepare_pending_rows_event() has never been called (since the cache_mngr
> +    is set up there). In that case, we just return NULL.
> +   */
> +  if (cache_mngr)
> +  {
> +    binlog_cache_data *cache_data=
> +      cache_mngr->get_binlog_cache_data(use_trans_cache(this,
> is_transactional));
> +
> +    rows= cache_data->pending();
> +  }
> +  return (rows);
> +}
> +
> +/**
> +  This function stores a pending row event into a cache which is specified
> +  through the parameter @c is_transactional. Respectively, when it is @c
> +  true, the pending event is stored into the transactional cache. Otherwise
> +  into the non-transactional cache.
> +
> +  @param evt               a pointer to the row event.
> +  @param is_transactional  @c true indicates a transactional cache,
> +                           otherwise @c false a non-transactional.
> +*/
> +void
> +THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional)
> +{
> +  if (thd_get_ha_data(this, binlog_hton) == NULL)
> +    binlog_setup_trx_data();
> +
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +
> +  DBUG_ASSERT(cache_mngr);
> +
> +  binlog_cache_data *cache_data=
> +    cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
> +
> +  cache_data->set_pending(ev);
> +}
> +
> +/**
> +  Decide on logging format to use for the statement and issue errors
> +  or warnings as needed.  The decision depends on the following
> +  parameters:
> +
> +  - The logging mode, i.e., the value of binlog_format.  Can be
> +    statement, mixed, or row.
> +
> +  - The type of statement.  There are three types of statements:
> +    "normal" safe statements; unsafe statements; and row injections.
> +    An unsafe statement is one that, if logged in statement format,
> +    might produce different results when replayed on the slave (e.g.,
> +    INSERT DELAYED).  A row injection is either a BINLOG statement, or
> +    a row event executed by the slave's SQL thread.
> +
> +  - The capabilities of tables modified by the statement.  The
> +    *capabilities vector* for a table is a set of flags associated
> +    with the table.  Currently, it only includes two flags: *row
> +    capability flag* and *statement capability flag*.
> +
> +    The row capability flag is set if and only if the engine can
> +    handle row-based logging. The statement capability flag is set if
> +    and only if the table can handle statement-based logging.
> +
> +  Decision table for logging format
> +  ---------------------------------
> +
> +  The following table summarizes how the format and generated
> +  warning/error depends on the tables' capabilities, the statement
> +  type, and the current binlog_format.
> +
> +     Row capable        N NNNNNNNNN YYYYYYYYY YYYYYYYYY
> +     Statement capable  N YYYYYYYYY NNNNNNNNN YYYYYYYYY
> +
> +     Statement type     * SSSUUUIII SSSUUUIII SSSUUUIII
> +
> +     binlog_format      * SMRSMRSMR SMRSMRSMR SMRSMRSMR
> +
> +     Logged format      - SS-S----- -RR-RR-RR SRRSRR-RR
> +     Warning/Error      1 --2732444 5--5--6-- ---7--6--
> +
> +  Legend
> +  ------
> +
> +  Row capable:    N - Some table not row-capable, Y - All tables row-capable
> +  Stmt capable:   N - Some table not stmt-capable, Y - All tables stmt-capable
> +  Statement type: (S)afe, (U)nsafe, or Row (I)njection
> +  binlog_format:  (S)TATEMENT, (M)IXED, or (R)OW
> +  Logged format:  (S)tatement or (R)ow
> +  Warning/Error:  Warnings and error messages are as follows:
> +
> +  1. Error: Cannot execute statement: binlogging impossible since both
> +     row-incapable engines and statement-incapable engines are
> +     involved.
> +
> +  2. Error: Cannot execute statement: binlogging impossible since
> +     BINLOG_FORMAT = ROW and at least one table uses a storage engine
> +     limited to statement-logging.
> +
> +  3. Error: Cannot execute statement: binlogging of unsafe statement
> +     is impossible when storage engine is limited to statement-logging
> +     and BINLOG_FORMAT = MIXED.
> +
> +  4. Error: Cannot execute row injection: binlogging impossible since
> +     at least one table uses a storage engine limited to
> +     statement-logging.
> +
> +  5. Error: Cannot execute statement: binlogging impossible since
> +     BINLOG_FORMAT = STATEMENT and at least one table uses a storage
> +     engine limited to row-logging.
> +
> +  6. Error: Cannot execute row injection: binlogging impossible since
> +     BINLOG_FORMAT = STATEMENT.
> +
> +  7. Warning: Unsafe statement binlogged in statement format since
> +     BINLOG_FORMAT = STATEMENT.
> +
> +  In addition, we can produce the following error (not depending on
> +  the variables of the decision diagram):
> +
> +  8. Error: Cannot execute statement: binlogging impossible since more
> +     than one engine is involved and at least one engine is
> +     self-logging.
> +
> +  For each error case above, the statement is prevented from being
> +  logged, we report an error, and roll back the statement.  For
> +  warnings, we set the thd->binlog_flags variable: the warning will be
> +  printed only if the statement is successfully logged.
> +
> +  @see THD::binlog_query
> +
> +  @param[in] thd    Client thread
> +  @param[in] tables Tables involved in the query
> +
> +  @retval 0 No error; statement can be logged.
> +  @retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
> +*/
> +
> +int THD::decide_logging_format(TABLE_LIST *tables)
> +{
> +  DBUG_ENTER("THD::decide_logging_format");
> +  DBUG_PRINT("info", ("query: %s", query()));
> +  DBUG_PRINT("info", ("variables.binlog_format: %u",
> +                      variables.binlog_format));
> +  DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
> +                      lex->get_stmt_unsafe_flags()));
> +
> +  /*
> +    We should not decide logging format if the binlog is closed or
> +    binlogging is off, or if the statement is filtered out from the
> +    binlog by filtering rules.
> +  */
> +  if (mysql_bin_log.is_open() && (variables.option_bits &
> OPTION_BIN_LOG) &&
> +      !(variables.binlog_format == BINLOG_FORMAT_STMT &&
> +        !binlog_filter->db_ok(db)))
> +  {
> +    /*
> +      Compute one bit field with the union of all the engine
> +      capabilities, and one with the intersection of all the engine
> +      capabilities.
> +    */
> +    handler::Table_flags flags_write_some_set= 0;
> +    handler::Table_flags flags_some_set= 0;
> +    handler::Table_flags flags_write_all_set=
> +      HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
> +
> +    /* 
> +       If different types of engines are about to be updated.
> +       For example: Innodb and Falcon; Innodb and MyIsam.
> +    */
> +    my_bool multi_write_engine= FALSE;
> +    /*
> +       If different types of engines are about to be accessed 
> +       and any of them is about to be updated. For example:
> +       Innodb and Falcon; Innodb and MyIsam.
> +    */
> +    my_bool multi_access_engine= FALSE;
> +    /*
> +       If non-transactional and transactional engines are about
> +       to be accessed and any of them is about to be updated.
> +       For example: Innodb and MyIsam.
> +    */
> +    my_bool trans_non_trans_access_engines= FALSE;
> +    /*
> +       If all engines that are about to be updated are
> +       transactional.
> +    */
> +    my_bool all_trans_write_engines= TRUE;
> +    TABLE* prev_write_table= NULL;
> +    TABLE* prev_access_table= NULL;
> +
> +#ifndef DBUG_OFF
> +    {
> +      static const char *prelocked_mode_name[] = {
> +        "NON_PRELOCKED",
> +        "PRELOCKED",
> +        "PRELOCKED_UNDER_LOCK_TABLES",
> +      };
> +      DBUG_PRINT("debug", ("prelocked_mode: %s",
> +                           prelocked_mode_name[locked_tables_mode]));
> +    }
> +#endif
> +
> +    /*
> +      Get the capabilities vector for all involved storage engines and
> +      mask out the flags for the binary log.
> +    */
> +    for (TABLE_LIST *table= tables; table; table= table->next_global)
> +    {
> +      if (table->placeholder())
> +        continue;
> +      if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
> +        lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
> +      handler::Table_flags const flags=
> table->table->file->ha_table_flags();
> +      DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
> +                          table->table_name, flags));
> +      if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
> +      {
> +        if (prev_write_table && prev_write_table->file->ht !=
> +            table->table->file->ht)
> +          multi_write_engine= TRUE;
> +        /*
> +          Every temporary table must be always written to the binary
> +          log in transaction boundaries and as such we artificially
> +          classify them as transactional.
> +
> +          Indirectly, this avoids classifying a temporary table created
> +          on a non-transactional engine as unsafe when it is modified
> +          after any transactional table:
> +
> +          BEGIN;
> +            INSERT INTO innodb_t VALUES (1);
> +            INSERT INTO myisam_t_temp VALUES (1);
> +          COMMIT;
> +
> +          BINARY LOG:
> +
> +          BEGIN;
> +            INSERT INTO innodb_t VALUES (1);
> +            INSERT INTO myisam_t_temp VALUES (1);
> +          COMMIT;
> +        */
> +        all_trans_write_engines= all_trans_write_engines &&
> +                                 (table->table->file->has_transactions()
> ||
> +                                  table->table->s->tmp_table);
> +        prev_write_table= table->table;
> +        flags_write_all_set &= flags;
> +        flags_write_some_set |= flags;
> +      }
> +      flags_some_set |= flags;
> +      /*
> +        The mixture of non-transactional and transactional tables must
> +        identified and classified as unsafe. However, a temporary table
> +        must be always handled as a transactional table. Based on that,
> +        we have the following statements classified as mixed and by
> +        consequence as unsafe:
> +
> +        1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +
> +        2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> +
> +        3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> +
> +        4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> +
> +        5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> +
> +        The following statements are not considered mixed and as such
> +        are safe:
> +
> +        1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
> +
> +        2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
> +      */
> +      if (!trans_non_trans_access_engines && prev_access_table &&
> +          (lex->sql_command != SQLCOM_CREATE_TABLE ||
> +          (lex->sql_command == SQLCOM_CREATE_TABLE &&
> +          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
> +      {
> +        my_bool prev_trans;
> +        my_bool act_trans;
> +        if (prev_access_table->s->tmp_table ||
> table->table->s->tmp_table)
> +        {
> +          prev_trans= prev_access_table->s->tmp_table ? TRUE :
> +                     prev_access_table->file->has_transactions();
> +          act_trans= table->table->s->tmp_table ? TRUE :
> +                    table->table->file->has_transactions();
> +        }
> +        else
> +        {
> +          prev_trans= prev_access_table->file->has_transactions();
> +          act_trans= table->table->file->has_transactions();
> +        }
> +        trans_non_trans_access_engines= (prev_trans != act_trans);
> +        multi_access_engine= TRUE;
> +      }
> +      thread_temporary_used |= table->table->s->tmp_table;
> +      prev_access_table= table->table;
> +    }
> +
> +    DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
> +    DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
> +    DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
> +    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
> +    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
> +    DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
> +                        trans_non_trans_access_engines));
> +
> +    int error= 0;
> +    int unsafe_flags;
> +
> +    /*
> +      Set the statement as unsafe if:
> +
> +      . it is a mixed statement, i.e. access transactional and non-transactional
> +      tables, and update any of them;
> +
> +      or:
> +
> +      . an early statement updated a transactional table;
> +      . and, the current statement updates a non-transactional table.
> +
> +      Any mixed statement is classified as unsafe to ensure that mixed mode is
> +      completely safe. Consider the following example to understand why we
> +      decided to do this:
> +
> +      Note that mixed statements such as
> +
> +      1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +
> +      2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> +
> +      3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> +
> +      4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> +
> +      5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> +
> +      are classified as unsafe to ensure that in mixed mode the execution is
> +      completely safe and equivalent to the row mode. Consider the following
> +      statements and sessions (connections) to understand the reason:
> +
> +      con1: INSERT INTO innodb_t VALUES (1);
> +      con1: INSERT INTO innodb_t VALUES (100);
> +
> +      con1: BEGIN
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
> +
> +      The point is that the concurrent statements may be written into the binary
> log
> +      in a way different from the execution. For example,
> +
> +      BINARY LOG:
> +
> +      con2: BEGIN;
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con2: COMMIT;
> +      con1: BEGIN
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
> +
> +      ....
> +
> +      or
> +
> +      BINARY LOG:
> +
> +      con1: BEGIN
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
> +      con2: BEGIN;
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con2: COMMIT;
> +
> +      Clearly, this may become a problem in STMT mode and setting the statement
> +      as unsafe will make rows to be written into the binary log in MIXED mode
> +      and as such the problem will not stand.
> +
> +      In STMT mode, although such statement is classified as unsafe, i.e.
> +
> +      INSERT INTO myisam_t SELECT * FROM innodb_t;
> +
> +      there is no enough information to avoid writing it outside the boundaries
> +      of a transaction. This is not a problem if we are considering snapshot
> +      isolation level but if we have pure repeatable read or serializable the
> +      lock history on the slave will be different from the master.
> +    */
> +    if (trans_non_trans_access_engines)
> +      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
> +    else if (trans_has_updated_trans_table(this) &&
> !all_trans_write_engines)
> +      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
> +
> +    /*
> +      If more than one engine is involved in the statement and at
> +      least one is doing it's own logging (is *self-logging*), the
> +      statement cannot be logged atomically, so we generate an error
> +      rather than allowing the binlog to become corrupt.
> +    */
> +    if (multi_write_engine &&
> +        (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
> +      my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
> +               MYF(0));
> +    else if (multi_access_engine && flags_some_set &
> HA_HAS_OWN_BINLOGGING)
> +     
> lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
> +
> +    /* both statement-only and row-only engines involved */
> +    if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE))
> == 0)
> +    {
> +      /*
> +        1. Error: Binary logging impossible since both row-incapable
> +           engines and statement-incapable engines are involved
> +      */
> +      my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
> +    }
> +    /* statement-only engines involved */
> +    else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
> +    {
> +      if (lex->is_stmt_row_injection())
> +      {
> +        /*
> +          4. Error: Cannot execute row injection since table uses
> +             storage engine limited to statement-logging
> +        */
> +        my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
> +      }
> +      else if (variables.binlog_format == BINLOG_FORMAT_ROW)
> +      {
> +        /*
> +          2. Error: Cannot modify table that uses a storage engine
> +             limited to statement-logging when BINLOG_FORMAT = ROW
> +        */
> +        my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
> +      }
> +      else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> +      {
> +        /*
> +          3. Error: Cannot execute statement: binlogging of unsafe
> +             statement is impossible when storage engine is limited to
> +             statement-logging and BINLOG_FORMAT = MIXED.
> +        */
> +        for (int unsafe_type= 0;
> +             unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> +             unsafe_type++)
> +          if (unsafe_flags & (1 << unsafe_type))
> +            my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
> +                     ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +      }
> +      /* log in statement format! */
> +    }
> +    /* no statement-only engines */
> +    else
> +    {
> +      /* binlog_format = STATEMENT */
> +      if (variables.binlog_format == BINLOG_FORMAT_STMT)
> +      {
> +        if (lex->is_stmt_row_injection())
> +        {
> +          /*
> +            6. Error: Cannot execute row injection since
> +               BINLOG_FORMAT = STATEMENT
> +          */
> +          my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
> +        }
> +        else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> +        {
> +          /*
> +            5. Error: Cannot modify table that uses a storage engine
> +               limited to row-logging when binlog_format = STATEMENT
> +          */
> +          my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
> +        }
> +        else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> +        {
> +          /*
> +            7. Warning: Unsafe statement logged as statement due to
> +               binlog_format = STATEMENT
> +          */
> +          binlog_unsafe_warning_flags|= unsafe_flags;
> +          DBUG_PRINT("info", ("Scheduling warning to be issued by "
> +                              "binlog_query: '%s'",
> +                              ER(ER_BINLOG_UNSAFE_STATEMENT)));
> +          DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
> +                              binlog_unsafe_warning_flags));
> +        }
> +        /* log in statement format! */
> +      }
> +      /* No statement-only engines and binlog_format != STATEMENT.
> +         I.e., nothing prevents us from row logging if needed. */
> +      else
> +      {
> +        if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
> +            || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> +        {
> +          /* log in row format! */
> +          set_current_stmt_binlog_format_row_if_mixed();
> +        }
> +      }
> +    }
> +
> +    if (error) {
> +      DBUG_PRINT("info", ("decision: no logging since an error was generated"));
> +      DBUG_RETURN(-1);
> +    }
> +    DBUG_PRINT("info", ("decision: logging in %s format",
> +                        is_current_stmt_binlog_format_row() ?
> +                        "ROW" : "STATEMENT"));
> +  }
> +#ifndef DBUG_OFF
> +  else
> +    DBUG_PRINT("info", ("decision: no logging since "
> +                        "mysql_bin_log.is_open() = %d "
> +                        "and (options & OPTION_BIN_LOG) = 0x%llx "
> +                        "and binlog_format = %u "
> +                        "and binlog_filter->db_ok(db) = %d",
> +                        mysql_bin_log.is_open(),
> +                        (variables.option_bits & OPTION_BIN_LOG),
> +                        variables.binlog_format,
> +                        binlog_filter->db_ok(db)));
> +#endif
> +
> +  DBUG_RETURN(0);
> +}
> +
> +
> +/*
> +  Implementation of interface to write rows to the binary log through the
> +  thread.  The thread is responsible for writing the rows it has
> +  inserted/updated/deleted.
> +*/
> +
> +#ifndef MYSQL_CLIENT
> +
> +/*
> +  Template member function for ensuring that there is an rows log
> +  event of the apropriate type before proceeding.
> +
> +  PRE CONDITION:
> +    - Events of type 'RowEventT' have the type code 'type_code'.
> +    
> +  POST CONDITION:
> +    If a non-NULL pointer is returned, the pending event for thread 'thd' will
> +    be an event of type 'RowEventT' (which have the type code 'type_code')
> +    will either empty or have enough space to hold 'needed' bytes.  In
> +    addition, the columns bitmap will be correct for the row, meaning that
> +    the pending event will be flushed if the columns in the event differ from
> +    the columns suppled to the function.
> +
> +  RETURNS
> +    If no error, a non-NULL pending event (either one which already existed or
> +    the newly created one).
> +    If error, NULL.
> + */
> +
> +template <class RowsEventT> Rows_log_event* 
> +THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
> +                                       MY_BITMAP const* cols,
> +                                       size_t colcnt,
> +                                       size_t needed,
> +                                       bool is_transactional,
> +				       RowsEventT *hint __attribute__((unused)))
> +{
> +  DBUG_ENTER("binlog_prepare_pending_rows_event");
> +  /* Pre-conditions */
> +  DBUG_ASSERT(table->s->table_map_id != ~0UL);
> +
> +  /* Fetch the type code for the RowsEventT template parameter */
> +  int const type_code= RowsEventT::TYPE_CODE;
> +
> +  /*
> +    There is no good place to set up the transactional data, so we
> +    have to do it here.
> +  */
> +  if (binlog_setup_trx_data())
> +    DBUG_RETURN(NULL);
> +
> +  Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
> +
> +  if (unlikely(pending && !pending->is_valid()))
> +    DBUG_RETURN(NULL);
> +
> +  /*
> +    Check if the current event is non-NULL and a write-rows
> +    event. Also check if the table provided is mapped: if it is not,
> +    then we have switched to writing to a new table.
> +    If there is no pending event, we need to create one. If there is a pending
> +    event, but it's not about the same table id, or not of the same type
> +    (between Write, Update and Delete), or not the same affected columns, or
> +    going to be too big, flush this event to disk and create a new pending
> +    event.
> +  */
> +  if (!pending ||
> +      pending->server_id != serv_id || 
> +      pending->get_table_id() != table->s->table_map_id ||
> +      pending->get_type_code() != type_code || 
> +      pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 
> +      pending->get_width() != colcnt ||
> +      !bitmap_cmp(pending->get_cols(), cols)) 
> +  {
> +    /* Create a new RowsEventT... */
> +    Rows_log_event* const
> +	ev= new RowsEventT(this, table, table->s->table_map_id, cols,
> +                           is_transactional);
> +    if (unlikely(!ev))
> +      DBUG_RETURN(NULL);
> +    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
> +    /*
> +      flush the pending event and replace it with the newly created
> +      event...
> +    */
> +    if (unlikely(
> +        mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
> +                                                       is_transactional)))
> +    {
> +      delete ev;
> +      DBUG_RETURN(NULL);
> +    }
> +
> +    DBUG_RETURN(ev);               /* This is the new pending event */
> +  }
> +  DBUG_RETURN(pending);        /* This is the current pending event */
> +}
> +
> +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
> +/*
> +  Instantiate the versions we need, we have -fno-implicit-template as
> +  compiling option.
> +*/
> +template Rows_log_event*
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t, size_t, bool,
> +				       Write_rows_log_event*);
> +
> +template Rows_log_event*
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t colcnt, size_t, bool,
> +				       Delete_rows_log_event *);
> +
> +template Rows_log_event* 
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t colcnt, size_t, bool,
> +				       Update_rows_log_event *);
> +#endif
> +
> +namespace {
> +  /**
> +     Class to handle temporary allocation of memory for row data.
> +
> +     The responsibilities of the class is to provide memory for
> +     packing one or two rows of packed data (depending on what
> +     constructor is called).
> +
> +     In order to make the allocation more efficient for "simple" rows,
> +     i.e., rows that do not contain any blobs, a pointer to the
> +     allocated memory is of memory is stored in the table structure
> +     for simple rows.  If memory for a table containing a blob field
> +     is requested, only memory for that is allocated, and subsequently
> +     released when the object is destroyed.
> +
> +   */
> +  class Row_data_memory {
> +  public:
> +    /**
> +      Build an object to keep track of a block-local piece of memory
> +      for storing a row of data.
> +
> +      @param table
> +      Table where the pre-allocated memory is stored.
> +
> +      @param length
> +      Length of data that is needed, if the record contain blobs.
> +     */
> +    Row_data_memory(TABLE *table, size_t const len1)
> +      : m_memory(0)
> +    {
> +#ifndef DBUG_OFF
> +      m_alloc_checked= FALSE;
> +#endif
> +      allocate_memory(table, len1);
> +      m_ptr[0]= has_memory() ? m_memory : 0;
> +      m_ptr[1]= 0;
> +    }
> +
> +    Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
> +      : m_memory(0)
> +    {
> +#ifndef DBUG_OFF
> +      m_alloc_checked= FALSE;
> +#endif
> +      allocate_memory(table, len1 + len2);
> +      m_ptr[0]= has_memory() ? m_memory        : 0;
> +      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
> +    }
> +
> +    ~Row_data_memory()
> +    {
> +      if (m_memory != 0 && m_release_memory_on_destruction)
> +        my_free((uchar*) m_memory, MYF(MY_WME));
> +    }
> +
> +    /**
> +       Is there memory allocated?
> +
> +       @retval true There is memory allocated
> +       @retval false Memory allocation failed
> +     */
> +    bool has_memory() const {
> +#ifndef DBUG_OFF
> +      m_alloc_checked= TRUE;
> +#endif
> +      return m_memory != 0;
> +    }
> +
> +    uchar *slot(uint s)
> +    {
> +      DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
> +      DBUG_ASSERT(m_ptr[s] != 0);
> +      DBUG_ASSERT(m_alloc_checked == TRUE);
> +      return m_ptr[s];
> +    }
> +
> +  private:
> +    void allocate_memory(TABLE *const table, size_t const total_length)
> +    {
> +      if (table->s->blob_fields == 0)
> +      {
> +        /*
> +          The maximum length of a packed record is less than this
> +          length. We use this value instead of the supplied length
> +          when allocating memory for records, since we don't know how
> +          the memory will be used in future allocations.
> +
> +          Since table->s->reclength is for unpacked records, we have
> +          to add two bytes for each field, which can potentially be
> +          added to hold the length of a packed field.
> +        */
> +        size_t const maxlen= table->s->reclength + 2 *
> table->s->fields;
> +
> +        /*
> +          Allocate memory for two records if memory hasn't been
> +          allocated. We allocate memory for two records so that it can
> +          be used when processing update rows as well.
> +        */
> +        if (table->write_row_record == 0)
> +          table->write_row_record=
> +            (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
> +        m_memory= table->write_row_record;
> +        m_release_memory_on_destruction= FALSE;
> +      }
> +      else
> +      {
> +        m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
> +        m_release_memory_on_destruction= TRUE;
> +      }
> +    }
> +
> +#ifndef DBUG_OFF
> +    mutable bool m_alloc_checked;
> +#endif
> +    bool m_release_memory_on_destruction;
> +    uchar *m_memory;
> +    uchar *m_ptr[2];
> +  };
> +}
> +
> +
> +int THD::binlog_write_row(TABLE* table, bool is_trans, 
> +                          MY_BITMAP const* cols, size_t colcnt, 
> +                          uchar const *record) 
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +
> +  /*
> +    Pack records into format for transfer. We are allocating more
> +    memory than needed, but that doesn't matter.
> +  */
> +  Row_data_memory memory(table, max_row_length(table, record));
> +  if (!memory.has_memory())
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  uchar *row_data= memory.slot(0);
> +
> +  size_t const len= pack_row(table, cols, row_data, record);
> +
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +                                      len, is_trans,
> +                                      static_cast<Write_rows_log_event*>(0));
> +
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  return ev->add_row_data(row_data, len);
> +}
> +
> +int THD::binlog_update_row(TABLE* table, bool is_trans,
> +                           MY_BITMAP const* cols, size_t colcnt,
> +                           const uchar *before_record,
> +                           const uchar *after_record)
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +
> +  size_t const before_maxlen = max_row_length(table, before_record);
> +  size_t const after_maxlen  = max_row_length(table, after_record);
> +
> +  Row_data_memory row_data(table, before_maxlen, after_maxlen);
> +  if (!row_data.has_memory())
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  uchar *before_row= row_data.slot(0);
> +  uchar *after_row= row_data.slot(1);
> +
> +  size_t const before_size= pack_row(table, cols, before_row,
> +                                        before_record);
> +  size_t const after_size= pack_row(table, cols, after_row,
> +                                       after_record);
> +
> +  /*
> +    Don't print debug messages when running valgrind since they can
> +    trigger false warnings.
> +   */
> +#ifndef HAVE_purify
> +  DBUG_DUMP("before_record", before_record, table->s->reclength);
> +  DBUG_DUMP("after_record",  after_record, table->s->reclength);
> +  DBUG_DUMP("before_row",    before_row, before_size);
> +  DBUG_DUMP("after_row",     after_row, after_size);
> +#endif
> +
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +				      before_size + after_size, is_trans,
> +				      static_cast<Update_rows_log_event*>(0));
> +
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  return
> +    ev->add_row_data(before_row, before_size) ||
> +    ev->add_row_data(after_row, after_size);
> +}
> +
> +int THD::binlog_delete_row(TABLE* table, bool is_trans, 
> +                           MY_BITMAP const* cols, size_t colcnt,
> +                           uchar const *record)
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +
> +  /* 
> +     Pack records into format for transfer. We are allocating more
> +     memory than needed, but that doesn't matter.
> +  */
> +  Row_data_memory memory(table, max_row_length(table, record));
> +  if (unlikely(!memory.has_memory()))
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  uchar *row_data= memory.slot(0);
> +
> +  size_t const len= pack_row(table, cols, row_data, record);
> +
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +				      len, is_trans,
> +				      static_cast<Delete_rows_log_event*>(0));
> +
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  return ev->add_row_data(row_data, len);
> +}
> +
> +
> +int THD::binlog_remove_pending_rows_event(bool clear_maps,
> +                                          bool is_transactional)
> +{
> +  DBUG_ENTER("THD::binlog_remove_pending_rows_event");
> +
> +  if (!mysql_bin_log.is_open())
> +    DBUG_RETURN(0);
> +
> +  mysql_bin_log.remove_pending_rows_event(this, is_transactional);
> +
> +  if (clear_maps)
> +    binlog_table_maps= 0;
> +
> +  DBUG_RETURN(0);
> +}
> +
> +int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
> +{
> +  DBUG_ENTER("THD::binlog_flush_pending_rows_event");
> +  /*
> +    We shall flush the pending event even if we are not in row-based
> +    mode: it might be the case that we left row-based mode before
> +    flushing anything (e.g., if we have explicitly locked tables).
> +   */
> +  if (!mysql_bin_log.is_open())
> +    DBUG_RETURN(0);
> +
> +  /*
> +    Mark the event as the last event of a statement if the stmt_end
> +    flag is set.
> +  */
> +  int error= 0;
> +  if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
> +  {
> +    if (stmt_end)
> +    {
> +      pending->set_flags(Rows_log_event::STMT_END_F);
> +      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> +      binlog_table_maps= 0;
> +    }
> +
> +    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
> +                                                          is_transactional);
> +  }
> +
> +  DBUG_RETURN(error);
> +}
> +
> +
> +#if !defined(DBUG_OFF) && !defined(_lint)
> +static const char *
> +show_query_type(THD::enum_binlog_query_type qtype)
> +{
> +  switch (qtype) {
> +  case THD::ROW_QUERY_TYPE:
> +    return "ROW";
> +  case THD::STMT_QUERY_TYPE:
> +    return "STMT";
> +  case THD::QUERY_TYPE_COUNT:
> +  default:
> +    DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
> +  }
> +  static char buf[64];
> +  sprintf(buf, "UNKNOWN#%d", qtype);
> +  return buf;
> +}
> +#endif
> +
> +
> +/**
> +  Auxiliary method used by @c binlog_query() to raise warnings.
> +
> +  The type of warning and the type of unsafeness is stored in
> +  THD::binlog_unsafe_warning_flags.
> +*/
> +void THD::issue_unsafe_warnings()
> +{
> +  DBUG_ENTER("issue_unsafe_warnings");
> +  /*
> +    Ensure that binlog_unsafe_warning_flags is big enough to hold all
> +    bits.  This is actually a constant expression.
> +  */
> +  DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
> +              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
> +
> +  uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
> +
> +  /*
> +    Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
> +    warnings that have been printed already.
> +  */
> +  unsafe_type_flags &= (LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS ^
> +                        (unsafe_type_flags >>
> LEX::BINLOG_STMT_UNSAFE_COUNT));
> +  /* If all warnings have been printed already, return. */
> +  if (unsafe_type_flags == 0)
> +    DBUG_VOID_RETURN;
> +
> +  DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
> +
> +  /*
> +    For each unsafe_type, check if the statement is unsafe in this way
> +    and issue a warning.
> +  */
> +  for (int unsafe_type=0;
> +       unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> +       unsafe_type++)
> +  {
> +    if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
> +    {
> +      push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
> +                          ER_BINLOG_UNSAFE_STATEMENT,
> +                          ER(ER_BINLOG_UNSAFE_STATEMENT),
> +                          ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +      if (global_system_variables.log_warnings)
> +      {
> +        char buf[MYSQL_ERRMSG_SIZE * 2];
> +        sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
> +                ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +        sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
> +      }
> +    }
> +  }
> +  /*
> +    Mark these unsafe types as already printed, to avoid printing
> +    warnings for them again.
> +  */
> +  binlog_unsafe_warning_flags|=
> +    unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +/**
> +  Log the current query.
> +
> +  The query will be logged in either row format or statement format
> +  depending on the value of @c current_stmt_binlog_format_row field and
> +  the value of the @c qtype parameter.
> +
> +  This function must be called:
> +
> +  - After the all calls to ha_*_row() functions have been issued.
> +
> +  - After any writes to system tables. Rationale: if system tables
> +    were written after a call to this function, and the master crashes
> +    after the call to this function and before writing the system
> +    tables, then the master and slave get out of sync.
> +
> +  - Before tables are unlocked and closed.
> +
> +  @see decide_logging_format
> +
> +  @retval 0 Success
> +
> +  @retval nonzero If there is a failure when writing the query (e.g.,
> +  write failure), then the error code is returned.
> +*/
> +int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
> +                      ulong query_len, bool is_trans, bool direct, 
> +                      bool suppress_use, int errcode)
> +{
> +  DBUG_ENTER("THD::binlog_query");
> +  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
> +                       show_query_type(qtype), query_arg));
> +  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
> +
> +  /*
> +    If we are not in prelocked mode, mysql_unlock_tables() will be
> +    called after this binlog_query(), so we have to flush the pending
> +    rows event with the STMT_END_F set to unlock all tables at the
> +    slave side as well.
> +
> +    If we are in prelocked mode, the flushing will be done inside the
> +    top-most close_thread_tables().
> +  */
> +  if (this->locked_tables_mode <= LTM_LOCK_TABLES)
> +    if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
> +      DBUG_RETURN(error);
> +
> +  /*
> +    Warnings for unsafe statements logged in statement format are
> +    printed here instead of in decide_logging_format().  This is
> +    because the warnings should be printed only if the statement is
> +    actually logged. When executing decide_logging_format(), we cannot
> +    know for sure if the statement will be logged.
> +  */
> +  if (sql_log_bin_toplevel)
> +    issue_unsafe_warnings();
> +
> +  switch (qtype) {
> +    /*
> +      ROW_QUERY_TYPE means that the statement may be logged either in
> +      row format or in statement format.  If
> +      current_stmt_binlog_format is row, it means that the
> +      statement has already been logged in row format and hence shall
> +      not be logged again.
> +    */
> +  case THD::ROW_QUERY_TYPE:
> +    DBUG_PRINT("debug",
> +               ("is_current_stmt_binlog_format_row: %d",
> +                is_current_stmt_binlog_format_row()));
> +    if (is_current_stmt_binlog_format_row())
> +      DBUG_RETURN(0);
> +    /* Fall through */
> +
> +    /*
> +      STMT_QUERY_TYPE means that the query must be logged in statement
> +      format; it cannot be logged in row format.  This is typically
> +      used by DDL statements.  It is an error to use this query type
> +      if current_stmt_binlog_format_row is row.
> +
> +      @todo Currently there are places that call this method with
> +      STMT_QUERY_TYPE and current_stmt_binlog_format is row.  Fix those
> +      places and add assert to ensure correct behavior. /Sven
> +    */
> +  case THD::STMT_QUERY_TYPE:
> +    /*
> +      The MYSQL_LOG::write() function will set the STMT_END_F flag and
> +      flush the pending rows event if necessary.
> +    */
> +    {
> +      Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
> +                            suppress_use, errcode);
> +      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> +      /*
> +        Binlog table maps will be irrelevant after a Query_log_event
> +        (they are just removed on the slave side) so after the query
> +        log event is written to the binary log, we pretend that no
> +        table maps were written.
> +       */
> +      int error= mysql_bin_log.write(&qinfo);
> +      binlog_table_maps= 0;
> +      DBUG_RETURN(error);
> +    }
> +    break;
> +
> +  case THD::QUERY_TYPE_COUNT:
> +  default:
> +    DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
> +  }
> +  DBUG_RETURN(0);
> +}
> +
> +#endif /* !defined(MYSQL_CLIENT) */
> +
> +#ifdef INNODB_COMPATIBILITY_HOOKS
> +/**
> +  Get the file name of the MySQL binlog.
> +  @return the name of the binlog file
> +*/
> +extern "C"
> +const char* mysql_bin_log_file_name(void)
> +{
> +  return mysql_bin_log.get_log_fname();
> +}
> +/**
> +  Get the current position of the MySQL binlog.
> +  @return byte offset from the beginning of the binlog
> +*/
> +extern "C"
> +ulonglong mysql_bin_log_file_pos(void)
> +{
> +  return (ulonglong) mysql_bin_log.get_log_file()->pos_in_file;
> +}
> +#endif /* INNODB_COMPATIBILITY_HOOKS */
> +
> +
> +struct st_mysql_storage_engine binlog_storage_engine=
> +{ MYSQL_HANDLERTON_INTERFACE_VERSION };
> +
> +mysql_declare_plugin(binlog)
> +{
> +  MYSQL_STORAGE_ENGINE_PLUGIN,
> +  &binlog_storage_engine,
> +  "binlog",
> +  "MySQL AB",
> +  "This is a pseudo storage engine to represent the binlog in a transaction",
> +  PLUGIN_LICENSE_GPL,
> +  binlog_init, /* Plugin Init */
> +  NULL, /* Plugin Deinit */
> +  0x0100 /* 1.0 */,
> +  NULL,                       /* status variables                */
> +  NULL,                       /* system variables                */
> +  NULL                        /* config options                  */
> +}
> +mysql_declare_plugin_end;
> 
> === added file 'sql/binlog.h'
> --- a/sql/binlog.h	1970-01-01 00:00:00 +0000
> +++ b/sql/binlog.h	2010-06-21 05:56:56 +0000
> @@ -0,0 +1,273 @@
> +#ifndef BINLOG_H_INCLUDED
> +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +#define BINLOG_H_INCLUDED
> +
> +#include "log_event.h"
> +#include "log.h"
> +
> +class Relay_log_info;
> +
> +class Format_description_log_event;
> +
> +class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
> +{
> + private:
> +  /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
> +  mysql_mutex_t LOCK_index;
> +  mysql_mutex_t LOCK_prep_xids;
> +  mysql_cond_t  COND_prep_xids;
> +  mysql_cond_t update_cond;
> +  ulonglong bytes_written;
> +  IO_CACHE index_file;
> +  char index_file_name[FN_REFLEN];
> +  /*
> +    purge_file is a temp file used in purge_logs so that the index file
> +    can be updated before deleting files from disk, yielding better crash
> +    recovery. It is created on demand the first time purge_logs is called
> +    and then reused for subsequent calls. It is cleaned up in cleanup().
> +  */
> +  IO_CACHE purge_index_file;
> +  char purge_index_file_name[FN_REFLEN];
> +  /*
> +     The max size before rotation (usable only if log_type == LOG_BIN: binary
> +     logs and relay logs).
> +     For a binlog, max_size should be max_binlog_size.
> +     For a relay log, it should be max_relay_log_size if this is non-zero,
> +     max_binlog_size otherwise.
> +     max_size is set in init(), and dynamically changed (when one does SET
> +     GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
> +     fix_max_relay_log_size).
> +  */
> +  ulong max_size;
> +  long prepared_xids; /* for tc log - number of xids to remember */
> +  // current file sequence number for load data infile binary logging
> +  uint file_id;
> +  uint open_count;				// For replication
> +  int readers_count;
> +  bool need_start_event;
> +  /*
> +    no_auto_events means we don't want any of these automatic events :
> +    Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't
> +    want a Rotate_log event to be written to the relay log. When we start a
> +    relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
> +    In 5.0 it's 0 for relay logs too!
> +  */
> +  bool no_auto_events;
> +
> +  ulonglong m_table_map_version;
> +
> +  /* pointer to the sync period variable, for binlog this will be
> +     sync_binlog_period, for relay log this will be
> +     sync_relay_log_period
> +  */
> +  uint *sync_period_ptr;
> +  uint sync_counter;
> +
> +  inline uint get_sync_period()
> +  {
> +    return *sync_period_ptr;
> +  }
> +
> +  int write_to_file(IO_CACHE *cache);
> +  /*
> +    This is used to start writing to a new log file. The difference from
> +    new_file() is locking. new_file_without_locking() does not acquire
> +    LOCK_log.
> +  */
> +  void new_file_without_locking();
> +  void new_file_impl(bool need_lock);
> +
> +public:
> +  MYSQL_LOG::generate_name;
> +  MYSQL_LOG::is_open;
> +//  int generate_new_name(char *new_name, const char *log_name);
> +
> +  /* This is relay log */
> +  bool is_relay_log;
> +  ulong signal_cnt;  // update of the counter is checked by heartbeat
> +  /*
> +    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
> +    necessary to have 2 distinct objects, because the I/O thread may be reading
> +    events in a different format from what the SQL thread is reading (consider
> +    the case of a master which has been upgraded from 5.0 to 5.1 without doing
> +    RESET MASTER, or from 4.x to 5.0).
> +  */
> +  Format_description_log_event *description_event_for_exec,
> +    *description_event_for_queue;
> +
> +  MYSQL_BIN_LOG(uint *sync_period);
> +  /*
> +    note that there's no destructor ~MYSQL_BIN_LOG() !
> +    The reason is that we don't want it to be automatically called
> +    on exit() - but only during the correct shutdown process
> +  */
> +
> +  int open(const char *opt_name);
> +  void close();
> +  int log_xid(THD *thd, my_xid xid);
> +  void unlog(ulong cookie, my_xid xid);
> +  int recover(IO_CACHE *log, Format_description_log_event *fdle);
> +#if !defined(MYSQL_CLIENT)
> +  bool is_table_mapped(TABLE *table) const
> +  {
> +    return table->s->table_map_version == table_map_version();
> +  }
> +
> +  ulonglong table_map_version() const { return m_table_map_version; }
> +  void update_table_map_version() { ++m_table_map_version; }
> +
> +  int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
> +                                       bool is_transactional);
> +  int remove_pending_rows_event(THD *thd, bool is_transactional);
> +
> +#endif /* !defined(MYSQL_CLIENT) */
> +  void reset_bytes_written()
> +  {
> +    bytes_written = 0;
> +  }
> +  void harvest_bytes_written(ulonglong* counter)
> +  {
> +#ifndef DBUG_OFF
> +    char buf1[22],buf2[22];
> +#endif
> +    DBUG_ENTER("harvest_bytes_written");
> +    (*counter)+=bytes_written;
> +    DBUG_PRINT("info",("counter: %s  bytes_written: %s", llstr(*counter,buf1),
> +		       llstr(bytes_written,buf2)));
> +    bytes_written=0;
> +    DBUG_VOID_RETURN;
> +  }
> +  void set_max_size(ulong max_size_arg);
> +  void signal_update();
> +  void wait_for_update_relay_log(THD* thd);
> +  int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
> +  void set_need_start_event() { need_start_event = 1; }
> +  void init(bool no_auto_events_arg, ulong max_size);
> +  void init_pthread_objects();
> +  void cleanup();
> +  bool open(const char *log_name,
> +            enum_log_type log_type,
> +            const char *new_name,
> +	    enum cache_type io_cache_type_arg,
> +	    bool no_auto_events_arg, ulong max_size,
> +            bool null_created,
> +            bool need_mutex);
> +  bool open_index_file(const char *index_file_name_arg,
> +                       const char *log_name, bool need_mutex);
> +  /* Use this to start writing a new log file */
> +  void new_file();
> +
> +  bool write(Log_event* event_info);
> +  bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
> +  bool write_incident(THD *thd, bool lock);
> +
> +  int  write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
> +  void set_write_error(THD *thd);
> +  bool check_write_error(THD *thd);
> +
> +  void start_union_events(THD *thd, query_id_t query_id_param);
> +  void stop_union_events(THD *thd);
> +  bool is_query_in_union(THD *thd, query_id_t query_id_param);
> +
> +  /*
> +    v stands for vector
> +    invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
> +  */
> +  bool appendv(const char* buf,uint len,...);
> +  bool append(Log_event* ev);
> +
> +  void make_log_name(char* buf, const char* log_ident);
> +  bool is_active(const char* log_file_name);
> +  int update_log_index(LOG_INFO* linfo, bool need_update_threads);
> +  void rotate_and_purge(uint flags);
> +  /**
> +     Flush binlog cache and synchronize to disk.
> +
> +     This function flushes events in binlog cache to binary log file,
> +     it will do synchronizing according to the setting of system
> +     variable 'sync_binlog'. If file is synchronized, @c synced will
> +     be set to 1, otherwise 0.
> +
> +     @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
> +
> +     @retval 0 Success
> +     @retval other Failure
> +  */
> +  bool flush_and_sync(bool *synced);
> +  int purge_logs(const char *to_log, bool included,
> +                 bool need_mutex, bool need_update_threads,
> +                 ulonglong *decrease_log_space);
> +  int purge_logs_before_date(time_t purge_time);
> +  int purge_first_log(Relay_log_info* rli, bool included);
> +  int set_purge_index_file_name(const char *base_file_name);
> +  int open_purge_index_file(bool destroy);
> +  bool is_inited_purge_index_file();
> +  int close_purge_index_file();
> +  int clean_purge_index_file();
> +  int sync_purge_index_file();
> +  int register_purge_index_entry(const char* entry);
> +  int register_create_index_entry(const char* entry);
> +  int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> +                        bool need_mutex);
> +  bool reset_logs(THD* thd);
> +  void close(uint exiting);
> +
> +  // iterating through the log index file
> +  int find_log_pos(LOG_INFO* linfo, const char* log_name,
> +		   bool need_mutex);
> +  int find_next_log(LOG_INFO* linfo, bool need_mutex);
> +  int get_current_log(LOG_INFO* linfo);
> +  int raw_get_current_log(LOG_INFO* linfo);
> +  uint next_file_id();
> +  inline char* get_index_fname() { return index_file_name;}
> +  inline char* get_log_fname() { return log_file_name; }
> +  inline char* get_name() { return name; }
> +  inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
> +  inline IO_CACHE* get_log_file() { return &log_file; }
> +
> +  inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
> +  inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
> +  inline IO_CACHE *get_index_file() { return &index_file;}
> +  inline uint32 get_open_count() { return open_count; }
> +};
> +
> +typedef struct st_load_file_info
> +{
> +  THD* thd;
> +  my_off_t last_pos_in_file;
> +  bool wrote_create_file, log_delayed;
> +} LOAD_FILE_INFO;
> +
> +extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
> +
> +bool trans_has_updated_trans_table(const THD* thd);
> +bool stmt_has_updated_trans_table(const THD *thd);
> +bool use_trans_cache(const THD* thd, bool is_transactional);
> +bool ending_trans(THD* thd, const bool all);
> +bool trans_has_updated_non_trans_table(const THD* thd);
> +bool stmt_has_updated_non_trans_table(const THD* thd);
> +
> +int log_loaded_block(IO_CACHE* file);
> +File open_binlog(IO_CACHE *log, const char *log_file_name,
> +                 const char **errmsg);
> +int check_binlog_magic(IO_CACHE* log, const char** errmsg);
> +bool purge_master_logs(THD* thd, const char* to_log);
> +bool purge_master_logs_before_date(THD* thd, time_t purge_time);
> +bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log);
> +
> +#endif /* BINLOG_H_INCLUDED */
> 
> === modified file 'sql/field.cc'
> --- a/sql/field.cc	2010-04-11 06:54:40 +0000
> +++ b/sql/field.cc	2010-06-21 06:01:50 +0000
> @@ -28,7 +28,7 @@
>  #include "sql_priv.h"
>  #include "sql_select.h"
>  #include "rpl_rli.h"                            // Pull in Relay_log_info
> -#include "slave.h"                              // Pull in rpl_master_has_bug()
> +#include "rpl_slave.h"                          // Pull in rpl_master_has_bug()
>  #include "strfunc.h"                            // find_type2, find_set
>  #include "sql_time.h"                    // str_to_datetime_with_warn,
>                                           // str_to_time_with_warn,
> 
> === modified file 'sql/ha_ndbcluster_binlog.cc'
> --- a/sql/ha_ndbcluster_binlog.cc	2010-05-17 12:10:26 +0000
> +++ b/sql/ha_ndbcluster_binlog.cc	2010-06-21 06:01:50 +0000
> @@ -23,7 +23,7 @@
>  #ifdef HAVE_NDB_BINLOG
>  #include "rpl_injector.h"
>  #include "rpl_filter.h"
> -#include "slave.h"
> +#include "rpl_slave.h"
>  #include "ha_ndbcluster_binlog.h"
>  #include "NdbDictionary.hpp"
>  #include "ndb_cluster_connection.hpp"
> 
> === modified file 'sql/ha_partition.cc'
> --- a/sql/ha_partition.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/ha_partition.cc	2010-06-21 06:01:50 +0000
> @@ -53,6 +53,7 @@
>  
>  #include "sql_priv.h"
>  #include "sql_parse.h"                          // append_file_to_dir
> +#include "binlog.h"                             // mysql_bin_log
>  
>  #ifdef WITH_PARTITION_STORAGE_ENGINE
>  #include "ha_partition.h"
> 
> === modified file 'sql/item_func.cc'
> --- a/sql/item_func.cc	2010-05-23 04:28:04 +0000
> +++ b/sql/item_func.cc	2010-06-21 06:01:50 +0000
> @@ -34,7 +34,7 @@
>  */
>  #include "sql_class.h"                          // set_var.h: THD
>  #include "set_var.h"
> -#include "slave.h"				// for wait_for_master_pos
> +#include "rpl_slave.h"				// for wait_for_master_pos
>  #include "sql_show.h"                           // append_identifier
>  #include "strfunc.h"                            // find_type
>  #include "sql_parse.h"                          // is_update_query
> 
> === modified file 'sql/log.cc'
> --- a/sql/log.cc	2010-04-30 04:13:44 +0000
> +++ b/sql/log.cc	2010-06-21 06:01:50 +0000
> @@ -28,15 +28,11 @@
>  #include "sql_priv.h"
>  #include "log.h"
>  #include "sql_base.h"                           // close_thread_tables
> -#include "sql_repl.h"
>  #include "sql_delete.h"                         // mysql_truncate
>  #include "sql_parse.h"                          // command_name
>  #include "sql_time.h"           // calc_time_from_sec, my_time_compare
>  #include "tztime.h"             // my_tz_OFFSET0, struct Time_zone
>  #include "sql_acl.h"            // SUPER_ACL
> -#include "log_event.h"          // Query_log_event
> -#include "rpl_filter.h"
> -#include "rpl_rli.h"
>  #include "sql_audit.h"
>  
>  #include <my_dir.h>
> @@ -47,29 +43,14 @@
>  #include "message.h"
>  #endif
>  
> -#include "sql_plugin.h"
> -#include "rpl_handler.h"
> -
>  /* max size of the log message */
>  #define MAX_LOG_BUFFER_SIZE 1024
>  #define MAX_TIME_SIZE 32
> -#define MY_OFF_T_UNDEF (~(my_off_t)0UL)
> -
> -#define FLAGSTR(V,F) ((V)&(F)?#F" ":"")
>  
>  LOGGER logger;
>  
> -MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
> -
>  static bool test_if_number(const char *str,
>  			   ulong *res, bool allow_wildcards);
> -static int binlog_init(void *p);
> -static int binlog_close_connection(handlerton *hton, THD *thd);
> -static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
> -static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv);
> -static int binlog_commit(handlerton *hton, THD *thd, bool all);
> -static int binlog_rollback(handlerton *hton, THD *thd, bool all);
> -static int binlog_prepare(handlerton *hton, THD *thd, bool all);
>  
>  /**
>     purge logs, master and slave sides both, related error code
> @@ -166,195 +147,6 @@ char *make_log_name(char *buff, const ch
>                     MYF(MY_UNPACK_FILENAME|MY_REPLACE_EXT));
>  }
>  
> -/*
> -  Helper class to hold a mutex for the duration of the
> -  block.
> -
> -  Eliminates the need for explicit unlocking of mutexes on, e.g.,
> -  error returns.  On passing a null pointer, the sentry will not do
> -  anything.
> - */
> -class Mutex_sentry
> -{
> -public:
> -  Mutex_sentry(mysql_mutex_t *mutex)
> -    : m_mutex(mutex)
> -  {
> -    if (m_mutex)
> -      mysql_mutex_lock(mutex);
> -  }
> -
> -  ~Mutex_sentry()
> -  {
> -    if (m_mutex)
> -      mysql_mutex_unlock(m_mutex);
> -#ifndef DBUG_OFF
> -    m_mutex= 0;
> -#endif
> -  }
> -
> -private:
> -  mysql_mutex_t *m_mutex;
> -
> -  // It's not allowed to copy this object in any way
> -  Mutex_sentry(Mutex_sentry const&);
> -  void operator=(Mutex_sentry const&);
> -};
> -
> -/*
> -  Helper classes to store non-transactional and transactional data
> -  before copying it to the binary log.
> -*/
> -class binlog_cache_data
> -{
> -public:
> -  binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
> -  incident(FALSE)
> -  {
> -    cache_log.end_of_file= max_binlog_cache_size;
> -  }
> -
> -  ~binlog_cache_data()
> -  {
> -    DBUG_ASSERT(empty());
> -    close_cached_file(&cache_log);
> -  }
> -
> -  bool empty() const
> -  {
> -    return pending() == NULL && my_b_tell(&cache_log) == 0;
> -  }
> -
> -  Rows_log_event *pending() const
> -  {
> -    return m_pending;
> -  }
> -
> -  void set_pending(Rows_log_event *const pending)
> -  {
> -    m_pending= pending;
> -  }
> -
> -  void set_incident(void)
> -  {
> -    incident= TRUE;
> -  }
> -  
> -  bool has_incident(void)
> -  {
> -    return(incident);
> -  }
> -
> -  void reset()
> -  {
> -    truncate(0);
> -    incident= FALSE;
> -    before_stmt_pos= MY_OFF_T_UNDEF;
> -    cache_log.end_of_file= max_binlog_cache_size;
> -    DBUG_ASSERT(empty());
> -  }
> -
> -  my_off_t get_byte_position() const
> -  {
> -    return my_b_tell(&cache_log);
> -  }
> -
> -  my_off_t get_prev_position()
> -  {
> -     return(before_stmt_pos);
> -  }
> -
> -  void set_prev_position(my_off_t pos)
> -  {
> -     before_stmt_pos= pos;
> -  }
> -  
> -  void restore_prev_position()
> -  {
> -    truncate(before_stmt_pos);
> -  }
> -
> -  void restore_savepoint(my_off_t pos)
> -  {
> -    truncate(pos);
> -    if (pos < before_stmt_pos)
> -      before_stmt_pos= MY_OFF_T_UNDEF;
> -  }
> -
> -  /*
> -    Cache to store data before copying it to the binary log.
> -  */
> -  IO_CACHE cache_log;
> -
> -private:
> -  /*
> -    Pending binrows event. This event is the event where the rows are currently
> -    written.
> -   */
> -  Rows_log_event *m_pending;
> -
> -  /*
> -    Binlog position before the start of the current statement.
> -  */
> -  my_off_t before_stmt_pos;
> - 
> -  /*
> -    This indicates that some events did not get into the cache and most likely
> -    it is corrupted.
> -  */ 
> -  bool incident;
> -
> -  /*
> -    It truncates the cache to a certain position. This includes deleting the
> -    pending event.
> -   */
> -  void truncate(my_off_t pos)
> -  {
> -    DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
> -    if (pending())
> -    {
> -      delete pending();
> -      set_pending(0);
> -    }
> -    reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
> -    cache_log.end_of_file= max_binlog_cache_size;
> -  }
> - 
> -  binlog_cache_data& operator=(const binlog_cache_data& info);
> -  binlog_cache_data(const binlog_cache_data& info);
> -};
> -
> -class binlog_cache_mngr {
> -public:
> -  binlog_cache_mngr() {}
> -
> -  void reset_cache(binlog_cache_data* cache_data)
> -  {
> -    cache_data->reset();
> -  }
> -
> -  binlog_cache_data* get_binlog_cache_data(bool is_transactional)
> -  {
> -    return (is_transactional ? &trx_cache : &stmt_cache);
> -  }
> -
> -  IO_CACHE* get_binlog_cache_log(bool is_transactional)
> -  {
> -    return (is_transactional ? &trx_cache.cache_log :
> &stmt_cache.cache_log);
> -  }
> -
> -  binlog_cache_data stmt_cache;
> -
> -  binlog_cache_data trx_cache;
> -
> -private:
> -
> -  binlog_cache_mngr& operator=(const binlog_cache_mngr& info);
> -  binlog_cache_mngr(const binlog_cache_mngr& info);
> -};
> -
> -handlerton *binlog_hton;
> -
>  bool LOGGER::is_log_table_enabled(uint log_table_type)
>  {
>    switch (log_table_type) {
> @@ -1392,3977 +1184,754 @@ int LOGGER::set_handlers(uint error_log_
>    return 0;
>  }
>  
> - /*
> -  Save position of binary log transaction cache.
> -
> -  SYNPOSIS
> -    binlog_trans_log_savepos()
> +#ifdef _WIN32
> +static int eventSource = 0;
>  
> -    thd      The thread to take the binlog data from
> -    pos      Pointer to variable where the position will be stored
> +static void setup_windows_event_source()
> +{
> +  HKEY    hRegKey= NULL;
> +  DWORD   dwError= 0;
> +  TCHAR   szPath[MAX_PATH];
> +  DWORD dwTypes;
>  
> -  DESCRIPTION
> +  if (eventSource)               // Ensure that we are only called once
> +    return;
> +  eventSource= 1;
>  
> -    Save the current position in the binary log transaction cache into
> -    the variable pointed to by 'pos'
> - */
> -
> -static void
> -binlog_trans_log_savepos(THD *thd, my_off_t *pos)
> -{
> -  DBUG_ENTER("binlog_trans_log_savepos");
> -  DBUG_ASSERT(pos != NULL);
> -  if (thd_get_ha_data(thd, binlog_hton) == NULL)
> -    thd->binlog_setup_trx_data();
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -  DBUG_ASSERT(mysql_bin_log.is_open());
> -  *pos= cache_mngr->trx_cache.get_byte_position();
> -  DBUG_PRINT("return", ("*pos: %lu", (ulong) *pos));
> -  DBUG_VOID_RETURN;
> -}
> +  // Create the event source registry key
> +  dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
> +                         
> "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL", 
> +                          &hRegKey);
>  
> +  /* Name of the PE module that contains the message resource */
> +  GetModuleFileName(NULL, szPath, MAX_PATH);
>  
> -/*
> -  Truncate the binary log transaction cache.
> +  /* Register EventMessageFile */
> +  dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
> +                          (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
>  
> -  SYNPOSIS
> -    binlog_trans_log_truncate()
> +  /* Register supported event types */
> +  dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
> +            EVENTLOG_INFORMATION_TYPE);
> +  dwError= RegSetValueEx(hRegKey, "TypesSupported", 0, REG_DWORD,
> +                         (LPBYTE) &dwTypes, sizeof dwTypes);
>  
> -    thd      The thread to take the binlog data from
> -    pos      Position to truncate to
> +  RegCloseKey(hRegKey);
> +}
>  
> -  DESCRIPTION
> +#endif /* _WIN32 */
>  
> -    Truncate the binary log to the given position. Will not change
> -    anything else.
> +/**
> +  Find a unique filename for 'filename.#'.
>  
> - */
> -static void
> -binlog_trans_log_truncate(THD *thd, my_off_t pos)
> -{
> -  DBUG_ENTER("binlog_trans_log_truncate");
> -  DBUG_PRINT("enter", ("pos: %lu", (ulong) pos));
> -
> -  DBUG_ASSERT(thd_get_ha_data(thd, binlog_hton) != NULL);
> -  /* Only true if binlog_trans_log_savepos() wasn't called before */
> -  DBUG_ASSERT(pos != ~(my_off_t) 0);
> -
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -  cache_mngr->trx_cache.restore_savepoint(pos);
> -  DBUG_VOID_RETURN;
> -}
> +  Set '#' to the number next to the maximum found in the most
> +  recent log file extension.
>  
> +  This function will return nonzero if: (i) the generated name
> +  exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
> +  or (iii) some other error happened while examining the filesystem.
>  
> -/*
> -  this function is mostly a placeholder.
> -  conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
> -  should be moved here.
> +  @return
> +    nonzero if not possible to get unique filename.
>  */
>  
> -int binlog_init(void *p)
> -{
> -  binlog_hton= (handlerton *)p;
> -  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
> -  binlog_hton->db_type=DB_TYPE_BINLOG;
> -  binlog_hton->savepoint_offset= sizeof(my_off_t);
> -  binlog_hton->close_connection= binlog_close_connection;
> -  binlog_hton->savepoint_set= binlog_savepoint_set;
> -  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
> -  binlog_hton->commit= binlog_commit;
> -  binlog_hton->rollback= binlog_rollback;
> -  binlog_hton->prepare= binlog_prepare;
> -  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
> -  return 0;
> -}
> -
> -static int binlog_close_connection(handlerton *hton, THD *thd)
> +static int find_uniq_filename(char *name)
>  {
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -  DBUG_ASSERT(cache_mngr->trx_cache.empty() &&
> cache_mngr->stmt_cache.empty());
> -  thd_set_ha_data(thd, binlog_hton, NULL);
> -  cache_mngr->~binlog_cache_mngr();
> -  my_free((uchar*)cache_mngr, MYF(0));
> -  return 0;
> -}
> -
> -/**
> -  This function flushes a transactional cache upon commit/rollback.
> -
> -  @param thd        The thread whose transaction should be flushed
> -  @param cache_mngr Pointer to the cache data to be flushed
> -  @param end_ev     The end event either commit/rollback.
> +  uint                  i;
> +  char                  buff[FN_REFLEN], ext_buf[FN_REFLEN];
> +  struct st_my_dir     *dir_info;
> +  reg1 struct fileinfo *file_info;
> +  ulong                 max_found= 0, next= 0, number= 0;
> +  size_t		buf_length, length;
> +  char			*start, *end;
> +  int                   error= 0;
> +  DBUG_ENTER("find_uniq_filename");
>  
> -  @return
> -    nonzero if an error pops up when flushing the transactional cache.
> -*/
> -static int
> -binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
> -                       Log_event *end_ev)
> -{
> -  DBUG_ENTER("binlog_flush_trx_cache");
> -  int error=0;
> -  IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log;
> +  length= dirname_part(buff, name, &buf_length);
> +  start=  name + length;
> +  end=    strend(start);
>  
> -  /*
> -    This function handles transactional changes and as such
> -    this flag equals to true.
> -  */
> -  bool const is_transactional= TRUE;
> +  *end='.';
> +  length= (size_t) (end - start + 1);
>  
> -  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
> +  if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))
> +  {						// This shouldn't happen
> +    strmov(end,".1");				// use name+1
>      DBUG_RETURN(1);
> -  /*
> -    Doing a commit or a rollback including non-transactional tables,
> -    i.e., ending a transaction where we might write the transaction
> -    cache to the binary log.
> -
> -    We can always end the statement when ending a transaction since
> -    transactions are not allowed inside stored functions. If they
> -    were, we would have to ensure that we're not ending a statement
> -    inside a stored function.
> -  */
> -  error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev,
> -                             cache_mngr->trx_cache.has_incident());
> -  cache_mngr->reset_cache(&cache_mngr->trx_cache);
> -
> -  /*
> -    We need to step the table map version after writing the
> -    transaction cache to disk.
> -  */
> -  mysql_bin_log.update_table_map_version();
> -  statistic_increment(binlog_cache_use, &LOCK_status);
> -  if (cache_log->disk_writes != 0)
> +  }
> +  file_info= dir_info->dir_entry;
> +  for (i= dir_info->number_off_files ; i-- ; file_info++)
>    {
> -    statistic_increment(binlog_cache_disk_use, &LOCK_status);
> -    cache_log->disk_writes= 0;
> +    if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
> +	test_if_number(file_info->name+length, &number,0))
> +    {
> +      set_if_bigger(max_found,(ulong) number);
> +    }
>    }
> +  my_dirend(dir_info);
>  
> -  DBUG_ASSERT(cache_mngr->trx_cache.empty());
> -  DBUG_RETURN(error);
> -}
> -
> -/**
> -  This function truncates the transactional cache upon committing or rolling
> -  back either a transaction or a statement.
> -
> -  @param thd        The thread whose transaction should be flushed
> -  @param cache_mngr Pointer to the cache data to be flushed
> -  @param all        @c true means truncate the transaction, otherwise the
> -                    statement must be truncated.
> -
> -  @return
> -    nonzero if an error pops up when truncating the transactional cache.
> -*/
> -static int
> -binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
> -{
> -  DBUG_ENTER("binlog_truncate_trx_cache");
> -  int error=0;
> -  /*
> -    This function handles transactional changes and as such this flag
> -    equals to true.
> -  */
> -  bool const is_transactional= TRUE;
> -
> -  DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s",
> -                      FLAGSTR(thd->variables.option_bits,
> OPTION_NOT_AUTOCOMMIT),
> -                      FLAGSTR(thd->variables.option_bits, OPTION_BEGIN),
> -                      all ? "all" : "stmt"));
> -  /*
> -    If rolling back an entire transaction or a single statement not
> -    inside a transaction, we reset the transaction cache.
> -  */
> -  thd->binlog_remove_pending_rows_event(TRUE, is_transactional);
> -  if (ending_trans(thd, all))
> +  /* check if reached the maximum possible extension number */
> +  if ((max_found == MAX_LOG_UNIQUE_FN_EXT))
>    {
> -    if (cache_mngr->trx_cache.has_incident())
> -      error= mysql_bin_log.write_incident(thd, TRUE);
> +    sql_print_error("Log filename extension number exhausted: %06lu. \
> +Please fix this by archiving old logs and \
> +updating the index files.", max_found);
> +    error= 1;
> +    goto end;
> +  }
>  
> -    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> +  next= max_found + 1;
> +  sprintf(ext_buf, "%06lu", next);
> +  *end++='.';
>  
> -    thd->clear_binlog_table_maps();
> +  /* 
> +    Check if the generated extension size + the file name exceeds the
> +    buffer size used. If one did not check this, then the filename might be
> +    truncated, resulting in error.
> +   */
> +  if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
> +  {
> +    sql_print_error("Log filename too large: %s%s (%zu). \
> +Please fix this by archiving old logs and updating the \
> +index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
> +    error= 1;
> +    goto end;
>    }
> -  /*
> -    If rolling back a statement in a transaction, we truncate the
> -    transaction cache to remove the statement.
> -  */
> -  else
> -    cache_mngr->trx_cache.restore_prev_position();
>  
> -  /*
> -    We need to step the table map version on a rollback to ensure that a new
> -    table map event is generated instead of the one that was written to the
> -    thrown-away transaction cache.
> -  */
> -  mysql_bin_log.update_table_map_version();
> +  sprintf(end, "%06lu", next);
> +
> +  /* print warning if reaching the end of available extensions. */
> +  if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
> +    sql_print_warning("Next log extension: %lu. \
> +Remaining log filename extensions: %lu. \
> +Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next));
>  
> -  DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL);
> +end:
>    DBUG_RETURN(error);
>  }
>  
> -static int binlog_prepare(handlerton *hton, THD *thd, bool all)
> +
> +void MYSQL_LOG::init(enum_log_type log_type_arg,
> +                     enum cache_type io_cache_type_arg)
>  {
> -  /*
> -    do nothing.
> -    just pretend we can do 2pc, so that MySQL won't
> -    switch to 1pc.
> -    real work will be done in MYSQL_BIN_LOG::log_xid()
> -  */
> -  return 0;
> +  DBUG_ENTER("MYSQL_LOG::init");
> +  log_type= log_type_arg;
> +  io_cache_type= io_cache_type_arg;
> +  DBUG_PRINT("info",("log_type: %d", log_type));
> +  DBUG_VOID_RETURN;
>  }
>  
> -/**
> -  This function flushes the non-transactional to the binary log upon
> -  committing or rolling back a statement.
> -
> -  @param thd        The thread whose transaction should be flushed
> -  @param cache_mngr Pointer to the cache data to be flushed
>  
> -  @return
> -    nonzero if an error pops up when flushing the non-transactional cache.
> -*/
> -static int
> -binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
> +bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
> +                                           const char *new_name,
> +                                           enum_log_type log_type_arg,
> +                                           enum cache_type io_cache_type_arg)
>  {
> -  int error= 0;
> -  DBUG_ENTER("binlog_flush_stmt_cache");
> -  /*
> -    If we are flushing the statement cache, it means that the changes get
> -    through otherwise the cache is empty and this routine should not be called.
> -  */
> -  DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE);
> -  /*
> -    This function handles non-transactional changes and as such this flag equals
> -    to false.
> -  */
> -  bool const is_transactional= FALSE;
> -  IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
> -
> -  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
> -    DBUG_RETURN(1);
> +  init(log_type_arg, io_cache_type_arg);
>  
> -  Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
> -  if ((error= mysql_bin_log.write(thd, cache_log, &qev,
> -                                  cache_mngr->stmt_cache.has_incident())))
> -    DBUG_RETURN(error);
> -  cache_mngr->reset_cache(&cache_mngr->stmt_cache);
> +  if (new_name && !strmov(log_file_name, new_name))
> +    return TRUE;
> +  else if (!new_name && generate_new_name(log_file_name, log_name))
> +    return TRUE;
>  
> -  /*
> -    We need to step the table map version after writing the
> -    transaction cache to disk.
> -  */
> -  mysql_bin_log.update_table_map_version();
> -  statistic_increment(binlog_cache_use, &LOCK_status);
> -  if (cache_log->disk_writes != 0)
> -  {
> -    statistic_increment(binlog_cache_disk_use, &LOCK_status);
> -    cache_log->disk_writes= 0;
> -  }
> -  DBUG_RETURN(error);
> +  return FALSE;
>  }
>  
> -/**
> -  This function is called once after each statement.
>  
> -  It has the responsibility to flush the caches to the binary log on commits.
> +/*
> +  Open a (new) log file.
> +
> +  SYNOPSIS
> +    open()
> +
> +    log_name            The name of the log to open
> +    log_type_arg        The type of the log. E.g. LOG_NORMAL
> +    new_name            The new name for the logfile. This is only needed
> +                        when the method is used to open the binlog file.
> +    io_cache_type_arg   The type of the IO_CACHE to use for this log file
>  
> -  @param hton  The binlog handlerton.
> -  @param thd   The client thread that executes the transaction.
> -  @param all   This is @c true if this is a real transaction commit, and
> -               @false otherwise.
> +  DESCRIPTION
> +    Open the logfile, init IO_CACHE and write startup messages
> +    (in case of general and slow query logs).
>  
> -  @see handlerton::commit
> +  RETURN VALUES
> +    0   ok
> +    1   error
>  */
> -static int binlog_commit(handlerton *hton, THD *thd, bool all)
> +
> +bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
> +                     const char *new_name, enum cache_type io_cache_type_arg)
>  {
> -  int error= 0;
> -  DBUG_ENTER("binlog_commit");
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  char buff[FN_REFLEN];
> +  File file= -1;
> +  int open_flags= O_CREAT | O_BINARY;
> +  DBUG_ENTER("MYSQL_LOG::open");
> +  DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg));
>  
> -  DBUG_PRINT("debug",
> -             ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s,
> stmt.modified_non_trans_table: %s",
> -              all,
> -              YESNO(thd->in_multi_stmt_transaction()),
> -              YESNO(thd->transaction.all.modified_non_trans_table),
> -              YESNO(thd->transaction.stmt.modified_non_trans_table)));
> +  write_error= 0;
>  
> -  if (!cache_mngr->stmt_cache.empty())
> +  if (!(name= my_strdup(log_name, MYF(MY_WME))))
>    {
> -    binlog_flush_stmt_cache(thd, cache_mngr);
> +    name= (char *)log_name; // for the error message
> +    goto err;
>    }
>  
> -  if (cache_mngr->trx_cache.empty())
> -  {
> -    /*
> -      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
> -    */
> -    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> -    DBUG_RETURN(0);
> -  }
> +  if (init_and_set_log_file_name(name, new_name,
> +                                 log_type_arg, io_cache_type_arg))
> +    goto err;
>  
> -  /*
> -    We commit the transaction if:
> -     - We are not in a transaction and committing a statement, or
> -     - We are in a transaction and a full transaction is committed.
> -    Otherwise, we accumulate the changes.
> -  */
> -  if (ending_trans(thd, all))
> +  if (io_cache_type == SEQ_READ_APPEND)
> +    open_flags |= O_RDWR | O_APPEND;
> +  else
> +    open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
> +
> +  db[0]= 0;
> +
> +  if ((file= mysql_file_open(key_file_MYSQL_LOG,
> +                             log_file_name, open_flags,
> +                             MYF(MY_WME | ME_WAITTANG))) < 0 ||
> +      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
> +                    mysql_file_tell(file, MYF(MY_WME)), 0,
> +                    MYF(MY_WME | MY_NABP |
> +                        ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
> +    goto err;
> +
> +  if (log_type == LOG_NORMAL)
>    {
> -    Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
> -    error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
> +    char *end;
> +    int len=my_snprintf(buff, sizeof(buff), "%s, Version: %s (%s). "
> +#ifdef EMBEDDED_LIBRARY
> +                        "embedded library\n",
> +                        my_progname, server_version, MYSQL_COMPILATION_COMMENT
> +#elif _WIN32
> +			"started with:\nTCP Port: %d, Named Pipe: %s\n",
> +                        my_progname, server_version, MYSQL_COMPILATION_COMMENT,
> +                        mysqld_port, mysqld_unix_port
> +#else
> +			"started with:\nTcp port: %d  Unix socket: %s\n",
> +                        my_progname, server_version, MYSQL_COMPILATION_COMMENT,
> +                        mysqld_port, mysqld_unix_port
> +#endif
> +                       );
> +    end= strnmov(buff + len, "Time                 Id Command    Argument\n",
> +                 sizeof(buff) - len);
> +    if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
> +	flush_io_cache(&log_file))
> +      goto err;
>    }
>  
> +  log_state= LOG_OPENED;
> +  DBUG_RETURN(0);
> +
> +err:
> +  sql_print_error("Could not use %s for logging (error %d). \
> +Turning logging off for the whole duration of the MySQL server process. \
> +To turn it on again: fix the cause, \
> +shutdown the MySQL server and restart it.", name, errno);
> +  if (file >= 0)
> +    mysql_file_close(file, MYF(0));
> +  end_io_cache(&log_file);
> +  safeFree(name);
> +  log_state= LOG_CLOSED;
> +  DBUG_RETURN(1);
> +}
> +
> +MYSQL_LOG::MYSQL_LOG()
> +  : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
> +    log_state(LOG_CLOSED)
> +{
>    /*
> -    This is part of the stmt rollback.
> +    We don't want to initialize LOCK_Log here as such initialization depends on
> +    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
> +    called only in main(). Doing initialization here would make it happen
> +    before main().
>    */
> -  if (!all)
> -    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
> -  DBUG_RETURN(error);
> +  bzero((char*) &log_file, sizeof(log_file));
>  }
>  
> -/**
> -  This function is called when a transaction or a statement is rolled back.
> +void MYSQL_LOG::init_pthread_objects()
> +{
> +  DBUG_ASSERT(inited == 0);
> +  inited= 1;
> +  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> +}
> +
> +/*
> +  Close the log file
>  
> -  @param hton  The binlog handlerton.
> -  @param thd   The client thread that executes the transaction.
> -  @param all   This is @c true if this is a real transaction rollback, and
> -               @false otherwise.
> +  SYNOPSIS
> +    close()
> +    exiting     Bitmask. For the slow and general logs the only used bit is
> +                LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
> +                open at once after close.
>  
> -  @see handlerton::rollback
> +  NOTES
> +    One can do an open on the object at once after doing a close.
> +    The internal structures are not freed until cleanup() is called
>  */
> -static int binlog_rollback(handlerton *hton, THD *thd, bool all)
> -{
> -  DBUG_ENTER("binlog_rollback");
> -  int error=0;
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s,
> stmt.modified_non_trans_table: %s",
> -                       YESNO(all),
> -                       YESNO(thd->transaction.all.modified_non_trans_table),
> -                       YESNO(thd->transaction.stmt.modified_non_trans_table)));
>  
> -  /*
> -    If an incident event is set we do not flush the content of the statement
> -    cache because it may be corrupted.
> -  */
> -  if (cache_mngr->stmt_cache.has_incident())
> -  {
> -    error= mysql_bin_log.write_incident(thd, TRUE);
> -    cache_mngr->reset_cache(&cache_mngr->stmt_cache);
> -  }
> -  else if (!cache_mngr->stmt_cache.empty())
> +void MYSQL_LOG::close(uint exiting)
> +{					// One can't set log_type here!
> +  DBUG_ENTER("MYSQL_LOG::close");
> +  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
> +  if (log_state == LOG_OPENED)
>    {
> -    binlog_flush_stmt_cache(thd, cache_mngr);
> -  }
> +    end_io_cache(&log_file);
>  
> -  if (cache_mngr->trx_cache.empty())
> -  {
> -    /* 
> -      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
> -    */
> -    cache_mngr->reset_cache(&cache_mngr->trx_cache);
> -    DBUG_RETURN(0);
> -  }
> +    if (mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error)
> +    {
> +      write_error= 1;
> +      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> +    }
>  
> -  if (mysql_bin_log.check_write_error(thd))
> -  {
> -    /*
> -      "all == true" means that a "rollback statement" triggered the error and
> -      this function was called. However, this must not happen as a rollback
> -      is written directly to the binary log. And in auto-commit mode, a single
> -      statement that is rolled back has the flag all == false.
> -    */
> -    DBUG_ASSERT(!all);
> -    /*
> -      We reach this point if the effect of a statement did not properly get into
> -      a cache and need to be rolled back.
> -    */
> -    error= binlog_truncate_trx_cache(thd, cache_mngr, all);
> -  }
> -  else
> -  {  
> -    /*
> -      We flush the cache wrapped in a beging/rollback if:
> -        . aborting a single or multi-statement transaction and;
> -        . the format is STMT and non-trans engines were updated or;
> -        . the OPTION_KEEP_LOG is activate.
> -    */
> -    if (ending_trans(thd, all) &&
> -        ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
> -         (trans_has_updated_non_trans_table(thd) &&
> -          thd->variables.binlog_format == BINLOG_FORMAT_STMT)))
> +    if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
>      {
> -      Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
> -      error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
> +      write_error= 1;
> +      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
>      }
> -    /*
> -      Truncate the cache if:
> -        . aborting a single or multi-statement transaction or;
> -        . the OPTION_KEEP_LOG is not activate and;
> -        . the format is not STMT or no non-trans were updated.
> -    */
> -    else if (ending_trans(thd, all) ||
> -             (!(thd->variables.option_bits & OPTION_KEEP_LOG) &&
> -              ((!stmt_has_updated_non_trans_table(thd) ||
> -               thd->variables.binlog_format != BINLOG_FORMAT_STMT))))
> -      error= binlog_truncate_trx_cache(thd, cache_mngr, all);
>    }
>  
> -  /* 
> -    This is part of the stmt rollback.
> -  */
> -  if (!all)
> -    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); 
> -  DBUG_RETURN(error);
> +  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> +  safeFree(name);
> +  DBUG_VOID_RETURN;
>  }
>  
> -void MYSQL_BIN_LOG::set_write_error(THD *thd)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
> -
> -  write_error= 1;
> -
> -  if (check_write_error(thd))
> -    DBUG_VOID_RETURN;
> -
> -  if (my_errno == EFBIG)
> -    my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
> -  else
> -    my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
> +/** This is called only once. */
>  
> +void MYSQL_LOG::cleanup()
> +{
> +  DBUG_ENTER("cleanup");
> +  if (inited)
> +  {
> +    inited= 0;
> +    mysql_mutex_destroy(&LOCK_log);
> +    close(0);
> +  }
>    DBUG_VOID_RETURN;
>  }
>  
> -bool MYSQL_BIN_LOG::check_write_error(THD *thd)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::check_write_error");
> -
> -  bool checked= FALSE;
>  
> -  if (!thd->is_error())
> -    DBUG_RETURN(checked);
> -
> -  switch (thd->stmt_da->sql_errno())
> +int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
> +{
> +  fn_format(new_name, log_name, mysql_data_home, "", 4);
> +  if (log_type == LOG_BIN)
>    {
> -    case ER_TRANS_CACHE_FULL:
> -    case ER_ERROR_ON_WRITE:
> -    case ER_BINLOG_LOGGING_IMPOSSIBLE:
> -      checked= TRUE;
> -    break;
> +    if (!fn_ext(log_name)[0])
> +    {
> +      if (find_uniq_filename(new_name))
> +      {
> +        /* 
> +          This should be treated as error once propagation of error further
> +          up in the stack gets proper handling.
> +        */
> +        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
> +                            ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
> +                            log_name);
> +	sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
> +	return 1;
> +      }
> +    }
>    }
> -
> -  DBUG_RETURN(checked);
> +  return 0;
>  }
>  
> -/**
> -  @note
> -  How do we handle this (unlikely but legal) case:
> -  @verbatim
> -    [transaction] + [update to non-trans table] + [rollback to savepoint] ?
> -  @endverbatim
> -  The problem occurs when a savepoint is before the update to the
> -  non-transactional table. Then when there's a rollback to the savepoint, if we
> -  simply truncate the binlog cache, we lose the part of the binlog cache where
> -  the update is. If we want to not lose it, we need to write the SAVEPOINT
> -  command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
> -  is easy: it's just write at the end of the binlog cache, but the former
> -  should be *inserted* to the place where the user called SAVEPOINT. The
> -  solution is that when the user calls SAVEPOINT, we write it to the binlog
> -  cache (so no need to later insert it). As transactions are never intermixed
> -  in the binary log (i.e. they are serialized), we won't have conflicts with
> -  savepoint names when using mysqlbinlog or in the slave SQL thread.
> -  Then when ROLLBACK TO SAVEPOINT is called, if we updated some
> -  non-transactional table, we don't truncate the binlog cache but instead write
> -  ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
> -  will chop the SAVEPOINT command from the binlog cache, which is good as in
> -  that case there is no need to have it in the binlog).
> +
> +/*
> +  Reopen the log file
> +
> +  SYNOPSIS
> +    reopen_file()
> +
> +  DESCRIPTION
> +    Reopen the log file. The method is used during FLUSH LOGS
> +    and locks LOCK_log mutex
>  */
>  
> -static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
> +
> +void MYSQL_QUERY_LOG::reopen_file()
>  {
> -  DBUG_ENTER("binlog_savepoint_set");
> +  char *save_name;
>  
> -  binlog_trans_log_savepos(thd, (my_off_t*) sv);
> -  /* Write it to the binary log */
> +  DBUG_ENTER("MYSQL_LOG::reopen_file");
> +  if (!is_open())
> +  {
> +    DBUG_PRINT("info",("log is closed"));
> +    DBUG_VOID_RETURN;
> +  }
>  
> -  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
> -  int const error=
> -    thd->binlog_query(THD::STMT_QUERY_TYPE,
> -                      thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
> -                      errcode);
> -  DBUG_RETURN(error);
> -}
> +  mysql_mutex_lock(&LOCK_log);
>  
> -static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
> -{
> -  DBUG_ENTER("binlog_savepoint_rollback");
> +  save_name= name;
> +  name= 0;				// Don't free name
> +  close(LOG_CLOSE_TO_BE_OPENED);
>  
>    /*
> -    Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
> -    non-transactional table. Otherwise, truncate the binlog cache starting
> -    from the SAVEPOINT command.
> +     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
>    */
> -  if (unlikely(trans_has_updated_non_trans_table(thd) ||
> -               (thd->variables.option_bits & OPTION_KEEP_LOG)))
> -  {
> -    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
> -    int error=
> -      thd->binlog_query(THD::STMT_QUERY_TYPE,
> -                        thd->query(), thd->query_length(), TRUE, FALSE,
> FALSE,
> -                        errcode);
> -    DBUG_RETURN(error);
> -  }
> -  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
> -  DBUG_RETURN(0);
> -}
>  
> +  open(save_name, log_type, 0, io_cache_type);
> +  my_free(save_name, MYF(0));
>  
> -int check_binlog_magic(IO_CACHE* log, const char** errmsg)
> -{
> -  char magic[4];
> -  DBUG_ASSERT(my_b_tell(log) == 0);
> +  mysql_mutex_unlock(&LOCK_log);
>  
> -  if (my_b_read(log, (uchar*) magic, sizeof(magic)))
> -  {
> -    *errmsg = "I/O error reading the header from the binary log";
> -    sql_print_error("%s, errno=%d, io cache code=%d", *errmsg, my_errno,
> -		    log->error);
> -    return 1;
> -  }
> -  if (memcmp(magic, BINLOG_MAGIC, sizeof(magic)))
> -  {
> -    *errmsg = "Binlog has bad magic number;  It's not a binary log file that can be
> used by this version of MySQL";
> -    return 1;
> -  }
> -  return 0;
> -}
> -
> -
> -File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
> -{
> -  File file;
> -  DBUG_ENTER("open_binlog");
> -
> -  if ((file= mysql_file_open(key_file_binlog,
> -                             log_file_name, O_RDONLY | O_BINARY | O_SHARE,
> -                             MYF(MY_WME))) < 0)
> -  {
> -    sql_print_error("Failed to open log (file '%s', errno %d)",
> -                    log_file_name, my_errno);
> -    *errmsg = "Could not open log file";
> -    goto err;
> -  }
> -  if (init_io_cache(log, file, IO_SIZE*2, READ_CACHE, 0, 0,
> -                    MYF(MY_WME|MY_DONT_CHECK_FILESIZE)))
> -  {
> -    sql_print_error("Failed to create a cache on log (file '%s')",
> -                    log_file_name);
> -    *errmsg = "Could not open log file";
> -    goto err;
> -  }
> -  if (check_binlog_magic(log,errmsg))
> -    goto err;
> -  DBUG_RETURN(file);
> -
> -err:
> -  if (file >= 0)
> -  {
> -    mysql_file_close(file, MYF(0));
> -    end_io_cache(log);
> -  }
> -  DBUG_RETURN(-1);
> -}
> -
> -#ifdef _WIN32
> -static int eventSource = 0;
> -
> -static void setup_windows_event_source()
> -{
> -  HKEY    hRegKey= NULL;
> -  DWORD   dwError= 0;
> -  TCHAR   szPath[MAX_PATH];
> -  DWORD dwTypes;
> -
> -  if (eventSource)               // Ensure that we are only called once
> -    return;
> -  eventSource= 1;
> -
> -  // Create the event source registry key
> -  dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
> -                         
> "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL", 
> -                          &hRegKey);
> -
> -  /* Name of the PE module that contains the message resource */
> -  GetModuleFileName(NULL, szPath, MAX_PATH);
> -
> -  /* Register EventMessageFile */
> -  dwError = RegSetValueEx(hRegKey, "EventMessageFile", 0, REG_EXPAND_SZ,
> -                          (PBYTE) szPath, (DWORD) (strlen(szPath) + 1));
> -
> -  /* Register supported event types */
> -  dwTypes= (EVENTLOG_ERROR_TYPE | EVENTLOG_WARNING_TYPE |
> -            EVENTLOG_INFORMATION_TYPE);
> -  dwError= RegSetValueEx(hRegKey, "TypesSupported", 0, REG_DWORD,
> -                         (LPBYTE) &dwTypes, sizeof dwTypes);
> -
> -  RegCloseKey(hRegKey);
> -}
> -
> -#endif /* _WIN32 */
> -
> -
> -/**
> -  Find a unique filename for 'filename.#'.
> -
> -  Set '#' to the number next to the maximum found in the most
> -  recent log file extension.
> -
> -  This function will return nonzero if: (i) the generated name
> -  exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
> -  or (iii) some other error happened while examining the filesystem.
> -
> -  @return
> -    nonzero if not possible to get unique filename.
> -*/
> -
> -static int find_uniq_filename(char *name)
> -{
> -  uint                  i;
> -  char                  buff[FN_REFLEN], ext_buf[FN_REFLEN];
> -  struct st_my_dir     *dir_info;
> -  reg1 struct fileinfo *file_info;
> -  ulong                 max_found= 0, next= 0, number= 0;
> -  size_t		buf_length, length;
> -  char			*start, *end;
> -  int                   error= 0;
> -  DBUG_ENTER("find_uniq_filename");
> -
> -  length= dirname_part(buff, name, &buf_length);
> -  start=  name + length;
> -  end=    strend(start);
> -
> -  *end='.';
> -  length= (size_t) (end - start + 1);
> -
> -  if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))
> -  {						// This shouldn't happen
> -    strmov(end,".1");				// use name+1
> -    DBUG_RETURN(1);
> -  }
> -  file_info= dir_info->dir_entry;
> -  for (i= dir_info->number_off_files ; i-- ; file_info++)
> -  {
> -    if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
> -	test_if_number(file_info->name+length, &number,0))
> -    {
> -      set_if_bigger(max_found,(ulong) number);
> -    }
> -  }
> -  my_dirend(dir_info);
> -
> -  /* check if reached the maximum possible extension number */
> -  if ((max_found == MAX_LOG_UNIQUE_FN_EXT))
> -  {
> -    sql_print_error("Log filename extension number exhausted: %06lu. \
> -Please fix this by archiving old logs and \
> -updating the index files.", max_found);
> -    error= 1;
> -    goto end;
> -  }
> -
> -  next= max_found + 1;
> -  sprintf(ext_buf, "%06lu", next);
> -  *end++='.';
> -
> -  /* 
> -    Check if the generated extension size + the file name exceeds the
> -    buffer size used. If one did not check this, then the filename might be
> -    truncated, resulting in error.
> -   */
> -  if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
> -  {
> -    sql_print_error("Log filename too large: %s%s (%zu). \
> -Please fix this by archiving old logs and updating the \
> -index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
> -    error= 1;
> -    goto end;
> -  }
> -
> -  sprintf(end, "%06lu", next);
> -
> -  /* print warning if reaching the end of available extensions. */
> -  if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
> -    sql_print_warning("Next log extension: %lu. \
> -Remaining log filename extensions: %lu. \
> -Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next));
> -
> -end:
> -  DBUG_RETURN(error);
> -}
> -
> -
> -void MYSQL_LOG::init(enum_log_type log_type_arg,
> -                     enum cache_type io_cache_type_arg)
> -{
> -  DBUG_ENTER("MYSQL_LOG::init");
> -  log_type= log_type_arg;
> -  io_cache_type= io_cache_type_arg;
> -  DBUG_PRINT("info",("log_type: %d", log_type));
>    DBUG_VOID_RETURN;
>  }
>  
>  
> -bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
> -                                           const char *new_name,
> -                                           enum_log_type log_type_arg,
> -                                           enum cache_type io_cache_type_arg)
> -{
> -  init(log_type_arg, io_cache_type_arg);
> -
> -  if (new_name && !strmov(log_file_name, new_name))
> -    return TRUE;
> -  else if (!new_name && generate_new_name(log_file_name, log_name))
> -    return TRUE;
> -
> -  return FALSE;
> -}
> -
> -
>  /*
> -  Open a (new) log file.
> +  Write a command to traditional general log file
>  
>    SYNOPSIS
> -    open()
> +    write()
>  
> -    log_name            The name of the log to open
> -    log_type_arg        The type of the log. E.g. LOG_NORMAL
> -    new_name            The new name for the logfile. This is only needed
> -                        when the method is used to open the binlog file.
> -    io_cache_type_arg   The type of the IO_CACHE to use for this log file
> +    event_time        command start timestamp
> +    user_host         the pointer to the string with user@host info
> +    user_host_len     length of the user_host string. this is computed once
> +                      and passed to all general log  event handlers
> +    thread_id         Id of the thread, issued a query
> +    command_type      the type of the command being logged
> +    command_type_len  the length of the string above
> +    sql_text          the very text of the query being executed
> +    sql_text_len      the length of sql_text string
>  
>    DESCRIPTION
> -    Open the logfile, init IO_CACHE and write startup messages
> -    (in case of general and slow query logs).
>  
> -  RETURN VALUES
> -    0   ok
> -    1   error
> +   Log given command to to normal (not rotable) log file
> +
> +  RETURN
> +    FASE - OK
> +    TRUE - error occured
>  */
>  
> -bool MYSQL_LOG::open(const char *log_name, enum_log_type log_type_arg,
> -                     const char *new_name, enum cache_type io_cache_type_arg)
> -{
> -  char buff[FN_REFLEN];
> -  File file= -1;
> -  int open_flags= O_CREAT | O_BINARY;
> -  DBUG_ENTER("MYSQL_LOG::open");
> -  DBUG_PRINT("enter", ("log_type: %d", (int) log_type_arg));
> -
> -  write_error= 0;
> -
> -  if (!(name= my_strdup(log_name, MYF(MY_WME))))
> -  {
> -    name= (char *)log_name; // for the error message
> -    goto err;
> -  }
> -
> -  if (init_and_set_log_file_name(name, new_name,
> -                                 log_type_arg, io_cache_type_arg))
> -    goto err;
> -
> -  if (io_cache_type == SEQ_READ_APPEND)
> -    open_flags |= O_RDWR | O_APPEND;
> -  else
> -    open_flags |= O_WRONLY | (log_type == LOG_BIN ? 0 : O_APPEND);
> -
> -  db[0]= 0;
> -
> -  if ((file= mysql_file_open(key_file_MYSQL_LOG,
> -                             log_file_name, open_flags,
> -                             MYF(MY_WME | ME_WAITTANG))) < 0 ||
> -      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
> -                    mysql_file_tell(file, MYF(MY_WME)), 0,
> -                    MYF(MY_WME | MY_NABP |
> -                        ((log_type == LOG_BIN) ? MY_WAIT_IF_FULL : 0))))
> -    goto err;
> -
> -  if (log_type == LOG_NORMAL)
> -  {
> -    char *end;
> -    int len=my_snprintf(buff, sizeof(buff), "%s, Version: %s (%s). "
> -#ifdef EMBEDDED_LIBRARY
> -                        "embedded library\n",
> -                        my_progname, server_version, MYSQL_COMPILATION_COMMENT
> -#elif _WIN32
> -			"started with:\nTCP Port: %d, Named Pipe: %s\n",
> -                        my_progname, server_version, MYSQL_COMPILATION_COMMENT,
> -                        mysqld_port, mysqld_unix_port
> -#else
> -			"started with:\nTcp port: %d  Unix socket: %s\n",
> -                        my_progname, server_version, MYSQL_COMPILATION_COMMENT,
> -                        mysqld_port, mysqld_unix_port
> -#endif
> -                       );
> -    end= strnmov(buff + len, "Time                 Id Command    Argument\n",
> -                 sizeof(buff) - len);
> -    if (my_b_write(&log_file, (uchar*) buff, (uint) (end-buff)) ||
> -	flush_io_cache(&log_file))
> -      goto err;
> -  }
> -
> -  log_state= LOG_OPENED;
> -  DBUG_RETURN(0);
> -
> -err:
> -  sql_print_error("Could not use %s for logging (error %d). \
> -Turning logging off for the whole duration of the MySQL server process. \
> -To turn it on again: fix the cause, \
> -shutdown the MySQL server and restart it.", name, errno);
> -  if (file >= 0)
> -    mysql_file_close(file, MYF(0));
> -  end_io_cache(&log_file);
> -  safeFree(name);
> -  log_state= LOG_CLOSED;
> -  DBUG_RETURN(1);
> -}
> -
> -MYSQL_LOG::MYSQL_LOG()
> -  : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
> -    log_state(LOG_CLOSED)
> -{
> -  /*
> -    We don't want to initialize LOCK_Log here as such initialization depends on
> -    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
> -    called only in main(). Doing initialization here would make it happen
> -    before main().
> -  */
> -  bzero((char*) &log_file, sizeof(log_file));
> -}
> -
> -void MYSQL_LOG::init_pthread_objects()
> -{
> -  DBUG_ASSERT(inited == 0);
> -  inited= 1;
> -  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> -}
> -
> -/*
> -  Close the log file
> -
> -  SYNOPSIS
> -    close()
> -    exiting     Bitmask. For the slow and general logs the only used bit is
> -                LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
> -                open at once after close.
> -
> -  NOTES
> -    One can do an open on the object at once after doing a close.
> -    The internal structures are not freed until cleanup() is called
> -*/
> -
> -void MYSQL_LOG::close(uint exiting)
> -{					// One can't set log_type here!
> -  DBUG_ENTER("MYSQL_LOG::close");
> -  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
> -  if (log_state == LOG_OPENED)
> -  {
> -    end_io_cache(&log_file);
> -
> -    if (mysql_file_sync(log_file.file, MYF(MY_WME)) && ! write_error)
> -    {
> -      write_error= 1;
> -      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> -    }
> -
> -    if (mysql_file_close(log_file.file, MYF(MY_WME)) && ! write_error)
> -    {
> -      write_error= 1;
> -      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> -    }
> -  }
> -
> -  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> -  safeFree(name);
> -  DBUG_VOID_RETURN;
> -}
> -
> -/** This is called only once. */
> -
> -void MYSQL_LOG::cleanup()
> -{
> -  DBUG_ENTER("cleanup");
> -  if (inited)
> -  {
> -    inited= 0;
> -    mysql_mutex_destroy(&LOCK_log);
> -    close(0);
> -  }
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -int MYSQL_LOG::generate_new_name(char *new_name, const char *log_name)
> -{
> -  fn_format(new_name, log_name, mysql_data_home, "", 4);
> -  if (log_type == LOG_BIN)
> -  {
> -    if (!fn_ext(log_name)[0])
> -    {
> -      if (find_uniq_filename(new_name))
> -      {
> -        /* 
> -          This should be treated as error once propagation of error further
> -          up in the stack gets proper handling.
> -        */
> -        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN, 
> -                            ER_NO_UNIQUE_LOGFILE, ER(ER_NO_UNIQUE_LOGFILE),
> -                            log_name);
> -	sql_print_error(ER(ER_NO_UNIQUE_LOGFILE), log_name);
> -	return 1;
> -      }
> -    }
> -  }
> -  return 0;
> -}
> -
> -
> -/*
> -  Reopen the log file
> -
> -  SYNOPSIS
> -    reopen_file()
> -
> -  DESCRIPTION
> -    Reopen the log file. The method is used during FLUSH LOGS
> -    and locks LOCK_log mutex
> -*/
> -
> -
> -void MYSQL_QUERY_LOG::reopen_file()
> -{
> -  char *save_name;
> -
> -  DBUG_ENTER("MYSQL_LOG::reopen_file");
> -  if (!is_open())
> -  {
> -    DBUG_PRINT("info",("log is closed"));
> -    DBUG_VOID_RETURN;
> -  }
> -
> -  mysql_mutex_lock(&LOCK_log);
> -
> -  save_name= name;
> -  name= 0;				// Don't free name
> -  close(LOG_CLOSE_TO_BE_OPENED);
> -
> -  /*
> -     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
> -  */
> -
> -  open(save_name, log_type, 0, io_cache_type);
> -  my_free(save_name, MYF(0));
> -
> -  mysql_mutex_unlock(&LOCK_log);
> -
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -/*
> -  Write a command to traditional general log file
> -
> -  SYNOPSIS
> -    write()
> -
> -    event_time        command start timestamp
> -    user_host         the pointer to the string with user@host info
> -    user_host_len     length of the user_host string. this is computed once
> -                      and passed to all general log  event handlers
> -    thread_id         Id of the thread, issued a query
> -    command_type      the type of the command being logged
> -    command_type_len  the length of the string above
> -    sql_text          the very text of the query being executed
> -    sql_text_len      the length of sql_text string
> -
> -  DESCRIPTION
> -
> -   Log given command to to normal (not rotable) log file
> -
> -  RETURN
> -    FASE - OK
> -    TRUE - error occured
> -*/
> -
> -bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
> -                            uint user_host_len, int thread_id,
> -                            const char *command_type, uint command_type_len,
> -                            const char *sql_text, uint sql_text_len)
> +bool MYSQL_QUERY_LOG::write(time_t event_time, const char *user_host,
> +                            uint user_host_len, int thread_id,
> +                            const char *command_type, uint command_type_len,
> +                            const char *sql_text, uint sql_text_len)
>  {
>    char buff[32];
>    uint length= 0;
>    char local_time_buff[MAX_TIME_SIZE];
>    struct tm start;
> -  uint time_buff_len= 0;
> -
> -  mysql_mutex_lock(&LOCK_log);
> -
> -  /* Test if someone closed between the is_open test and lock */
> -  if (is_open())
> -  {
> -    /* for testing output of timestamp and thread id */
> -    DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;);
> -
> -    /* Note that my_b_write() assumes it knows the length for this */
> -      if (event_time != last_time)
> -      {
> -        last_time= event_time;
> -
> -        localtime_r(&event_time, &start);
> -
> -        time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE,
> -                                   "%02d%02d%02d %2d:%02d:%02d\t",
> -                                   start.tm_year % 100, start.tm_mon + 1,
> -                                   start.tm_mday, start.tm_hour,
> -                                   start.tm_min, start.tm_sec);
> -
> -        if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len))
> -          goto err;
> -      }
> -      else
> -        if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
> -          goto err;
> -
> -      /* command_type, thread_id */
> -      length= my_snprintf(buff, 32, "%5ld ", (long) thread_id);
> -
> -    if (my_b_write(&log_file, (uchar*) buff, length))
> -      goto err;
> -
> -    if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
> -      goto err;
> -
> -    if (my_b_write(&log_file, (uchar*) "\t", 1))
> -      goto err;
> -
> -    /* sql_text */
> -    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
> -      goto err;
> -
> -    if (my_b_write(&log_file, (uchar*) "\n", 1) ||
> -        flush_io_cache(&log_file))
> -      goto err;
> -  }
> -
> -  mysql_mutex_unlock(&LOCK_log);
> -  return FALSE;
> -err:
> -
> -  if (!write_error)
> -  {
> -    write_error= 1;
> -    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> -  }
> -  mysql_mutex_unlock(&LOCK_log);
> -  return TRUE;
> -}
> -
> -
> -/*
> -  Log a query to the traditional slow log file
> -
> -  SYNOPSIS
> -    write()
> -
> -    thd               THD of the query
> -    current_time      current timestamp
> -    query_start_arg   command start timestamp
> -    user_host         the pointer to the string with user@host info
> -    user_host_len     length of the user_host string. this is computed once
> -                      and passed to all general log event handlers
> -    query_utime       Amount of time the query took to execute (in microseconds)
> -    lock_utime        Amount of time the query was locked (in microseconds)
> -    is_command        The flag, which determines, whether the sql_text is a
> -                      query or an administrator command.
> -    sql_text          the very text of the query or administrator command
> -                      processed
> -    sql_text_len      the length of sql_text string
> -
> -  DESCRIPTION
> -
> -   Log a query to the slow log file.
> -
> -  RETURN
> -    FALSE - OK
> -    TRUE - error occured
> -*/
> -
> -bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
> -                            time_t query_start_arg, const char *user_host,
> -                            uint user_host_len, ulonglong query_utime,
> -                            ulonglong lock_utime, bool is_command,
> -                            const char *sql_text, uint sql_text_len)
> -{
> -  bool error= 0;
> -  DBUG_ENTER("MYSQL_QUERY_LOG::write");
> -
> -  mysql_mutex_lock(&LOCK_log);
> -
> -  if (!is_open())
> -  {
> -    mysql_mutex_unlock(&LOCK_log);
> -    DBUG_RETURN(0);
> -  }
> -
> -  if (is_open())
> -  {						// Safety agains reopen
> -    int tmp_errno= 0;
> -    char buff[80], *end;
> -    char query_time_buff[22+7], lock_time_buff[22+7];
> -    uint buff_len;
> -    end= buff;
> -
> -    if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
> -    {
> -      if (current_time != last_time)
> -      {
> -        last_time= current_time;
> -        struct tm start;
> -        localtime_r(&current_time, &start);
> -
> -        buff_len= my_snprintf(buff, sizeof buff,
> -                              "# Time: %02d%02d%02d %2d:%02d:%02d\n",
> -                              start.tm_year % 100, start.tm_mon + 1,
> -                              start.tm_mday, start.tm_hour,
> -                              start.tm_min, start.tm_sec);
> -
> -        /* Note that my_b_write() assumes it knows the length for this */
> -        if (my_b_write(&log_file, (uchar*) buff, buff_len))
> -          tmp_errno= errno;
> -      }
> -      const uchar uh[]= "# User@Host: ";
> -      if (my_b_write(&log_file, uh, sizeof(uh) - 1))
> -        tmp_errno= errno;
> -      if (my_b_write(&log_file, (uchar*) user_host, user_host_len))
> -        tmp_errno= errno;
> -      if (my_b_write(&log_file, (uchar*) "\n", 1))
> -        tmp_errno= errno;
> -    }
> -    /* For slow query log */
> -    sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
> -    sprintf(lock_time_buff,  "%.6f", ulonglong2double(lock_utime)/1000000.0);
> -    if (my_b_printf(&log_file,
> -                    "# Query_time: %s  Lock_time: %s"
> -                    " Rows_sent: %lu  Rows_examined: %lu\n",
> -                    query_time_buff, lock_time_buff,
> -                    (ulong) thd->sent_row_count,
> -                    (ulong) thd->examined_row_count) == (uint) -1)
> -      tmp_errno= errno;
> -    if (thd->db && strcmp(thd->db, db))
> -    {						// Database changed
> -      if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
> -        tmp_errno= errno;
> -      strmov(db,thd->db);
> -    }
> -    if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
> -    {
> -      end=strmov(end, ",last_insert_id=");
> -      end=longlong10_to_str((longlong)
> -                           
> thd->first_successful_insert_id_in_prev_stmt_for_binlog,
> -                            end, -10);
> -    }
> -    // Save value if we do an insert.
> -    if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
> -    {
> -      if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
> -      {
> -        end=strmov(end,",insert_id=");
> -        end=longlong10_to_str((longlong)
> -                             
> thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
> -                              end, -10);
> -      }
> -    }
> -
> -    /*
> -      This info used to show up randomly, depending on whether the query
> -      checked the query start time or not. now we always write current
> -      timestamp to the slow log
> -    */
> -    end= strmov(end, ",timestamp=");
> -    end= int10_to_str((long) current_time, end, 10);
> -
> -    if (end != buff)
> -    {
> -      *end++=';';
> -      *end='\n';
> -      if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
> -          my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
> -        tmp_errno= errno;
> -    }
> -    if (is_command)
> -    {
> -      end= strxmov(buff, "# administrator command: ", NullS);
> -      buff_len= (ulong) (end - buff);
> -      my_b_write(&log_file, (uchar*) buff, buff_len);
> -    }
> -    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
> -        my_b_write(&log_file, (uchar*) ";\n",2) ||
> -        flush_io_cache(&log_file))
> -      tmp_errno= errno;
> -    if (tmp_errno)
> -    {
> -      error= 1;
> -      if (! write_error)
> -      {
> -        write_error= 1;
> -        sql_print_error(ER(ER_ERROR_ON_WRITE), name, error);
> -      }
> -    }
> -  }
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_RETURN(error);
> -}
> -
> -
> -/**
> -  @todo
> -  The following should be using fn_format();  We just need to
> -  first change fn_format() to cut the file name if it's too long.
> -*/
> -const char *MYSQL_LOG::generate_name(const char *log_name,
> -                                      const char *suffix,
> -                                      bool strip_ext, char *buff)
> -{
> -  if (!log_name || !log_name[0])
> -  {
> -    strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
> -    return (const char *)
> -      fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
> -  }
> -  // get rid of extension if the log is binary to avoid problems
> -  if (strip_ext)
> -  {
> -    char *p= fn_ext(log_name);
> -    uint length= (uint) (p - log_name);
> -    strmake(buff, log_name, min(length, FN_REFLEN-1));
> -    return (const char*)buff;
> -  }
> -  return log_name;
> -}
> -
> -
> -
> -MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
> -  :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
> -   need_start_event(TRUE), m_table_map_version(0),
> -   sync_period_ptr(sync_period),
> -   is_relay_log(0), signal_cnt(0),
> -   description_event_for_exec(0), description_event_for_queue(0)
> -{
> -  /*
> -    We don't want to initialize locks here as such initialization depends on
> -    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
> -    called only in main(). Doing initialization here would make it happen
> -    before main().
> -  */
> -  index_file_name[0] = 0;
> -  bzero((char*) &index_file, sizeof(index_file));
> -  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> -}
> -
> -/* this is called only once */
> -
> -void MYSQL_BIN_LOG::cleanup()
> -{
> -  DBUG_ENTER("cleanup");
> -  if (inited)
> -  {
> -    inited= 0;
> -    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
> -    delete description_event_for_queue;
> -    delete description_event_for_exec;
> -    mysql_mutex_destroy(&LOCK_log);
> -    mysql_mutex_destroy(&LOCK_index);
> -    mysql_cond_destroy(&update_cond);
> -  }
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -/* Init binlog-specific vars */
> -void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::init");
> -  no_auto_events= no_auto_events_arg;
> -  max_size= max_size_arg;
> -  DBUG_PRINT("info",("max_size: %lu", max_size));
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -void MYSQL_BIN_LOG::init_pthread_objects()
> -{
> -  DBUG_ASSERT(inited == 0);
> -  inited= 1;
> -  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> -  mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
> -  mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0);
> -}
> -
> -
> -bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
> -                                    const char *log_name, bool need_mutex)
> -{
> -  File index_file_nr= -1;
> -  DBUG_ASSERT(!my_b_inited(&index_file));
> -
> -  /*
> -    First open of this class instance
> -    Create an index file that will hold all file names uses for logging.
> -    Add new entries to the end of it.
> -  */
> -  myf opt= MY_UNPACK_FILENAME;
> -  if (!index_file_name_arg)
> -  {
> -    index_file_name_arg= log_name;    // Use same basename for index file
> -    opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
> -  }
> -  fn_format(index_file_name, index_file_name_arg, mysql_data_home,
> -            ".index", opt);
> -  if ((index_file_nr= mysql_file_open(key_file_binlog_index,
> -                                      index_file_name,
> -                                      O_RDWR | O_CREAT | O_BINARY,
> -                                      MYF(MY_WME))) < 0 ||
> -       mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
> -       init_io_cache(&index_file, index_file_nr,
> -                     IO_SIZE, WRITE_CACHE,
> -                     mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
> -                                     0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
> -      DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
> -  {
> -    /*
> -      TODO: all operations creating/deleting the index file or a log, should
> -      call my_sync_dir() or my_sync_dir_by_file() to be durable.
> -      TODO: file creation should be done with mysql_file_create()
> -      not mysql_file_open().
> -    */
> -    if (index_file_nr >= 0)
> -      mysql_file_close(index_file_nr, MYF(0));
> -    return TRUE;
> -  }
> -
> -#ifdef HAVE_REPLICATION
> -  /*
> -    Sync the index by purging any binary log file that is not registered.
> -    In other words, either purge binary log files that were removed from
> -    the index but not purged from the file system due to a crash or purge
> -    any binary log file that was created but not register in the index
> -    due to a crash.
> -  */
> -
> -  if (set_purge_index_file_name(index_file_name_arg) ||
> -      open_purge_index_file(FALSE) ||
> -      purge_index_entry(NULL, NULL, need_mutex) ||
> -      close_purge_index_file() ||
> -      DBUG_EVALUATE_IF("fault_injection_recovering_index", 1, 0))
> -  {
> -    sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
> -                    "file.");
> -    return TRUE;
> -  }
> -#endif
> -
> -  return FALSE;
> -}
> -
> -
> -/**
> -  Open a (new) binlog file.
> -
> -  - Open the log file and the index file. Register the new
> -  file name in it
> -  - When calling this when the file is in use, you must have a locks
> -  on LOCK_log and LOCK_index.
> -
> -  @retval
> -    0	ok
> -  @retval
> -    1	error
> -*/
> -
> -bool MYSQL_BIN_LOG::open(const char *log_name,
> -                         enum_log_type log_type_arg,
> -                         const char *new_name,
> -                         enum cache_type io_cache_type_arg,
> -                         bool no_auto_events_arg,
> -                         ulong max_size_arg,
> -                         bool null_created_arg,
> -                         bool need_mutex)
> -{
> -  File file= -1;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG::open");
> -  DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
> -
> -  if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
> -                                 io_cache_type_arg))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
> -    DBUG_RETURN(1);
> -  }
> -
> -#ifdef HAVE_REPLICATION
> -  if (open_purge_index_file(TRUE) ||
> -      register_create_index_entry(log_file_name) ||
> -      sync_purge_index_file() ||
> -      DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
> -    DBUG_RETURN(1);
> -  }
> -  DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_ABORT(););
> -#endif
> -
> -  write_error= 0;
> -
> -  /* open the main log file */
> -  if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
> -                      io_cache_type_arg))
> -  {
> -#ifdef HAVE_REPLICATION
> -    close_purge_index_file();
> -#endif
> -    DBUG_RETURN(1);                            /* all warnings issued */
> -  }
> -
> -  init(no_auto_events_arg, max_size_arg);
> -
> -  open_count++;
> -
> -  DBUG_ASSERT(log_type == LOG_BIN);
> -
> -  {
> -    bool write_file_name_to_index_file=0;
> -
> -    if (!my_b_filelength(&log_file))
> -    {
> -      /*
> -	The binary log file was empty (probably newly created)
> -	This is the normal case and happens when the user doesn't specify
> -	an extension for the binary log files.
> -	In this case we write a standard header to it.
> -      */
> -      if (my_b_safe_write(&log_file, (uchar*) BINLOG_MAGIC,
> -			  BIN_LOG_HEADER_SIZE))
> -        goto err;
> -      bytes_written+= BIN_LOG_HEADER_SIZE;
> -      write_file_name_to_index_file= 1;
> -    }
> -
> -    if (need_start_event && !no_auto_events)
> -    {
> -      /*
> -        In 4.x we set need_start_event=0 here, but in 5.0 we want a Start event
> -        even if this is not the very first binlog.
> -      */
> -      Format_description_log_event s(BINLOG_VERSION);
> -      /*
> -        don't set LOG_EVENT_BINLOG_IN_USE_F for SEQ_READ_APPEND io_cache
> -        as we won't be able to reset it later
> -      */
> -      if (io_cache_type == WRITE_CACHE)
> -        s.flags|= LOG_EVENT_BINLOG_IN_USE_F;
> -      if (!s.is_valid())
> -        goto err;
> -      s.dont_set_created= null_created_arg;
> -      if (s.write(&log_file))
> -        goto err;
> -      bytes_written+= s.data_written;
> -    }
> -    if (description_event_for_queue &&
> -        description_event_for_queue->binlog_version>=4)
> -    {
> -      /*
> -        This is a relay log written to by the I/O slave thread.
> -        Write the event so that others can later know the format of this relay
> -        log.
> -        Note that this event is very close to the original event from the
> -        master (it has binlog version of the master, event types of the
> -        master), so this is suitable to parse the next relay log's event. It
> -        has been produced by
> -        Format_description_log_event::Format_description_log_event(char* buf,).
> -        Why don't we want to write the description_event_for_queue if this
> -        event is for format<4 (3.23 or 4.x): this is because in that case, the
> -        description_event_for_queue describes the data received from the
> -        master, but not the data written to the relay log (*conversion*),
> -        which is in format 4 (slave's).
> -      */
> -      /*
> -        Set 'created' to 0, so that in next relay logs this event does not
> -        trigger cleaning actions on the slave in
> -        Format_description_log_event::apply_event_impl().
> -      */
> -      description_event_for_queue->created= 0;
> -      /* Don't set log_pos in event header */
> -      description_event_for_queue->set_artificial_event();
> -
> -      if (description_event_for_queue->write(&log_file))
> -        goto err;
> -      bytes_written+= description_event_for_queue->data_written;
> -    }
> -    if (flush_io_cache(&log_file) ||
> -        mysql_file_sync(log_file.file, MYF(MY_WME)))
> -      goto err;
> -
> -    if (write_file_name_to_index_file)
> -    {
> -#ifdef HAVE_REPLICATION
> -      DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_ABORT(););
> -#endif
> -
> -      DBUG_ASSERT(my_b_inited(&index_file) != 0);
> -      reinit_io_cache(&index_file, WRITE_CACHE,
> -                      my_b_filelength(&index_file), 0, 0);
> -      /*
> -        As this is a new log file, we write the file name to the index
> -        file. As every time we write to the index file, we sync it.
> -      */
> -      if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
> -          my_b_write(&index_file, (uchar*) log_file_name,
> -                     strlen(log_file_name)) ||
> -          my_b_write(&index_file, (uchar*) "\n", 1) ||
> -          flush_io_cache(&index_file) ||
> -          mysql_file_sync(index_file.file, MYF(MY_WME)))
> -        goto err;
> -
> -#ifdef HAVE_REPLICATION
> -      DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_ABORT(););
> -#endif
> -    }
> -  }
> -  log_state= LOG_OPENED;
> -
> -#ifdef HAVE_REPLICATION
> -  close_purge_index_file();
> -#endif
> -
> -  DBUG_RETURN(0);
> -
> -err:
> -#ifdef HAVE_REPLICATION
> -  if (is_inited_purge_index_file())
> -    purge_index_entry(NULL, NULL, need_mutex);
> -  close_purge_index_file();
> -#endif
> -  sql_print_error("Could not use %s for logging (error %d). \
> -Turning logging off for the whole duration of the MySQL server process. \
> -To turn it on again: fix the cause, \
> -shutdown the MySQL server and restart it.", name, errno);
> -  if (file >= 0)
> -    mysql_file_close(file, MYF(0));
> -  end_io_cache(&log_file);
> -  end_io_cache(&index_file);
> -  safeFree(name);
> -  log_state= LOG_CLOSED;
> -  DBUG_RETURN(1);
> -}
> -
> -
> -int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
> -{
> -  mysql_mutex_lock(&LOCK_log);
> -  int ret = raw_get_current_log(linfo);
> -  mysql_mutex_unlock(&LOCK_log);
> -  return ret;
> -}
> -
> -int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
> -{
> -  strmake(linfo->log_file_name, log_file_name,
> sizeof(linfo->log_file_name)-1);
> -  linfo->pos = my_b_tell(&log_file);
> -  return 0;
> -}
> -
> -/**
> -  Move all data up in a file in an filename index file.
> -
> -    We do the copy outside of the IO_CACHE as the cache buffers would just
> -    make things slower and more complicated.
> -    In most cases the copy loop should only do one read.
> -
> -  @param index_file			File to move
> -  @param offset			Move everything from here to beginning
> -
> -  @note
> -    File will be truncated to be 'offset' shorter or filled up with newlines
> -
> -  @retval
> -    0	ok
> -*/
> -
> -#ifdef HAVE_REPLICATION
> -
> -static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
> -{
> -  int bytes_read;
> -  my_off_t init_offset= offset;
> -  File file= index_file->file;
> -  uchar io_buf[IO_SIZE*2];
> -  DBUG_ENTER("copy_up_file_and_fill");
> -
> -  for (;; offset+= bytes_read)
> -  {
> -    mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0));
> -    if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf),
> -                                           MYF(MY_WME)))
> -	< 0)
> -      goto err;
> -    if (!bytes_read)
> -      break;					// end of file
> -    mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
> -    if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
> -      goto err;
> -  }
> -  /* The following will either truncate the file or fill the end with \n' */
> -  if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
> -      mysql_file_sync(file, MYF(MY_WME)))
> -    goto err;
> -
> -  /* Reset data in old index cache */
> -  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
> -  DBUG_RETURN(0);
> -
> -err:
> -  DBUG_RETURN(1);
> -}
> -
> -#endif /* HAVE_REPLICATION */
> -
> -/**
> -  Find the position in the log-index-file for the given log name.
> -
> -  @param linfo		Store here the found log file name and position to
> -                       the NEXT log file name in the index file.
> -  @param log_name	Filename to find in the index file.
> -                       Is a null pointer if we want to read the first entry
> -  @param need_lock	Set this to 1 if the parent doesn't already have a
> -                       lock on LOCK_index
> -
> -  @note
> -    On systems without the truncate function the file will end with one or
> -    more empty lines.  These will be ignored when reading the file.
> -
> -  @retval
> -    0			ok
> -  @retval
> -    LOG_INFO_EOF	        End of log-index-file found
> -  @retval
> -    LOG_INFO_IO		Got IO error while reading file
> -*/
> -
> -int MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
> -			    bool need_lock)
> -{
> -  int error= 0;
> -  char *fname= linfo->log_file_name;
> -  uint log_name_len= log_name ? (uint) strlen(log_name) : 0;
> -  DBUG_ENTER("find_log_pos");
> -  DBUG_PRINT("enter",("log_name: %s", log_name ? log_name : "NULL"));
> -
> -  /*
> -    Mutex needed because we need to make sure the file pointer does not
> -    move from under our feet
> -  */
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_index);
> -  mysql_mutex_assert_owner(&LOCK_index);
> -
> -  /* As the file is flushed, we can't get an error here */
> -  (void) reinit_io_cache(&index_file, READ_CACHE, (my_off_t) 0, 0, 0);
> -
> -  for (;;)
> -  {
> -    uint length;
> -    my_off_t offset= my_b_tell(&index_file);
> -
> -    DBUG_EXECUTE_IF("simulate_find_log_pos_error",
> -                    error=  LOG_INFO_EOF; break;);
> -    /* If we get 0 or 1 characters, this is the end of the file */
> -    if ((length= my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
> -    {
> -      /* Did not find the given entry; Return not found or error */
> -      error= !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
> -      break;
> -    }
> -
> -    // if the log entry matches, null string matching anything
> -    if (!log_name ||
> -	(log_name_len == length-1 && fname[log_name_len] == '\n' &&
> -	 !memcmp(fname, log_name, log_name_len)))
> -    {
> -      DBUG_PRINT("info",("Found log file entry"));
> -      fname[length-1]=0;			// remove last \n
> -      linfo->index_file_start_offset= offset;
> -      linfo->index_file_offset = my_b_tell(&index_file);
> -      break;
> -    }
> -  }
> -
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> -}
> -
> -
> -/**
> -  Find the position in the log-index-file for the given log name.
> -
> -  @param
> -    linfo		Store here the next log file name and position to
> -			the file name after that.
> -  @param
> -    need_lock		Set this to 1 if the parent doesn't already have a
> -			lock on LOCK_index
> -
> -  @note
> -    - Before calling this function, one has to call find_log_pos()
> -    to set up 'linfo'
> -    - Mutex needed because we need to make sure the file pointer does not move
> -    from under our feet
> -
> -  @retval
> -    0			ok
> -  @retval
> -    LOG_INFO_EOF	        End of log-index-file found
> -  @retval
> -    LOG_INFO_IO		Got IO error while reading file
> -*/
> -
> -int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
> -{
> -  int error= 0;
> -  uint length;
> -  char *fname= linfo->log_file_name;
> -
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_index);
> -  mysql_mutex_assert_owner(&LOCK_index);
> -
> -  /* As the file is flushed, we can't get an error here */
> -  (void) reinit_io_cache(&index_file, READ_CACHE, linfo->index_file_offset,
> 0,
> -			 0);
> -
> -  linfo->index_file_start_offset= linfo->index_file_offset;
> -  if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
> -  {
> -    error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
> -    goto err;
> -  }
> -  fname[length-1]=0;				// kill \n
> -  linfo->index_file_offset = my_b_tell(&index_file);
> -
> -err:
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_index);
> -  return error;
> -}
> -
> -
> -/**
> -  Delete all logs refered to in the index file.
> -  Start writing to a new log file.
> -
> -  The new index file will only contain this file.
> -
> -  @param thd		Thread
> -
> -  @note
> -    If not called from slave thread, write start event to new log
> -
> -  @retval
> -    0	ok
> -  @retval
> -    1   error
> -*/
> -
> -bool MYSQL_BIN_LOG::reset_logs(THD* thd)
> -{
> -  LOG_INFO linfo;
> -  bool error=0;
> -  int err;
> -  const char* save_name;
> -  DBUG_ENTER("reset_logs");
> -
> -  ha_reset_logs(thd);
> -  /*
> -    We need to get both locks to be sure that no one is trying to
> -    write to the index log file.
> -  */
> -  mysql_mutex_lock(&LOCK_log);
> -  mysql_mutex_lock(&LOCK_index);
> -
> -  /*
> -    The following mutex is needed to ensure that no threads call
> -    'delete thd' as we would then risk missing a 'rollback' from this
> -    thread. If the transaction involved MyISAM tables, it should go
> -    into binlog even on rollback.
> -  */
> -  mysql_mutex_lock(&LOCK_thread_count);
> -
> -  /* Save variables so that we can reopen the log */
> -  save_name=name;
> -  name=0;					// Protect against free
> -  close(LOG_CLOSE_TO_BE_OPENED);
> -
> -  /*
> -    First delete all old log files and then update the index file.
> -    As we first delete the log files and do not use sort of logging,
> -    a crash may lead to an inconsistent state where the index has
> -    references to non-existent files.
> -
> -    We need to invert the steps and use the purge_index_file methods
> -    in order to make the operation safe.
> -  */
> -
> -  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
> -  {
> -    uint errcode= purge_log_get_error_code(err);
> -    sql_print_error("Failed to locate old binlog or relay log files");
> -    my_message(errcode, ER(errcode), MYF(0));
> -    error= 1;
> -    goto err;
> -  }
> -
> -  for (;;)
> -  {
> -    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
> -    {
> -      if (my_errno == ENOENT) 
> -      {
> -        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> -                            linfo.log_file_name);
> -        sql_print_information("Failed to delete file '%s'",
> -                              linfo.log_file_name);
> -        my_errno= 0;
> -        error= 0;
> -      }
> -      else
> -      {
> -        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                            ER_BINLOG_PURGE_FATAL_ERR,
> -                            "a problem with deleting %s; "
> -                            "consider examining correspondence "
> -                            "of your binlog index file "
> -                            "to the actual binlog files",
> -                            linfo.log_file_name);
> -        error= 1;
> -        goto err;
> -      }
> -    }
> -    if (find_next_log(&linfo, 0))
> -      break;
> -  }
> -
> -  /* Start logging with a new file */
> -  close(LOG_CLOSE_INDEX);
> -  if ((error= my_delete_allow_opened(index_file_name, MYF(0))))	// Reset (open will
> update)
> -  {
> -    if (my_errno == ENOENT) 
> -    {
> -      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> -                          index_file_name);
> -      sql_print_information("Failed to delete file '%s'",
> -                            index_file_name);
> -      my_errno= 0;
> -      error= 0;
> -    }
> -    else
> -    {
> -      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                          ER_BINLOG_PURGE_FATAL_ERR,
> -                          "a problem with deleting %s; "
> -                          "consider examining correspondence "
> -                          "of your binlog index file "
> -                          "to the actual binlog files",
> -                          index_file_name);
> -      error= 1;
> -      goto err;
> -    }
> -  }
> -  if (!thd->slave_thread)
> -    need_start_event=1;
> -  if (!open_index_file(index_file_name, 0, FALSE))
> -    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0,
> FALSE);
> -  my_free((uchar*) save_name, MYF(0));
> -
> -err:
> -  if (error == 1)
> -    name= const_cast<char*>(save_name);
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  mysql_mutex_unlock(&LOCK_index);
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_RETURN(error);
> -}
> -
> -
> -/**
> -  Delete relay log files prior to rli->group_relay_log_name
> -  (i.e. all logs which are not involved in a non-finished group
> -  (transaction)), remove them from the index file and start on next
> -  relay log.
> -
> -  IMPLEMENTATION
> -  - Protects index file with LOCK_index
> -  - Delete relevant relay log files
> -  - Copy all file names after these ones to the front of the index file
> -  - If the OS has truncate, truncate the file, else fill it with \n'
> -  - Read the next file name from the index file and store in rli->linfo
> -
> -  @param rli	       Relay log information
> -  @param included     If false, all relay logs that are strictly before
> -                      rli->group_relay_log_name are deleted ; if true, the
> -                      latter is deleted too (i.e. all relay logs
> -                      read by the SQL slave thread are deleted).
> -
> -  @note
> -    - This is only called from the slave-execute thread when it has read
> -    all commands from a relay log and want to switch to a new relay log.
> -    - When this happens, we can be in an active transaction as
> -    a transaction can span over two relay logs
> -    (although it is always written as a single block to the master's binary
> -    log, hence cannot span over two master's binary logs).
> -
> -  @retval
> -    0			ok
> -  @retval
> -    LOG_INFO_EOF	        End of log-index-file found
> -  @retval
> -    LOG_INFO_SEEK	Could not allocate IO cache
> -  @retval
> -    LOG_INFO_IO		Got IO error while reading file
> -*/
> -
> -#ifdef HAVE_REPLICATION
> -
> -int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
> -{
> -  int error;
> -  char *to_purge_if_included= NULL;
> -  DBUG_ENTER("purge_first_log");
> -
> -  DBUG_ASSERT(is_open());
> -  DBUG_ASSERT(rli->slave_running == 1);
> -  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
> -
> -  mysql_mutex_lock(&LOCK_index);
> -  to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
> -
> -  /*
> -    Read the next log file name from the index file and pass it back to
> -    the caller.
> -  */
> -  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) || 
> -     (error=find_next_log(&rli->linfo, 0)))
> -  {
> -    char buff[22];
> -    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> -                    error,
> -                    llstr(rli->linfo.index_file_offset,buff),
> -                    rli->event_relay_log_name,
> -                    included);
> -    goto err;
> -  }
> -
> -  /*
> -    Reset rli's coordinates to the current log.
> -  */
> -  rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
> -  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
> -	  sizeof(rli->event_relay_log_name)-1);
> -
> -  /*
> -    If we removed the rli->group_relay_log_name file,
> -    we must update the rli->group* coordinates, otherwise do not touch it as the
> -    group's execution is not finished (e.g. COMMIT not executed)
> -  */
> -  if (included)
> -  {
> -    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
> -    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
> -            sizeof(rli->group_relay_log_name)-1);
> -    rli->notify_group_relay_log_name_update();
> -  }
> -
> -  /* Store where we are in the new file for the execution thread */
> -  flush_relay_log_info(rli);
> -
> -  DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_ABORT(););
> -
> -  mysql_mutex_lock(&rli->log_space_lock);
> -  rli->relay_log.purge_logs(to_purge_if_included, included,
> -                            0, 0, &rli->log_space_total);
> -  // Tell the I/O thread to take the relay_log_space_limit into account
> -  rli->ignore_log_space_limit= 0;
> -  mysql_mutex_unlock(&rli->log_space_lock);
> -
> -  /*
> -    Ok to broadcast after the critical region as there is no risk of
> -    the mutex being destroyed by this thread later - this helps save
> -    context switches
> -  */
> -  mysql_cond_broadcast(&rli->log_space_cond);
> -
> -  /*
> -   * Need to update the log pos because purge logs has been called 
> -   * after fetching initially the log pos at the begining of the method.
> -   */
> -  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
> -  {
> -    char buff[22];
> -    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> -                    error,
> -                    llstr(rli->linfo.index_file_offset,buff),
> -                    rli->group_relay_log_name,
> -                    included);
> -    goto err;
> -  }
> -
> -  /* If included was passed, rli->linfo should be the first entry. */
> -  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
> -
> -err:
> -  my_free(to_purge_if_included, MYF(0));
> -  mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> -}
> -
> -/**
> -  Update log index_file.
> -*/
> -
> -int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
> -{
> -  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
> -    return LOG_INFO_IO;
> -
> -  // now update offsets in index file for running threads
> -  if (need_update_threads)
> -    adjust_linfo_offsets(log_info->index_file_start_offset);
> -  return 0;
> -}
> -
> -/**
> -  Remove all logs before the given log from disk and from the index file.
> -
> -  @param to_log	      Delete all log file name before this file.
> -  @param included            If true, to_log is deleted too.
> -  @param need_mutex
> -  @param need_update_threads If we want to update the log coordinates of
> -                             all threads. False for relay logs, true otherwise.
> -  @param freed_log_space     If not null, decrement this variable of
> -                             the amount of log space freed
> -
> -  @note
> -    If any of the logs before the deleted one is in use,
> -    only purge logs up to this one.
> -
> -  @retval
> -    0			ok
> -  @retval
> -    LOG_INFO_EOF		to_log not found
> -    LOG_INFO_EMFILE             too many files opened
> -    LOG_INFO_FATAL              if any other than ENOENT error from
> -                                mysql_file_stat() or mysql_file_delete()
> -*/
> -
> -int MYSQL_BIN_LOG::purge_logs(const char *to_log, 
> -                          bool included,
> -                          bool need_mutex, 
> -                          bool need_update_threads, 
> -                          ulonglong *decrease_log_space)
> -{
> -  int error= 0;
> -  bool exit_loop= 0;
> -  LOG_INFO log_info;
> -  THD *thd= current_thd;
> -  DBUG_ENTER("purge_logs");
> -  DBUG_PRINT("info",("to_log= %s",to_log));
> -
> -  if (need_mutex)
> -    mysql_mutex_lock(&LOCK_index);
> -  if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) 
> -  {
> -    sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
> -                    "listed in the index.", to_log);
> -    goto err;
> -  }
> -
> -  if ((error= open_purge_index_file(TRUE)))
> -  {
> -    sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
> -    goto err;
> -  }
> -
> -  /*
> -    File name exists in index file; delete until we find this file
> -    or a file that is used.
> -  */
> -  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> -    goto err;
> -  while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
> -         !is_active(log_info.log_file_name) &&
> -         !log_in_use(log_info.log_file_name))
> -  {
> -    if ((error= register_purge_index_entry(log_info.log_file_name)))
> -    {
> -      sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register
> file.",
> -                      log_info.log_file_name);
> -      goto err;
> -    }
> -
> -    if (find_next_log(&log_info, 0) || exit_loop)
> -      break;
> -  }
> -
> -  DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_ABORT(););
> -
> -  if ((error= sync_purge_index_file()))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
> -    goto err;
> -  }
> -
> -  /* We know how many files to delete. Update index file. */
> -  if ((error=update_log_index(&log_info, need_update_threads)))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
> -    goto err;
> -  }
> -
> -  DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_ABORT(););
> -
> -err:
> -  /* Read each entry from purge_index_file and delete the file. */
> -  if (is_inited_purge_index_file() &&
> -      (error= purge_index_entry(thd, decrease_log_space, FALSE)))
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
> -                    " that would be purged.");
> -  close_purge_index_file();
> -
> -  DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_ABORT(););
> -
> -  if (need_mutex)
> -    mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> -}
> -
> -int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
> -{
> -  int error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
> -  if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
> -                ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
> -                              MY_REPLACE_EXT)) == NULL)
> -  {
> -    error= 1;
> -    sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
> -                      "file name.");
> -  }
> -  DBUG_RETURN(error);
> -}
> -
> -int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
> -{
> -  int error= 0;
> -  File file= -1;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
> -
> -  if (destroy)
> -    close_purge_index_file();
> -
> -  if (!my_b_inited(&purge_index_file))
> -  {
> -    if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
> -                       MYF(MY_WME | ME_WAITTANG))) < 0  ||
> -        init_io_cache(&purge_index_file, file, IO_SIZE,
> -                      (destroy ? WRITE_CACHE : READ_CACHE),
> -                      0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
> -    {
> -      error= 1;
> -      sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register
> "
> -                      " file.");
> -    }
> -  }
> -  DBUG_RETURN(error);
> -}
> -
> -int MYSQL_BIN_LOG::close_purge_index_file()
> -{
> -  int error= 0;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
> -
> -  if (my_b_inited(&purge_index_file))
> -  {
> -    end_io_cache(&purge_index_file);
> -    error= my_close(purge_index_file.file, MYF(0));
> -  }
> -  my_delete(purge_index_file_name, MYF(0));
> -  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> -
> -  DBUG_RETURN(error);
> -}
> -
> -bool MYSQL_BIN_LOG::is_inited_purge_index_file()
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
> -  DBUG_RETURN (my_b_inited(&purge_index_file));
> -}
> -
> -int MYSQL_BIN_LOG::sync_purge_index_file()
> -{
> -  int error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
> -
> -  if ((error= flush_io_cache(&purge_index_file)) ||
> -      (error= my_sync(purge_index_file.file, MYF(MY_WME))))
> -    DBUG_RETURN(error);
> -
> -  DBUG_RETURN(error);
> -}
> -
> -int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
> -{
> -  int error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
> -
> -  if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry)))
> ||
> -      (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
> -    DBUG_RETURN (error);
> -
> -  DBUG_RETURN(error);
> -}
> -
> -int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
> -  DBUG_RETURN(register_purge_index_entry(entry));
> -}
> -
> -int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> -                                     bool need_mutex)
> -{
> -  MY_STAT s;
> -  int error= 0;
> -  LOG_INFO log_info;
> -  LOG_INFO check_log_info;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
> -
> -  DBUG_ASSERT(my_b_inited(&purge_index_file));
> -
> -  if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file
> "
> -                    "for read");
> -    goto err;
> -  }
> -
> -  for (;;)
> -  {
> -    uint length;
> -
> -    if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
> -                          FN_REFLEN)) <= 1)
> -    {
> -      if (purge_index_file.error)
> -      {
> -        error= purge_index_file.error;
> -        sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
> -                        "register file.", error);
> -        goto err;
> -      }
> -
> -      /* Reached EOF */
> -      break;
> -    }
> -
> -    /* Get rid of the trailing '\n' */
> -    log_info.log_file_name[length-1]= 0;
> -
> -    if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0)))
> -    {
> -      if (my_errno == ENOENT) 
> -      {
> -        /*
> -          It's not fatal if we can't stat a log file that does not exist;
> -          If we could not stat, we won't delete.
> -        */
> -        if (thd)
> -        {
> -          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> -                              log_info.log_file_name);
> -        }
> -        sql_print_information("Failed to execute mysql_file_stat on file '%s'",
> -			      log_info.log_file_name);
> -        my_errno= 0;
> -      }
> -      else
> -      {
> -        /*
> -          Other than ENOENT are fatal
> -        */
> -        if (thd)
> -        {
> -          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                              ER_BINLOG_PURGE_FATAL_ERR,
> -                              "a problem with getting info on being purged %s; "
> -                              "consider examining correspondence "
> -                              "of your binlog index file "
> -                              "to the actual binlog files",
> -                              log_info.log_file_name);
> -        }
> -        else
> -        {
> -          sql_print_information("Failed to delete log file '%s'; "
> -                                "consider examining correspondence "
> -                                "of your binlog index file "
> -                                "to the actual binlog files",
> -                                log_info.log_file_name);
> -        }
> -        error= LOG_INFO_FATAL;
> -        goto err;
> -      }
> -    }
> -    else
> -    {
> -      if ((error= find_log_pos(&check_log_info, log_info.log_file_name,
> need_mutex)))
> -      {
> -        if (error != LOG_INFO_EOF)
> -        {
> -          if (thd)
> -          {
> -            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                                ER_BINLOG_PURGE_FATAL_ERR,
> -                                "a problem with deleting %s and "
> -                                "reading the binlog index file",
> -                                log_info.log_file_name);
> -          }
> -          else
> -          {
> -            sql_print_information("Failed to delete file '%s' and "
> -                                  "read the binlog index file",
> -                                  log_info.log_file_name);
> -          }
> -          goto err;
> -        }
> -           
> -        error= 0;
> -        if (!need_mutex)
> -        {
> -          /*
> -            This is to avoid triggering an error in NDB.
> -          */
> -          ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
> -        }
> -
> -        DBUG_PRINT("info",("purging %s",log_info.log_file_name));
> -        if (!my_delete(log_info.log_file_name, MYF(0)))
> -        {
> -          if (decrease_log_space)
> -            *decrease_log_space-= s.st_size;
> -        }
> -        else
> -        {
> -          if (my_errno == ENOENT)
> -          {
> -            if (thd)
> -            {
> -              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                                  ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> -                                  log_info.log_file_name);
> -            }
> -            sql_print_information("Failed to delete file '%s'",
> -                                  log_info.log_file_name);
> -            my_errno= 0;
> -          }
> -          else
> -          {
> -            if (thd)
> -            {
> -              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                                  ER_BINLOG_PURGE_FATAL_ERR,
> -                                  "a problem with deleting %s; "
> -                                  "consider examining correspondence "
> -                                  "of your binlog index file "
> -                                  "to the actual binlog files",
> -                                  log_info.log_file_name);
> -            }
> -            else
> -            {
> -              sql_print_information("Failed to delete file '%s'; "
> -                                    "consider examining correspondence "
> -                                    "of your binlog index file "
> -                                    "to the actual binlog files",
> -                                    log_info.log_file_name);
> -            }
> -            if (my_errno == EMFILE)
> -            {
> -              DBUG_PRINT("info",
> -                         ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
> -              error= LOG_INFO_EMFILE;
> -              goto err;
> -            }
> -            error= LOG_INFO_FATAL;
> -            goto err;
> -          }
> -        }
> -      }
> -    }
> -  }
> -
> -err:
> -  DBUG_RETURN(error);
> -}
> -
> -/**
> -  Remove all logs before the given file date from disk and from the
> -  index file.
> -
> -  @param thd		Thread pointer
> -  @param purge_time	Delete all log files before given date.
> -
> -  @note
> -    If any of the logs before the deleted one is in use,
> -    only purge logs up to this one.
> -
> -  @retval
> -    0				ok
> -  @retval
> -    LOG_INFO_PURGE_NO_ROTATE	Binary file that can't be rotated
> -    LOG_INFO_FATAL              if any other than ENOENT error from
> -                                mysql_file_stat() or mysql_file_delete()
> -*/
> -
> -int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
> -{
> -  int error;
> -  char to_log[FN_REFLEN];
> -  LOG_INFO log_info;
> -  MY_STAT stat_area;
> -  THD *thd= current_thd;
> -  
> -  DBUG_ENTER("purge_logs_before_date");
> -
> -  mysql_mutex_lock(&LOCK_index);
> -  to_log[0]= 0;
> -
> -  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> -    goto err;
> -
> -  while (strcmp(log_file_name, log_info.log_file_name) &&
> -	 !is_active(log_info.log_file_name) &&
> -         !log_in_use(log_info.log_file_name))
> -  {
> -    if (!mysql_file_stat(key_file_binlog,
> -                         log_info.log_file_name, &stat_area, MYF(0)))
> -    {
> -      if (my_errno == ENOENT) 
> -      {
> -        /*
> -          It's not fatal if we can't stat a log file that does not exist.
> -        */
> -        my_errno= 0;
> -      }
> -      else
> -      {
> -        /*
> -          Other than ENOENT are fatal
> -        */
> -        if (thd)
> -        {
> -          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                              ER_BINLOG_PURGE_FATAL_ERR,
> -                              "a problem with getting info on being purged %s; "
> -                              "consider examining correspondence "
> -                              "of your binlog index file "
> -                              "to the actual binlog files",
> -                              log_info.log_file_name);
> -        }
> -        else
> -        {
> -          sql_print_information("Failed to delete log file '%s'",
> -                                log_info.log_file_name);
> -        }
> -        error= LOG_INFO_FATAL;
> -        goto err;
> -      }
> -    }
> -    else
> -    {
> -      if (stat_area.st_mtime < purge_time) 
> -        strmake(to_log, 
> -                log_info.log_file_name, 
> -                sizeof(log_info.log_file_name) - 1);
> -      else
> -        break;
> -    }
> -    if (find_next_log(&log_info, 0))
> -      break;
> -  }
> -
> -  error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
> -
> -err:
> -  mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> -}
> -#endif /* HAVE_REPLICATION */
> -
> -
> -/**
> -  Create a new log file name.
> -
> -  @param buf		buf of at least FN_REFLEN where new name is stored
> -
> -  @note
> -    If file name will be longer then FN_REFLEN it will be truncated
> -*/
> -
> -void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
> -{
> -  uint dir_len = dirname_length(log_file_name); 
> -  if (dir_len >= FN_REFLEN)
> -    dir_len=FN_REFLEN-1;
> -  strnmov(buf, log_file_name, dir_len);
> -  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
> -}
> -
> -
> -/**
> -  Check if we are writing/reading to the given log file.
> -*/
> -
> -bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
> -{
> -  return !strcmp(log_file_name, log_file_name_arg);
> -}
> -
> -
> -/*
> -  Wrappers around new_file_impl to avoid using argument
> -  to control locking. The argument 1) less readable 2) breaks
> -  incapsulation 3) allows external access to the class without
> -  a lock (which is not possible with private new_file_without_locking
> -  method).
> -*/
> -
> -void MYSQL_BIN_LOG::new_file()
> -{
> -  new_file_impl(1);
> -}
> -
> -
> -void MYSQL_BIN_LOG::new_file_without_locking()
> -{
> -  new_file_impl(0);
> -}
> -
> -
> -/**
> -  Start writing to a new log file or reopen the old file.
> -
> -  @param need_lock		Set to 1 if caller has not locked LOCK_log
> -
> -  @note
> -    The new file name is stored last in the index file
> -*/
> -
> -void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
> -{
> -  char new_name[FN_REFLEN], *new_name_ptr, *old_name;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
> -  if (!is_open())
> -  {
> -    DBUG_PRINT("info",("log is closed"));
> -    DBUG_VOID_RETURN;
> -  }
> -
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_log);
> -  mysql_mutex_lock(&LOCK_index);
> -
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  mysql_mutex_assert_owner(&LOCK_index);
> -
> -  /*
> -    if binlog is used as tc log, be sure all xids are "unlogged",
> -    so that on recover we only need to scan one - latest - binlog file
> -    for prepared xids. As this is expected to be a rare event,
> -    simple wait strategy is enough. We're locking LOCK_log to be sure no
> -    new Xid_log_event's are added to the log (and prepared_xids is not
> -    increased), and waiting on COND_prep_xids for late threads to
> -    catch up.
> -  */
> -  if (prepared_xids)
> -  {
> -    tc_log_page_waits++;
> -    mysql_mutex_lock(&LOCK_prep_xids);
> -    while (prepared_xids) {
> -      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> -      mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
> -    }
> -    mysql_mutex_unlock(&LOCK_prep_xids);
> -  }
> -
> -  /* Reuse old name if not binlog and not update log */
> -  new_name_ptr= name;
> -
> -  /*
> -    If user hasn't specified an extension, generate a new log name
> -    We have to do this here and not in open as we want to store the
> -    new file name in the current binary log file.
> -  */
> -  if (generate_new_name(new_name, name))
> -    goto end;
> -  new_name_ptr=new_name;
> -
> -  if (log_type == LOG_BIN)
> -  {
> -    if (!no_auto_events)
> -    {
> -      /*
> -        We log the whole file name for log file as the user may decide
> -        to change base names at some point.
> -      */
> -      Rotate_log_event r(new_name+dirname_length(new_name),
> -                         0, LOG_EVENT_OFFSET, is_relay_log ?
> Rotate_log_event::RELAY_LOG : 0);
> -      r.write(&log_file);
> -      bytes_written += r.data_written;
> -    }
> -    /*
> -      Update needs to be signalled even if there is no rotate event
> -      log rotation should give the waiting thread a signal to
> -      discover EOF and move on to the next log.
> -    */
> -    signal_update();
> -  }
> -  old_name=name;
> -  name=0;				// Don't free name
> -  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
> -
> -  /*
> -     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
> -  */
> -
> -  /*
> -     new_file() is only used for rotation (in FLUSH LOGS or because size >
> -     max_binlog_size or max_relay_log_size).
> -     If this is a binary log, the Format_description_log_event at the beginning of
> -     the new file should have created=0 (to distinguish with the
> -     Format_description_log_event written at server startup, which should
> -     trigger temp tables deletion on slaves.
> -  */
> -
> -  /* reopen index binlog file, BUG#34582 */
> -  if (!open_index_file(index_file_name, 0, FALSE))
> -    open(old_name, log_type, new_name_ptr,
> -         io_cache_type, no_auto_events, max_size, 1, FALSE);
> -  my_free(old_name,MYF(0));
> -
> -end:
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_log);
> -  mysql_mutex_unlock(&LOCK_index);
> -
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -bool MYSQL_BIN_LOG::append(Log_event* ev)
> -{
> -  bool error = 0;
> -  mysql_mutex_lock(&LOCK_log);
> -  DBUG_ENTER("MYSQL_BIN_LOG::append");
> -
> -  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> -  /*
> -    Log_event::write() is smart enough to use my_b_write() or
> -    my_b_append() depending on the kind of cache we have.
> -  */
> -  if (ev->write(&log_file))
> -  {
> -    error=1;
> -    goto err;
> -  }
> -  bytes_written+= ev->data_written;
> -  DBUG_PRINT("info",("max_size: %lu",max_size));
> -  if (flush_and_sync(0))
> -    goto err;
> -  if ((uint) my_b_append_tell(&log_file) > max_size)
> -    new_file_without_locking();
> -
> -err:
> -  mysql_mutex_unlock(&LOCK_log);
> -  signal_update();				// Safe as we don't call close
> -  DBUG_RETURN(error);
> -}
> -
> -
> -bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
> -{
> -  bool error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::appendv");
> -  va_list(args);
> -  va_start(args,len);
> -
> -  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> -
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  do
> -  {
> -    if (my_b_append(&log_file,(uchar*) buf,len))
> -    {
> -      error= 1;
> -      goto err;
> -    }
> -    bytes_written += len;
> -  } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
> -  DBUG_PRINT("info",("max_size: %lu",max_size));
> -  if (flush_and_sync(0))
> -    goto err;
> -  if ((uint) my_b_append_tell(&log_file) > max_size)
> -    new_file_without_locking();
> -
> -err:
> -  if (!error)
> -    signal_update();
> -  DBUG_RETURN(error);
> -}
> -
> -bool MYSQL_BIN_LOG::flush_and_sync(bool *synced)
> -{
> -  int err=0, fd=log_file.file;
> -  if (synced)
> -    *synced= 0;
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  if (flush_io_cache(&log_file))
> -    return 1;
> -  uint sync_period= get_sync_period();
> -  if (sync_period && ++sync_counter >= sync_period)
> -  {
> -    sync_counter= 0;
> -    err= mysql_file_sync(fd, MYF(MY_WME));
> -    if (synced)
> -      *synced= 1;
> -  }
> -  return err;
> -}
> -
> -void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
> -{
> -  DBUG_ASSERT(!thd->binlog_evt_union.do_union);
> -  thd->binlog_evt_union.do_union= TRUE;
> -  thd->binlog_evt_union.unioned_events= FALSE;
> -  thd->binlog_evt_union.unioned_events_trans= FALSE;
> -  thd->binlog_evt_union.first_query_id= query_id_param;
> -}
> -
> -void MYSQL_BIN_LOG::stop_union_events(THD *thd)
> -{
> -  DBUG_ASSERT(thd->binlog_evt_union.do_union);
> -  thd->binlog_evt_union.do_union= FALSE;
> -}
> -
> -bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
> -{
> -  return (thd->binlog_evt_union.do_union && 
> -          query_id_param >= thd->binlog_evt_union.first_query_id);
> -}
> -
> -/** 
> -  This function checks if a transactional table was updated by the
> -  current transaction.
> -
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a transactional table was updated, @c false otherwise.
> -*/
> -bool
> -trans_has_updated_trans_table(const THD* thd)
> -{
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
> -}
> -
> -/** 
> -  This function checks if a transactional table was updated by the
> -  current statement.
> -
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a transactional table was updated, @c false otherwise.
> -*/
> -bool
> -stmt_has_updated_trans_table(const THD *thd)
> -{
> -  Ha_trx_info *ha_info;
> -
> -  for (ha_info= thd->transaction.stmt.ha_list; ha_info;
> -       ha_info= ha_info->next())
> -  {
> -    if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
> -      return (TRUE);
> -  }
> -  return (FALSE);
> -}
> -
> -/** 
> -  This function checks if either a trx-cache or a non-trx-cache should
> -  be used. If @c bin_log_direct_non_trans_update is active or the format
> -  is either MIXED or ROW, the cache to be used depends on the flag @c
> -  is_transactional. 
> -
> -  On the other hand, if binlog_format is STMT or direct option is
> -  OFF, the trx-cache should be used if and only if the statement is
> -  transactional or the trx-cache is not empty. Otherwise, the
> -  non-trx-cache should be used.
> -
> -  @param thd              The client thread.
> -  @param is_transactional The changes are related to a trx-table.
> -  @return
> -    @c true if a trx-cache should be used, @c false otherwise.
> -*/
> -bool use_trans_cache(const THD* thd, bool is_transactional)
> -{
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  return
> -    ((thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
> -     thd->variables.binlog_direct_non_trans_update) ? is_transactional :
> -     (is_transactional || !cache_mngr->trx_cache.empty()));
> -}
> -
> -/**
> -  This function checks if a transaction, either a multi-statement
> -  or a single statement transaction is about to commit or not.
> -
> -  @param thd The client thread that executed the current statement.
> -  @param all Committing a transaction (i.e. TRUE) or a statement
> -             (i.e. FALSE).
> -  @return
> -    @c true if committing a transaction, otherwise @c false.
> -*/
> -bool ending_trans(THD* thd, const bool all)
> -{
> -  return (all || (!all && !thd->in_multi_stmt_transaction()));
> -}
> -
> -/**
> -  This function checks if a non-transactional table was updated by
> -  the current transaction.
> -
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a non-transactional table was updated, @c false
> -    otherwise.
> -*/
> -bool trans_has_updated_non_trans_table(const THD* thd)
> -{
> -  return (thd->transaction.all.modified_non_trans_table ||
> -          thd->transaction.stmt.modified_non_trans_table);
> -}
> -
> -/**
> -  This function checks if a non-transactional table was updated by the
> -  current statement.
> -
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a non-transactional table was updated, @c false otherwise.
> -*/
> -bool stmt_has_updated_non_trans_table(const THD* thd)
> -{
> -  return (thd->transaction.stmt.modified_non_trans_table);
> -}
> -
> -/*
> -  These functions are placed in this file since they need access to
> -  binlog_hton, which has internal linkage.
> -*/
> -
> -int THD::binlog_setup_trx_data()
> -{
> -  DBUG_ENTER("THD::binlog_setup_trx_data");
> -  binlog_cache_mngr *cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -
> -  if (cache_mngr)
> -    DBUG_RETURN(0);                             // Already set up
> -
> -  cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr),
> MYF(MY_ZEROFILL));
> -  if (!cache_mngr ||
> -      open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
> -                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)) ||
> -      open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir,
> -                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
> -  {
> -    my_free((uchar*)cache_mngr, MYF(MY_ALLOW_ZERO_PTR));
> -    DBUG_RETURN(1);                      // Didn't manage to set it up
> -  }
> -  thd_set_ha_data(this, binlog_hton, cache_mngr);
> -
> -  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
> -
> -  DBUG_RETURN(0);
> -}
> -
> -/*
> -  Function to start a statement and optionally a transaction for the
> -  binary log.
> -
> -  SYNOPSIS
> -    binlog_start_trans_and_stmt()
> -
> -  DESCRIPTION
> -
> -    This function does three things:
> -    - Start a transaction if not in autocommit mode or if a BEGIN
> -      statement has been seen.
> -
> -    - Start a statement transaction to allow us to truncate the cache.
> -
> -    - Save the currrent binlog position so that we can roll back the
> -      statement by truncating the cache.
> -
> -      We only update the saved position if the old one was undefined,
> -      the reason is that there are some cases (e.g., for CREATE-SELECT)
> -      where the position is saved twice (e.g., both in
> -      select_create::prepare() and THD::binlog_write_table_map()) , but
> -      we should use the first. This means that calls to this function
> -      can be used to start the statement before the first table map
> -      event, to include some extra events.
> - */
> -
> -void
> -THD::binlog_start_trans_and_stmt()
> -{
> -  binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this,
> binlog_hton);
> -  DBUG_ENTER("binlog_start_trans_and_stmt");
> -  DBUG_PRINT("enter", ("cache_mngr: %p 
> cache_mngr->trx_cache.get_prev_position(): %lu",
> -                       cache_mngr,
> -                       (cache_mngr ? (ulong)
> cache_mngr->trx_cache.get_prev_position() :
> -                        (ulong) 0)));
> -
> -  if (cache_mngr == NULL ||
> -      cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
> -  {
> -    this->binlog_set_stmt_begin();
> -    if (in_multi_stmt_transaction())
> -      trans_register_ha(this, TRUE, binlog_hton);
> -    trans_register_ha(this, FALSE, binlog_hton);
> -    /*
> -      Mark statement transaction as read/write. We never start
> -      a binary log transaction and keep it read-only,
> -      therefore it's best to mark the transaction read/write just
> -      at the same time we start it.
> -      Not necessary to mark the normal transaction read/write
> -      since the statement-level flag will be propagated automatically
> -      inside ha_commit_trans.
> -    */
> -    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
> -  }
> -  DBUG_VOID_RETURN;
> -}
> -
> -void THD::binlog_set_stmt_begin() {
> -  binlog_cache_mngr *cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -
> -  /*
> -    The call to binlog_trans_log_savepos() might create the cache_mngr
> -    structure, if it didn't exist before, so we save the position
> -    into an auto variable and then write it into the transaction
> -    data for the binary log (i.e., cache_mngr).
> -  */
> -  my_off_t pos= 0;
> -  binlog_trans_log_savepos(this, &pos);
> -  cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -  cache_mngr->trx_cache.set_prev_position(pos);
> -}
> -
> -
> -/**
> -  This function writes a table map to the binary log. 
> -  Note that in order to keep the signature uniform with related methods,
> -  we use a redundant parameter to indicate whether a transactional table
> -  was changed or not.
> - 
> -  @param table             a pointer to the table.
> -  @param is_transactional  @c true indicates a transactional table,
> -                           otherwise @c false a non-transactional.
> -  @return
> -    nonzero if an error pops up when writing the table map event.
> -*/
> -int THD::binlog_write_table_map(TABLE *table, bool is_transactional)
> -{
> -  int error;
> -  DBUG_ENTER("THD::binlog_write_table_map");
> -  DBUG_PRINT("enter", ("table: 0x%lx  (%s: #%lu)",
> -                       (long) table, table->s->table_name.str,
> -                       table->s->table_map_id));
> -
> -  /* Pre-conditions */
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
> -
> -  Table_map_log_event
> -    the_event(this, table, table->s->table_map_id, is_transactional);
> -
> -  if (binlog_table_maps == 0)
> -    binlog_start_trans_and_stmt();
> -
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -
> -  IO_CACHE *file=
> -    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
> -  if ((error= the_event.write(file)))
> -    DBUG_RETURN(error);
> -
> -  binlog_table_maps++;
> -  table->s->table_map_version= mysql_bin_log.table_map_version();
> -  DBUG_RETURN(0);
> -}
> -
> -/**
> -  This function retrieves a pending row event from a cache which is
> -  specified through the parameter @c is_transactional. Respectively, when it
> -  is @c true, the pending event is returned from the transactional cache.
> -  Otherwise from the non-transactional cache.
> -
> -  @param is_transactional  @c true indicates a transactional cache,
> -                           otherwise @c false a non-transactional.
> -  @return
> -    The row event if any. 
> -*/
> -Rows_log_event*
> -THD::binlog_get_pending_rows_event(bool is_transactional) const
> -{
> -  Rows_log_event* rows= NULL;
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -
> -  /*
> -    This is less than ideal, but here's the story: If there is no cache_mngr,
> -    prepare_pending_rows_event() has never been called (since the cache_mngr
> -    is set up there). In that case, we just return NULL.
> -   */
> -  if (cache_mngr)
> -  {
> -    binlog_cache_data *cache_data=
> -      cache_mngr->get_binlog_cache_data(use_trans_cache(this,
> is_transactional));
> -
> -    rows= cache_data->pending();
> -  }
> -  return (rows);
> -}
> -
> -/**
> -  This function stores a pending row event into a cache which is specified
> -  through the parameter @c is_transactional. Respectively, when it is @c
> -  true, the pending event is stored into the transactional cache. Otherwise
> -  into the non-transactional cache.
> -
> -  @param evt               a pointer to the row event.
> -  @param is_transactional  @c true indicates a transactional cache,
> -                           otherwise @c false a non-transactional.
> -*/
> -void
> -THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional)
> -{
> -  if (thd_get_ha_data(this, binlog_hton) == NULL)
> -    binlog_setup_trx_data();
> -
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> -
> -  DBUG_ASSERT(cache_mngr);
> -
> -  binlog_cache_data *cache_data=
> -    cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
> -
> -  cache_data->set_pending(ev);
> -}
> -
> -
> -/**
> -  This function removes the pending rows event, discarding any outstanding
> -  rows. If there is no pending rows event available, this is effectively a
> -  no-op.
> -
> -  @param thd               a pointer to the user thread.
> -  @param is_transactional  @c true indicates a transactional cache,
> -                           otherwise @c false a non-transactional.
> -*/
> -int
> -MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, bool is_transactional)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event");
> -
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  DBUG_ASSERT(cache_mngr);
> -
> -  binlog_cache_data *cache_data=
> -    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> -
> -  if (Rows_log_event* pending= cache_data->pending())
> -  {
> -    delete pending;
> -    cache_data->set_pending(NULL);
> -  }
> -
> -  DBUG_RETURN(0);
> -}
> -
> -/*
> -  Moves the last bunch of rows from the pending Rows event to a cache (either
> -  transactional cache if is_transaction is @c true, or the non-transactional
> -  cache otherwise. Sets a new pending event.
> -
> -  @param thd               a pointer to the user thread.
> -  @param evt               a pointer to the row event.
> -  @param is_transactional  @c true indicates a transactional cache,
> -                           otherwise @c false a non-transactional.
> -*/
> -int
> -MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
> -                                                Rows_log_event* event,
> -                                                bool is_transactional)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
> -  DBUG_ASSERT(mysql_bin_log.is_open());
> -  DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
> -
> -  int error= 0;
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  DBUG_ASSERT(cache_mngr);
> -
> -  binlog_cache_data *cache_data=
> -    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> -
> -  DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long)
> cache_data->pending()));
> -
> -  if (Rows_log_event* pending= cache_data->pending())
> -  {
> -    IO_CACHE *file= &cache_data->cache_log;
> -
> -    /*
> -      Write pending event to the cache.
> -    */
> -    if (pending->write(file))
> -    {
> -      set_write_error(thd);
> -      if (check_write_error(thd) && cache_data &&
> -          stmt_has_updated_non_trans_table(thd))
> -        cache_data->set_incident();
> -      DBUG_RETURN(1);
> -    }
> -
> -    /*
> -      We step the table map version if we are writing an event
> -      representing the end of a statement.
> -
> -      In an ideal world, we could avoid stepping the table map version,
> -      since we could then reuse the table map that was written earlier
> -      in the cache. This does not work since STMT_END_F implies closing
> -      all table mappings on the slave side.
> -    
> -      TODO: Find a solution so that table maps does not have to be
> -      written several times within a transaction.
> -    */
> -    if (pending->get_flags(Rows_log_event::STMT_END_F))
> -      ++m_table_map_version;
> -
> -    delete pending;
> -  }
> -
> -  thd->binlog_set_pending_rows_event(event, is_transactional);
> -
> -  DBUG_RETURN(error);
> -}
> -
> -/**
> -  Write an event to the binary log.
> -*/
> -
> -bool MYSQL_BIN_LOG::write(Log_event *event_info)
> -{
> -  THD *thd= event_info->thd;
> -  bool error= 1;
> -  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
> -  binlog_cache_data *cache_data= 0;
> -
> -  if (thd->binlog_evt_union.do_union)
> -  {
> -    /*
> -      In Stored function; Remember that function call caused an update.
> -      We will log the function call to the binary log on function exit
> -    */
> -    thd->binlog_evt_union.unioned_events= TRUE;
> -    thd->binlog_evt_union.unioned_events_trans |=
> -      event_info->use_trans_cache();
> -    DBUG_RETURN(0);
> -  }
> -
> -  /*
> -    We only end the statement if we are in a top-level statement.  If
> -    we are inside a stored function, we do not end the statement since
> -    this will close all tables on the slave.
> -  */
> -  bool const end_stmt=
> -    thd->locked_tables_mode && thd->lex->requires_prelocking();
> -  if (thd->binlog_flush_pending_rows_event(end_stmt,
> -                                           event_info->use_trans_cache()))
> -    DBUG_RETURN(error);
> -
> -  /*
> -     In most cases this is only called if 'is_open()' is true; in fact this is
> -     mostly called if is_open() *was* true a few instructions before, but it
> -     could have changed since.
> -  */
> -  if (likely(is_open()))
> -  {
> -#ifdef HAVE_REPLICATION
> -    /*
> -      In the future we need to add to the following if tests like
> -      "do the involved tables match (to be implemented)
> -      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
> -    */
> -    const char *local_db= event_info->get_db();
> -    if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
> -	!binlog_filter->db_ok(local_db))
> -      DBUG_RETURN(0);
> -#endif /* HAVE_REPLICATION */
> -
> -    IO_CACHE *file= NULL;
> -
> -    if (event_info->use_direct_logging())
> -    {
> -      file= &log_file;
> -      mysql_mutex_lock(&LOCK_log);
> -    }
> -    else
> -    {
> -      if (thd->binlog_setup_trx_data())
> -        goto err;
> -
> -      binlog_cache_mngr *const cache_mngr=
> -        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -      bool is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
> -      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
> -      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
> -
> -      thd->binlog_start_trans_and_stmt();
> -    }
> -    DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
> -
> -    /*
> -       No check for auto events flag here - this write method should
> -       never be called if auto-events are enabled.
> -
> -       Write first log events which describe the 'run environment'
> -       of the SQL command. If row-based binlogging, Insert_id, Rand
> -       and other kind of "setting context" events are not needed.
> -    */
> -    if (thd)
> -    {
> -      if (!thd->is_current_stmt_binlog_format_row())
> -      {
> -        if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
> -        {
> -          Intvar_log_event e(thd,(uchar) LAST_INSERT_ID_EVENT,
> -                            
> thd->first_successful_insert_id_in_prev_stmt_for_binlog);
> -          if (e.write(file))
> -            goto err;
> -        }
> -        if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
> -        {
> -          DBUG_PRINT("info",("number of auto_inc intervals: %u",
> -                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
> -                             nb_elements()));
> -          Intvar_log_event e(thd, (uchar) INSERT_ID_EVENT,
> -                             thd->auto_inc_intervals_in_cur_stmt_for_binlog.
> -                             minimum());
> -          if (e.write(file))
> -            goto err;
> -        }
> -        if (thd->rand_used)
> -        {
> -          Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
> -          if (e.write(file))
> -            goto err;
> -        }
> -        if (thd->user_var_events.elements)
> -        {
> -          for (uint i= 0; i < thd->user_var_events.elements; i++)
> -          {
> -            BINLOG_USER_VAR_EVENT *user_var_event;
> -            get_dynamic(&thd->user_var_events,(uchar*) &user_var_event,
> i);
> -
> -            /* setting flags for user var log event */
> -            uchar flags= User_var_log_event::UNDEF_F;
> -            if (user_var_event->unsigned_flag)
> -              flags|= User_var_log_event::UNSIGNED_F;
> -
> -            User_var_log_event e(thd,
> user_var_event->user_var_event->name.str,
> -                                 user_var_event->user_var_event->name.length,
> -                                 user_var_event->value,
> -                                 user_var_event->length,
> -                                 user_var_event->type,
> -                                 user_var_event->charset_number,
> -                                 flags);
> -            if (e.write(file))
> -              goto err;
> -          }
> -        }
> -      }
> -    }
> -
> -    /*
> -      Write the event.
> -    */
> -    if (event_info->write(file) ||
> -        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
> -      goto err;
> -
> -    error= 0;
> -
> -err:
> -    if (event_info->use_direct_logging())
> -    {
> -      if (!error)
> -      {
> -        bool synced;
> -        if ((error= flush_and_sync(&synced)))
> -          goto unlock;
> -
> -        if ((error= RUN_HOOK(binlog_storage, after_flush,
> -                 (thd, log_file_name, file->pos_in_file, synced))))
> -        {
> -          sql_print_error("Failed to run 'after_flush' hooks");
> -          goto unlock;
> -        }
> -        signal_update();
> -        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> -      }
> -unlock:
> -      mysql_mutex_unlock(&LOCK_log);
> -    }
> -
> -    if (error)
> -    {
> -      set_write_error(thd);
> -      if (check_write_error(thd) && cache_data &&
> -          stmt_has_updated_non_trans_table(thd))
> -        cache_data->set_incident();
> -    }
> -  }
> -
> -  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
> -    ++m_table_map_version;
> -
> -  DBUG_RETURN(error);
> -}
> -
> -
> -int error_log_print(enum loglevel level, const char *format,
> -                    va_list args)
> -{
> -  return logger.error_log_print(level, format, args);
> -}
> -
> -
> -bool slow_log_print(THD *thd, const char *query, uint query_length,
> -                    ulonglong current_utime)
> -{
> -  return logger.slow_log_print(thd, query, query_length, current_utime);
> -}
> -
> -
> -bool LOGGER::log_command(THD *thd, enum enum_server_command command)
> -{
> -#ifndef NO_EMBEDDED_ACCESS_CHECKS
> -  Security_context *sctx= thd->security_ctx;
> -#endif
> -  /*
> -    Log command if we have at least one log event handler enabled and want
> -    to log this king of commands
> -  */
> -  if (*general_log_handler_list && (what_to_log & (1L << (uint)
> command)))
> +  uint time_buff_len= 0;
> +
> +  mysql_mutex_lock(&LOCK_log);
> +
> +  /* Test if someone closed between the is_open test and lock */
> +  if (is_open())
>    {
> -    if ((thd->variables.option_bits & OPTION_LOG_OFF)
> -#ifndef NO_EMBEDDED_ACCESS_CHECKS
> -         && (sctx->master_access & SUPER_ACL)
> -#endif
> -       )
> -    {
> -      /* No logging */
> -      return FALSE;
> -    }
> +    /* for testing output of timestamp and thread id */
> +    DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;);
>  
> -    return TRUE;
> -  }
> +    /* Note that my_b_write() assumes it knows the length for this */
> +      if (event_time != last_time)
> +      {
> +        last_time= event_time;
>  
> -  return FALSE;
> -}
> +        localtime_r(&event_time, &start);
>  
> +        time_buff_len= my_snprintf(local_time_buff, MAX_TIME_SIZE,
> +                                   "%02d%02d%02d %2d:%02d:%02d\t",
> +                                   start.tm_year % 100, start.tm_mon + 1,
> +                                   start.tm_mday, start.tm_hour,
> +                                   start.tm_min, start.tm_sec);
>  
> -bool general_log_print(THD *thd, enum enum_server_command command,
> -                       const char *format, ...)
> -{
> -  va_list args;
> -  uint error= 0;
> +        if (my_b_write(&log_file, (uchar*) local_time_buff, time_buff_len))
> +          goto err;
> +      }
> +      else
> +        if (my_b_write(&log_file, (uchar*) "\t\t" ,2) < 0)
> +          goto err;
>  
> -  /* Print the message to the buffer if we want to log this king of commands */
> -  if (! logger.log_command(thd, command))
> -    return FALSE;
> +      /* command_type, thread_id */
> +      length= my_snprintf(buff, 32, "%5ld ", (long) thread_id);
>  
> -  va_start(args, format);
> -  error= logger.general_log_print(thd, command, format, args);
> -  va_end(args);
> +    if (my_b_write(&log_file, (uchar*) buff, length))
> +      goto err;
>  
> -  return error;
> -}
> +    if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
> +      goto err;
>  
> -bool general_log_write(THD *thd, enum enum_server_command command,
> -                       const char *query, uint query_length)
> -{
> -  /* Write the message to the log if we want to log this king of commands */
> -  if (logger.log_command(thd, command))
> -    return logger.general_log_write(thd, command, query, query_length);
> +    if (my_b_write(&log_file, (uchar*) "\t", 1))
> +      goto err;
>  
> -  return FALSE;
> -}
> +    /* sql_text */
> +    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
> +      goto err;
>  
> -void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
> -{
> -#ifdef HAVE_REPLICATION
> -  bool check_purge= false;
> -#endif
> -  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> -    mysql_mutex_lock(&LOCK_log);
> -  if ((flags & RP_FORCE_ROTATE) ||
> -      (my_b_tell(&log_file) >= (my_off_t) max_size))
> -  {
> -    new_file_without_locking();
> -#ifdef HAVE_REPLICATION
> -    check_purge= true;
> -#endif
> +    if (my_b_write(&log_file, (uchar*) "\n", 1) ||
> +        flush_io_cache(&log_file))
> +      goto err;
>    }
> -  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> -    mysql_mutex_unlock(&LOCK_log);
>  
> -#ifdef HAVE_REPLICATION
> -  /*
> -    NOTE: Run purge_logs wo/ holding LOCK_log
> -          as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
> -  */
> -  if (check_purge && expire_logs_days)
> +  mysql_mutex_unlock(&LOCK_log);
> +  return FALSE;
> +err:
> +
> +  if (!write_error)
>    {
> -    time_t purge_time= my_time(0) - expire_logs_days*24*60*60;
> -    if (purge_time >= 0)
> -      purge_logs_before_date(purge_time);
> +    write_error= 1;
> +    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
>    }
> -#endif
> -}
> -
> -uint MYSQL_BIN_LOG::next_file_id()
> -{
> -  uint res;
> -  mysql_mutex_lock(&LOCK_log);
> -  res = file_id++;
>    mysql_mutex_unlock(&LOCK_log);
> -  return res;
> +  return TRUE;
>  }
>  
>  
>  /*
> -  Write the contents of a cache to the binary log.
> +  Log a query to the traditional slow log file
>  
>    SYNOPSIS
> -    write_cache()
> -    cache    Cache to write to the binary log
> -    lock_log True if the LOCK_log mutex should be aquired, false otherwise
> -    sync_log True if the log should be flushed and synced
> +    write()
> +
> +    thd               THD of the query
> +    current_time      current timestamp
> +    query_start_arg   command start timestamp
> +    user_host         the pointer to the string with user@host info
> +    user_host_len     length of the user_host string. this is computed once
> +                      and passed to all general log event handlers
> +    query_utime       Amount of time the query took to execute (in microseconds)
> +    lock_utime        Amount of time the query was locked (in microseconds)
> +    is_command        The flag, which determines, whether the sql_text is a
> +                      query or an administrator command.
> +    sql_text          the very text of the query or administrator command
> +                      processed
> +    sql_text_len      the length of sql_text string
>  
>    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.
> - */
> -
> -int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
> -{
> -  Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
> -
> -  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;
> -  long val;
> -  uchar header[LOG_EVENT_HEADER_LEN];
>  
> -  /*
> -    The events in the buffer have incorrect end_log_pos data
> -    (relative to beginning of group rather than absolute),
> -    so we'll recalculate them in situ so the binlog is always
> -    correct, even in the middle of a group. This is possible
> -    because we now know the start position of the group (the
> -    offset of this cache in the log, if you will); all we need
> -    to do is to find all event-headers, and add the position of
> -    the group to the end_log_pos of each event.  This is pretty
> -    straight forward, except that we read the cache in segments,
> -    so an event-header might end up on the cache-border and get
> -    split.
> -  */
> +   Log a query to the slow log file.
>  
> -  group= (uint)my_b_tell(&log_file);
> -  hdr_offs= carry= 0;
> +  RETURN
> +    FALSE - OK
> +    TRUE - error occured
> +*/
>  
> -  do
> -  {
> -    /*
> -      if we only got a partial header in the last iteration,
> -      get the other half now and process a full header.
> -    */
> -    if (unlikely(carry > 0))
> -    {
> -      DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN);
> +bool MYSQL_QUERY_LOG::write(THD *thd, time_t current_time,
> +                            time_t query_start_arg, const char *user_host,
> +                            uint user_host_len, ulonglong query_utime,
> +                            ulonglong lock_utime, bool is_command,
> +                            const char *sql_text, uint sql_text_len)
> +{
> +  bool error= 0;
> +  DBUG_ENTER("MYSQL_QUERY_LOG::write");
>  
> -      /* assemble both halves */
> -      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN -
> carry);
> +  mysql_mutex_lock(&LOCK_log);
>  
> -      /* fix end_log_pos */
> -      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
> -      int4store(&header[LOG_POS_OFFSET], val);
> +  if (!is_open())
> +  {
> +    mysql_mutex_unlock(&LOCK_log);
> +    DBUG_RETURN(0);
> +  }
>  
> -      /* write the first half of the split header */
> -      if (my_b_write(&log_file, header, carry))
> -        return ER_ERROR_ON_WRITE;
> +  if (is_open())
> +  {						// Safety agains reopen
> +    int tmp_errno= 0;
> +    char buff[80], *end;
> +    char query_time_buff[22+7], lock_time_buff[22+7];
> +    uint buff_len;
> +    end= buff;
>  
> -      /*
> -        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);
> +    if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
> +    {
> +      if (current_time != last_time)
> +      {
> +        last_time= current_time;
> +        struct tm start;
> +        localtime_r(&current_time, &start);
>  
> -      /* next event header at ... */
> -      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
> +        buff_len= my_snprintf(buff, sizeof buff,
> +                              "# Time: %02d%02d%02d %2d:%02d:%02d\n",
> +                              start.tm_year % 100, start.tm_mon + 1,
> +                              start.tm_mday, start.tm_hour,
> +                              start.tm_min, start.tm_sec);
>  
> -      carry= 0;
> +        /* Note that my_b_write() assumes it knows the length for this */
> +        if (my_b_write(&log_file, (uchar*) buff, buff_len))
> +          tmp_errno= errno;
> +      }
> +      const uchar uh[]= "# User@Host: ";
> +      if (my_b_write(&log_file, uh, sizeof(uh) - 1))
> +        tmp_errno= errno;
> +      if (my_b_write(&log_file, (uchar*) user_host, user_host_len))
> +        tmp_errno= errno;
> +      if (my_b_write(&log_file, (uchar*) "\n", 1))
> +        tmp_errno= errno;
>      }
> -
> -    /* if there is anything to write, process it. */
> -
> -    if (likely(length > 0))
> +    /* For slow query log */
> +    sprintf(query_time_buff, "%.6f", ulonglong2double(query_utime)/1000000.0);
> +    sprintf(lock_time_buff,  "%.6f", ulonglong2double(lock_utime)/1000000.0);
> +    if (my_b_printf(&log_file,
> +                    "# Query_time: %s  Lock_time: %s"
> +                    " Rows_sent: %lu  Rows_examined: %lu\n",
> +                    query_time_buff, lock_time_buff,
> +                    (ulong) thd->sent_row_count,
> +                    (ulong) thd->examined_row_count) == (uint) -1)
> +      tmp_errno= errno;
> +    if (thd->db && strcmp(thd->db, db))
> +    {						// Database changed
> +      if (my_b_printf(&log_file,"use %s;\n",thd->db) == (uint) -1)
> +        tmp_errno= errno;
> +      strmov(db,thd->db);
> +    }
> +    if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
>      {
> -      /*
> -        process all event-headers in this (partial) cache.
> -        if next header is beyond current read-buffer,
> -        we'll get it later (though not necessarily in the
> -        very next iteration, just "eventually").
> -      */
> -
> -      while (hdr_offs < length)
> +      end=strmov(end, ",last_insert_id=");
> +      end=longlong10_to_str((longlong)
> +                           
> thd->first_successful_insert_id_in_prev_stmt_for_binlog,
> +                            end, -10);
> +    }
> +    // Save value if we do an insert.
> +    if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
> +    {
> +      if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
>        {
> -        /*
> -          partial header only? save what we can get, process once
> -          we get the rest.
> -        */
> -
> -        if (hdr_offs + LOG_EVENT_HEADER_LEN > length)
> -        {
> -          carry= length - hdr_offs;
> -          memcpy(header, (char *)cache->read_pos + hdr_offs, carry);
> -          length= hdr_offs;
> -        }
> -        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;
> -
> -          /* fix end_log_pos */
> -          val= uint4korr(log_pos) + group;
> -          int4store(log_pos, val);
> -
> -          /* next event header at ... */
> -          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
> -          hdr_offs += uint4korr(log_pos);
> -
> -        }
> +        end=strmov(end,",insert_id=");
> +        end=longlong10_to_str((longlong)
> +                             
> thd->auto_inc_intervals_in_cur_stmt_for_binlog.minimum(),
> +                              end, -10);
>        }
> -
> -      /*
> -        Adjust hdr_offs. Note that it may still point beyond the segment
> -        read in the next iteration; if the current event is very long,
> -        it may take a couple of read-iterations (and subsequent adjustments
> -        of hdr_offs) for it to point into the then-current segment.
> -        If we have a split header (!carry), hdr_offs will be set at the
> -        beginning of the next iteration, overwriting the value we set here:
> -      */
> -      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;
> -    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);
> -
> -  return 0;                                     // All OK
> -}
> -
> -/*
> -  Helper function to get the error code of the query to be binlogged.
> - */
> -int query_error_code(THD *thd, bool not_killed)
> -{
> -  int error;
> -  
> -  if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
> -  {
> -    error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
> -
> -    /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or
> -       ER_QUERY_INTERRUPTED, So here we need to make sure that error
> -       is not set to these errors when specified not_killed by the
> -       caller.
> +    /*
> +      This info used to show up randomly, depending on whether the query
> +      checked the query start time or not. now we always write current
> +      timestamp to the slow log
>      */
> -    if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED)
> -      error= 0;
> -  }
> -  else
> -  {
> -    /* killed status for DELAYED INSERT thread should never be used */
> -    DBUG_ASSERT(!(thd->system_thread & SYSTEM_THREAD_DELAYED_INSERT));
> -    error= thd->killed_errno();
> -  }
> -
> -  return error;
> -}
> +    end= strmov(end, ",timestamp=");
> +    end= int10_to_str((long) current_time, end, 10);
>  
> -bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
> -{
> -  uint error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
> -  LEX_STRING const write_error_msg=
> -    { C_STRING_WITH_LEN("error writing to the binary log") };
> -  Incident incident= INCIDENT_LOST_EVENTS;
> -  Incident_log_event ev(thd, incident, write_error_msg);
> -  if (lock)
> -    mysql_mutex_lock(&LOCK_log);
> -  error= ev.write(&log_file);
> -  if (lock)
> -  {
> -    if (!error && !(error= flush_and_sync(0)))
> +    if (end != buff)
>      {
> -      signal_update();
> -      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> +      *end++=';';
> +      *end='\n';
> +      if (my_b_write(&log_file, (uchar*) "SET ", 4) ||
> +          my_b_write(&log_file, (uchar*) buff + 1, (uint) (end-buff)))
> +        tmp_errno= errno;
>      }
> -    mysql_mutex_unlock(&LOCK_log);
> -  }
> -  DBUG_RETURN(error);
> -}
> -
> -/**
> -  Write a cached log entry to the binary log.
> -  - To support transaction over replication, we wrap the transaction
> -  with BEGIN/COMMIT or BEGIN/ROLLBACK in the binary log.
> -  We want to write a BEGIN/ROLLBACK block when a non-transactional table
> -  was updated in a transaction which was rolled back. This is to ensure
> -  that the same updates are run on the slave.
> -
> -  @param thd
> -  @param cache		The cache to copy to the binlog
> -  @param commit_event   The commit event to print after writing the
> -                        contents of the cache.
> -  @param incident       Defines if an incident event should be created to
> -                        notify that some non-transactional changes did
> -                        not get into the binlog.
> -
> -  @note
> -    We only come here if there is something in the cache.
> -  @note
> -    The thing in the cache is always a complete transaction.
> -  @note
> -    'cache' needs to be reinitialized after this functions returns.
> -*/
> -
> -bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
> -                          bool incident)
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
> -  mysql_mutex_lock(&LOCK_log);
> -
> -  DBUG_ASSERT(is_open());
> -  if (likely(is_open()))                       // Should always be true
> -  {
> -    /*
> -      We only bother to write to the binary log if there is anything
> -      to write.
> -     */
> -    if (my_b_tell(cache) > 0)
> +    if (is_command)
> +    {
> +      end= strxmov(buff, "# administrator command: ", NullS);
> +      buff_len= (ulong) (end - buff);
> +      my_b_write(&log_file, (uchar*) buff, buff_len);
> +    }
> +    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len) ||
> +        my_b_write(&log_file, (uchar*) ";\n",2) ||
> +        flush_io_cache(&log_file))
> +      tmp_errno= errno;
> +    if (tmp_errno)
>      {
> -      /*
> -        Log "BEGIN" at the beginning of every transaction.  Here, a
> -        transaction is either a BEGIN..COMMIT block or a single
> -        statement in autocommit mode.
> -      */
> -      Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
> -      if (qinfo.write(&log_file))
> -        goto err;
> -      DBUG_EXECUTE_IF("crash_before_writing_xid",
> -                      {
> -                        if ((write_error= write_cache(cache, false, true)))
> -                          DBUG_PRINT("info", ("error writing binlog cache: %d",
> -                                               write_error));
> -                        DBUG_PRINT("info", ("crashing before writing xid"));
> -                        DBUG_ABORT();
> -                      });
> -
> -      if ((write_error= write_cache(cache, false, false)))
> -        goto err;
> -
> -      if (commit_event && commit_event->write(&log_file))
> -        goto err;
> -
> -      if (incident && write_incident(thd, FALSE))
> -        goto err;
> -
> -      bool synced= 0;
> -      if (flush_and_sync(&synced))
> -        goto err;
> -      DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
> -      if (cache->error)				// Error on read
> -      {
> -        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
> -        write_error=1;				// Don't give more errors
> -        goto err;
> -      }
> -
> -      if (RUN_HOOK(binlog_storage, after_flush,
> -                   (thd, log_file_name, log_file.pos_in_file, synced)))
> +      error= 1;
> +      if (! write_error)
>        {
> -        sql_print_error("Failed to run 'after_flush' hooks");
> -        write_error=1;
> -        goto err;
> +        write_error= 1;
> +        sql_print_error(ER(ER_ERROR_ON_WRITE), name, error);
>        }
> -
> -      signal_update();
> -    }
> -
> -    /*
> -      if commit_event is Xid_log_event, increase the number of
> -      prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
> -      if there're prepared xids in it - see the comment in new_file() for
> -      an explanation.
> -      If the commit_event is not Xid_log_event (then it's a Query_log_event)
> -      rotate binlog, if necessary.
> -    */
> -    if (commit_event && commit_event->get_type_code() == XID_EVENT)
> -    {
> -      mysql_mutex_lock(&LOCK_prep_xids);
> -      prepared_xids++;
> -      mysql_mutex_unlock(&LOCK_prep_xids);
>      }
> -    else
> -      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
>    }
>    mysql_mutex_unlock(&LOCK_log);
> +  DBUG_RETURN(error);
> +}
>  
> -  DBUG_RETURN(0);
>  
> -err:
> -  if (!write_error)
> +/**
> +  @todo
> +  The following should be using fn_format();  We just need to
> +  first change fn_format() to cut the file name if it's too long.
> +*/
> +const char *MYSQL_LOG::generate_name(const char *log_name,
> +                                      const char *suffix,
> +                                      bool strip_ext, char *buff)
> +{
> +  if (!log_name || !log_name[0])
>    {
> -    write_error= 1;
> -    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> +    strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
> +    return (const char *)
> +      fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
>    }
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_RETURN(1);
> +  // get rid of extension if the log is binary to avoid problems
> +  if (strip_ext)
> +  {
> +    char *p= fn_ext(log_name);
> +    uint length= (uint) (p - log_name);
> +    strmake(buff, log_name, min(length, FN_REFLEN-1));
> +    return (const char*)buff;
> +  }
> +  return log_name;
>  }
>  
>  
> -/**
> -  Wait until we get a signal that the relay log has been updated.
> -
> -  @param thd		Thread variable
> -
> -  @note
> -    One must have a lock on LOCK_log before calling this function.
> -    This lock will be released before return! That's required by
> -    THD::enter_cond() (see NOTES in sql_class.h).
> -*/
>  
> -void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
> +int error_log_print(enum loglevel level, const char *format,
> +                    va_list args)
>  {
> -  const char *old_msg;
> -  DBUG_ENTER("wait_for_update_relay_log");
> -
> -  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> -                           "Slave has read all relay log; "
> -                           "waiting for the slave I/O "
> -                           "thread to update it" );
> -  mysql_cond_wait(&update_cond, &LOCK_log);
> -  thd->exit_cond(old_msg);
> -  DBUG_VOID_RETURN;
> +  return logger.error_log_print(level, format, args);
>  }
>  
> -/**
> -  Wait until we get a signal that the binary log has been updated.
> -  Applies to master only.
> -     
> -  NOTES
> -  @param[in] thd        a THD struct
> -  @param[in] timeout    a pointer to a timespec;
> -                        NULL means to wait w/o timeout.
> -  @retval    0          if got signalled on update
> -  @retval    non-0      if wait timeout elapsed
> -  @note
> -    LOCK_log must be taken before calling this function.
> -    LOCK_log is being released while the thread is waiting.
> -    LOCK_log is released by the caller.
> -*/
>  
> -int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
> -                                           const struct timespec *timeout)
> +bool slow_log_print(THD *thd, const char *query, uint query_length,
> +                    ulonglong current_utime)
>  {
> -  int ret= 0;
> -  const char* old_msg = thd->proc_info;
> -  DBUG_ENTER("wait_for_update_bin_log");
> -  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> -                           "Master has sent all binlog to slave; "
> -                           "waiting for binlog to be updated");
> -  if (!timeout)
> -    mysql_cond_wait(&update_cond, &LOCK_log);
> -  else
> -    ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
> -                              const_cast<struct timespec *>(timeout));
> -  DBUG_RETURN(ret);
> +  return logger.slow_log_print(thd, query, query_length, current_utime);
>  }
>  
>  
> -/**
> -  Close the log file.
> -
> -  @param exiting     Bitmask for one or more of the following bits:
> -          - LOG_CLOSE_INDEX : if we should close the index file
> -          - LOG_CLOSE_TO_BE_OPENED : if we intend to call open
> -                                     at once after close.
> -          - LOG_CLOSE_STOP_EVENT : write a 'stop' event to the log
> -
> -  @note
> -    One can do an open on the object at once after doing a close.
> -    The internal structures are not freed until cleanup() is called
> -*/
> -
> -void MYSQL_BIN_LOG::close(uint exiting)
> -{					// One can't set log_type here!
> -  DBUG_ENTER("MYSQL_BIN_LOG::close");
> -  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
> -  if (log_state == LOG_OPENED)
> -  {
> -#ifdef HAVE_REPLICATION
> -    if (log_type == LOG_BIN && !no_auto_events &&
> -	(exiting & LOG_CLOSE_STOP_EVENT))
> -    {
> -      Stop_log_event s;
> -      s.write(&log_file);
> -      bytes_written+= s.data_written;
> -      signal_update();
> -    }
> -#endif /* HAVE_REPLICATION */
> -
> -    /* 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 org_position= mysql_file_tell(log_file.file, MYF(0));
> -      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
> -      mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
> -      /*
> -        Restore position so that anything we have in the IO_cache is written
> -        to the correct position.
> -        We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the
> -        original position on system that doesn't support pwrite().
> -      */
> -      mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
> -    }
> -
> -    /* this will cleanup IO_CACHE, sync and close the file */
> -    MYSQL_LOG::close(exiting);
> -  }
> -
> +bool LOGGER::log_command(THD *thd, enum enum_server_command command)
> +{
> +#ifndef NO_EMBEDDED_ACCESS_CHECKS
> +  Security_context *sctx= thd->security_ctx;
> +#endif
>    /*
> -    The following test is needed even if is_open() is not set, as we may have
> -    called a not complete close earlier and the index file is still open.
> +    Log command if we have at least one log event handler enabled and want
> +    to log this king of commands
>    */
> -
> -  if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
> +  if (*general_log_handler_list && (what_to_log & (1L << (uint)
> command)))
>    {
> -    end_io_cache(&index_file);
> -    if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error)
> +    if ((thd->variables.option_bits & OPTION_LOG_OFF)
> +#ifndef NO_EMBEDDED_ACCESS_CHECKS
> +         && (sctx->master_access & SUPER_ACL)
> +#endif
> +       )
>      {
> -      write_error= 1;
> -      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
> +      /* No logging */
> +      return FALSE;
>      }
> +
> +    return TRUE;
>    }
> -  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> -  safeFree(name);
> -  DBUG_VOID_RETURN;
> +
> +  return FALSE;
>  }
>  
>  
> -void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
> +bool general_log_print(THD *thd, enum enum_server_command command,
> +                       const char *format, ...)
>  {
> -  /*
> -    We need to take locks, otherwise this may happen:
> -    new_file() is called, calls open(old_max_size), then before open() starts,
> -    set_max_size() sets max_size to max_size_arg, then open() starts and
> -    uses the old_max_size argument, so max_size_arg has been overwritten and
> -    it's like if the SET command was never run.
> -  */
> -  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
> -  mysql_mutex_lock(&LOCK_log);
> -  if (is_open())
> -    max_size= max_size_arg;
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_VOID_RETURN;
> +  va_list args;
> +  uint error= 0;
> +
> +  /* Print the message to the buffer if we want to log this king of commands */
> +  if (! logger.log_command(thd, command))
> +    return FALSE;
> +
> +  va_start(args, format);
> +  error= logger.general_log_print(thd, command, format, args);
> +  va_end(args);
> +
> +  return error;
> +}
> +
> +bool general_log_write(THD *thd, enum enum_server_command command,
> +                       const char *query, uint query_length)
> +{
> +  /* Write the message to the log if we want to log this king of commands */
> +  if (logger.log_command(thd, command))
> +    return logger.general_log_write(thd, command, query, query_length);
> +
> +  return FALSE;
>  }
>  
>  
> +
>  /**
>    Check if a string is a valid number.
>  
> @@ -5482,14 +2051,6 @@ bool flush_error_log()
>     return result;
>  }
>  
> -void MYSQL_BIN_LOG::signal_update()
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
> -  signal_cnt++;
> -  mysql_cond_broadcast(&update_cond);
> -  DBUG_VOID_RETURN;
> -}
> -
>  #ifdef _WIN32
>  static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
>                                          size_t length, size_t buffLen)
> @@ -6123,232 +2684,3 @@ int TC_LOG::using_heuristic_recover()
>    sql_print_information("Please restart mysqld without --tc-heuristic-recover");
>    return 1;
>  }
> -
> -/****** transaction coordinator log for 2pc - binlog() based solution ******/
> -#define TC_LOG_BINLOG MYSQL_BIN_LOG
> -
> -/**
> -  @todo
> -  keep in-memory list of prepared transactions
> -  (add to list in log(), remove on unlog())
> -  and copy it to the new binlog if rotated
> -  but let's check the behaviour of tc_log_page_waits first!
> -*/
> -
> -int TC_LOG_BINLOG::open(const char *opt_name)
> -{
> -  LOG_INFO log_info;
> -  int      error= 1;
> -
> -  DBUG_ASSERT(total_ha_2pc > 1);
> -  DBUG_ASSERT(opt_name && opt_name[0]);
> -
> -  mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
> -                   &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
> -  mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
> -
> -  if (!my_b_inited(&index_file))
> -  {
> -    /* There was a failure to open the index file, can't open the binlog */
> -    cleanup();
> -    return 1;
> -  }
> -
> -  if (using_heuristic_recover())
> -  {
> -    /* generate a new binlog to mask a corrupted one */
> -    open(opt_name, LOG_BIN, 0, WRITE_CACHE, 0, max_binlog_size, 0, TRUE);
> -    cleanup();
> -    return 1;
> -  }
> -
> -  if ((error= find_log_pos(&log_info, NullS, 1)))
> -  {
> -    if (error != LOG_INFO_EOF)
> -      sql_print_error("find_log_pos() failed (error: %d)", error);
> -    else
> -      error= 0;
> -    goto err;
> -  }
> -
> -  {
> -    const char *errmsg;
> -    IO_CACHE    log;
> -    File        file;
> -    Log_event  *ev=0;
> -    Format_description_log_event fdle(BINLOG_VERSION);
> -    char        log_name[FN_REFLEN];
> -
> -    if (! fdle.is_valid())
> -      goto err;
> -
> -    do
> -    {
> -      strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
> -    } while (!(error= find_next_log(&log_info, 1)));
> -
> -    if (error !=  LOG_INFO_EOF)
> -    {
> -      sql_print_error("find_log_pos() failed (error: %d)", error);
> -      goto err;
> -    }
> -
> -    if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
> -    {
> -      sql_print_error("%s", errmsg);
> -      goto err;
> -    }
> -
> -    if ((ev= Log_event::read_log_event(&log, 0, &fdle)) &&
> -        ev->get_type_code() == FORMAT_DESCRIPTION_EVENT &&
> -        ev->flags & LOG_EVENT_BINLOG_IN_USE_F)
> -    {
> -      sql_print_information("Recovering after a crash using %s", opt_name);
> -      error= recover(&log, (Format_description_log_event *)ev);
> -    }
> -    else
> -      error=0;
> -
> -    delete ev;
> -    end_io_cache(&log);
> -    mysql_file_close(file, MYF(MY_WME));
> -
> -    if (error)
> -      goto err;
> -  }
> -
> -err:
> -  return error;
> -}
> -
> -/** This is called on shutdown, after ha_panic. */
> -void TC_LOG_BINLOG::close()
> -{
> -  DBUG_ASSERT(prepared_xids==0);
> -  mysql_mutex_destroy(&LOCK_prep_xids);
> -  mysql_cond_destroy(&COND_prep_xids);
> -}
> -
> -/**
> -  @todo
> -  group commit
> -
> -  @retval
> -    0    error
> -  @retval
> -    1    success
> -*/
> -int TC_LOG_BINLOG::log_xid(THD *thd, my_xid xid)
> -{
> -  DBUG_ENTER("TC_LOG_BINLOG::log");
> -  Xid_log_event xle(thd, xid);
> -  binlog_cache_mngr *cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -  /*
> -    We always commit the entire transaction when writing an XID. Also
> -    note that the return value is inverted.
> -   */
> -  DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) &&
> -              !binlog_flush_trx_cache(thd, cache_mngr, &xle));
> -}
> -
> -void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
> -{
> -  mysql_mutex_lock(&LOCK_prep_xids);
> -  DBUG_ASSERT(prepared_xids > 0);
> -  if (--prepared_xids == 0) {
> -    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> -    mysql_cond_signal(&COND_prep_xids);
> -  }
> -  mysql_mutex_unlock(&LOCK_prep_xids);
> -  rotate_and_purge(0);     // as ::write() did not rotate
> -}
> -
> -int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
> -{
> -  Log_event  *ev;
> -  HASH xids;
> -  MEM_ROOT mem_root;
> -
> -  if (! fdle->is_valid() ||
> -      my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
> -                   sizeof(my_xid), 0, 0, MYF(0)))
> -    goto err1;
> -
> -  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
> -
> -  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())
> -  {
> -    if (ev->get_type_code() == XID_EVENT)
> -    {
> -      Xid_log_event *xev=(Xid_log_event *)ev;
> -      uchar *x= (uchar *) memdup_root(&mem_root, (uchar*) &xev->xid,
> -                                      sizeof(xev->xid));
> -      if (!x || my_hash_insert(&xids, x))
> -        goto err2;
> -    }
> -    delete ev;
> -  }
> -
> -  if (ha_recover(&xids))
> -    goto err2;
> -
> -  free_root(&mem_root, MYF(0));
> -  my_hash_free(&xids);
> -  return 0;
> -
> -err2:
> -  free_root(&mem_root, MYF(0));
> -  my_hash_free(&xids);
> -err1:
> -  sql_print_error("Crash recovery failed. Either correct the problem "
> -                  "(if it's, for example, out of memory error) and restart, "
> -                  "or delete (or rename) binary log and start mysqld with "
> -                  "--tc-heuristic-recover={commit|rollback}");
> -  return 1;
> -}
> -
> -
> -#ifdef INNODB_COMPATIBILITY_HOOKS
> -/**
> -  Get the file name of the MySQL binlog.
> -  @return the name of the binlog file
> -*/
> -extern "C"
> -const char* mysql_bin_log_file_name(void)
> -{
> -  return mysql_bin_log.get_log_fname();
> -}
> -/**
> -  Get the current position of the MySQL binlog.
> -  @return byte offset from the beginning of the binlog
> -*/
> -extern "C"
> -ulonglong mysql_bin_log_file_pos(void)
> -{
> -  return (ulonglong) mysql_bin_log.get_log_file()->pos_in_file;
> -}
> -#endif /* INNODB_COMPATIBILITY_HOOKS */
> -
> -
> -struct st_mysql_storage_engine binlog_storage_engine=
> -{ MYSQL_HANDLERTON_INTERFACE_VERSION };
> -
> -mysql_declare_plugin(binlog)
> -{
> -  MYSQL_STORAGE_ENGINE_PLUGIN,
> -  &binlog_storage_engine,
> -  "binlog",
> -  "MySQL AB",
> -  "This is a pseudo storage engine to represent the binlog in a transaction",
> -  PLUGIN_LICENSE_GPL,
> -  binlog_init, /* Plugin Init */
> -  NULL, /* Plugin Deinit */
> -  0x0100 /* 1.0 */,
> -  NULL,                       /* status variables                */
> -  NULL,                       /* system variables                */
> -  NULL                        /* config options                  */
> -}
> -mysql_declare_plugin_end;
> 
> === modified file 'sql/log.h'
> --- a/sql/log.h	2010-04-20 11:58:28 +0000
> +++ b/sql/log.h	2010-06-21 06:01:50 +0000
> @@ -19,17 +19,6 @@
>  #include "unireg.h"                    // REQUIRED: for other includes
>  #include "handler.h"                            /* my_xid */
>  
> -class Relay_log_info;
> -
> -class Format_description_log_event;
> -
> -bool trans_has_updated_trans_table(const THD* thd);
> -bool stmt_has_updated_trans_table(const THD *thd);
> -bool use_trans_cache(const THD* thd, bool is_transactional);
> -bool ending_trans(THD* thd, const bool all);
> -bool trans_has_updated_non_trans_table(const THD* thd);
> -bool stmt_has_updated_non_trans_table(const THD* thd);
> -
>  /*
>    Transaction Coordinator log - a base abstract class
>    for two different implementations
> @@ -144,8 +133,6 @@ extern TC_LOG_DUMMY tc_log_dummy;
>  */
>  #define LOG_WARN_UNIQUE_FN_EXT_LEFT 1000
>  
> -class Relay_log_info;
> -
>  #ifdef HAVE_PSI_INTERFACE
>  extern PSI_mutex_key key_LOG_INFO_lock;
>  #endif
> @@ -178,9 +165,6 @@ typedef struct st_log_info
>  #define LOG_FILE       2
>  #define LOG_TABLE      4
>  
> -class Log_event;
> -class Rows_log_event;
> -
>  enum enum_log_type { LOG_UNKNOWN, LOG_NORMAL, LOG_BIN };
>  enum enum_log_state { LOG_OPENED, LOG_CLOSED, LOG_TO_BE_OPENED };
>  
> @@ -254,228 +238,6 @@ private:
>    time_t last_time;
>  };
>  
> -class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
> -{
> - private:
> -  /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
> -  mysql_mutex_t LOCK_index;
> -  mysql_mutex_t LOCK_prep_xids;
> -  mysql_cond_t  COND_prep_xids;
> -  mysql_cond_t update_cond;
> -  ulonglong bytes_written;
> -  IO_CACHE index_file;
> -  char index_file_name[FN_REFLEN];
> -  /*
> -    purge_file is a temp file used in purge_logs so that the index file
> -    can be updated before deleting files from disk, yielding better crash
> -    recovery. It is created on demand the first time purge_logs is called
> -    and then reused for subsequent calls. It is cleaned up in cleanup().
> -  */
> -  IO_CACHE purge_index_file;
> -  char purge_index_file_name[FN_REFLEN];
> -  /*
> -     The max size before rotation (usable only if log_type == LOG_BIN: binary
> -     logs and relay logs).
> -     For a binlog, max_size should be max_binlog_size.
> -     For a relay log, it should be max_relay_log_size if this is non-zero,
> -     max_binlog_size otherwise.
> -     max_size is set in init(), and dynamically changed (when one does SET
> -     GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
> -     fix_max_relay_log_size).
> -  */
> -  ulong max_size;
> -  long prepared_xids; /* for tc log - number of xids to remember */
> -  // current file sequence number for load data infile binary logging
> -  uint file_id;
> -  uint open_count;				// For replication
> -  int readers_count;
> -  bool need_start_event;
> -  /*
> -    no_auto_events means we don't want any of these automatic events :
> -    Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't
> -    want a Rotate_log event to be written to the relay log. When we start a
> -    relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
> -    In 5.0 it's 0 for relay logs too!
> -  */
> -  bool no_auto_events;
> -
> -  ulonglong m_table_map_version;
> -
> -  /* pointer to the sync period variable, for binlog this will be
> -     sync_binlog_period, for relay log this will be
> -     sync_relay_log_period
> -  */
> -  uint *sync_period_ptr;
> -  uint sync_counter;
> -
> -  inline uint get_sync_period()
> -  {
> -    return *sync_period_ptr;
> -  }
> -
> -  int write_to_file(IO_CACHE *cache);
> -  /*
> -    This is used to start writing to a new log file. The difference from
> -    new_file() is locking. new_file_without_locking() does not acquire
> -    LOCK_log.
> -  */
> -  void new_file_without_locking();
> -  void new_file_impl(bool need_lock);
> -
> -public:
> -  MYSQL_LOG::generate_name;
> -  MYSQL_LOG::is_open;
> -
> -  /* This is relay log */
> -  bool is_relay_log;
> -  ulong signal_cnt;  // update of the counter is checked by heartbeat
> -  /*
> -    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
> -    necessary to have 2 distinct objects, because the I/O thread may be reading
> -    events in a different format from what the SQL thread is reading (consider
> -    the case of a master which has been upgraded from 5.0 to 5.1 without doing
> -    RESET MASTER, or from 4.x to 5.0).
> -  */
> -  Format_description_log_event *description_event_for_exec,
> -    *description_event_for_queue;
> -
> -  MYSQL_BIN_LOG(uint *sync_period);
> -  /*
> -    note that there's no destructor ~MYSQL_BIN_LOG() !
> -    The reason is that we don't want it to be automatically called
> -    on exit() - but only during the correct shutdown process
> -  */
> -
> -  int open(const char *opt_name);
> -  void close();
> -  int log_xid(THD *thd, my_xid xid);
> -  void unlog(ulong cookie, my_xid xid);
> -  int recover(IO_CACHE *log, Format_description_log_event *fdle);
> -#if !defined(MYSQL_CLIENT)
> -  bool is_table_mapped(TABLE *table) const
> -  {
> -    return table->s->table_map_version == table_map_version();
> -  }
> -
> -  ulonglong table_map_version() const { return m_table_map_version; }
> -  void update_table_map_version() { ++m_table_map_version; }
> -
> -  int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
> -                                       bool is_transactional);
> -  int remove_pending_rows_event(THD *thd, bool is_transactional);
> -
> -#endif /* !defined(MYSQL_CLIENT) */
> -  void reset_bytes_written()
> -  {
> -    bytes_written = 0;
> -  }
> -  void harvest_bytes_written(ulonglong* counter)
> -  {
> -#ifndef DBUG_OFF
> -    char buf1[22],buf2[22];
> -#endif
> -    DBUG_ENTER("harvest_bytes_written");
> -    (*counter)+=bytes_written;
> -    DBUG_PRINT("info",("counter: %s  bytes_written: %s", llstr(*counter,buf1),
> -		       llstr(bytes_written,buf2)));
> -    bytes_written=0;
> -    DBUG_VOID_RETURN;
> -  }
> -  void set_max_size(ulong max_size_arg);
> -  void signal_update();
> -  void wait_for_update_relay_log(THD* thd);
> -  int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
> -  void set_need_start_event() { need_start_event = 1; }
> -  void init(bool no_auto_events_arg, ulong max_size);
> -  void init_pthread_objects();
> -  void cleanup();
> -  bool open(const char *log_name,
> -            enum_log_type log_type,
> -            const char *new_name,
> -	    enum cache_type io_cache_type_arg,
> -	    bool no_auto_events_arg, ulong max_size,
> -            bool null_created,
> -            bool need_mutex);
> -  bool open_index_file(const char *index_file_name_arg,
> -                       const char *log_name, bool need_mutex);
> -  /* Use this to start writing a new log file */
> -  void new_file();
> -
> -  bool write(Log_event* event_info);
> -  bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
> -  bool write_incident(THD *thd, bool lock);
> -
> -  int  write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
> -  void set_write_error(THD *thd);
> -  bool check_write_error(THD *thd);
> -
> -  void start_union_events(THD *thd, query_id_t query_id_param);
> -  void stop_union_events(THD *thd);
> -  bool is_query_in_union(THD *thd, query_id_t query_id_param);
> -
> -  /*
> -    v stands for vector
> -    invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
> -  */
> -  bool appendv(const char* buf,uint len,...);
> -  bool append(Log_event* ev);
> -
> -  void make_log_name(char* buf, const char* log_ident);
> -  bool is_active(const char* log_file_name);
> -  int update_log_index(LOG_INFO* linfo, bool need_update_threads);
> -  void rotate_and_purge(uint flags);
> -  /**
> -     Flush binlog cache and synchronize to disk.
> -
> -     This function flushes events in binlog cache to binary log file,
> -     it will do synchronizing according to the setting of system
> -     variable 'sync_binlog'. If file is synchronized, @c synced will
> -     be set to 1, otherwise 0.
> -
> -     @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
> -
> -     @retval 0 Success
> -     @retval other Failure
> -  */
> -  bool flush_and_sync(bool *synced);
> -  int purge_logs(const char *to_log, bool included,
> -                 bool need_mutex, bool need_update_threads,
> -                 ulonglong *decrease_log_space);
> -  int purge_logs_before_date(time_t purge_time);
> -  int purge_first_log(Relay_log_info* rli, bool included);
> -  int set_purge_index_file_name(const char *base_file_name);
> -  int open_purge_index_file(bool destroy);
> -  bool is_inited_purge_index_file();
> -  int close_purge_index_file();
> -  int clean_purge_index_file();
> -  int sync_purge_index_file();
> -  int register_purge_index_entry(const char* entry);
> -  int register_create_index_entry(const char* entry);
> -  int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> -                        bool need_mutex);
> -  bool reset_logs(THD* thd);
> -  void close(uint exiting);
> -
> -  // iterating through the log index file
> -  int find_log_pos(LOG_INFO* linfo, const char* log_name,
> -		   bool need_mutex);
> -  int find_next_log(LOG_INFO* linfo, bool need_mutex);
> -  int get_current_log(LOG_INFO* linfo);
> -  int raw_get_current_log(LOG_INFO* linfo);
> -  uint next_file_id();
> -  inline char* get_index_fname() { return index_file_name;}
> -  inline char* get_log_fname() { return log_file_name; }
> -  inline char* get_name() { return name; }
> -  inline mysql_mutex_t* get_log_lock() { return &LOCK_log; }
> -  inline IO_CACHE* get_log_file() { return &log_file; }
> -
> -  inline void lock_index() { mysql_mutex_lock(&LOCK_index);}
> -  inline void unlock_index() { mysql_mutex_unlock(&LOCK_index);}
> -  inline IO_CACHE *get_index_file() { return &index_file;}
> -  inline uint32 get_open_count() { return open_count; }
> -};
> -
>  class Log_event_handler
>  {
>  public:
> @@ -674,12 +436,8 @@ bool general_log_write(THD *thd, enum en
>  void sql_perror(const char *message);
>  bool flush_error_log();
>  
> -File open_binlog(IO_CACHE *log, const char *log_file_name,
> -                 const char **errmsg);
> -
>  char *make_log_name(char *buff, const char *name, const char* log_ext);
>  
> -extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
>  extern LOGGER logger;
>  
>  #endif /* LOG_H */
> 
> === modified file 'sql/log_event.cc'
> --- a/sql/log_event.cc	2010-05-14 18:38:28 +0000
> +++ b/sql/log_event.cc	2010-06-21 06:01:50 +0000
> @@ -37,7 +37,7 @@
>  #include "tztime.h"     // struct Time_zone
>  #include "sql_load.h"   // mysql_load
>  #include "sql_db.h"     // load_db_opt_by_name
> -#include "slave.h"
> +#include "rpl_slave.h"
>  #include "rpl_rli.h"
>  #include "rpl_mi.h"
>  #include "rpl_filter.h"
> 
> === modified file 'sql/log_event.h'
> --- a/sql/log_event.h	2010-04-01 19:34:09 +0000
> +++ b/sql/log_event.h	2010-06-21 06:01:50 +0000
> @@ -1755,8 +1755,7 @@ public:        /* !!! Public in this pat
>    @class Slave_log_event
>  
>    Note that this class is currently not used at all; no code writes a
> -  @c Slave_log_event (though some code in @c repl_failsafe.cc reads @c
> -  Slave_log_event).  So it's not a problem if this code is not
> +  @c Slave_log_event.  So it's not a problem if this code is not
>    maintained.
>  
>    @section Slave_log_event_binary_format Binary Format
> 
> === modified file 'sql/mysqld.cc'
> --- a/sql/mysqld.cc	2010-04-19 08:29:52 +0000
> +++ b/sql/mysqld.cc	2010-06-21 06:01:50 +0000
> @@ -53,11 +53,10 @@
>  #include <m_ctype.h>
>  #include <my_dir.h>
>  #include <my_bit.h>
> -#include "slave.h"
> +#include "rpl_slave.h"
> +#include "rpl_master.h"
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
>  #include "rpl_filter.h"
> -#include "repl_failsafe.h"
>  #include <my_stacktrace.h>
>  #include "mysqld_suffix.h"
>  #include "mysys_err.h"
> @@ -540,7 +539,6 @@ ulong slow_launch_threads = 0;
>  uint sync_binlog_period= 0, sync_relaylog_period= 0,
>       sync_relayloginfo_period= 0, sync_masterinfo_period= 0;
>  ulong expire_logs_days = 0;
> -ulong rpl_recovery_rank=0;
>  
>  const double log_10[] = {
>    1e000, 1e001, 1e002, 1e003, 1e004, 1e005, 1e006, 1e007, 1e008, 1e009,
> @@ -1615,10 +1613,6 @@ static void clean_up_mutexes()
>    OPENSSL_free(openssl_stdlocks);
>  #endif
>  #endif
> -#ifdef HAVE_REPLICATION
> -  mysql_mutex_destroy(&LOCK_rpl_status);
> -  mysql_cond_destroy(&COND_rpl_status);
> -#endif
>    mysql_mutex_destroy(&LOCK_active_mi);
>    mysql_rwlock_destroy(&LOCK_sys_init_connect);
>    mysql_rwlock_destroy(&LOCK_sys_init_slave);
> @@ -3820,10 +3814,6 @@ static int init_thread_environment()
>    mysql_cond_init(key_COND_thread_cache, &COND_thread_cache, NULL);
>    mysql_cond_init(key_COND_flush_thread_cache, &COND_flush_thread_cache, NULL);
>    mysql_cond_init(key_COND_manager, &COND_manager, NULL);
> -#ifdef HAVE_REPLICATION
> -  mysql_mutex_init(key_LOCK_rpl_status, &LOCK_rpl_status, MY_MUTEX_INIT_FAST);
> -  mysql_cond_init(key_COND_rpl_status, &COND_rpl_status, NULL);
> -#endif
>    mysql_mutex_init(key_LOCK_server_started,
>                     &LOCK_server_started, MY_MUTEX_INIT_FAST);
>    mysql_cond_init(key_COND_server_started, &COND_server_started, NULL);
> @@ -6129,9 +6119,6 @@ thread is in the master's binlogs.",
>     (uchar**) &master_retry_count, (uchar**) &master_retry_count, 0,
> GET_ULONG,
>     REQUIRED_ARG, 3600*24, 0, 0, 0, 0, 0},
>  #ifdef HAVE_REPLICATION
> -  {"init-rpl-role", 0, "Set the replication role.",
> -    (uchar**)&rpl_status, (uchar**)&rpl_status, &rpl_role_typelib,
> -   GET_ENUM, REQUIRED_ARG, 0, 0, 0, 0, 0, 0},
>    {"max-binlog-dump-events", 0,
>     "Option used by mysql-test for debugging and testing of replication.",
>     (uchar**) &max_binlog_dump_events, (uchar**) &max_binlog_dump_events, 0,
> @@ -6335,13 +6322,6 @@ static int show_flushstatustime(THD *thd
>  #endif
>  
>  #ifdef HAVE_REPLICATION
> -static int show_rpl_status(THD *thd, SHOW_VAR *var, char *buff)
> -{
> -  var->type= SHOW_CHAR;
> -  var->value= const_cast<char*>(rpl_status_type[(int)rpl_status]);
> -  return 0;
> -}
> -
>  static int show_slave_running(THD *thd, SHOW_VAR *var, char *buff)
>  {
>    var->type= SHOW_MY_BOOL;
> @@ -6761,9 +6741,6 @@ SHOW_VAR status_vars[]= {
>  #endif /*HAVE_QUERY_CACHE*/
>    {"Queries",                  (char*) &show_queries,            SHOW_FUNC},
>    {"Questions",                (char*) offsetof(STATUS_VAR, questions),
> SHOW_LONG_STATUS},
> -#ifdef HAVE_REPLICATION
> -  {"Rpl_status",               (char*) &show_rpl_status,          SHOW_FUNC},
> -#endif
>    {"Select_full_join",         (char*) offsetof(STATUS_VAR, select_full_join_count),
> SHOW_LONG_STATUS},
>    {"Select_full_range_join",   (char*) offsetof(STATUS_VAR,
> select_full_range_join_count), SHOW_LONG_STATUS},
>    {"Select_range",             (char*) offsetof(STATUS_VAR, select_range_count),
> SHOW_LONG_STATUS},
> @@ -7912,7 +7889,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key
>    key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
>    key_LOCK_lock_db, key_LOCK_manager, key_LOCK_mapped_file,
>    key_LOCK_mysql_create_db, key_LOCK_open, key_LOCK_prepared_stmt_count,
> -  key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
> +  key_LOCK_server_started, key_LOCK_status,
>    key_LOCK_system_variables_hash, key_LOCK_table_share, key_LOCK_thd_data,
>    key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
>    key_master_info_data_lock, key_master_info_run_lock,
> @@ -7954,7 +7931,6 @@ static PSI_mutex_info all_server_mutexes
>    { &key_LOCK_mysql_create_db, "LOCK_mysql_create_db", PSI_FLAG_GLOBAL},
>    { &key_LOCK_open, "LOCK_open", PSI_FLAG_GLOBAL},
>    { &key_LOCK_prepared_stmt_count, "LOCK_prepared_stmt_count",
> PSI_FLAG_GLOBAL},
> -  { &key_LOCK_rpl_status, "LOCK_rpl_status", PSI_FLAG_GLOBAL},
>    { &key_LOCK_server_started, "LOCK_server_started", PSI_FLAG_GLOBAL},
>    { &key_LOCK_status, "LOCK_status", PSI_FLAG_GLOBAL},
>    { &key_LOCK_system_variables_hash, "LOCK_system_variables_hash",
> PSI_FLAG_GLOBAL},
> @@ -7999,7 +7975,7 @@ PSI_cond_key key_PAGE_cond, key_COND_act
>  
>  PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
>    key_COND_cache_status_changed, key_COND_global_read_lock, key_COND_manager,
> -  key_COND_refresh, key_COND_rpl_status, key_COND_server_started,
> +  key_COND_refresh, key_COND_server_started,
>    key_delayed_insert_cond, key_delayed_insert_cond_client,
>    key_item_func_sleep_cond, key_master_info_data_cond,
>    key_master_info_start_cond, key_master_info_stop_cond,
> @@ -8024,7 +8000,6 @@ static PSI_cond_info all_server_conds[]=
>    { &key_COND_global_read_lock, "COND_global_read_lock", PSI_FLAG_GLOBAL},
>    { &key_COND_manager, "COND_manager", PSI_FLAG_GLOBAL},
>    { &key_COND_refresh, "COND_refresh", PSI_FLAG_GLOBAL},
> -  { &key_COND_rpl_status, "COND_rpl_status", PSI_FLAG_GLOBAL},
>    { &key_COND_server_started, "COND_server_started", PSI_FLAG_GLOBAL},
>    { &key_delayed_insert_cond, "Delayed_insert::cond", 0},
>    { &key_delayed_insert_cond_client, "Delayed_insert::cond_client", 0},
> 
> === modified file 'sql/mysqld.h'
> --- a/sql/mysqld.h	2010-04-12 13:35:06 +0000
> +++ b/sql/mysqld.h	2010-06-21 05:56:56 +0000
> @@ -177,7 +177,7 @@ 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 ulong rpl_recovery_rank, thread_cache_size, thread_pool_size;
> +extern ulong thread_cache_size, thread_pool_size;
>  extern ulong back_log;
>  extern char language[FN_REFLEN];
>  extern ulong server_id, concurrency;
> @@ -234,7 +234,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_ind
>    key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
>    key_LOCK_lock_db, key_LOCK_logger, key_LOCK_manager, key_LOCK_mapped_file,
>    key_LOCK_mysql_create_db, key_LOCK_open, key_LOCK_prepared_stmt_count,
> -  key_LOCK_rpl_status, key_LOCK_server_started, key_LOCK_status,
> +  key_LOCK_server_started, key_LOCK_status,
>    key_LOCK_table_share, key_LOCK_thd_data,
>    key_LOCK_user_conn, key_LOCK_uuid_generator, key_LOG_LOCK_log,
>    key_master_info_data_lock, key_master_info_run_lock,
> @@ -253,7 +253,7 @@ extern PSI_cond_key key_PAGE_cond, key_C
>  
>  extern PSI_cond_key key_BINLOG_COND_prep_xids, key_BINLOG_update_cond,
>    key_COND_cache_status_changed, key_COND_global_read_lock, key_COND_manager,
> -  key_COND_refresh, key_COND_rpl_status, key_COND_server_started,
> +  key_COND_refresh, key_COND_server_started,
>    key_delayed_insert_cond, key_delayed_insert_cond_client,
>    key_item_func_sleep_cond, key_master_info_data_cond,
>    key_master_info_start_cond, key_master_info_stop_cond,
> 
> === removed file 'sql/repl_failsafe.cc'
> --- a/sql/repl_failsafe.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/repl_failsafe.cc	1970-01-01 00:00:00 +0000
> @@ -1,745 +0,0 @@
> -/* Copyright (C) 2001-2006 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
> -
> -   This program is free software; you can redistribute it and/or modify
> -   it under the terms of the GNU General Public License as published by
> -   the Free Software Foundation; version 2 of the License.
> -
> -   This program is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -   GNU General Public License for more details.
> -
> -   You should have received a copy of the GNU General Public License
> -   along with this program; if not, write to the Free Software
> -   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> -
> -/**
> -  @file
> -
> -  All of the functions defined in this file which are not used (the ones to
> -  handle failsafe) are not used; their code has not been updated for more
> -  than one year now so should be considered as BADLY BROKEN. Do not enable
> -  it. The used functions (to handle LOAD DATA FROM MASTER, plus some small
> -  functions like register_slave()) are working.
> -*/
> -
> -#include "sql_priv.h"
> -#include "sql_parse.h"                          // check_access
> -#ifdef HAVE_REPLICATION
> -
> -#include "repl_failsafe.h"
> -#include "sql_acl.h"                            // REPL_SLAVE_ACL
> -#include "sql_repl.h"
> -#include "slave.h"
> -#include "rpl_mi.h"
> -#include "rpl_filter.h"
> -#include "log_event.h"
> -#include "sql_db.h"                             // mysql_create_db
> -#include <mysql.h>
> -
> -#define SLAVE_LIST_CHUNK 128
> -#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
> -
> -
> -RPL_STATUS rpl_status=RPL_NULL;
> -mysql_mutex_t LOCK_rpl_status;
> -mysql_cond_t COND_rpl_status;
> -HASH slave_list;
> -
> -const char *rpl_role_type[] = {"MASTER","SLAVE",NullS};
> -TYPELIB rpl_role_typelib = {array_elements(rpl_role_type)-1,"",
> -			    rpl_role_type, NULL};
> -
> -const char* rpl_status_type[]=
> -{
> -  "AUTH_MASTER","IDLE_SLAVE","ACTIVE_SLAVE","LOST_SOLDIER","TROOP_SOLDIER",
> -  "RECOVERY_CAPTAIN","NULL",NullS
> -};
> -TYPELIB rpl_status_typelib= {array_elements(rpl_status_type)-1,"",
> -			     rpl_status_type, NULL};
> -
> -
> -static Slave_log_event* find_slave_event(IO_CACHE* log,
> -					 const char* log_file_name,
> -					 char* errmsg);
> -
> -/*
> -  All of the functions defined in this file which are not used (the ones to
> -  handle failsafe) are not used; their code has not been updated for more than
> -  one year now so should be considered as BADLY BROKEN. Do not enable it.
> -  The used functions (to handle LOAD DATA FROM MASTER, plus some small
> -  functions like register_slave()) are working.
> -*/
> -
> -#if NOT_USED
> -static int init_failsafe_rpl_thread(THD* thd)
> -{
> -  DBUG_ENTER("init_failsafe_rpl_thread");
> -  thd->system_thread = SYSTEM_THREAD_DELAYED_INSERT;
> -  /*
> -    thd->bootstrap is to report errors barely to stderr; if this code is
> -    enable again one day, one should check if bootstrap is still needed (maybe
> -    this thread has no other error reporting method).
> -  */
> -  thd->bootstrap = 1;
> -  thd->security_ctx->skip_grants();
> -  my_net_init(&thd->net, 0);
> -  thd->net.read_timeout = slave_net_timeout;
> -  thd->max_client_packet_length=thd->net.max_packet;
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  thd->thread_id= thd->variables.pseudo_thread_id= thread_id++;
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -
> -  if (init_thr_lock() || thd->store_globals())
> -  {
> -    /* purecov: begin inspected */
> -    close_connection(thd, ER_OUT_OF_RESOURCES, 1); // is this needed?
> -    statistic_increment(aborted_connects,&LOCK_status);
> -    one_thread_per_connection_end(thd,0);
> -    DBUG_RETURN(-1);
> -    /* purecov: end */
> -  }
> -
> -  thd->mem_root->free= thd->mem_root->used= 0;
> -  thd_proc_info(thd, "Thread initialized");
> -  thd->version=refresh_version;
> -  thd->set_time();
> -  DBUG_RETURN(0);
> -}
> -#endif
> -
> -void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status)
> -{
> -  mysql_mutex_lock(&LOCK_rpl_status);
> -  if (rpl_status == from_status || rpl_status == RPL_ANY)
> -    rpl_status = to_status;
> -  mysql_cond_signal(&COND_rpl_status);
> -  mysql_mutex_unlock(&LOCK_rpl_status);
> -}
> -
> -
> -#define get_object(p, obj, msg) \
> -{\
> -  uint len = (uint)*p++;  \
> -  if (p + len > p_end || len >= sizeof(obj)) \
> -  {\
> -    errmsg= msg;\
> -    goto err; \
> -  }\
> -  strmake(obj,(char*) p,len); \
> -  p+= len; \
> -}\
> -
> -
> -static inline int cmp_master_pos(Slave_log_event* sev, LEX_MASTER_INFO* mi)
> -{
> -  return cmp_master_pos(sev->master_log, sev->master_pos,
> mi->log_file_name,
> -			mi->pos);
> -}
> -
> -
> -void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
> -{
> -  if (thd->server_id)
> -  {
> -    if (need_mutex)
> -      mysql_mutex_lock(&LOCK_slave_list);
> -
> -    SLAVE_INFO* old_si;
> -    if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
> -                                              (uchar*)&thd->server_id, 4))
> &&
> -	(!only_mine || old_si->thd == thd))
> -    my_hash_delete(&slave_list, (uchar*)old_si);
> -
> -    if (need_mutex)
> -      mysql_mutex_unlock(&LOCK_slave_list);
> -  }
> -}
> -
> -
> -/**
> -  Register slave in 'slave_list' hash table.
> -
> -  @return
> -    0	ok
> -  @return
> -    1	Error.   Error message sent to client
> -*/
> -
> -int register_slave(THD* thd, uchar* packet, uint packet_length)
> -{
> -  int res;
> -  SLAVE_INFO *si;
> -  uchar *p= packet, *p_end= packet + packet_length;
> -  const char *errmsg= "Wrong parameters to function register_slave";
> -
> -  if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
> -    return 1;
> -  if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
> -    goto err2;
> -
> -  thd->server_id= si->server_id= uint4korr(p);
> -  p+= 4;
> -  get_object(p,si->host, "Failed to register slave: too long 'report-host'");
> -  get_object(p,si->user, "Failed to register slave: too long 'report-user'");
> -  get_object(p,si->password, "Failed to register slave; too long
> 'report-password'");
> -  if (p+10 > p_end)
> -    goto err;
> -  si->port= uint2korr(p);
> -  p += 2;
> -  /* 
> -     We need to by pass the bytes used in the fake rpl_recovery_rank
> -     variable. It was removed in patch for BUG#13963. But this would 
> -     make a server with that patch unable to connect to an old master.
> -     See: BUG#49259
> -  */
> -  // si->rpl_recovery_rank= uint4korr(p);
> -  p += 4;
> -  if (!(si->master_id= uint4korr(p)))
> -    si->master_id= server_id;
> -  si->thd= thd;
> -
> -  mysql_mutex_lock(&LOCK_slave_list);
> -  unregister_slave(thd,0,0);
> -  res= my_hash_insert(&slave_list, (uchar*) si);
> -  mysql_mutex_unlock(&LOCK_slave_list);
> -  return res;
> -
> -err:
> -  my_free(si, MYF(MY_WME));
> -  my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
> -err2:
> -  return 1;
> -}
> -
> -extern "C" uint32
> -*slave_list_key(SLAVE_INFO* si, size_t *len,
> -		my_bool not_used __attribute__((unused)))
> -{
> -  *len = 4;
> -  return &si->server_id;
> -}
> -
> -extern "C" void slave_info_free(void *s)
> -{
> -  my_free(s, MYF(MY_WME));
> -}
> -
> -#ifdef HAVE_PSI_INTERFACE
> -static PSI_mutex_key key_LOCK_slave_list;
> -
> -static PSI_mutex_info all_slave_list_mutexes[]=
> -{
> -  { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
> -};
> -
> -static void init_all_slave_list_mutexes(void)
> -{
> -  const char* category= "sql";
> -  int count;
> -
> -  if (PSI_server == NULL)
> -    return;
> -
> -  count= array_elements(all_slave_list_mutexes);
> -  PSI_server->register_mutex(category, all_slave_list_mutexes, count);
> -}
> -#endif /* HAVE_PSI_INTERFACE */
> -
> -void init_slave_list()
> -{
> -#ifdef HAVE_PSI_INTERFACE
> -  init_all_slave_list_mutexes();
> -#endif
> -
> -  my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
> -               (my_hash_get_key) slave_list_key,
> -               (my_hash_free_key) slave_info_free, 0);
> -  mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
> -}
> -
> -void end_slave_list()
> -{
> -  /* No protection by a mutex needed as we are only called at shutdown */
> -  if (my_hash_inited(&slave_list))
> -  {
> -    my_hash_free(&slave_list);
> -    mysql_mutex_destroy(&LOCK_slave_list);
> -  }
> -}
> -
> -static int find_target_pos(LEX_MASTER_INFO *mi, IO_CACHE *log, char *errmsg)
> -{
> -  my_off_t log_pos =	    (my_off_t) mi->pos;
> -  uint32 target_server_id = mi->server_id;
> -
> -  for (;;)
> -  {
> -    Log_event* ev;
> -    if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*) 0, 0)))
> -    {
> -      if (log->error > 0)
> -	strmov(errmsg, "Binary log truncated in the middle of event");
> -      else if (log->error < 0)
> -	strmov(errmsg, "I/O error reading binary log");
> -      else
> -	strmov(errmsg, "Could not find target event in the binary log");
> -      return 1;
> -    }
> -
> -    if (ev->log_pos >= log_pos && ev->server_id ==
> target_server_id)
> -    {
> -      delete ev;
> -      mi->pos = my_b_tell(log);
> -      return 0;
> -    }
> -    delete ev;
> -  }
> -  /* Impossible */
> -}
> -
> -/**
> -  @details 
> -  Before 4.0.15 we had a member of THD called log_pos, it was meant for
> -  failsafe replication code in repl_failsafe.cc which is disabled until
> -  it is reworked. Event's log_pos used to be preserved through 
> -  log-slave-updates to make code in repl_failsafe.cc work (this 
> -  function, SHOW NEW MASTER); but on the other side it caused unexpected
> -  values in Exec_Master_Log_Pos in A->B->C replication setup, 
> -  synchronization problems in master_pos_wait(), ... So we 
> -  (Dmitri & Guilhem) removed it.
> -  
> -  So for now this function is broken. 
> -*/
> -
> -int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg)
> -{
> -  LOG_INFO linfo;
> -  char last_log_name[FN_REFLEN];
> -  IO_CACHE log;
> -  File file = -1, last_file = -1;
> -  mysql_mutex_t *log_lock;
> -  const char* errmsg_p;
> -  Slave_log_event* sev = 0;
> -  my_off_t last_pos = 0;
> -  int error = 1;
> -  int cmp_res;
> -  LINT_INIT(cmp_res);
> -  DBUG_ENTER("translate_master");
> -
> -  if (!mysql_bin_log.is_open())
> -  {
> -    strmov(errmsg,"Binary log is not open");
> -    DBUG_RETURN(1);
> -  }
> -
> -  if (!server_id_supplied)
> -  {
> -    strmov(errmsg, "Misconfigured master - server id was not set");
> -    DBUG_RETURN(1);
> -  }
> -
> -  if (mysql_bin_log.find_log_pos(&linfo, NullS, 1))
> -  {
> -    strmov(errmsg,"Could not find first log");
> -    DBUG_RETURN(1);
> -  }
> -  thd->current_linfo = &linfo;
> -
> -  bzero((char*) &log,sizeof(log));
> -  log_lock = mysql_bin_log.get_log_lock();
> -  mysql_mutex_lock(log_lock);
> -
> -  for (;;)
> -  {
> -    if ((file=open_binlog(&log, linfo.log_file_name, &errmsg_p)) < 0)
> -    {
> -      strmov(errmsg, errmsg_p);
> -      goto err;
> -    }
> -
> -    if (!(sev = find_slave_event(&log, linfo.log_file_name, errmsg)))
> -      goto err;
> -
> -    cmp_res = cmp_master_pos(sev, mi);
> -    delete sev;
> -
> -    if (!cmp_res)
> -    {
> -      /* Copy basename */
> -      fn_format(mi->log_file_name, linfo.log_file_name, "","",1);
> -      mi->pos = my_b_tell(&log);
> -      goto mi_inited;
> -    }
> -    else if (cmp_res > 0)
> -    {
> -      if (!last_pos)
> -      {
> -	strmov(errmsg,
> -	       "Slave event in first log points past the target position");
> -	goto err;
> -      }
> -      end_io_cache(&log);
> -      mysql_file_close(file, MYF(MY_WME));
> -      if (init_io_cache(&log, (file = last_file), IO_SIZE, READ_CACHE, 0, 0,
> -			MYF(MY_WME)))
> -      {
> -	errmsg[0] = 0;
> -	goto err;
> -      }
> -      break;
> -    }
> -
> -    strmov(last_log_name, linfo.log_file_name);
> -    last_pos = my_b_tell(&log);
> -
> -    switch (mysql_bin_log.find_next_log(&linfo, 1)) {
> -    case LOG_INFO_EOF:
> -      if (last_file >= 0)
> -       mysql_file_close(last_file, MYF(MY_WME));
> -      last_file = -1;
> -      goto found_log;
> -    case 0:
> -      break;
> -    default:
> -      strmov(errmsg, "Error reading log index");
> -      goto err;
> -    }
> -
> -    end_io_cache(&log);
> -    if (last_file >= 0)
> -      mysql_file_close(last_file, MYF(MY_WME));
> -    last_file = file;
> -  }
> -
> -found_log:
> -  my_b_seek(&log, last_pos);
> -  if (find_target_pos(mi,&log,errmsg))
> -    goto err;
> -  fn_format(mi->log_file_name, last_log_name, "","",1);  /* Copy basename */
> -
> -mi_inited:
> -  error = 0;
> -err:
> -  mysql_mutex_unlock(log_lock);
> -  end_io_cache(&log);
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  thd->current_linfo = 0;
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  if (file >= 0)
> -    mysql_file_close(file, MYF(MY_WME));
> -  if (last_file >= 0 && last_file != file)
> -    mysql_file_close(last_file, MYF(MY_WME));
> -
> -  DBUG_RETURN(error);
> -}
> -
> -
> -/**
> -  Caller must delete result when done.
> -*/
> -
> -static Slave_log_event* find_slave_event(IO_CACHE* log,
> -					 const char* log_file_name,
> -					 char* errmsg)
> -{
> -  Log_event* ev;
> -  int i;
> -  bool slave_event_found = 0;
> -  LINT_INIT(ev);
> -
> -  for (i = 0; i < 2; i++)
> -  {
> -    if (!(ev= Log_event::read_log_event(log, (mysql_mutex_t*)0, 0)))
> -    {
> -      my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
> -		  "Error reading event in log '%s'",
> -		  (char*)log_file_name);
> -      return 0;
> -    }
> -    if (ev->get_type_code() == SLAVE_EVENT)
> -    {
> -      slave_event_found = 1;
> -      break;
> -    }
> -    delete ev;
> -  }
> -  if (!slave_event_found)
> -  {
> -    my_snprintf(errmsg, SLAVE_ERRMSG_SIZE,
> -		"Could not find slave event in log '%s'",
> -		(char*)log_file_name);
> -    return 0;
> -  }
> -
> -  return (Slave_log_event*)ev;
> -}
> -
> -/**
> -  This function is broken now. 
> -
> -  @seealso translate_master()
> -*/
> -
> -bool show_new_master(THD* thd)
> -{
> -  Protocol *protocol= thd->protocol;
> -  DBUG_ENTER("show_new_master");
> -  List<Item> field_list;
> -  char errmsg[SLAVE_ERRMSG_SIZE];
> -  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
> -
> -  errmsg[0]=0;					// Safety
> -  if (translate_master(thd, lex_mi, errmsg))
> -  {
> -    if (errmsg[0])
> -      my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
> -               "SHOW NEW MASTER", errmsg);
> -    DBUG_RETURN(TRUE);
> -  }
> -  else
> -  {
> -    field_list.push_back(new Item_empty_string("Log_name", 20));
> -    field_list.push_back(new Item_return_int("Log_pos", 10,
> -					     MYSQL_TYPE_LONGLONG));
> -    if (protocol->send_result_set_metadata(&field_list,
> -                              Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> -      DBUG_RETURN(TRUE);
> -    protocol->prepare_for_resend();
> -    protocol->store(lex_mi->log_file_name, &my_charset_bin);
> -    protocol->store((ulonglong) lex_mi->pos);
> -    if (protocol->write())
> -      DBUG_RETURN(TRUE);
> -    my_eof(thd);
> -    DBUG_RETURN(FALSE);
> -  }
> -}
> -
> -/**
> -  Asks the master for the list of its other connected slaves.
> -
> -  This is for failsafe replication:
> -  in order for failsafe replication to work, the servers involved in
> -  replication must know of each other. We accomplish this by having each
> -  slave report to the master how to reach it, and on connection, each
> -  slave receives information about where the other slaves are.
> -
> -  @param mysql           pre-existing connection to the master
> -  @param mi              master info
> -
> -  @note
> -    mi is used only to give detailed error messages which include the
> -    hostname/port of the master, the username used by the slave to connect to
> -    the master.
> -    If the user used by the slave to connect to the master does not have the
> -    REPLICATION SLAVE privilege, it will pop in this function because
> -    SHOW SLAVE HOSTS will fail on the master.
> -
> -  @retval
> -    1           error
> -  @retval
> -    0           success
> -*/
> -
> -int update_slave_list(MYSQL* mysql, Master_info* mi)
> -{
> -  MYSQL_RES* res=0;
> -  MYSQL_ROW row;
> -  const char* error=0;
> -  bool have_auth_info;
> -  int port_ind;
> -  DBUG_ENTER("update_slave_list");
> -
> -  if (mysql_real_query(mysql, STRING_WITH_LEN("SHOW SLAVE HOSTS")) ||
> -      !(res = mysql_store_result(mysql)))
> -  {
> -    error= mysql_error(mysql);
> -    goto err;
> -  }
> -
> -  switch (mysql_num_fields(res)) {
> -  case 5:
> -    have_auth_info = 0;
> -    port_ind=2;
> -    break;
> -  case 7:
> -    have_auth_info = 1;
> -    port_ind=4;
> -    break;
> -  default:
> -    error= "the master returned an invalid number of fields for SHOW SLAVE \
> -HOSTS";
> -    goto err;
> -  }
> -
> -  mysql_mutex_lock(&LOCK_slave_list);
> -
> -  while ((row= mysql_fetch_row(res)))
> -  {
> -    uint32 log_server_id;
> -    SLAVE_INFO* si, *old_si;
> -    log_server_id = atoi(row[0]);
> -    if ((old_si= (SLAVE_INFO*)my_hash_search(&slave_list,
> -                                             (uchar*)&log_server_id,4)))
> -      si = old_si;
> -    else
> -    {
> -      if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
> -      {
> -	error= "the slave is out of memory";
> -        mysql_mutex_unlock(&LOCK_slave_list);
> -	goto err;
> -      }
> -      si->server_id = log_server_id;
> -      if (my_hash_insert(&slave_list, (uchar*)si))
> -      {
> -        error= "the slave is out of memory";
> -        mysql_mutex_unlock(&LOCK_slave_list);
> -        goto err;
> -      }
> -    }
> -    strmake(si->host, row[1], sizeof(si->host)-1);
> -    si->port = atoi(row[port_ind]);
> -    si->rpl_recovery_rank = atoi(row[port_ind+1]);
> -    si->master_id = atoi(row[port_ind+2]);
> -    if (have_auth_info)
> -    {
> -      strmake(si->user, row[2], sizeof(si->user)-1);
> -      strmake(si->password, row[3], sizeof(si->password)-1);
> -    }
> -  }
> -  mysql_mutex_unlock(&LOCK_slave_list);
> -
> -err:
> -  if (res)
> -    mysql_free_result(res);
> -  if (error)
> -  {
> -    sql_print_error("While trying to obtain the list of slaves from the master "
> -                    "'%s:%d', user '%s' got the following error: '%s'", 
> -                    mi->host, mi->port, mi->user, error);
> -    DBUG_RETURN(1);
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -
> -#if NOT_USED
> -int find_recovery_captain(THD* thd, MYSQL* mysql)
> -{
> -  return 0;
> -}
> -#endif
> -
> -#if NOT_USED
> -pthread_handler_t handle_failsafe_rpl(void *arg)
> -{
> -  DBUG_ENTER("handle_failsafe_rpl");
> -  THD *thd = new THD;
> -  thd->thread_stack = (char*)&thd;
> -  MYSQL* recovery_captain = 0;
> -  const char* msg;
> -
> -  pthread_detach_this_thread();
> -  if (init_failsafe_rpl_thread(thd) || !(recovery_captain=mysql_init(0)))
> -  {
> -    sql_print_error("Could not initialize failsafe replication thread");
> -    goto err;
> -  }
> -  mysql_mutex_lock(&LOCK_rpl_status);
> -  msg= thd->enter_cond(&COND_rpl_status,
> -                       &LOCK_rpl_status, "Waiting for request");
> -  while (!thd->killed && !abort_loop)
> -  {
> -    bool break_req_chain = 0;
> -    mysql_cond_wait(&COND_rpl_status, &LOCK_rpl_status);
> -    thd_proc_info(thd, "Processing request");
> -    while (!break_req_chain)
> -    {
> -      switch (rpl_status) {
> -      case RPL_LOST_SOLDIER:
> -	if (find_recovery_captain(thd, recovery_captain))
> -	  rpl_status=RPL_TROOP_SOLDIER;
> -	else
> -	  rpl_status=RPL_RECOVERY_CAPTAIN;
> -	break_req_chain=1; /* for now until other states are implemented */
> -	break;
> -      default:
> -	break_req_chain=1;
> -	break;
> -      }
> -    }
> -  }
> -  thd->exit_cond(msg);
> -err:
> -  if (recovery_captain)
> -    mysql_close(recovery_captain);
> -  delete thd;
> -
> -  DBUG_LEAVE;                                   // Must match DBUG_ENTER()
> -  my_thread_end();
> -  pthread_exit(0);
> -  return 0;                                     // Avoid compiler warnings
> -}
> -#endif
> -
> -
> -/**
> -  Execute a SHOW SLAVE HOSTS statement.
> -
> -  @param thd Pointer to THD object for the client thread executing the
> -  statement.
> -
> -  @retval FALSE success
> -  @retval TRUE failure
> -*/
> -bool show_slave_hosts(THD* thd)
> -{
> -  List<Item> field_list;
> -  Protocol *protocol= thd->protocol;
> -  DBUG_ENTER("show_slave_hosts");
> -
> -  field_list.push_back(new Item_return_int("Server_id", 10,
> -					   MYSQL_TYPE_LONG));
> -  field_list.push_back(new Item_empty_string("Host", 20));
> -  if (opt_show_slave_auth_info)
> -  {
> -    field_list.push_back(new Item_empty_string("User",20));
> -    field_list.push_back(new Item_empty_string("Password",20));
> -  }
> -  field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
> -  field_list.push_back(new Item_return_int("Master_id", 10,
> -					   MYSQL_TYPE_LONG));
> -
> -  if (protocol->send_result_set_metadata(&field_list,
> -                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> -    DBUG_RETURN(TRUE);
> -
> -  mysql_mutex_lock(&LOCK_slave_list);
> -
> -  for (uint i = 0; i < slave_list.records; ++i)
> -  {
> -    SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
> -    protocol->prepare_for_resend();
> -    protocol->store((uint32) si->server_id);
> -    protocol->store(si->host, &my_charset_bin);
> -    if (opt_show_slave_auth_info)
> -    {
> -      protocol->store(si->user, &my_charset_bin);
> -      protocol->store(si->password, &my_charset_bin);
> -    }
> -    protocol->store((uint32) si->port);
> -    protocol->store((uint32) si->master_id);
> -    if (protocol->write())
> -    {
> -      mysql_mutex_unlock(&LOCK_slave_list);
> -      DBUG_RETURN(TRUE);
> -    }
> -  }
> -  mysql_mutex_unlock(&LOCK_slave_list);
> -  my_eof(thd);
> -  DBUG_RETURN(FALSE);
> -}
> -
> -#endif /* HAVE_REPLICATION */
> -
> 
> === removed file 'sql/repl_failsafe.h'
> --- a/sql/repl_failsafe.h	2010-01-25 21:34:34 +0000
> +++ b/sql/repl_failsafe.h	1970-01-01 00:00:00 +0000
> @@ -1,55 +0,0 @@
> -#ifndef REPL_FAILSAFE_INCLUDED
> -#define REPL_FAILSAFE_INCLUDED
> -
> -/* Copyright (C) 2001-2005 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
> -
> -   This program is free software; you can redistribute it and/or modify
> -   it under the terms of the GNU General Public License as published by
> -   the Free Software Foundation; version 2 of the License.
> -
> -   This program is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -   GNU General Public License for more details.
> -
> -   You should have received a copy of the GNU General Public License
> -   along with this program; if not, write to the Free Software
> -   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> -
> -#ifdef HAVE_REPLICATION
> -
> -#include "mysql.h"
> -#include "my_sys.h"
> -#include "slave.h"
> -
> -typedef enum {RPL_AUTH_MASTER=0,RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE,
> -	      RPL_LOST_SOLDIER,RPL_TROOP_SOLDIER,
> -	      RPL_RECOVERY_CAPTAIN,RPL_NULL /* inactive */,
> -	      RPL_ANY /* wild card used by change_rpl_status */ } RPL_STATUS;
> -extern RPL_STATUS rpl_status;
> -
> -extern mysql_mutex_t LOCK_rpl_status;
> -extern mysql_cond_t COND_rpl_status;
> -extern TYPELIB rpl_role_typelib, rpl_status_typelib;
> -extern const char* rpl_role_type[], *rpl_status_type[];
> -
> -pthread_handler_t handle_failsafe_rpl(void *arg);
> -void change_rpl_status(RPL_STATUS from_status, RPL_STATUS to_status);
> -int find_recovery_captain(THD* thd, MYSQL* mysql);
> -int update_slave_list(MYSQL* mysql, Master_info* mi);
> -
> -extern HASH slave_list;
> -
> -bool load_master_data(THD* thd);
> -int connect_to_master(THD *thd, MYSQL* mysql, Master_info* mi);
> -
> -bool show_new_master(THD* thd);
> -bool show_slave_hosts(THD* thd);
> -int translate_master(THD* thd, LEX_MASTER_INFO* mi, char* errmsg);
> -void init_slave_list();
> -void end_slave_list();
> -int register_slave(THD* thd, uchar* packet, uint packet_length);
> -void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
> -
> -#endif /* HAVE_REPLICATION */
> -#endif /* REPL_FAILSAFE_INCLUDED */
> 
> === modified file 'sql/rpl_handler.cc'
> --- a/sql/rpl_handler.cc	2010-03-31 14:05:33 +0000
> +++ b/sql/rpl_handler.cc	2010-06-21 05:56:56 +0000
> @@ -17,7 +17,6 @@
>  #include "unireg.h"
>  
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
>  #include "log_event.h"
>  #include "rpl_filter.h"
>  #include <my_dir.h>
> 
> === modified file 'sql/rpl_injector.cc'
> --- a/sql/rpl_injector.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/rpl_injector.cc	2010-06-21 06:01:50 +0000
> @@ -20,6 +20,7 @@
>  #include "sql_parse.h"                          // begin_trans, end_trans, COMMIT
>  #include "sql_base.h"                           // close_thread_tables
>  #include "log_event.h"                          // Incident_log_event
> +#include "binlog.h"                             // mysql_bin_log
>  
>  /*
>    injector::transaction - member definitions
> 
> === added file 'sql/rpl_master.cc'
> --- a/sql/rpl_master.cc	1970-01-01 00:00:00 +0000
> +++ b/sql/rpl_master.cc	2010-06-21 05:56:56 +0000
> @@ -0,0 +1,1267 @@
> +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +
> +#include "sql_priv.h"
> +#include "unireg.h"
> +#include "sql_parse.h"                          // check_access
> +#ifdef HAVE_REPLICATION
> +
> +#include "sql_acl.h"                            // SUPER_ACL
> +#include "log_event.h"
> +#include "rpl_filter.h"
> +#include <my_dir.h>
> +#include "rpl_handler.h"
> +#include "rpl_master.h"
> +
> +int max_binlog_dump_events = 0; // unlimited
> +my_bool opt_sporadic_binlog_dump_fail = 0;
> +extern my_bool opt_show_slave_auth_info;
> +
> +#ifndef DBUG_OFF
> +static int binlog_dump_count = 0;
> +#endif
> +
> +#define SLAVE_LIST_CHUNK 128
> +#define SLAVE_ERRMSG_SIZE (FN_REFLEN+64)
> +HASH slave_list;
> +
> +#define get_object(p, obj, msg) \
> +{\
> +  uint len = (uint)*p++;  \
> +  if (p + len > p_end || len >= sizeof(obj)) \
> +  {\
> +    errmsg= msg;\
> +    goto err; \
> +  }\
> +  strmake(obj,(char*) p,len); \
> +  p+= len; \
> +}\
> +
> +typedef struct st_slave_info
> +{
> +  uint32 server_id;
> +  uint32 master_id;
> +  char host[HOSTNAME_LENGTH+1];
> +  char user[USERNAME_LENGTH+1];
> +  char password[MAX_PASSWORD_LENGTH+1];
> +  uint16 port;
> +  THD* thd;
> +} SLAVE_INFO;
> +
> +extern "C" uint32
> +*slave_list_key(SLAVE_INFO* si, size_t *len,
> +		my_bool not_used __attribute__((unused)))
> +{
> +  *len = 4;
> +  return &si->server_id;
> +}
> +
> +extern "C" void slave_info_free(void *s)
> +{
> +  my_free(s, MYF(MY_WME));
> +}
> +
> +#ifdef HAVE_PSI_INTERFACE
> +static PSI_mutex_key key_LOCK_slave_list;
> +
> +static PSI_mutex_info all_slave_list_mutexes[]=
> +{
> +  { &key_LOCK_slave_list, "LOCK_slave_list", PSI_FLAG_GLOBAL}
> +};
> +
> +static void init_all_slave_list_mutexes(void)
> +{
> +  const char* category= "sql";
> +  int count;
> +
> +  if (PSI_server == NULL)
> +    return;
> +
> +  count= array_elements(all_slave_list_mutexes);
> +  PSI_server->register_mutex(category, all_slave_list_mutexes, count);
> +}
> +#endif /* HAVE_PSI_INTERFACE */
> +
> +void init_slave_list()
> +{
> +#ifdef HAVE_PSI_INTERFACE
> +  init_all_slave_list_mutexes();
> +#endif
> +
> +  my_hash_init(&slave_list, system_charset_info, SLAVE_LIST_CHUNK, 0, 0,
> +               (my_hash_get_key) slave_list_key,
> +               (my_hash_free_key) slave_info_free, 0);
> +  mysql_mutex_init(key_LOCK_slave_list, &LOCK_slave_list, MY_MUTEX_INIT_FAST);
> +}
> +
> +void end_slave_list()
> +{
> +  /* No protection by a mutex needed as we are only called at shutdown */
> +  if (my_hash_inited(&slave_list))
> +  {
> +    my_hash_free(&slave_list);
> +    mysql_mutex_destroy(&LOCK_slave_list);
> +  }
> +}
> +
> +/**
> +  Register slave in 'slave_list' hash table.
> +
> +  @return
> +    0	ok
> +  @return
> +    1	Error.   Error message sent to client
> +*/
> +
> +int register_slave(THD* thd, uchar* packet, uint packet_length)
> +{
> +  int res;
> +  SLAVE_INFO *si;
> +  uchar *p= packet, *p_end= packet + packet_length;
> +  const char *errmsg= "Wrong parameters to function register_slave";
> +
> +  if (check_access(thd, REPL_SLAVE_ACL, any_db, NULL, NULL, 0, 0))
> +    return 1;
> +  if (!(si = (SLAVE_INFO*)my_malloc(sizeof(SLAVE_INFO), MYF(MY_WME))))
> +    goto err2;
> +
> +  thd->server_id= si->server_id= uint4korr(p);
> +  p+= 4;
> +  get_object(p,si->host, "Failed to register slave: too long 'report-host'");
> +  get_object(p,si->user, "Failed to register slave: too long 'report-user'");
> +  get_object(p,si->password, "Failed to register slave; too long
> 'report-password'");
> +  if (p+10 > p_end)
> +    goto err;
> +  si->port= uint2korr(p);
> +  p += 2;
> +  /* 
> +     We need to by pass the bytes used in the fake rpl_recovery_rank
> +     variable. It was removed in patch for BUG#13963. But this would 
> +     make a server with that patch unable to connect to an old master.
> +     See: BUG#49259
> +  */
> +  p += 4;
> +  if (!(si->master_id= uint4korr(p)))
> +    si->master_id= server_id;
> +  si->thd= thd;
> +
> +  mysql_mutex_lock(&LOCK_slave_list);
> +  unregister_slave(thd,0,0);
> +  res= my_hash_insert(&slave_list, (uchar*) si);
> +  mysql_mutex_unlock(&LOCK_slave_list);
> +  return res;
> +
> +err:
> +  my_free(si, MYF(MY_WME));
> +  my_message(ER_UNKNOWN_ERROR, errmsg, MYF(0)); /* purecov: inspected */
> +err2:
> +  return 1;
> +}
> +
> +void unregister_slave(THD* thd, bool only_mine, bool need_mutex)
> +{
> +  if (thd->server_id)
> +  {
> +    if (need_mutex)
> +      mysql_mutex_lock(&LOCK_slave_list);
> +
> +    SLAVE_INFO* old_si;
> +    if ((old_si = (SLAVE_INFO*)my_hash_search(&slave_list,
> +                                              (uchar*)&thd->server_id, 4))
> &&
> +	(!only_mine || old_si->thd == thd))
> +    my_hash_delete(&slave_list, (uchar*)old_si);
> +
> +    if (need_mutex)
> +      mysql_mutex_unlock(&LOCK_slave_list);
> +  }
> +}
> +
> +
> +/**
> +  Execute a SHOW SLAVE HOSTS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool show_slave_hosts(THD* thd)
> +{
> +  List<Item> field_list;
> +  Protocol *protocol= thd->protocol;
> +  DBUG_ENTER("show_slave_hosts");
> +
> +  field_list.push_back(new Item_return_int("Server_id", 10,
> +					   MYSQL_TYPE_LONG));
> +  field_list.push_back(new Item_empty_string("Host", 20));
> +  if (opt_show_slave_auth_info)
> +  {
> +    field_list.push_back(new Item_empty_string("User",20));
> +    field_list.push_back(new Item_empty_string("Password",20));
> +  }
> +  field_list.push_back(new Item_return_int("Port", 7, MYSQL_TYPE_LONG));
> +  field_list.push_back(new Item_return_int("Master_id", 10,
> +					   MYSQL_TYPE_LONG));
> +
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +
> +  mysql_mutex_lock(&LOCK_slave_list);
> +
> +  for (uint i = 0; i < slave_list.records; ++i)
> +  {
> +    SLAVE_INFO* si = (SLAVE_INFO*) my_hash_element(&slave_list, i);
> +    protocol->prepare_for_resend();
> +    protocol->store((uint32) si->server_id);
> +    protocol->store(si->host, &my_charset_bin);
> +    if (opt_show_slave_auth_info)
> +    {
> +      protocol->store(si->user, &my_charset_bin);
> +      protocol->store(si->password, &my_charset_bin);
> +    }
> +    protocol->store((uint32) si->port);
> +    protocol->store((uint32) si->master_id);
> +    if (protocol->write())
> +    {
> +      mysql_mutex_unlock(&LOCK_slave_list);
> +      DBUG_RETURN(TRUE);
> +    }
> +  }
> +  mysql_mutex_unlock(&LOCK_slave_list);
> +  my_eof(thd);
> +  DBUG_RETURN(FALSE);
> +}
> +
> +
> +/*
> +    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
> +    send to the slave (because the slave may not know it if it just asked for
> +    MASTER_LOG_FILE='', MASTER_LOG_POS=4).
> +    < 4.0.14, fake_rotate_event() was called only if the requested pos was 4.
> +    After this version we always call it, so that a 3.23.58 slave can rely on
> +    it to detect if the master is 4.0 (and stop) (the _fake_ Rotate event has
> +    zeros in the good positions which, by chance, make it possible for the 3.23
> +    slave to detect that this event is unexpected) (this is luck which happens
> +    because the master and slave disagree on the size of the header of
> +    Log_event).
> +
> +    Relying on the event length of the Rotate event instead of these
> +    well-placed zeros was not possible as Rotate events have a variable-length
> +    part.
> +*/
> +
> +static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
> +                             ulonglong position, const char** errmsg)
> +{
> +  DBUG_ENTER("fake_rotate_event");
> +  char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN+100];
> +  /*
> +    '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;
> +
> +  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;
> +  int4store(header + SERVER_ID_OFFSET, server_id);
> +  int4store(header + EVENT_LEN_OFFSET, event_len);
> +  int2store(header + FLAGS_OFFSET, LOG_EVENT_ARTIFICIAL_F);
> +
> +  // 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);
> +  packet->append(buf, ROTATE_HEADER_LEN);
> +  packet->append(p,ident_len);
> +  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
> +  {
> +    *errmsg = "failed on my_net_write()";
> +    DBUG_RETURN(-1);
> +  }
> +  DBUG_RETURN(0);
> +}
> +
> +/*
> +  Reset thread transmit packet buffer for event sending
> +
> +  This function allocates header bytes for event transmission, and
> +  should be called before store the event data to the packet buffer.
> +*/
> +static int reset_transmit_packet(THD *thd, ushort flags,
> +                                 ulong *ev_offset, const char **errmsg)
> +{
> +  int ret= 0;
> +  String *packet= &thd->packet;
> +
> +  /* reserve and set default header */
> +  packet->length(0);
> +  packet->set("\0", 1, &my_charset_bin);
> +
> +  if (RUN_HOOK(binlog_transmit, reserve_header, (thd, flags, packet)))
> +  {
> +    *errmsg= "Failed to run hook 'reserve_header'";
> +    my_errno= ER_UNKNOWN_ERROR;
> +    ret= 1;
> +  }
> +  *ev_offset= packet->length();
> +  return ret;
> +}
> +
> +static int send_file(THD *thd)
> +{
> +  NET* net = &thd->net;
> +  int fd = -1, error = 1;
> +  size_t bytes;
> +  char fname[FN_REFLEN+1];
> +  const char *errmsg = 0;
> +  int old_timeout;
> +  unsigned long packet_len;
> +  uchar buf[IO_SIZE];				// It's safe to alloc this
> +  DBUG_ENTER("send_file");
> +
> +  /*
> +    The client might be slow loading the data, give him wait_timeout to do
> +    the job
> +  */
> +  old_timeout= net->read_timeout;
> +  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
> +
> +  /*
> +    We need net_flush here because the client will not know it needs to send
> +    us the file name until it has processed the load event entry
> +  */
> +  if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error)
> +  {
> +    errmsg = "while reading file name";
> +    goto err;
> +  }
> +
> +  // terminate with \0 for fn_format
> +  *((char*)net->read_pos +  packet_len) = 0;
> +  fn_format(fname, (char*) net->read_pos + 1, "", "", 4);
> +  // this is needed to make replicate-ignore-db
> +  if (!strcmp(fname,"/dev/null"))
> +    goto end;
> +
> +  if ((fd= mysql_file_open(key_file_send_file,
> +                           fname, O_RDONLY, MYF(0))) < 0)
> +  {
> +    errmsg = "on open of file";
> +    goto err;
> +  }
> +
> +  while ((long) (bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) > 0)
> +  {
> +    if (my_net_write(net, buf, bytes))
> +    {
> +      errmsg = "while writing data to client";
> +      goto err;
> +    }
> +  }
> +
> + end:
> +  if (my_net_write(net, (uchar*) "", 0) || net_flush(net) ||
> +      (my_net_read(net) == packet_error))
> +  {
> +    errmsg = "while negotiating file transfer close";
> +    goto err;
> +  }
> +  error = 0;
> +
> + err:
> +  my_net_set_read_timeout(net, old_timeout);
> +  if (fd >= 0)
> +    mysql_file_close(fd, MYF(0));
> +  if (errmsg)
> +  {
> +    sql_print_error("Failed in send_file() %s", errmsg);
> +    DBUG_PRINT("error", ("%s", errmsg));
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +
> +int test_for_non_eof_log_read_errors(int error, const char **errmsg)
> +{
> +  if (error == LOG_READ_EOF)
> +    return 0;
> +  my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +  switch (error) {
> +  case LOG_READ_BOGUS:
> +    *errmsg = "bogus data in log event";
> +    break;
> +  case LOG_READ_TOO_LARGE:
> +    *errmsg = "log event entry exceeded max_allowed_packet; \
> +Increase max_allowed_packet on master";
> +    break;
> +  case LOG_READ_IO:
> +    *errmsg = "I/O error reading log event";
> +    break;
> +  case LOG_READ_MEM:
> +    *errmsg = "memory allocation failed reading log event";
> +    break;
> +  case LOG_READ_TRUNC:
> +    *errmsg = "binlog truncated in the middle of event";
> +    break;
> +  default:
> +    *errmsg = "unknown error reading log event on the master";
> +    break;
> +  }
> +  return error;
> +}
> +
> +
> +/**
> +  An auxiliary function for calling in mysql_binlog_send
> +  to initialize the heartbeat timeout in waiting for a binlogged event.
> +
> +  @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 ulonglong get_heartbeat_period(THD * thd)
> +{
> +  my_bool null_value;
> +  LEX_STRING name=  { C_STRING_WITH_LEN("master_heartbeat_period")};
> +  user_var_entry *entry= 
> +    (user_var_entry*) my_hash_search(&thd->user_vars, (uchar*) name.str,
> +                                  name.length);
> +  return entry? entry->val_int(&null_value) : 0;
> +}
> +
> +/*
> +  Function prepares and sends repliation heartbeat event.
> +
> +  @param net                net object of THD
> +  @param packet             buffer to store the heartbeat instance
> +  @param event_coordinates  binlog file name and position of the last
> +                            real event master sent from binlog
> +
> +  @note 
> +    Among three essential pieces of heartbeat data Log_event::when
> +    is computed locally.
> +    The  error to send is serious and should force terminating
> +    the dump thread.
> +*/
> +static int send_heartbeat_event(NET* net, String* packet,
> +                                const struct event_coordinates *coord)
> +{
> +  DBUG_ENTER("send_heartbeat_event");
> +  char header[LOG_EVENT_HEADER_LEN];
> +  /*
> +    'when' (the timestamp) is set to 0 so that slave could distinguish between
> +    real and fake Rotate events (if necessary)
> +  */
> +  memset(header, 0, 4);  // when
> +
> +  header[EVENT_TYPE_OFFSET] = HEARTBEAT_LOG_EVENT;
> +
> +  char* p= coord->file_name + dirname_length(coord->file_name);
> +
> +  uint ident_len = strlen(p);
> +  ulong event_len = ident_len + LOG_EVENT_HEADER_LEN;
> +  int4store(header + SERVER_ID_OFFSET, server_id);
> +  int4store(header + EVENT_LEN_OFFSET, event_len);
> +  int2store(header + FLAGS_OFFSET, 0);
> +
> +  int4store(header + LOG_POS_OFFSET, coord->pos);  // log_pos
> +
> +  packet->append(header, sizeof(header));
> +  packet->append(p, ident_len);             // log_file_name
> +
> +  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) ||
> +      net_flush(net))
> +  {
> +    DBUG_RETURN(-1);
> +  }
> +  DBUG_RETURN(0);
> +}
> +
> +/*
> +  TODO: Clean up loop to only have one call to send_file()
> +*/
> +
> +void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos,
> +		       ushort flags)
> +{
> +  LOG_INFO linfo;
> +  char *log_file_name = linfo.log_file_name;
> +  char search_file_name[FN_REFLEN], *name;
> +
> +  ulong ev_offset;
> +
> +  IO_CACHE log;
> +  File file = -1;
> +  String* packet = &thd->packet;
> +  int error;
> +  const char *errmsg = "Unknown error";
> +  NET* net = &thd->net;
> +  mysql_mutex_t *log_lock;
> +  bool binlog_can_be_corrupted= FALSE;
> +#ifndef DBUG_OFF
> +  int left_events = max_binlog_dump_events;
> +#endif
> +  DBUG_ENTER("mysql_binlog_send");
> +  DBUG_PRINT("enter",("log_ident: '%s'  pos: %ld", log_ident, (long) pos));
> +
> +  bzero((char*) &log,sizeof(log));
> +  /* 
> +     heartbeat_period from @master_heartbeat_period user variable
> +  */
> +  ulonglong heartbeat_period= get_heartbeat_period(thd);
> +  struct timespec heartbeat_buf;
> +  struct event_coordinates coord_buf;
> +  struct timespec *heartbeat_ts= NULL;
> +  struct event_coordinates *coord= NULL;
> +  if (heartbeat_period != LL(0))
> +  {
> +    heartbeat_ts= &heartbeat_buf;
> +    set_timespec_nsec(*heartbeat_ts, 0);
> +    coord= &coord_buf;
> +    coord->file_name= log_file_name; // initialization basing on what slave
> remembers
> +    coord->pos= pos;
> +  }
> +  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'";
> +    my_errno= ER_UNKNOWN_ERROR;
> +    goto err;
> +  }
> +
> +#ifndef DBUG_OFF
> +  if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
> +  {
> +    errmsg = "Master failed COM_BINLOG_DUMP to test if slave can recover";
> +    my_errno= ER_UNKNOWN_ERROR;
> +    goto err;
> +  }
> +#endif
> +
> +  if (!mysql_bin_log.is_open())
> +  {
> +    errmsg = "Binary log is not open";
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +  if (!server_id_supplied)
> +  {
> +    errmsg = "Misconfigured master - server id was not set";
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +
> +  name=search_file_name;
> +  if (log_ident[0])
> +    mysql_bin_log.make_log_name(search_file_name, log_ident);
> +  else
> +    name=0;					// Find first log
> +
> +  linfo.index_file_offset = 0;
> +
> +  if (mysql_bin_log.find_log_pos(&linfo, name, 1))
> +  {
> +    errmsg = "Could not find first log file name in binary log index file";
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  thd->current_linfo = &linfo;
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +
> +  if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0)
> +  {
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +  if (pos < BIN_LOG_HEADER_SIZE || pos > my_b_filelength(&log))
> +  {
> +    errmsg= "Client requested master to start replication from \
> +impossible position";
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +
> +  /* reset transmit packet for the fake rotate event below */
> +  if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +    goto err;
> +
> +  /*
> +    Tell the client about the log name with a fake Rotate event;
> +    this is needed even if we also send a Format_description_log_event
> +    just after, because that event does not contain the binlog's name.
> +    Note that as this Rotate event is sent before
> +    Format_description_log_event, the slave cannot have any info to
> +    understand this event's format, so the header len of
> +    Rotate_log_event is FROZEN (so in 5.0 it will have a header shorter
> +    than other events except FORMAT_DESCRIPTION_EVENT).
> +    Before 4.0.14 we called fake_rotate_event below only if (pos ==
> +    BIN_LOG_HEADER_SIZE), because if this is false then the slave
> +    already knows the binlog's name.
> +    Since, we always call fake_rotate_event; if the slave already knew
> +    the log's name (ex: CHANGE MASTER TO MASTER_LOG_FILE=...) this is
> +    useless but does not harm much. It is nice for 3.23 (>=.58) slaves
> +    which test Rotate events to see if the master is 4.0 (then they
> +    choose to stop because they can't replicate 4.0); by always calling
> +    fake_rotate_event we are sure that 3.23.58 and newer will detect the
> +    problem as soon as replication starts (BUG#198).
> +    Always calling fake_rotate_event makes sending of normal
> +    (=from-binlog) Rotate events a priori unneeded, but it is not so
> +    simple: the 2 Rotate events are not equivalent, the normal one is
> +    before the Stop event, the fake one is after. If we don't send the
> +    normal one, then the Stop event will be interpreted (by existing 4.0
> +    slaves) as "the master stopped", which is wrong. So for safety,
> +    given that we want minimum modification of 4.0, we send the normal
> +    and fake Rotates.
> +  */
> +  if (fake_rotate_event(net, packet, log_file_name, pos, &errmsg))
> +  {
> +    /*
> +       This error code is not perfect, as fake_rotate_event() does not
> +       read anything from the binlog; if it fails it's because of an
> +       error in my_net_write(), fortunately it will say so in errmsg.
> +    */
> +    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +    goto err;
> +  }
> +
> +  /*
> +    Adding MAX_LOG_EVENT_HEADER_LEN, since a binlog event can become
> +    this larger than the corresponding packet (query) sent 
> +    from client to master.
> +  */
> +  thd->variables.max_allowed_packet+= MAX_LOG_EVENT_HEADER;
> +
> +  /*
> +    We can set log_lock now, it does not move (it's a member of
> +    mysql_bin_log, and it's already inited, and it will be destroyed
> +    only at shutdown).
> +  */
> +  log_lock = mysql_bin_log.get_log_lock();
> +  if (pos > BIN_LOG_HEADER_SIZE)
> +  {
> +    /* reset transmit packet for the event read from binary log
> +       file */
> +    if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +      goto err;
> +
> +     /*
> +       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)))
> +     {
> +       /*
> +         The packet has offsets equal to the normal offsets in a
> +         binlog event + ev_offset (the first ev_offset characters are
> +         the header (default \0)).
> +       */
> +       DBUG_PRINT("info",
> +                  ("Looked for a Format_description_log_event, found event type
> %d",
> +                   (*packet)[EVENT_TYPE_OFFSET+ev_offset]));
> +       if ((*packet)[EVENT_TYPE_OFFSET+ev_offset] == FORMAT_DESCRIPTION_EVENT)
> +       {
> +         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;
> +         /*
> +           mark that this event with "log_pos=0", so the slave
> +           should not increment master's binlog position
> +           (rli->group_master_log_pos)
> +         */
> +         int4store((char*) packet->ptr()+LOG_POS_OFFSET+ev_offset, 0);
> +         /*
> +           if reconnect master sends FD event with `created' as 0
> +           to avoid destroying temp tables.
> +          */
> +         int4store((char*) packet->ptr()+LOG_EVENT_MINIMAL_HEADER_LEN+
> +                   ST_CREATED_OFFSET+ev_offset, (ulong) 0);
> +         /* send it */
> +         if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
> +         {
> +           errmsg = "Failed on my_net_write()";
> +           my_errno= ER_UNKNOWN_ERROR;
> +           goto err;
> +         }
> +
> +         /*
> +           No need to save this event. We are only doing simple reads
> +           (no real parsing of the events) so we don't need it. And so
> +           we don't need the artificial Format_description_log_event of
> +           3.23&4.x.
> +         */
> +       }
> +     }
> +     else
> +     {
> +       if (test_for_non_eof_log_read_errors(error, &errmsg))
> +         goto err;
> +       /*
> +         It's EOF, nothing to do, go on reading next events, the
> +         Format_description_log_event will be found naturally if it is written.
> +       */
> +     }
> +  } /* end of if (pos > BIN_LOG_HEADER_SIZE); */
> +  else
> +  {
> +    /* The Format_description_log_event event will be found naturally. */
> +  }
> +
> +  /* seek to the requested position, to start the requested dump */
> +  my_b_seek(&log, pos);			// Seek will done on next read
> +
> +  while (!net->error && net->vio != 0 && !thd->killed)
> +  {
> +    Log_event_type event_type= UNKNOWN_EVENT;
> +
> +    /* reset the transmit packet for the event read from binary log
> +       file */
> +    if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +      goto err;
> +    while (!(error = Log_event::read_log_event(&log, packet, log_lock)))
> +    {
> +#ifndef DBUG_OFF
> +      if (max_binlog_dump_events && !left_events--)
> +      {
> +	net_flush(net);
> +	errmsg = "Debugging binlog dump abort";
> +	my_errno= ER_UNKNOWN_ERROR;
> +	goto err;
> +      }
> +#endif
> +      /*
> +        log's filename does not change while it's active
> +      */
> +      if (coord)
> +        coord->pos= uint4korr(packet->ptr() + ev_offset + LOG_POS_OFFSET);
> +
> +      event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
> +      if (event_type == FORMAT_DESCRIPTION_EVENT)
> +      {
> +        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;
> +      }
> +      else if (event_type == STOP_EVENT)
> +        binlog_can_be_corrupted= FALSE;
> +
> +      pos = my_b_tell(&log);
> +      if (RUN_HOOK(binlog_transmit, before_send_event,
> +                   (thd, flags, packet, log_file_name, pos)))
> +      {
> +        my_errno= ER_UNKNOWN_ERROR;
> +        errmsg= "run 'before_send_event' hook failed";
> +        goto err;
> +      }
> +
> +      if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
> +      {
> +	errmsg = "Failed on my_net_write()";
> +	my_errno= ER_UNKNOWN_ERROR;
> +	goto err;
> +      }
> +
> +      DBUG_PRINT("info", ("log event code %d", event_type));
> +      if (event_type == LOAD_EVENT)
> +      {
> +	if (send_file(thd))
> +	{
> +	  errmsg = "failed in send_file()";
> +	  my_errno= ER_UNKNOWN_ERROR;
> +	  goto err;
> +	}
> +      }
> +
> +      if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
> +      {
> +        errmsg= "Failed to run hook 'after_send_event'";
> +        my_errno= ER_UNKNOWN_ERROR;
> +        goto err;
> +      }
> +
> +      /* reset transmit packet for next loop */
> +      if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +        goto err;
> +    }
> +
> +    /*
> +      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)
> +      error=LOG_READ_EOF;
> +    /*
> +      TODO: now that we are logging the offset, check to make sure
> +      the recorded offset and the actual match.
> +      Guilhem 2003-06: this is not true if this master is a slave
> +      <4.0.15 running with --log-slave-updates, because then log_pos may
> +      be the offset in the-master-of-this-master's binlog.
> +    */
> +    if (test_for_non_eof_log_read_errors(error, &errmsg))
> +      goto err;
> +
> +    if (!(flags & BINLOG_DUMP_NON_BLOCK) &&
> +        mysql_bin_log.is_active(log_file_name))
> +    {
> +      /*
> +	Block until there is more data in the log
> +      */
> +      if (net_flush(net))
> +      {
> +	errmsg = "failed on net_flush()";
> +	my_errno= ER_UNKNOWN_ERROR;
> +	goto err;
> +      }
> +
> +      /*
> +	We may have missed the update broadcast from the log
> +	that has just happened, let's try to catch it if it did.
> +	If we did not miss anything, we just wait for other threads
> +	to signal us.
> +      */
> +      {
> +	log.error=0;
> +	bool read_packet = 0;
> +
> +#ifndef DBUG_OFF
> +	if (max_binlog_dump_events && !left_events--)
> +	{
> +	  errmsg = "Debugging binlog dump abort";
> +	  my_errno= ER_UNKNOWN_ERROR;
> +	  goto err;
> +	}
> +#endif
> +
> +        /* reset the transmit packet for the event read from binary log
> +           file */
> +        if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +          goto err;
> +        
> +	/*
> +	  No one will update the log while we are reading
> +	  now, but we'll be quick and just read one record
> +
> +	  TODO:
> +          Add an counter that is incremented for each time we update the
> +          binary log.  We can avoid the following read if the counter
> +          has not been updated since last read.
> +	*/
> +
> +        mysql_mutex_lock(log_lock);
> +        switch (error= Log_event::read_log_event(&log, packet, (mysql_mutex_t*)
> 0)) {
> +	case 0:
> +	  /* we read successfully, so we'll need to send it to the slave */
> +          mysql_mutex_unlock(log_lock);
> +	  read_packet = 1;
> +          if (coord)
> +            coord->pos= uint4korr(packet->ptr() + ev_offset +
> LOG_POS_OFFSET);
> +          event_type= (Log_event_type)((*packet)[LOG_EVENT_OFFSET+ev_offset]);
> +	  break;
> +
> +	case LOG_READ_EOF:
> +        {
> +          int ret;
> +          ulong signal_cnt;
> +	  DBUG_PRINT("wait",("waiting for data in binary log"));
> +	  if (thd->server_id==0) // for mysqlbinlog (mysqlbinlog.server_id==0)
> +	  {
> +            mysql_mutex_unlock(log_lock);
> +	    goto end;
> +	  }
> +
> +#ifndef DBUG_OFF
> +          ulong hb_info_counter= 0;
> +#endif
> +          signal_cnt= mysql_bin_log.signal_cnt;
> +          do 
> +          {
> +            if (coord)
> +            {
> +              DBUG_ASSERT(heartbeat_ts && heartbeat_period != 0);
> +              set_timespec_nsec(*heartbeat_ts, heartbeat_period);
> +            }
> +            ret= mysql_bin_log.wait_for_update_bin_log(thd, heartbeat_ts);
> +            DBUG_ASSERT(ret == 0 || (heartbeat_period != 0 && coord !=
> NULL));
> +            if (ret == ETIMEDOUT || ret == ETIME)
> +            {
> +#ifndef DBUG_OFF
> +              if (hb_info_counter < 3)
> +              {
> +                sql_print_information("master sends heartbeat message");
> +                hb_info_counter++;
> +                if (hb_info_counter == 3)
> +                  sql_print_information("the rest of heartbeat info skipped ...");
> +              }
> +#endif
> +              /* reset transmit packet for the heartbeat event */
> +              if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +                goto err;
> +              if (send_heartbeat_event(net, packet, coord))
> +              {
> +                errmsg = "Failed on my_net_write()";
> +                my_errno= ER_UNKNOWN_ERROR;
> +                mysql_mutex_unlock(log_lock);
> +                goto err;
> +              }
> +            }
> +            else
> +            {
> +              DBUG_PRINT("wait",("binary log received update or a broadcast signal
> caught"));
> +            }
> +          } while (signal_cnt == mysql_bin_log.signal_cnt &&
> !thd->killed);
> +          mysql_mutex_unlock(log_lock);
> +        }
> +        break;
> +            
> +        default:
> +          mysql_mutex_unlock(log_lock);
> +          test_for_non_eof_log_read_errors(error, &errmsg);
> +          goto err;
> +	}
> +
> +	if (read_packet)
> +        {
> +          thd_proc_info(thd, "Sending binlog event to slave");
> +          pos = my_b_tell(&log);
> +          if (RUN_HOOK(binlog_transmit, before_send_event,
> +                       (thd, flags, packet, log_file_name, pos)))
> +          {
> +            my_errno= ER_UNKNOWN_ERROR;
> +            errmsg= "run 'before_send_event' hook failed";
> +            goto err;
> +          }
> +	  
> +	  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()) )
> +	  {
> +	    errmsg = "Failed on my_net_write()";
> +	    my_errno= ER_UNKNOWN_ERROR;
> +	    goto err;
> +	  }
> +
> +	  if (event_type == LOAD_EVENT)
> +	  {
> +	    if (send_file(thd))
> +	    {
> +	      errmsg = "failed in send_file()";
> +	      my_errno= ER_UNKNOWN_ERROR;
> +	      goto err;
> +	    }
> +	  }
> +
> +          if (RUN_HOOK(binlog_transmit, after_send_event, (thd, flags, packet)))
> +          {
> +            my_errno= ER_UNKNOWN_ERROR;
> +            errmsg= "Failed to run hook 'after_send_event'";
> +            goto err;
> +          }
> +	}
> +
> +	log.error=0;
> +      }
> +    }
> +    else
> +    {
> +      bool loop_breaker = 0;
> +      /* need this to break out of the for loop from switch */
> +
> +      thd_proc_info(thd, "Finished reading one binlog; switching to next binlog");
> +      switch (mysql_bin_log.find_next_log(&linfo, 1)) {
> +      case 0:
> +	break;
> +      case LOG_INFO_EOF:
> +        if (mysql_bin_log.is_active(log_file_name))
> +        {
> +          loop_breaker = (flags & BINLOG_DUMP_NON_BLOCK);
> +          break;
> +        }
> +      default:
> +	errmsg = "could not find next log";
> +	my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +	goto err;
> +      }
> +
> +      if (loop_breaker)
> +        break;
> +
> +      end_io_cache(&log);
> +      mysql_file_close(file, MYF(MY_WME));
> +
> +      /* reset transmit packet for the possible fake rotate event */
> +      if (reset_transmit_packet(thd, flags, &ev_offset, &errmsg))
> +        goto err;
> +      
> +      /*
> +        Call fake_rotate_event() in case the previous log (the one which
> +        we have just finished reading) did not contain a Rotate event
> +        (for example (I don't know any other example) the previous log
> +        was the last one before the master was shutdown & restarted).
> +        This way we tell the slave about the new log's name and
> +        position.  If the binlog is 5.0, the next event we are going to
> +        read and send is Format_description_log_event.
> +      */
> +      if ((file=open_binlog(&log, log_file_name, &errmsg)) < 0 ||
> +	  fake_rotate_event(net, packet, log_file_name, BIN_LOG_HEADER_SIZE,
> +                            &errmsg))
> +      {
> +	my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
> +	goto err;
> +      }
> +
> +      if (coord)
> +        coord->file_name= log_file_name; // reset to the next
> +    }
> +  }
> +
> +end:
> +  end_io_cache(&log);
> +  mysql_file_close(file, MYF(MY_WME));
> +
> +  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
> +  my_eof(thd);
> +  thd_proc_info(thd, "Waiting to finalize termination");
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  thd->current_linfo = 0;
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  DBUG_VOID_RETURN;
> +
> +err:
> +  thd_proc_info(thd, "Waiting to finalize termination");
> +  end_io_cache(&log);
> +  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
> +  /*
> +    Exclude  iteration through thread list
> +    this is needed for purge_logs() - it will iterate through
> +    thread list and update thd->current_linfo->index_file_offset
> +    this mutex will make sure that it never tried to update our linfo
> +    after we return from this stack frame
> +  */
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  thd->current_linfo = 0;
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  if (file >= 0)
> +    mysql_file_close(file, MYF(MY_WME));
> +
> +  my_message(my_errno, errmsg, MYF(0));
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +void kill_zombie_dump_threads(uint32 slave_server_id)
> +{
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  I_List_iterator<THD> it(threads);
> +  THD *tmp;
> +
> +  while ((tmp=it++))
> +  {
> +    if (tmp->command == COM_BINLOG_DUMP &&
> +       tmp->server_id == slave_server_id)
> +    {
> +      mysql_mutex_lock(&tmp->LOCK_thd_data);    // Lock from delete
> +      break;
> +    }
> +  }
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  if (tmp)
> +  {
> +    /*
> +      Here we do not call kill_one_thread() as
> +      it will be slow because it will iterate through the list
> +      again. We just to do kill the thread ourselves.
> +    */
> +    tmp->awake(THD::KILL_QUERY);
> +    mysql_mutex_unlock(&tmp->LOCK_thd_data);
> +  }
> +}
> +
> +
> +/**
> +  Execute a RESET MASTER statement.
> +
> +  @param thd Pointer to THD object of the client thread executing the
> +  statement.
> +
> +  @retval 0 success
> +  @retval 1 error
> +*/
> +int reset_master(THD* thd)
> +{
> +  if (!mysql_bin_log.is_open())
> +  {
> +    my_message(ER_FLUSH_MASTER_BINLOG_CLOSED,
> +               ER(ER_FLUSH_MASTER_BINLOG_CLOSED), MYF(ME_BELL+ME_WAITTANG));
> +    return 1;
> +  }
> +
> +  if (mysql_bin_log.reset_logs(thd))
> +    return 1;
> +  RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */));
> +  return 0;
> +}
> +
> +int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
> +		   const char* log_file_name2, ulonglong log_pos2)
> +{
> +  int res;
> +  size_t log_file_name1_len=  strlen(log_file_name1);
> +  size_t log_file_name2_len=  strlen(log_file_name2);
> +
> +  //  We assume that both log names match up to '.'
> +  if (log_file_name1_len == log_file_name2_len)
> +  {
> +    if ((res= strcmp(log_file_name1, log_file_name2)))
> +      return res;
> +    return (log_pos1 < log_pos2) ? -1 : (log_pos1 == log_pos2) ? 0 : 1;
> +  }
> +  return ((log_file_name1_len < log_file_name2_len) ? -1 : 1);
> +}
> +
> +
> +/**
> +  Execute a SHOW MASTER STATUS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool show_binlog_info(THD* thd)
> +{
> +  Protocol *protocol= thd->protocol;
> +  DBUG_ENTER("show_binlog_info");
> +  List<Item> field_list;
> +  field_list.push_back(new Item_empty_string("File", FN_REFLEN));
> +  field_list.push_back(new Item_return_int("Position",20,
> +					   MYSQL_TYPE_LONGLONG));
> +  field_list.push_back(new Item_empty_string("Binlog_Do_DB",255));
> +  field_list.push_back(new Item_empty_string("Binlog_Ignore_DB",255));
> +
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +  protocol->prepare_for_resend();
> +
> +  if (mysql_bin_log.is_open())
> +  {
> +    LOG_INFO li;
> +    mysql_bin_log.get_current_log(&li);
> +    int dir_len = dirname_length(li.log_file_name);
> +    protocol->store(li.log_file_name + dir_len, &my_charset_bin);
> +    protocol->store((ulonglong) li.pos);
> +    protocol->store(binlog_filter->get_do_db());
> +    protocol->store(binlog_filter->get_ignore_db());
> +    if (protocol->write())
> +      DBUG_RETURN(TRUE);
> +  }
> +  my_eof(thd);
> +  DBUG_RETURN(FALSE);
> +}
> +
> +
> +/**
> +  Execute a SHOW BINARY LOGS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool show_binlogs(THD* thd)
> +{
> +  IO_CACHE *index_file;
> +  LOG_INFO cur;
> +  File file;
> +  char fname[FN_REFLEN];
> +  List<Item> field_list;
> +  uint length;
> +  int cur_dir_len;
> +  Protocol *protocol= thd->protocol;
> +  DBUG_ENTER("show_binlogs");
> +
> +  if (!mysql_bin_log.is_open())
> +  {
> +    my_message(ER_NO_BINARY_LOGGING, ER(ER_NO_BINARY_LOGGING), MYF(0));
> +    DBUG_RETURN(TRUE);
> +  }
> +
> +  field_list.push_back(new Item_empty_string("Log_name", 255));
> +  field_list.push_back(new Item_return_int("File_size", 20,
> +                                           MYSQL_TYPE_LONGLONG));
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +  
> +  mysql_mutex_lock(mysql_bin_log.get_log_lock());
> +  mysql_bin_log.lock_index();
> +  index_file=mysql_bin_log.get_index_file();
> +  
> +  mysql_bin_log.raw_get_current_log(&cur); // dont take mutex
> +  mysql_mutex_unlock(mysql_bin_log.get_log_lock()); // lockdep, OK
> +  
> +  cur_dir_len= dirname_length(cur.log_file_name);
> +
> +  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 0);
> +
> +  /* The file ends with EOF or empty line */
> +  while ((length=my_b_gets(index_file, fname, sizeof(fname))) > 1)
> +  {
> +    int dir_len;
> +    ulonglong file_length= 0;                   // Length if open fails
> +    fname[--length] = '\0';                     // remove the newline
> +
> +    protocol->prepare_for_resend();
> +    dir_len= dirname_length(fname);
> +    length-= dir_len;
> +    protocol->store(fname + dir_len, length, &my_charset_bin);
> +
> +    if (!(strncmp(fname+dir_len, cur.log_file_name+cur_dir_len, length)))
> +      file_length= cur.pos;  /* The active log, use the active position */
> +    else
> +    {
> +      /* this is an old log, open it and find the size */
> +      if ((file= mysql_file_open(key_file_binlog,
> +                                 fname, O_RDONLY | O_SHARE | O_BINARY,
> +                                 MYF(0))) >= 0)
> +      {
> +        file_length= (ulonglong) mysql_file_seek(file, 0L, MY_SEEK_END, MYF(0));
> +        mysql_file_close(file, MYF(0));
> +      }
> +    }
> +    protocol->store(file_length);
> +    if (protocol->write())
> +      goto err;
> +  }
> +  mysql_bin_log.unlock_index();
> +  my_eof(thd);
> +  DBUG_RETURN(FALSE);
> +
> +err:
> +  mysql_bin_log.unlock_index();
> +  DBUG_RETURN(TRUE);
> +}
> +
> +#endif /* HAVE_REPLICATION */
> 
> === added file 'sql/rpl_master.h'
> --- a/sql/rpl_master.h	1970-01-01 00:00:00 +0000
> +++ b/sql/rpl_master.h	2010-06-21 05:56:56 +0000
> @@ -0,0 +1,34 @@
> +#ifndef RPL_MASTER_H_INCLUDED
> +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +
> +#define RPL_MASTER_H_INCLUDED
> +extern bool server_id_supplied;
> +extern int max_binlog_dump_events;
> +extern my_bool opt_sporadic_binlog_dump_fail;
> +
> +void init_slave_list();
> +void end_slave_list();
> +int register_slave(THD* thd, uchar* packet, uint packet_length);
> +void unregister_slave(THD* thd, bool only_mine, bool need_mutex);
> +bool show_slave_hosts(THD* thd);
> +
> +bool mysql_show_binlog_events(THD* thd);
> +bool show_binlogs(THD* thd);
> +void kill_zombie_dump_threads(uint32 slave_server_id);
> +void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
> +int reset_master(THD* thd);
> +#endif /* RPL_MASTER_H_INCLUDED */
> 
> === modified file 'sql/rpl_mi.cc'
> --- a/sql/rpl_mi.cc	2010-05-18 15:35:14 +0000
> +++ b/sql/rpl_mi.cc	2010-06-21 06:01:50 +0000
> @@ -18,7 +18,7 @@
>  #include <my_dir.h>
>  #include "unireg.h"                             // REQUIRED by other includes
>  #include "rpl_mi.h"
> -#include "slave.h"                              // SLAVE_MAX_HEARTBEAT_PERIOD
> +#include "rpl_slave.h"                          // SLAVE_MAX_HEARTBEAT_PERIOD
>  
>  #ifdef HAVE_REPLICATION
>  
> 
> === modified file 'sql/rpl_record.cc'
> --- a/sql/rpl_record.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/rpl_record.cc	2010-06-21 06:01:50 +0000
> @@ -17,7 +17,7 @@
>  #include "unireg.h"
>  #include "rpl_rli.h"
>  #include "rpl_record.h"
> -#include "slave.h"                  // Need to pull in slave_print_msg
> +#include "rpl_slave.h"                  // Need to pull in slave_print_msg
>  #include "rpl_utility.h"
>  #include "rpl_rli.h"
>  
> 
> === modified file 'sql/rpl_rli.cc'
> --- a/sql/rpl_rli.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/rpl_rli.cc	2010-06-21 06:01:50 +0000
> @@ -19,10 +19,10 @@
>  #include "rpl_rli.h"
>  #include "sql_base.h"                        // close_thread_tables
>  #include <my_dir.h>    // For MY_STAT
> -#include "sql_repl.h"  // For check_binlog_magic
>  #include "log_event.h" // Format_description_log_event, Log_event,
>                         // FORMAT_DESCRIPTION_LOG_EVENT, ROTATE_EVENT,
>                         // PREFIX_SQL_LOAD
> +#include "rpl_slave.h"
>  #include "rpl_utility.h"
>  #include "transaction.h"
>  #include "sql_parse.h"                          // end_trans, ROLLBACK
> @@ -1261,4 +1261,32 @@ void Relay_log_info::slave_close_thread_
>    close_thread_tables(thd);
>    clear_tables_to_lock();
>  }
> +/**
> +  Execute a SHOW RELAYLOG EVENTS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool mysql_show_relaylog_events(THD* thd)
> +{
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  DBUG_ENTER("mysql_show_relaylog_events");
> +
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
> +
> +  Log_event::init_show_field_list(&field_list);
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +
> +  if (!active_mi)
> +    DBUG_RETURN(TRUE);
> +  
> +  DBUG_RETURN(show_binlog_events(thd, &active_mi->rli.relay_log));
> +}
> +
>  #endif
> 
> === modified file 'sql/rpl_rli.h'
> --- a/sql/rpl_rli.h	2010-04-01 19:34:09 +0000
> +++ b/sql/rpl_rli.h	2010-06-21 06:01:50 +0000
> @@ -19,7 +19,8 @@
>  #include "rpl_tblmap.h"
>  #include "rpl_reporting.h"
>  #include "rpl_utility.h"
> -#include "log.h"                         /* LOG_INFO, MYSQL_BIN_LOG */
> +#include "log.h"                         /* LOG_INFO */
> +#include "binlog.h"                      /* MYSQL_BIN_LOG */
>  #include "sql_class.h"                   /* THD */
>  
>  struct RPL_TABLE_LIST;
> @@ -449,6 +450,15 @@ private:
>  
>  // Defined in rpl_rli.cc
>  int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
> -
> +bool flush_relay_log_info(Relay_log_info* rli);
> +void end_relay_log_info(Relay_log_info* rli);
> +int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
> +		       bool need_data_lock, const char** errmsg,
> +                       bool look_for_description_event);
> +
> +int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
> +		     const char** errmsg);
> +void rotate_relay_log(Master_info* mi);
> +bool mysql_show_relaylog_events(THD* thd);
>  
>  #endif /* RPL_RLI_H */
> 
> === renamed file 'sql/slave.cc' => 'sql/rpl_slave.cc'
> --- a/sql/slave.cc	2010-05-18 15:35:14 +0000
> +++ b/sql/rpl_slave.cc	2010-06-21 06:01:50 +0000
> @@ -26,14 +26,12 @@
>  
>  #include "sql_priv.h"
>  #include "my_global.h"
> -#include "slave.h"
> +#include "rpl_slave.h"
>  #include "sql_parse.h"                         // execute_init_command
>  #include "sql_table.h"                         // mysql_rm_table
>  #include "rpl_mi.h"
>  #include "rpl_rli.h"
> -#include "sql_repl.h"
>  #include "rpl_filter.h"
> -#include "repl_failsafe.h"
>  #include "transaction.h"
>  #include <thr_alarm.h>
>  #include <my_dir.h>
> @@ -3043,8 +3041,6 @@ err:
>    /* Forget the relay log's format */
>    delete mi->rli.relay_log.description_event_for_queue;
>    mi->rli.relay_log.description_event_for_queue= 0;
> -  // TODO: make rpl_status part of Master_info
> -  change_rpl_status(RPL_ACTIVE_SLAVE,RPL_IDLE_SLAVE);
>    DBUG_ASSERT(thd->net.buff != 0);
>    net_end(&thd->net); // destructor will not free it, because net.vio is 0
>    close_thread_tables(thd);
> @@ -4201,8 +4197,6 @@ static int connect_to_master(THD* thd, M
>      if (++err_count == master_retry_count)
>      {
>        slave_was_killed=1;
> -      if (reconnect)
> -        change_rpl_status(RPL_ACTIVE_SLAVE,RPL_LOST_SOLDIER);
>        break;
>      }
>      safe_sleep(thd,mi->connect_retry,(CHECK_KILLED_FUNC)io_slave_killed,
> @@ -4223,7 +4217,6 @@ replication resumed in log '%s' at posit
>      }
>      else
>      {
> -      change_rpl_status(RPL_IDLE_SLAVE,RPL_ACTIVE_SLAVE);
>        general_log_print(thd, COM_CONNECT_OUT, "%s@%s:%d",
>                          mi->user, mi->host, mi->port);
>      }
> @@ -4932,6 +4925,591 @@ template class I_List_iterator<i_string_
>  #endif
>  
>  /**
> +  a copy of active_mi->rli->slave_skip_counter, for showing in SHOW
> VARIABLES,
> +  INFORMATION_SCHEMA.GLOBAL_VARIABLES and @@sql_slave_skip_counter without
> +  taking all the mutexes needed to access active_mi->rli->slave_skip_counter
> +  properly.
> +*/
> +uint sql_slave_skip_counter;
> +
> +/**
> +  Execute a START SLAVE statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param mi Pointer to Master_info object for the slave's IO thread.
> +
> +  @param net_report If true, saves the exit status into thd->stmt_da.
> +
> +  @retval 0 success
> +  @retval 1 error
> +*/
> +int start_slave(THD* thd , Master_info* mi,  bool net_report)
> +{
> +  int slave_errno= 0;
> +  int thread_mask;
> +  DBUG_ENTER("start_slave");
> +
> +  if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
> +    DBUG_RETURN(1);
> +  lock_slave_threads(mi);  // this allows us to cleanly read slave_running
> +  // Get a mask of _stopped_ threads
> +  init_thread_mask(&thread_mask,mi,1 /* inverse */);
> +  /*
> +    Below we will start all stopped threads.  But if the user wants to
> +    start only one thread, do as if the other thread was running (as we
> +    don't wan't to touch the other thread), so set the bit to 0 for the
> +    other thread
> +  */
> +  if (thd->lex->slave_thd_opt)
> +    thread_mask&= thd->lex->slave_thd_opt;
> +  if (thread_mask) //some threads are stopped, start them
> +  {
> +    if (init_master_info(mi,master_info_file,relay_log_info_file, 0,
> +			 thread_mask))
> +      slave_errno=ER_MASTER_INFO;
> +    else if (server_id_supplied && *mi->host)
> +    {
> +      /*
> +        If we will start SQL thread we will care about UNTIL options If
> +        not and they are specified we will ignore them and warn user
> +        about this fact.
> +      */
> +      if (thread_mask & SLAVE_SQL)
> +      {
> +        mysql_mutex_lock(&mi->rli.data_lock);
> +
> +        if (thd->lex->mi.pos)
> +        {
> +          mi->rli.until_condition= Relay_log_info::UNTIL_MASTER_POS;
> +          mi->rli.until_log_pos= thd->lex->mi.pos;
> +          /*
> +             We don't check thd->lex->mi.log_file_name for NULL here
> +             since it is checked in sql_yacc.yy
> +          */
> +          strmake(mi->rli.until_log_name, thd->lex->mi.log_file_name,
> +                  sizeof(mi->rli.until_log_name)-1);
> +        }
> +        else if (thd->lex->mi.relay_log_pos)
> +        {
> +          mi->rli.until_condition= Relay_log_info::UNTIL_RELAY_POS;
> +          mi->rli.until_log_pos= thd->lex->mi.relay_log_pos;
> +          strmake(mi->rli.until_log_name, thd->lex->mi.relay_log_name,
> +                  sizeof(mi->rli.until_log_name)-1);
> +        }
> +        else
> +          mi->rli.clear_until_condition();
> +
> +        if (mi->rli.until_condition != Relay_log_info::UNTIL_NONE)
> +        {
> +          /* Preparing members for effective until condition checking */
> +          const char *p= fn_ext(mi->rli.until_log_name);
> +          char *p_end;
> +          if (*p)
> +          {
> +            //p points to '.'
> +            mi->rli.until_log_name_extension= strtoul(++p,&p_end, 10);
> +            /*
> +              p_end points to the first invalid character. If it equals
> +              to p, no digits were found, error. If it contains '\0' it
> +              means  conversion went ok.
> +            */
> +            if (p_end==p || *p_end)
> +              slave_errno=ER_BAD_SLAVE_UNTIL_COND;
> +          }
> +          else
> +            slave_errno=ER_BAD_SLAVE_UNTIL_COND;
> +
> +          /* mark the cached result of the UNTIL comparison as "undefined" */
> +          mi->rli.until_log_names_cmp_result=
> +            Relay_log_info::UNTIL_LOG_NAMES_CMP_UNKNOWN;
> +
> +          /* Issuing warning then started without --skip-slave-start */
> +          if (!opt_skip_slave_start)
> +            push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
> +                         ER_MISSING_SKIP_SLAVE,
> +                         ER(ER_MISSING_SKIP_SLAVE));
> +        }
> +
> +        mysql_mutex_unlock(&mi->rli.data_lock);
> +      }
> +      else if (thd->lex->mi.pos || thd->lex->mi.relay_log_pos)
> +        push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_UNTIL_COND_IGNORED,
> +                     ER(ER_UNTIL_COND_IGNORED));
> +
> +      if (!slave_errno)
> +        slave_errno = start_slave_threads(0 /*no mutex */,
> +					1 /* wait for start */,
> +					mi,
> +					master_info_file,relay_log_info_file,
> +					thread_mask);
> +    }
> +    else
> +      slave_errno = ER_BAD_SLAVE;
> +  }
> +  else
> +  {
> +    /* no error if all threads are already started, only a warning */
> +    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_RUNNING,
> +                 ER(ER_SLAVE_WAS_RUNNING));
> +  }
> +
> +  unlock_slave_threads(mi);
> +
> +  if (slave_errno)
> +  {
> +    if (net_report)
> +      my_message(slave_errno, ER(slave_errno), MYF(0));
> +    DBUG_RETURN(1);
> +  }
> +  else if (net_report)
> +    my_ok(thd);
> +
> +  DBUG_RETURN(0);
> +}
> +
> +
> +/**
> +  Execute a STOP SLAVE statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param mi Pointer to Master_info object for the slave's IO thread.
> +
> +  @param net_report If true, saves the exit status into thd->stmt_da.
> +
> +  @retval 0 success
> +  @retval 1 error
> +*/
> +int stop_slave(THD* thd, Master_info* mi, bool net_report )
> +{
> +  DBUG_ENTER("stop_slave");
> +  
> +  int slave_errno;
> +  if (!thd)
> +    thd = current_thd;
> +
> +  if (check_access(thd, SUPER_ACL, any_db, NULL, NULL, 0, 0))
> +    DBUG_RETURN(1);
> +  thd_proc_info(thd, "Killing slave");
> +  int thread_mask;
> +  lock_slave_threads(mi);
> +  // Get a mask of _running_ threads
> +  init_thread_mask(&thread_mask,mi,0 /* not inverse*/);
> +  /*
> +    Below we will stop all running threads.
> +    But if the user wants to stop only one thread, do as if the other thread
> +    was stopped (as we don't wan't to touch the other thread), so set the
> +    bit to 0 for the other thread
> +  */
> +  if (thd->lex->slave_thd_opt)
> +    thread_mask &= thd->lex->slave_thd_opt;
> +
> +  if (thread_mask)
> +  {
> +    slave_errno= terminate_slave_threads(mi,thread_mask,
> +                                         1 /*skip lock */);
> +  }
> +  else
> +  {
> +    //no error if both threads are already stopped, only a warning
> +    slave_errno= 0;
> +    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE, ER_SLAVE_WAS_NOT_RUNNING,
> +                 ER(ER_SLAVE_WAS_NOT_RUNNING));
> +  }
> +  unlock_slave_threads(mi);
> +  thd_proc_info(thd, 0);
> +
> +  if (slave_errno)
> +  {
> +    if (net_report)
> +      my_message(slave_errno, ER(slave_errno), MYF(0));
> +    DBUG_RETURN(1);
> +  }
> +  else if (net_report)
> +    my_ok(thd);
> +
> +  DBUG_RETURN(0);
> +}
> +
> +
> +/**
> +  Execute a RESET SLAVE statement.
> +
> +  @param thd Pointer to THD object of the client thread executing the
> +  statement.
> +
> +  @param mi Pointer to Master_info object for the slave.
> +
> +  @retval 0 success
> +  @retval 1 error
> +*/
> +int reset_slave(THD *thd, Master_info* mi)
> +{
> +  MY_STAT stat_area;
> +  char fname[FN_REFLEN];
> +  int thread_mask= 0, error= 0;
> +  uint sql_errno=ER_UNKNOWN_ERROR;
> +  const char* errmsg= "Unknown error occured while reseting slave";
> +  DBUG_ENTER("reset_slave");
> +
> +  lock_slave_threads(mi);
> +  init_thread_mask(&thread_mask,mi,0 /* not inverse */);
> +  if (thread_mask) // We refuse if any slave thread is running
> +  {
> +    sql_errno= ER_SLAVE_MUST_STOP;
> +    error=1;
> +    goto err;
> +  }
> +
> +  ha_reset_slave(thd);
> +
> +  // delete relay logs, clear relay log coordinates
> +  if ((error= purge_relay_logs(&mi->rli, thd,
> +			       1 /* just reset */,
> +			       &errmsg)))
> +  {
> +    sql_errno= ER_RELAY_LOG_FAIL;
> +    goto err;
> +  }
> +
> +  /* Clear master's log coordinates */
> +  init_master_log_pos(mi);
> +  /*
> +     Reset errors (the idea is that we forget about the
> +     old master).
> +  */
> +  mi->clear_error();
> +  mi->rli.clear_error();
> +  mi->rli.clear_until_condition();
> +
> +  // close master_info_file, relay_log_info_file, set
> mi->inited=rli->inited=0
> +  end_master_info(mi);
> +  // and delete these two files
> +  fn_format(fname, master_info_file, mysql_data_home, "", 4+32);
> +  if (mysql_file_stat(key_file_master_info, fname, &stat_area, MYF(0))
> &&
> +      mysql_file_delete(key_file_master_info, fname, MYF(MY_WME)))
> +  {
> +    error=1;
> +    goto err;
> +  }
> +  // delete relay_log_info_file
> +  fn_format(fname, relay_log_info_file, mysql_data_home, "", 4+32);
> +  if (mysql_file_stat(key_file_relay_log_info, fname, &stat_area, MYF(0))
> &&
> +      mysql_file_delete(key_file_relay_log_info, fname, MYF(MY_WME)))
> +  {
> +    error=1;
> +    goto err;
> +  }
> +
> +  RUN_HOOK(binlog_relay_io, after_reset_slave, (thd, mi));
> +err:
> +  unlock_slave_threads(mi);
> +  if (error)
> +    my_error(sql_errno, MYF(0), errmsg);
> +  DBUG_RETURN(error);
> +}
> +
> +/*
> +
> +  Kill all Binlog_dump threads which previously talked to the same slave
> +  ("same" means with the same server id). Indeed, if the slave stops, if the
> +  Binlog_dump thread is waiting (mysql_cond_wait) for binlog update, then it
> +  will keep existing until a query is written to the binlog. If the master is
> +  idle, then this could last long, and if the slave reconnects, we could have 2
> +  Binlog_dump threads in SHOW PROCESSLIST, until a query is written to the
> +  binlog. To avoid this, when the slave reconnects and sends COM_BINLOG_DUMP,
> +  the master kills any existing thread with the slave's server id (if this id is
> +  not zero; it will be true for real slaves, but false for mysqlbinlog when it
> +  sends COM_BINLOG_DUMP to get a remote binlog dump).
> +
> +  SYNOPSIS
> +    kill_zombie_dump_threads()
> +    slave_server_id     the slave's server id
> +
> +*/
> +
> +
> +/**
> +  Execute a CHANGE MASTER statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param mi Pointer to Master_info object belonging to the slave's IO
> +  thread.
> +
> +  @retval FALSE success
> +  @retval TRUE error
> +*/
> +bool change_master(THD* thd, Master_info* mi)
> +{
> +  int thread_mask;
> +  const char* errmsg= 0;
> +  bool need_relay_log_purge= 1;
> +  bool ret= FALSE;
> +  DBUG_ENTER("change_master");
> +
> +  lock_slave_threads(mi);
> +  init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
> +  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
> +  if (thread_mask) // We refuse if any slave thread is running
> +  {
> +    my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
> +    ret= TRUE;
> +    goto err;
> +  }
> +
> +  thd_proc_info(thd, "Changing master");
> +  /* 
> +    We need to check if there is an empty master_host. Otherwise
> +    change master succeeds, a master.info file is created containing 
> +    empty master_host string and when issuing: start slave; an error
> +    is thrown stating that the server is not configured as slave.
> +    (See BUG#28796).
> +  */
> +  if(lex_mi->host && !*lex_mi->host) 
> +  {
> +    my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST");
> +    unlock_slave_threads(mi);
> +    DBUG_RETURN(TRUE);
> +  }
> +  // TODO: see if needs re-write
> +  if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
> +		       thread_mask))
> +  {
> +    my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
> +    ret= TRUE;
> +    goto err;
> +  }
> +
> +  /*
> +    Data lock not needed since we have already stopped the running threads,
> +    and we have the hold on the run locks which will keep all threads that
> +    could possibly modify the data structures from running
> +  */
> +
> +  /*
> +    If the user specified host or port without binlog or position,
> +    reset binlog's name to FIRST and position to 4.
> +  */
> +
> +  if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name
> && !lex_mi->pos)
> +  {
> +    mi->master_log_name[0] = 0;
> +    mi->master_log_pos= BIN_LOG_HEADER_SIZE;
> +  }
> +
> +  if (lex_mi->log_file_name)
> +    strmake(mi->master_log_name, lex_mi->log_file_name,
> +	    sizeof(mi->master_log_name)-1);
> +  if (lex_mi->pos)
> +  {
> +    mi->master_log_pos= lex_mi->pos;
> +  }
> +  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
> +
> +  if (lex_mi->host)
> +    strmake(mi->host, lex_mi->host, sizeof(mi->host)-1);
> +  if (lex_mi->user)
> +    strmake(mi->user, lex_mi->user, sizeof(mi->user)-1);
> +  if (lex_mi->password)
> +    strmake(mi->password, lex_mi->password, sizeof(mi->password)-1);
> +  if (lex_mi->port)
> +    mi->port = lex_mi->port;
> +  if (lex_mi->connect_retry)
> +    mi->connect_retry = lex_mi->connect_retry;
> +  if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
> +    mi->heartbeat_period = lex_mi->heartbeat_period;
> +  else
> +    mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
> +                                      (slave_net_timeout/2.0));
> +  mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd
> +  /*
> +    reset the last time server_id list if the current CHANGE MASTER 
> +    is mentioning IGNORE_SERVER_IDS= (...)
> +  */
> +  if (lex_mi->repl_ignore_server_ids_opt == LEX_MASTER_INFO::LEX_MI_ENABLE)
> +    reset_dynamic(&mi->ignore_server_ids);
> +  for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++)
> +  {
> +    ulong s_id;
> +    get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i);
> +    if (s_id == ::server_id && replicate_same_server_id)
> +    {
> +      my_error(ER_SLAVE_IGNORE_SERVER_IDS, MYF(0), s_id);
> +      ret= TRUE;
> +      goto err;
> +    }
> +    else
> +    {
> +      if (bsearch((const ulong *) &s_id,
> +                  mi->ignore_server_ids.buffer,
> +                  mi->ignore_server_ids.elements, sizeof(ulong),
> +                  (int (*) (const void*, const void*))
> +                  change_master_server_id_cmp) == NULL)
> +        insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id);
> +    }
> +  }
> +  sort_dynamic(&mi->ignore_server_ids, (qsort_cmp)
> change_master_server_id_cmp);
> +
> +  if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
> +    mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
> +
> +  if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
> +    mi->ssl_verify_server_cert=
> +      (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
> +
> +  if (lex_mi->ssl_ca)
> +    strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
> +  if (lex_mi->ssl_capath)
> +    strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1);
> +  if (lex_mi->ssl_cert)
> +    strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1);
> +  if (lex_mi->ssl_cipher)
> +    strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1);
> +  if (lex_mi->ssl_key)
> +    strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1);
> +#ifndef HAVE_OPENSSL
> +  if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
> +      lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ||
> +      lex_mi->ssl_verify_server_cert )
> +    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
> +                 ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS));
> +#endif
> +
> +  if (lex_mi->relay_log_name)
> +  {
> +    need_relay_log_purge= 0;
> +    char relay_log_name[FN_REFLEN];
> +    mi->rli.relay_log.make_log_name(relay_log_name, lex_mi->relay_log_name);
> +    strmake(mi->rli.group_relay_log_name, relay_log_name,
> +	    sizeof(mi->rli.group_relay_log_name)-1);
> +    strmake(mi->rli.event_relay_log_name, relay_log_name,
> +	    sizeof(mi->rli.event_relay_log_name)-1);
> +  }
> +
> +  if (lex_mi->relay_log_pos)
> +  {
> +    need_relay_log_purge= 0;
> +    mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos=
> lex_mi->relay_log_pos;
> +  }
> +
> +  /*
> +    If user did specify neither host nor port nor any log name nor any log
> +    pos, i.e. he specified only user/password/master_connect_retry, he probably
> +    wants replication to resume from where it had left, i.e. from the
> +    coordinates of the **SQL** thread (imagine the case where the I/O is ahead
> +    of the SQL; restarting from the coordinates of the I/O would lose some
> +    events which is probably unwanted when you are just doing minor changes
> +    like changing master_connect_retry).
> +    A side-effect is that if only the I/O thread was started, this thread may
> +    restart from ''/4 after the CHANGE MASTER. That's a minor problem (it is a
> +    much more unlikely situation than the one we are fixing here).
> +    Note: coordinates of the SQL thread must be read here, before the
> +    'if (need_relay_log_purge)' block which resets them.
> +  */
> +  if (!lex_mi->host && !lex_mi->port &&
> +      !lex_mi->log_file_name && !lex_mi->pos &&
> +      need_relay_log_purge)
> +   {
> +     /*
> +       Sometimes mi->rli.master_log_pos == 0 (it happens when the SQL thread is
> +       not initialized), so we use a max().
> +       What happens to mi->rli.master_log_pos during the initialization stages
> +       of replication is not 100% clear, so we guard against problems using
> +       max().
> +      */
> +     mi->master_log_pos = max(BIN_LOG_HEADER_SIZE,
> +			      mi->rli.group_master_log_pos);
> +     strmake(mi->master_log_name, mi->rli.group_master_log_name,
> +             sizeof(mi->master_log_name)-1);
> +  }
> +  /*
> +    Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never
> +    a slave before).
> +  */
> +  if (flush_master_info(mi, FALSE, FALSE))
> +  {
> +    my_error(ER_RELAY_LOG_INIT, MYF(0), "Failed to flush master info file");
> +    ret= TRUE;
> +    goto err;
> +  }
> +  if (need_relay_log_purge)
> +  {
> +    relay_log_purge= 1;
> +    thd_proc_info(thd, "Purging old relay logs");
> +    if (purge_relay_logs(&mi->rli, thd,
> +			 0 /* not only reset, but also reinit */,
> +			 &errmsg))
> +    {
> +      my_error(ER_RELAY_LOG_FAIL, MYF(0), errmsg);
> +      ret= TRUE;
> +      goto err;
> +    }
> +  }
> +  else
> +  {
> +    const char* msg;
> +    relay_log_purge= 0;
> +    /* Relay log is already initialized */
> +    if (init_relay_log_pos(&mi->rli,
> +			   mi->rli.group_relay_log_name,
> +			   mi->rli.group_relay_log_pos,
> +			   0 /*no data lock*/,
> +			   &msg, 0))
> +    {
> +      my_error(ER_RELAY_LOG_INIT, MYF(0), msg);
> +      ret= TRUE;
> +      goto err;
> +    }
> +  }
> +  /*
> +    Coordinates in rli were spoilt by the 'if (need_relay_log_purge)' block,
> +    so restore them to good values. If we left them to ''/0, that would work;
> +    but that would fail in the case of 2 successive CHANGE MASTER (without a
> +    START SLAVE in between): because first one would set the coords in mi to
> +    the good values of those in rli, the set those in rli to ''/0, then
> +    second CHANGE MASTER would set the coords in mi to those of rli, i.e. to
> +    ''/0: we have lost all copies of the original good coordinates.
> +    That's why we always save good coords in rli.
> +  */
> +  mi->rli.group_master_log_pos= mi->master_log_pos;
> +  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
> +  strmake(mi->rli.group_master_log_name,mi->master_log_name,
> +	  sizeof(mi->rli.group_master_log_name)-1);
> +
> +  if (!mi->rli.group_master_log_name[0]) // uninitialized case
> +    mi->rli.group_master_log_pos=0;
> +
> +  mysql_mutex_lock(&mi->rli.data_lock);
> +  mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
> +  /* Clear the errors, for a clean start */
> +  mi->rli.clear_error();
> +  mi->rli.clear_until_condition();
> +  /*
> +    If we don't write new coordinates to disk now, then old will remain in
> +    relay-log.info until START SLAVE is issued; but if mysqld is shutdown
> +    before START SLAVE, then old will remain in relay-log.info, and will be the
> +    in-memory value at restart (thus causing errors, as the old relay log does
> +    not exist anymore).
> +  */
> +  flush_relay_log_info(&mi->rli);
> +  mysql_cond_broadcast(&mi->data_cond);
> +  mysql_mutex_unlock(&mi->rli.data_lock);
> +
> +err:
> +  unlock_slave_threads(mi);
> +  thd_proc_info(thd, 0);
> +  if (ret == FALSE)
> +    my_ok(thd);
> +  delete_dynamic(&lex_mi->repl_ignore_server_ids); //freeing of parser-time
> alloc
> +  DBUG_RETURN(ret);
> +}
> +
> +/**
>    @} (end of group Replication)
>  */
>  
> 
> === renamed file 'sql/slave.h' => 'sql/rpl_slave.h'
> --- a/sql/slave.h	2010-04-01 19:34:09 +0000
> +++ b/sql/rpl_slave.h	2010-06-21 06:01:50 +0000
> @@ -13,8 +13,8 @@
>     along with this program; if not, write to the Free Software
>     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
>  
> -#ifndef SLAVE_H
> -#define SLAVE_H
> +#ifndef RPL_SLAVE_H
> +#define RPL_SLAVE_H
>  
>  /**
>    @defgroup Replication Replication
> @@ -36,6 +36,7 @@
>  #ifdef HAVE_REPLICATION
>  
>  #include "log.h"
> +#include "binlog.h"
>  #include "my_list.h"
>  #include "rpl_filter.h"
>  #include "rpl_tblmap.h"
> @@ -48,6 +49,7 @@
>  class Relay_log_info;
>  class Master_info;
>  
> +extern bool server_id_supplied;
>  
>  /*****************************************************************************
>  
> @@ -144,10 +146,15 @@ extern ulonglong relay_log_space_limit;
>  */
>  #define SLAVE_FORCE_ALL 4
>  
> +int start_slave(THD* thd, Master_info* mi, bool net_report);
> +int stop_slave(THD* thd, Master_info* mi, bool net_report);
> +bool change_master(THD* thd, Master_info* mi);
> +int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
> +		   const char* log_file_name2, ulonglong log_pos2);
> +int reset_slave(THD *thd, Master_info* mi);
>  int init_slave();
>  int init_recovery(Master_info* mi, const char** errmsg);
>  void init_slave_skip_errors(const char* arg);
> -bool flush_relay_log_info(Relay_log_info* rli);
>  int register_slave_on_master(MYSQL* mysql);
>  int terminate_slave_threads(Master_info* mi, int thread_mask,
>  			     bool skip_lock = 0);
> @@ -193,19 +200,11 @@ void end_slave(); /* release slave threa
>  void close_active_mi(); /* clean up slave threads data */
>  void clear_until_condition(Relay_log_info* rli);
>  void clear_slave_error(Relay_log_info* rli);
> -void end_relay_log_info(Relay_log_info* rli);
>  void lock_slave_threads(Master_info* mi);
>  void unlock_slave_threads(Master_info* mi);
>  void init_thread_mask(int* mask,Master_info* mi,bool inverse);
> -int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
> -		       bool need_data_lock, const char** errmsg,
> -                       bool look_for_description_event);
> -
> -int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
> -		     const char** errmsg);
>  void set_slave_thread_options(THD* thd);
>  void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
> -void rotate_relay_log(Master_info* mi);
>  int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli);
>  
>  pthread_handler_t handle_slave_io(void *arg);
> 
> === modified file 'sql/set_var.h'
> --- a/sql/set_var.h	2010-04-01 19:34:09 +0000
> +++ b/sql/set_var.h	2010-06-21 06:01:50 +0000
> @@ -169,7 +169,7 @@ protected:
>    { return ((uchar*)&global_system_variables) + offset; }
>  };
>  
> -#include "log.h"                           /* binlog_format_typelib */
> +#include "binlog.h"                           /* binlog_format_typelib */
>  #include "sql_plugin.h"                    /* SHOW_HA_ROWS, SHOW_MY_BOOL */
>  
>  /****************************************************************************
> 
> === modified file 'sql/sql_binlog.cc'
> --- a/sql/sql_binlog.cc	2010-03-31 14:05:33 +0000
> +++ b/sql/sql_binlog.cc	2010-06-21 05:56:56 +0000
> @@ -19,7 +19,7 @@
>  #include "sql_acl.h"                            // *_ACL
>  #include "rpl_rli.h"
>  #include "base64.h"
> -#include "slave.h"                              // apply_event_and_update_pos
> +#include "rpl_slave.h"                              // apply_event_and_update_pos
>  #include "log_event.h"                          // Format_description_log_event,
>                                                  // EVENT_LEN_OFFSET,
>                                                  // EVENT_TYPE_OFFSET,
> 
> === modified file 'sql/sql_class.cc'
> --- a/sql/sql_class.cc	2010-05-14 05:29:47 +0000
> +++ b/sql/sql_class.cc	2010-06-21 06:01:50 +0000
> @@ -40,7 +40,7 @@
>  #include "rpl_rli.h"
>  #include "rpl_filter.h"
>  #include "rpl_record.h"
> -#include "slave.h"
> +#include "rpl_slave.h"
>  #include <my_bitmap.h>
>  #include "log_event.h"
>  #include "sql_audit.h"
> @@ -3473,610 +3473,6 @@ void xid_cache_delete(XID_STATE *xid_sta
>  }
>  
>  
> -/**
> -  Decide on logging format to use for the statement and issue errors
> -  or warnings as needed.  The decision depends on the following
> -  parameters:
> -
> -  - The logging mode, i.e., the value of binlog_format.  Can be
> -    statement, mixed, or row.
> -
> -  - The type of statement.  There are three types of statements:
> -    "normal" safe statements; unsafe statements; and row injections.
> -    An unsafe statement is one that, if logged in statement format,
> -    might produce different results when replayed on the slave (e.g.,
> -    INSERT DELAYED).  A row injection is either a BINLOG statement, or
> -    a row event executed by the slave's SQL thread.
> -
> -  - The capabilities of tables modified by the statement.  The
> -    *capabilities vector* for a table is a set of flags associated
> -    with the table.  Currently, it only includes two flags: *row
> -    capability flag* and *statement capability flag*.
> -
> -    The row capability flag is set if and only if the engine can
> -    handle row-based logging. The statement capability flag is set if
> -    and only if the table can handle statement-based logging.
> -
> -  Decision table for logging format
> -  ---------------------------------
> -
> -  The following table summarizes how the format and generated
> -  warning/error depends on the tables' capabilities, the statement
> -  type, and the current binlog_format.
> -
> -     Row capable        N NNNNNNNNN YYYYYYYYY YYYYYYYYY
> -     Statement capable  N YYYYYYYYY NNNNNNNNN YYYYYYYYY
> -
> -     Statement type     * SSSUUUIII SSSUUUIII SSSUUUIII
> -
> -     binlog_format      * SMRSMRSMR SMRSMRSMR SMRSMRSMR
> -
> -     Logged format      - SS-S----- -RR-RR-RR SRRSRR-RR
> -     Warning/Error      1 --2732444 5--5--6-- ---7--6--
> -
> -  Legend
> -  ------
> -
> -  Row capable:    N - Some table not row-capable, Y - All tables row-capable
> -  Stmt capable:   N - Some table not stmt-capable, Y - All tables stmt-capable
> -  Statement type: (S)afe, (U)nsafe, or Row (I)njection
> -  binlog_format:  (S)TATEMENT, (M)IXED, or (R)OW
> -  Logged format:  (S)tatement or (R)ow
> -  Warning/Error:  Warnings and error messages are as follows:
> -
> -  1. Error: Cannot execute statement: binlogging impossible since both
> -     row-incapable engines and statement-incapable engines are
> -     involved.
> -
> -  2. Error: Cannot execute statement: binlogging impossible since
> -     BINLOG_FORMAT = ROW and at least one table uses a storage engine
> -     limited to statement-logging.
> -
> -  3. Error: Cannot execute statement: binlogging of unsafe statement
> -     is impossible when storage engine is limited to statement-logging
> -     and BINLOG_FORMAT = MIXED.
> -
> -  4. Error: Cannot execute row injection: binlogging impossible since
> -     at least one table uses a storage engine limited to
> -     statement-logging.
> -
> -  5. Error: Cannot execute statement: binlogging impossible since
> -     BINLOG_FORMAT = STATEMENT and at least one table uses a storage
> -     engine limited to row-logging.
> -
> -  6. Error: Cannot execute row injection: binlogging impossible since
> -     BINLOG_FORMAT = STATEMENT.
> -
> -  7. Warning: Unsafe statement binlogged in statement format since
> -     BINLOG_FORMAT = STATEMENT.
> -
> -  In addition, we can produce the following error (not depending on
> -  the variables of the decision diagram):
> -
> -  8. Error: Cannot execute statement: binlogging impossible since more
> -     than one engine is involved and at least one engine is
> -     self-logging.
> -
> -  For each error case above, the statement is prevented from being
> -  logged, we report an error, and roll back the statement.  For
> -  warnings, we set the thd->binlog_flags variable: the warning will be
> -  printed only if the statement is successfully logged.
> -
> -  @see THD::binlog_query
> -
> -  @param[in] thd    Client thread
> -  @param[in] tables Tables involved in the query
> -
> -  @retval 0 No error; statement can be logged.
> -  @retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
> -*/
> -
> -int THD::decide_logging_format(TABLE_LIST *tables)
> -{
> -  DBUG_ENTER("THD::decide_logging_format");
> -  DBUG_PRINT("info", ("query: %s", query()));
> -  DBUG_PRINT("info", ("variables.binlog_format: %u",
> -                      variables.binlog_format));
> -  DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
> -                      lex->get_stmt_unsafe_flags()));
> -
> -  /*
> -    We should not decide logging format if the binlog is closed or
> -    binlogging is off, or if the statement is filtered out from the
> -    binlog by filtering rules.
> -  */
> -  if (mysql_bin_log.is_open() && (variables.option_bits &
> OPTION_BIN_LOG) &&
> -      !(variables.binlog_format == BINLOG_FORMAT_STMT &&
> -        !binlog_filter->db_ok(db)))
> -  {
> -    /*
> -      Compute one bit field with the union of all the engine
> -      capabilities, and one with the intersection of all the engine
> -      capabilities.
> -    */
> -    handler::Table_flags flags_write_some_set= 0;
> -    handler::Table_flags flags_some_set= 0;
> -    handler::Table_flags flags_write_all_set=
> -      HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
> -
> -    /* 
> -       If different types of engines are about to be updated.
> -       For example: Innodb and Falcon; Innodb and MyIsam.
> -    */
> -    my_bool multi_write_engine= FALSE;
> -    /*
> -       If different types of engines are about to be accessed 
> -       and any of them is about to be updated. For example:
> -       Innodb and Falcon; Innodb and MyIsam.
> -    */
> -    my_bool multi_access_engine= FALSE;
> -    /*
> -       If non-transactional and transactional engines are about
> -       to be accessed and any of them is about to be updated.
> -       For example: Innodb and MyIsam.
> -    */
> -    my_bool trans_non_trans_access_engines= FALSE;
> -    /*
> -       If all engines that are about to be updated are
> -       transactional.
> -    */
> -    my_bool all_trans_write_engines= TRUE;
> -    TABLE* prev_write_table= NULL;
> -    TABLE* prev_access_table= NULL;
> -
> -#ifndef DBUG_OFF
> -    {
> -      static const char *prelocked_mode_name[] = {
> -        "NON_PRELOCKED",
> -        "PRELOCKED",
> -        "PRELOCKED_UNDER_LOCK_TABLES",
> -      };
> -      DBUG_PRINT("debug", ("prelocked_mode: %s",
> -                           prelocked_mode_name[locked_tables_mode]));
> -    }
> -#endif
> -
> -    /*
> -      Get the capabilities vector for all involved storage engines and
> -      mask out the flags for the binary log.
> -    */
> -    for (TABLE_LIST *table= tables; table; table= table->next_global)
> -    {
> -      if (table->placeholder())
> -        continue;
> -      if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
> -        lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
> -      handler::Table_flags const flags=
> table->table->file->ha_table_flags();
> -      DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
> -                          table->table_name, flags));
> -      if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
> -      {
> -        if (prev_write_table && prev_write_table->file->ht !=
> -            table->table->file->ht)
> -          multi_write_engine= TRUE;
> -        /*
> -          Every temporary table must be always written to the binary
> -          log in transaction boundaries and as such we artificially
> -          classify them as transactional.
> -
> -          Indirectly, this avoids classifying a temporary table created
> -          on a non-transactional engine as unsafe when it is modified
> -          after any transactional table:
> -
> -          BEGIN;
> -            INSERT INTO innodb_t VALUES (1);
> -            INSERT INTO myisam_t_temp VALUES (1);
> -          COMMIT;
> -
> -          BINARY LOG:
> -
> -          BEGIN;
> -            INSERT INTO innodb_t VALUES (1);
> -            INSERT INTO myisam_t_temp VALUES (1);
> -          COMMIT;
> -        */
> -        all_trans_write_engines= all_trans_write_engines &&
> -                                 (table->table->file->has_transactions()
> ||
> -                                  table->table->s->tmp_table);
> -        prev_write_table= table->table;
> -        flags_write_all_set &= flags;
> -        flags_write_some_set |= flags;
> -      }
> -      flags_some_set |= flags;
> -      /*
> -        The mixture of non-transactional and transactional tables must
> -        identified and classified as unsafe. However, a temporary table
> -        must be always handled as a transactional table. Based on that,
> -        we have the following statements classified as mixed and by
> -        consequence as unsafe:
> -
> -        1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -        2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> -
> -        3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> -
> -        4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> -
> -        5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> -
> -        The following statements are not considered mixed and as such
> -        are safe:
> -
> -        1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
> -
> -        2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
> -      */
> -      if (!trans_non_trans_access_engines && prev_access_table &&
> -          (lex->sql_command != SQLCOM_CREATE_TABLE ||
> -          (lex->sql_command == SQLCOM_CREATE_TABLE &&
> -          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
> -      {
> -        my_bool prev_trans;
> -        my_bool act_trans;
> -        if (prev_access_table->s->tmp_table ||
> table->table->s->tmp_table)
> -        {
> -          prev_trans= prev_access_table->s->tmp_table ? TRUE :
> -                     prev_access_table->file->has_transactions();
> -          act_trans= table->table->s->tmp_table ? TRUE :
> -                    table->table->file->has_transactions();
> -        }
> -        else
> -        {
> -          prev_trans= prev_access_table->file->has_transactions();
> -          act_trans= table->table->file->has_transactions();
> -        }
> -        trans_non_trans_access_engines= (prev_trans != act_trans);
> -        multi_access_engine= TRUE;
> -      }
> -      thread_temporary_used |= table->table->s->tmp_table;
> -      prev_access_table= table->table;
> -    }
> -
> -    DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
> -    DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
> -    DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
> -    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
> -    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
> -    DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
> -                        trans_non_trans_access_engines));
> -
> -    int error= 0;
> -    int unsafe_flags;
> -
> -    /*
> -      Set the statement as unsafe if:
> -
> -      . it is a mixed statement, i.e. access transactional and non-transactional
> -      tables, and update any of them;
> -
> -      or:
> -
> -      . an early statement updated a transactional table;
> -      . and, the current statement updates a non-transactional table.
> -
> -      Any mixed statement is classified as unsafe to ensure that mixed mode is
> -      completely safe. Consider the following example to understand why we
> -      decided to do this:
> -
> -      Note that mixed statements such as
> -
> -      1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -      2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> -
> -      3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> -
> -      4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> -
> -      5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> -
> -      are classified as unsafe to ensure that in mixed mode the execution is
> -      completely safe and equivalent to the row mode. Consider the following
> -      statements and sessions (connections) to understand the reason:
> -
> -      con1: INSERT INTO innodb_t VALUES (1);
> -      con1: INSERT INTO innodb_t VALUES (100);
> -
> -      con1: BEGIN
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -
> -      The point is that the concurrent statements may be written into the binary
> log
> -      in a way different from the execution. For example,
> -
> -      BINARY LOG:
> -
> -      con2: BEGIN;
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con2: COMMIT;
> -      con1: BEGIN
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -
> -      ....
> -
> -      or
> -
> -      BINARY LOG:
> -
> -      con1: BEGIN
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -      con2: BEGIN;
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con2: COMMIT;
> -
> -      Clearly, this may become a problem in STMT mode and setting the statement
> -      as unsafe will make rows to be written into the binary log in MIXED mode
> -      and as such the problem will not stand.
> -
> -      In STMT mode, although such statement is classified as unsafe, i.e.
> -
> -      INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -      there is no enough information to avoid writing it outside the boundaries
> -      of a transaction. This is not a problem if we are considering snapshot
> -      isolation level but if we have pure repeatable read or serializable the
> -      lock history on the slave will be different from the master.
> -    */
> -    if (trans_non_trans_access_engines)
> -      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
> -    else if (trans_has_updated_trans_table(this) &&
> !all_trans_write_engines)
> -      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
> -
> -    /*
> -      If more than one engine is involved in the statement and at
> -      least one is doing it's own logging (is *self-logging*), the
> -      statement cannot be logged atomically, so we generate an error
> -      rather than allowing the binlog to become corrupt.
> -    */
> -    if (multi_write_engine &&
> -        (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
> -      my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
> -               MYF(0));
> -    else if (multi_access_engine && flags_some_set &
> HA_HAS_OWN_BINLOGGING)
> -     
> lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
> -
> -    /* both statement-only and row-only engines involved */
> -    if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE))
> == 0)
> -    {
> -      /*
> -        1. Error: Binary logging impossible since both row-incapable
> -           engines and statement-incapable engines are involved
> -      */
> -      my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
> -    }
> -    /* statement-only engines involved */
> -    else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
> -    {
> -      if (lex->is_stmt_row_injection())
> -      {
> -        /*
> -          4. Error: Cannot execute row injection since table uses
> -             storage engine limited to statement-logging
> -        */
> -        my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
> -      }
> -      else if (variables.binlog_format == BINLOG_FORMAT_ROW)
> -      {
> -        /*
> -          2. Error: Cannot modify table that uses a storage engine
> -             limited to statement-logging when BINLOG_FORMAT = ROW
> -        */
> -        my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
> -      }
> -      else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> -      {
> -        /*
> -          3. Error: Cannot execute statement: binlogging of unsafe
> -             statement is impossible when storage engine is limited to
> -             statement-logging and BINLOG_FORMAT = MIXED.
> -        */
> -        for (int unsafe_type= 0;
> -             unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> -             unsafe_type++)
> -          if (unsafe_flags & (1 << unsafe_type))
> -            my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
> -                     ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -      }
> -      /* log in statement format! */
> -    }
> -    /* no statement-only engines */
> -    else
> -    {
> -      /* binlog_format = STATEMENT */
> -      if (variables.binlog_format == BINLOG_FORMAT_STMT)
> -      {
> -        if (lex->is_stmt_row_injection())
> -        {
> -          /*
> -            6. Error: Cannot execute row injection since
> -               BINLOG_FORMAT = STATEMENT
> -          */
> -          my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
> -        }
> -        else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> -        {
> -          /*
> -            5. Error: Cannot modify table that uses a storage engine
> -               limited to row-logging when binlog_format = STATEMENT
> -          */
> -          my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
> -        }
> -        else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> -        {
> -          /*
> -            7. Warning: Unsafe statement logged as statement due to
> -               binlog_format = STATEMENT
> -          */
> -          binlog_unsafe_warning_flags|= unsafe_flags;
> -          DBUG_PRINT("info", ("Scheduling warning to be issued by "
> -                              "binlog_query: '%s'",
> -                              ER(ER_BINLOG_UNSAFE_STATEMENT)));
> -          DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
> -                              binlog_unsafe_warning_flags));
> -        }
> -        /* log in statement format! */
> -      }
> -      /* No statement-only engines and binlog_format != STATEMENT.
> -         I.e., nothing prevents us from row logging if needed. */
> -      else
> -      {
> -        if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
> -            || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> -        {
> -          /* log in row format! */
> -          set_current_stmt_binlog_format_row_if_mixed();
> -        }
> -      }
> -    }
> -
> -    if (error) {
> -      DBUG_PRINT("info", ("decision: no logging since an error was generated"));
> -      DBUG_RETURN(-1);
> -    }
> -    DBUG_PRINT("info", ("decision: logging in %s format",
> -                        is_current_stmt_binlog_format_row() ?
> -                        "ROW" : "STATEMENT"));
> -  }
> -#ifndef DBUG_OFF
> -  else
> -    DBUG_PRINT("info", ("decision: no logging since "
> -                        "mysql_bin_log.is_open() = %d "
> -                        "and (options & OPTION_BIN_LOG) = 0x%llx "
> -                        "and binlog_format = %u "
> -                        "and binlog_filter->db_ok(db) = %d",
> -                        mysql_bin_log.is_open(),
> -                        (variables.option_bits & OPTION_BIN_LOG),
> -                        variables.binlog_format,
> -                        binlog_filter->db_ok(db)));
> -#endif
> -
> -  DBUG_RETURN(0);
> -}
> -
> -
> -/*
> -  Implementation of interface to write rows to the binary log through the
> -  thread.  The thread is responsible for writing the rows it has
> -  inserted/updated/deleted.
> -*/
> -
> -#ifndef MYSQL_CLIENT
> -
> -/*
> -  Template member function for ensuring that there is an rows log
> -  event of the apropriate type before proceeding.
> -
> -  PRE CONDITION:
> -    - Events of type 'RowEventT' have the type code 'type_code'.
> -    
> -  POST CONDITION:
> -    If a non-NULL pointer is returned, the pending event for thread 'thd' will
> -    be an event of type 'RowEventT' (which have the type code 'type_code')
> -    will either empty or have enough space to hold 'needed' bytes.  In
> -    addition, the columns bitmap will be correct for the row, meaning that
> -    the pending event will be flushed if the columns in the event differ from
> -    the columns suppled to the function.
> -
> -  RETURNS
> -    If no error, a non-NULL pending event (either one which already existed or
> -    the newly created one).
> -    If error, NULL.
> - */
> -
> -template <class RowsEventT> Rows_log_event* 
> -THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
> -                                       MY_BITMAP const* cols,
> -                                       size_t colcnt,
> -                                       size_t needed,
> -                                       bool is_transactional,
> -				       RowsEventT *hint __attribute__((unused)))
> -{
> -  DBUG_ENTER("binlog_prepare_pending_rows_event");
> -  /* Pre-conditions */
> -  DBUG_ASSERT(table->s->table_map_id != ~0UL);
> -
> -  /* Fetch the type code for the RowsEventT template parameter */
> -  int const type_code= RowsEventT::TYPE_CODE;
> -
> -  /*
> -    There is no good place to set up the transactional data, so we
> -    have to do it here.
> -  */
> -  if (binlog_setup_trx_data())
> -    DBUG_RETURN(NULL);
> -
> -  Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
> -
> -  if (unlikely(pending && !pending->is_valid()))
> -    DBUG_RETURN(NULL);
> -
> -  /*
> -    Check if the current event is non-NULL and a write-rows
> -    event. Also check if the table provided is mapped: if it is not,
> -    then we have switched to writing to a new table.
> -    If there is no pending event, we need to create one. If there is a pending
> -    event, but it's not about the same table id, or not of the same type
> -    (between Write, Update and Delete), or not the same affected columns, or
> -    going to be too big, flush this event to disk and create a new pending
> -    event.
> -  */
> -  if (!pending ||
> -      pending->server_id != serv_id || 
> -      pending->get_table_id() != table->s->table_map_id ||
> -      pending->get_type_code() != type_code || 
> -      pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 
> -      pending->get_width() != colcnt ||
> -      !bitmap_cmp(pending->get_cols(), cols)) 
> -  {
> -    /* Create a new RowsEventT... */
> -    Rows_log_event* const
> -	ev= new RowsEventT(this, table, table->s->table_map_id, cols,
> -                           is_transactional);
> -    if (unlikely(!ev))
> -      DBUG_RETURN(NULL);
> -    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
> -    /*
> -      flush the pending event and replace it with the newly created
> -      event...
> -    */
> -    if (unlikely(
> -        mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
> -                                                       is_transactional)))
> -    {
> -      delete ev;
> -      DBUG_RETURN(NULL);
> -    }
> -
> -    DBUG_RETURN(ev);               /* This is the new pending event */
> -  }
> -  DBUG_RETURN(pending);        /* This is the current pending event */
> -}
> -
> -#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
> -/*
> -  Instantiate the versions we need, we have -fno-implicit-template as
> -  compiling option.
> -*/
> -template Rows_log_event*
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t, size_t, bool,
> -				       Write_rows_log_event*);
> -
> -template Rows_log_event*
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t colcnt, size_t, bool,
> -				       Delete_rows_log_event *);
> -
> -template Rows_log_event* 
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t colcnt, size_t, bool,
> -				       Update_rows_log_event *);
> -#endif
> -
>  #ifdef NOT_USED
>  static char const* 
>  field_type_name(enum_field_types type) 
> @@ -4140,505 +3536,3 @@ field_type_name(enum_field_types type) 
>    return "Unknown";
>  }
>  #endif
> -
> -
> -namespace {
> -  /**
> -     Class to handle temporary allocation of memory for row data.
> -
> -     The responsibilities of the class is to provide memory for
> -     packing one or two rows of packed data (depending on what
> -     constructor is called).
> -
> -     In order to make the allocation more efficient for "simple" rows,
> -     i.e., rows that do not contain any blobs, a pointer to the
> -     allocated memory is of memory is stored in the table structure
> -     for simple rows.  If memory for a table containing a blob field
> -     is requested, only memory for that is allocated, and subsequently
> -     released when the object is destroyed.
> -
> -   */
> -  class Row_data_memory {
> -  public:
> -    /**
> -      Build an object to keep track of a block-local piece of memory
> -      for storing a row of data.
> -
> -      @param table
> -      Table where the pre-allocated memory is stored.
> -
> -      @param length
> -      Length of data that is needed, if the record contain blobs.
> -     */
> -    Row_data_memory(TABLE *table, size_t const len1)
> -      : m_memory(0)
> -    {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= FALSE;
> -#endif
> -      allocate_memory(table, len1);
> -      m_ptr[0]= has_memory() ? m_memory : 0;
> -      m_ptr[1]= 0;
> -    }
> -
> -    Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
> -      : m_memory(0)
> -    {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= FALSE;
> -#endif
> -      allocate_memory(table, len1 + len2);
> -      m_ptr[0]= has_memory() ? m_memory        : 0;
> -      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
> -    }
> -
> -    ~Row_data_memory()
> -    {
> -      if (m_memory != 0 && m_release_memory_on_destruction)
> -        my_free((uchar*) m_memory, MYF(MY_WME));
> -    }
> -
> -    /**
> -       Is there memory allocated?
> -
> -       @retval true There is memory allocated
> -       @retval false Memory allocation failed
> -     */
> -    bool has_memory() const {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= TRUE;
> -#endif
> -      return m_memory != 0;
> -    }
> -
> -    uchar *slot(uint s)
> -    {
> -      DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
> -      DBUG_ASSERT(m_ptr[s] != 0);
> -      DBUG_ASSERT(m_alloc_checked == TRUE);
> -      return m_ptr[s];
> -    }
> -
> -  private:
> -    void allocate_memory(TABLE *const table, size_t const total_length)
> -    {
> -      if (table->s->blob_fields == 0)
> -      {
> -        /*
> -          The maximum length of a packed record is less than this
> -          length. We use this value instead of the supplied length
> -          when allocating memory for records, since we don't know how
> -          the memory will be used in future allocations.
> -
> -          Since table->s->reclength is for unpacked records, we have
> -          to add two bytes for each field, which can potentially be
> -          added to hold the length of a packed field.
> -        */
> -        size_t const maxlen= table->s->reclength + 2 *
> table->s->fields;
> -
> -        /*
> -          Allocate memory for two records if memory hasn't been
> -          allocated. We allocate memory for two records so that it can
> -          be used when processing update rows as well.
> -        */
> -        if (table->write_row_record == 0)
> -          table->write_row_record=
> -            (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
> -        m_memory= table->write_row_record;
> -        m_release_memory_on_destruction= FALSE;
> -      }
> -      else
> -      {
> -        m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
> -        m_release_memory_on_destruction= TRUE;
> -      }
> -    }
> -
> -#ifndef DBUG_OFF
> -    mutable bool m_alloc_checked;
> -#endif
> -    bool m_release_memory_on_destruction;
> -    uchar *m_memory;
> -    uchar *m_ptr[2];
> -  };
> -}
> -
> -
> -int THD::binlog_write_row(TABLE* table, bool is_trans, 
> -                          MY_BITMAP const* cols, size_t colcnt, 
> -                          uchar const *record) 
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  /*
> -    Pack records into format for transfer. We are allocating more
> -    memory than needed, but that doesn't matter.
> -  */
> -  Row_data_memory memory(table, max_row_length(table, record));
> -  if (!memory.has_memory())
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *row_data= memory.slot(0);
> -
> -  size_t const len= pack_row(table, cols, row_data, record);
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -                                      len, is_trans,
> -                                      static_cast<Write_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return ev->add_row_data(row_data, len);
> -}
> -
> -int THD::binlog_update_row(TABLE* table, bool is_trans,
> -                           MY_BITMAP const* cols, size_t colcnt,
> -                           const uchar *before_record,
> -                           const uchar *after_record)
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  size_t const before_maxlen = max_row_length(table, before_record);
> -  size_t const after_maxlen  = max_row_length(table, after_record);
> -
> -  Row_data_memory row_data(table, before_maxlen, after_maxlen);
> -  if (!row_data.has_memory())
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *before_row= row_data.slot(0);
> -  uchar *after_row= row_data.slot(1);
> -
> -  size_t const before_size= pack_row(table, cols, before_row,
> -                                        before_record);
> -  size_t const after_size= pack_row(table, cols, after_row,
> -                                       after_record);
> -
> -  /*
> -    Don't print debug messages when running valgrind since they can
> -    trigger false warnings.
> -   */
> -#ifndef HAVE_purify
> -  DBUG_DUMP("before_record", before_record, table->s->reclength);
> -  DBUG_DUMP("after_record",  after_record, table->s->reclength);
> -  DBUG_DUMP("before_row",    before_row, before_size);
> -  DBUG_DUMP("after_row",     after_row, after_size);
> -#endif
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -				      before_size + after_size, is_trans,
> -				      static_cast<Update_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return
> -    ev->add_row_data(before_row, before_size) ||
> -    ev->add_row_data(after_row, after_size);
> -}
> -
> -int THD::binlog_delete_row(TABLE* table, bool is_trans, 
> -                           MY_BITMAP const* cols, size_t colcnt,
> -                           uchar const *record)
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  /* 
> -     Pack records into format for transfer. We are allocating more
> -     memory than needed, but that doesn't matter.
> -  */
> -  Row_data_memory memory(table, max_row_length(table, record));
> -  if (unlikely(!memory.has_memory()))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *row_data= memory.slot(0);
> -
> -  size_t const len= pack_row(table, cols, row_data, record);
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -				      len, is_trans,
> -				      static_cast<Delete_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return ev->add_row_data(row_data, len);
> -}
> -
> -
> -int THD::binlog_remove_pending_rows_event(bool clear_maps,
> -                                          bool is_transactional)
> -{
> -  DBUG_ENTER("THD::binlog_remove_pending_rows_event");
> -
> -  if (!mysql_bin_log.is_open())
> -    DBUG_RETURN(0);
> -
> -  mysql_bin_log.remove_pending_rows_event(this, is_transactional);
> -
> -  if (clear_maps)
> -    binlog_table_maps= 0;
> -
> -  DBUG_RETURN(0);
> -}
> -
> -int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
> -{
> -  DBUG_ENTER("THD::binlog_flush_pending_rows_event");
> -  /*
> -    We shall flush the pending event even if we are not in row-based
> -    mode: it might be the case that we left row-based mode before
> -    flushing anything (e.g., if we have explicitly locked tables).
> -   */
> -  if (!mysql_bin_log.is_open())
> -    DBUG_RETURN(0);
> -
> -  /*
> -    Mark the event as the last event of a statement if the stmt_end
> -    flag is set.
> -  */
> -  int error= 0;
> -  if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
> -  {
> -    if (stmt_end)
> -    {
> -      pending->set_flags(Rows_log_event::STMT_END_F);
> -      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> -      binlog_table_maps= 0;
> -    }
> -
> -    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
> -                                                          is_transactional);
> -  }
> -
> -  DBUG_RETURN(error);
> -}
> -
> -
> -#if !defined(DBUG_OFF) && !defined(_lint)
> -static const char *
> -show_query_type(THD::enum_binlog_query_type qtype)
> -{
> -  switch (qtype) {
> -  case THD::ROW_QUERY_TYPE:
> -    return "ROW";
> -  case THD::STMT_QUERY_TYPE:
> -    return "STMT";
> -  case THD::QUERY_TYPE_COUNT:
> -  default:
> -    DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
> -  }
> -  static char buf[64];
> -  sprintf(buf, "UNKNOWN#%d", qtype);
> -  return buf;
> -}
> -#endif
> -
> -
> -/**
> -  Auxiliary method used by @c binlog_query() to raise warnings.
> -
> -  The type of warning and the type of unsafeness is stored in
> -  THD::binlog_unsafe_warning_flags.
> -*/
> -void THD::issue_unsafe_warnings()
> -{
> -  DBUG_ENTER("issue_unsafe_warnings");
> -  /*
> -    Ensure that binlog_unsafe_warning_flags is big enough to hold all
> -    bits.  This is actually a constant expression.
> -  */
> -  DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
> -              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
> -
> -  uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
> -
> -  /*
> -    Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
> -    warnings that have been printed already.
> -  */
> -  unsafe_type_flags &= (LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS ^
> -                        (unsafe_type_flags >>
> LEX::BINLOG_STMT_UNSAFE_COUNT));
> -  /* If all warnings have been printed already, return. */
> -  if (unsafe_type_flags == 0)
> -    DBUG_VOID_RETURN;
> -
> -  DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
> -
> -  /*
> -    For each unsafe_type, check if the statement is unsafe in this way
> -    and issue a warning.
> -  */
> -  for (int unsafe_type=0;
> -       unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> -       unsafe_type++)
> -  {
> -    if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
> -    {
> -      push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
> -                          ER_BINLOG_UNSAFE_STATEMENT,
> -                          ER(ER_BINLOG_UNSAFE_STATEMENT),
> -                          ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -      if (global_system_variables.log_warnings)
> -      {
> -        char buf[MYSQL_ERRMSG_SIZE * 2];
> -        sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
> -                ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -        sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
> -      }
> -    }
> -  }
> -  /*
> -    Mark these unsafe types as already printed, to avoid printing
> -    warnings for them again.
> -  */
> -  binlog_unsafe_warning_flags|=
> -    unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -/**
> -  Log the current query.
> -
> -  The query will be logged in either row format or statement format
> -  depending on the value of @c current_stmt_binlog_format_row field and
> -  the value of the @c qtype parameter.
> -
> -  This function must be called:
> -
> -  - After the all calls to ha_*_row() functions have been issued.
> -
> -  - After any writes to system tables. Rationale: if system tables
> -    were written after a call to this function, and the master crashes
> -    after the call to this function and before writing the system
> -    tables, then the master and slave get out of sync.
> -
> -  - Before tables are unlocked and closed.
> -
> -  @see decide_logging_format
> -
> -  @retval 0 Success
> -
> -  @retval nonzero If there is a failure when writing the query (e.g.,
> -  write failure), then the error code is returned.
> -*/
> -int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
> -                      ulong query_len, bool is_trans, bool direct, 
> -                      bool suppress_use, int errcode)
> -{
> -  DBUG_ENTER("THD::binlog_query");
> -  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
> -                       show_query_type(qtype), query_arg));
> -  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
> -
> -  /*
> -    If we are not in prelocked mode, mysql_unlock_tables() will be
> -    called after this binlog_query(), so we have to flush the pending
> -    rows event with the STMT_END_F set to unlock all tables at the
> -    slave side as well.
> -
> -    If we are in prelocked mode, the flushing will be done inside the
> -    top-most close_thread_tables().
> -  */
> -  if (this->locked_tables_mode <= LTM_LOCK_TABLES)
> -    if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
> -      DBUG_RETURN(error);
> -
> -  /*
> -    Warnings for unsafe statements logged in statement format are
> -    printed here instead of in decide_logging_format().  This is
> -    because the warnings should be printed only if the statement is
> -    actually logged. When executing decide_logging_format(), we cannot
> -    know for sure if the statement will be logged.
> -  */
> -  if (sql_log_bin_toplevel)
> -    issue_unsafe_warnings();
> -
> -  switch (qtype) {
> -    /*
> -      ROW_QUERY_TYPE means that the statement may be logged either in
> -      row format or in statement format.  If
> -      current_stmt_binlog_format is row, it means that the
> -      statement has already been logged in row format and hence shall
> -      not be logged again.
> -    */
> -  case THD::ROW_QUERY_TYPE:
> -    DBUG_PRINT("debug",
> -               ("is_current_stmt_binlog_format_row: %d",
> -                is_current_stmt_binlog_format_row()));
> -    if (is_current_stmt_binlog_format_row())
> -      DBUG_RETURN(0);
> -    /* Fall through */
> -
> -    /*
> -      STMT_QUERY_TYPE means that the query must be logged in statement
> -      format; it cannot be logged in row format.  This is typically
> -      used by DDL statements.  It is an error to use this query type
> -      if current_stmt_binlog_format_row is row.
> -
> -      @todo Currently there are places that call this method with
> -      STMT_QUERY_TYPE and current_stmt_binlog_format is row.  Fix those
> -      places and add assert to ensure correct behavior. /Sven
> -    */
> -  case THD::STMT_QUERY_TYPE:
> -    /*
> -      The MYSQL_LOG::write() function will set the STMT_END_F flag and
> -      flush the pending rows event if necessary.
> -    */
> -    {
> -      Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
> -                            suppress_use, errcode);
> -      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> -      /*
> -        Binlog table maps will be irrelevant after a Query_log_event
> -        (they are just removed on the slave side) so after the query
> -        log event is written to the binary log, we pretend that no
> -        table maps were written.
> -       */
> -      int error= mysql_bin_log.write(&qinfo);
> -      binlog_table_maps= 0;
> -      DBUG_RETURN(error);
> -    }
> -    break;
> -
> -  case THD::QUERY_TYPE_COUNT:
> -  default:
> -    DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
> -                                 ulonglong incr)
> -{
> -  DBUG_ENTER("Discrete_intervals_list::append");
> -  /* first, see if this can be merged with previous */
> -  if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
> -  {
> -    /* it cannot, so need to add a new interval */
> -    Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
> -    DBUG_RETURN(append(new_interval));
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -bool Discrete_intervals_list::append(Discrete_interval *new_interval)
> -{
> -  DBUG_ENTER("Discrete_intervals_list::append");
> -  if (unlikely(new_interval == NULL))
> -    DBUG_RETURN(1);
> -  DBUG_PRINT("info",("adding new auto_increment interval"));
> -  if (head == NULL)
> -    head= current= new_interval;
> -  else
> -    tail->next= new_interval;
> -  tail= new_interval;
> -  elements++;
> -  DBUG_RETURN(0);
> -}
> -
> -#endif /* !defined(MYSQL_CLIENT) */
> 
> === modified file 'sql/sql_db.cc'
> --- a/sql/sql_db.cc	2010-04-07 12:02:19 +0000
> +++ b/sql/sql_db.cc	2010-06-21 06:01:50 +0000
> @@ -36,6 +36,7 @@
>  #include <my_dir.h>
>  #include <m_ctype.h>
>  #include "log.h"
> +#include "binlog.h"                             // mysql_bin_log
>  #ifdef __WIN__
>  #include <direct.h>
>  #endif
> 
> === modified file 'sql/sql_insert.cc'
> --- a/sql/sql_insert.cc	2010-05-14 05:29:47 +0000
> +++ b/sql/sql_insert.cc	2010-06-21 06:01:50 +0000
> @@ -70,7 +70,7 @@
>  #include "sql_trigger.h"
>  #include "sql_select.h"
>  #include "sql_show.h"
> -#include "slave.h"
> +#include "rpl_slave.h"
>  #include "sql_parse.h"                          // end_active_trans
>  #include "rpl_mi.h"
>  #include "transaction.h"
> 
> === modified file 'sql/sql_load.cc'
> --- a/sql/sql_load.cc	2010-05-05 10:45:26 +0000
> +++ b/sql/sql_load.cc	2010-06-21 06:01:50 +0000
> @@ -34,7 +34,7 @@
>                          // LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F
>  #include <m_ctype.h>
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
> +#include "rpl_slave.h"
>  #include "sp_head.h"
>  #include "sql_trigger.h"
>  
> 
> === modified file 'sql/sql_parse.cc'
> --- a/sql/sql_parse.cc	2010-05-14 18:38:28 +0000
> +++ b/sql/sql_parse.cc	2010-06-21 06:01:50 +0000
> @@ -76,9 +76,9 @@
>  #include "sql_help.h"         // mysqld_help
>  #include "rpl_constants.h"    // Incident, INCIDENT_LOST_EVENTS
>  #include "log_event.h"
> -#include "sql_repl.h"
> +#include "rpl_slave.h"
> +#include "rpl_master.h"
>  #include "rpl_filter.h"
> -#include "repl_failsafe.h"
>  #include <m_ctype.h>
>  #include <myisam.h>
>  #include <my_dir.h>
> @@ -2356,14 +2356,9 @@ case SQLCOM_PREPARE:
>    {
>      if (check_global_access(thd, REPL_SLAVE_ACL))
>        goto error;
> -    /* This query don't work now. See comment in repl_failsafe.cc */
> -#ifndef WORKING_NEW_MASTER
> +    /* This query don't work now.*/
>      my_error(ER_NOT_SUPPORTED_YET, MYF(0), "SHOW NEW MASTER");
>      goto error;
> -#else
> -    res = show_new_master(thd);
> -    break;
> -#endif
>    }
>  
>  #ifdef HAVE_REPLICATION
> @@ -2374,7 +2369,13 @@ case SQLCOM_PREPARE:
>      res = show_slave_hosts(thd);
>      break;
>    }
> -  case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
> +  case SQLCOM_SHOW_RELAYLOG_EVENTS:
> +  {
> +    if (check_global_access(thd, REPL_SLAVE_ACL))
> +      goto error;
> +    res = mysql_show_relaylog_events(thd);
> +    break;
> +  }
>    case SQLCOM_SHOW_BINLOG_EVENTS:
>    {
>      if (check_global_access(thd, REPL_SLAVE_ACL))
> 
> === removed file 'sql/sql_repl.cc'
> --- a/sql/sql_repl.cc	2010-04-01 19:34:09 +0000
> +++ b/sql/sql_repl.cc	1970-01-01 00:00:00 +0000
> @@ -1,2005 +0,0 @@
> -/* Copyright (C) 2000-2006 MySQL AB & Sasha, 2008-2009 Sun Microsystems, Inc
> -
> -   This program is free software; you can redistribute it and/or modify
> -   it under the terms of the GNU General Public License as published by
> -   the Free Software Foundation; version 2 of the License.
> -
> -   This program is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -   GNU General Public License for more details.
> -
> -   You should have received a copy of the GNU General Public License
> -   along with this program; if not, write to the Free Software
> -   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> -
> -#include "sql_priv.h"
> -#include "unireg.h"
> -#include "sql_parse.h"                          // check_access
> -#ifdef HAVE_REPLICATION
> -
> -#include "rpl_mi.h"
> -#include "sql_repl.h"
> -#include "sql_acl.h"                            // SUPER_ACL
> -#include "log_event.h"
> -#include "rpl_filter.h"
> -#include <my_dir.h>
> -#include "rpl_handler.h"
> -
> -int max_binlog_dump_events = 0; // unlimited
> -my_bool opt_sporadic_binlog_dump_fail = 0;
> -#ifndef DBUG_OFF
> -static int binlog_dump_count = 0;
> -#endif
> -
> -/**
> -  a copy of active_mi->rli->slave_skip_counter, for showing in SHOW
> VARIABLES,
> -  INFORMATION_SCHEMA.GLOBAL_VARIABLES and @@sql_slave_skip_counter without
> -  taking all the mutexes needed to access active_mi->rli->slave_skip_counter
> -  properly.
> -*/
> -uint sql_slave_skip_counter;
> -
> -/*
> -    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
> -    send to the slave (because the slave may not know it if it just asked for
> -    MASTER_LOG_FILE='', MASTER_LOG_POS=4).
> -    < 4.0.14, fake_rotate_event() was called only if the requested pos was 4.
> -    After this version we always call it, so that a 3.23.58 slave can rely on
> -    it to detect if the master is 4.0 (and stop) (the _fake_ Rotate event has
> -    zeros in the good positions which, by chance, make it possible for the 3.23
> -    slave to detect that this event is unexpected) (this is luck which happens
> -    because the master and slave disagree on the size of the header of
> -    Log_event).
> -
> -    Relying on the event length of the Rotate event instead of these
> -    well-placed zeros was not possible as Rotate events have a variable-length
> -    part.
> -*/
> -
> -static int fake_rotate_event(NET* net, String* packet, char* log_file_name,
> -                             ulonglong position, const char** errmsg)
> -{
> -  DBUG_ENTER("fake_rotate_event");
> -  char header[LOG_EVENT_HEADER_LEN], buf[ROTATE_HEADER_LEN+100];
> -  /*
> -    '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;
> -
> -  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;
> -  int4store(header + SERVER_ID_OFFSET, server_id);
> -  int4store(header + EVENT_LEN_OFFSET, event_len);
> -  int2store(header + FLAGS_OFFSET, LOG_EVENT_ARTIFICIAL_F);
> -
> -  // 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);
> -  packet->append(buf, ROTATE_HEADER_LEN);
> -  packet->append(p,ident_len);
> -  if (my_net_write(net, (uchar*) packet->ptr(), packet->length()))
> -  {
> -    *errmsg = "failed on my_net_write()";
> -    DBUG_RETURN(-1);
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -/*
> -  Reset thread transmit packet buffer for event sending
> -
> -  This function allocates header bytes for event transmission, and
> -  should be called before store the event data to the packet buffer.
> -*/
> -static int reset_transmit_packet(THD *thd, ushort flags,
> -                                 ulong *ev_offset, const char **errmsg)
> -{
> -  int ret= 0;
> -  String *packet= &thd->packet;
> -
> -  /* reserve and set default header */
> -  packet->length(0);
> -  packet->set("\0", 1, &my_charset_bin);
> -
> -  if (RUN_HOOK(binlog_transmit, reserve_header, (thd, flags, packet)))
> -  {
> -    *errmsg= "Failed to run hook 'reserve_header'";
> -    my_errno= ER_UNKNOWN_ERROR;
> -    ret= 1;
> -  }
> -  *ev_offset= packet->length();
> -  return ret;
> -}
> -
> -static int send_file(THD *thd)
> -{
> -  NET* net = &thd->net;
> -  int fd = -1, error = 1;
> -  size_t bytes;
> -  char fname[FN_REFLEN+1];
> -  const char *errmsg = 0;
> -  int old_timeout;
> -  unsigned long packet_len;
> -  uchar buf[IO_SIZE];				// It's safe to alloc this
> -  DBUG_ENTER("send_file");
> -
> -  /*
> -    The client might be slow loading the data, give him wait_timeout to do
> -    the job
> -  */
> -  old_timeout= net->read_timeout;
> -  my_net_set_read_timeout(net, thd->variables.net_wait_timeout);
> -
> -  /*
> -    We need net_flush here because the client will not know it needs to send
> -    us the file name until it has processed the load event entry
> -  */
> -  if (net_flush(net) || (packet_len = my_net_read(net)) == packet_error)
> -  {
> -    errmsg = "while reading file name";
> -    goto err;
> -  }
> -
> -  // terminate with \0 for fn_format
> -  *((char*)net->read_pos +  packet_len) = 0;
> -  fn_format(fname, (char*) net->read_pos + 1, "", "", 4);
> -  // this is needed to make replicate-ignore-db
> -  if (!strcmp(fname,"/dev/null"))
> -    goto end;
> -
> -  if ((fd= mysql_file_open(key_file_send_file,
> -                           fname, O_RDONLY, MYF(0))) < 0)
> -  {
> -    errmsg = "on open of file";
> -    goto err;
> -  }
> -
> -  while ((long) (bytes= mysql_file_read(fd, buf, IO_SIZE, MYF(0))) > 0)
> -  {
> -    if (my_net_write(net, buf, bytes))
> -    {
> -      errmsg = "while writing data to client";
> -      goto err;
> -    }
> -  }
> -
> - end:
> -  if (my_net_write(net, (uchar*) "", 0) || net_flush(net) ||
> -      (my_net_read(net) == packet_error))
> -  {
> -    errmsg = "while negotiating file transfer close";
> -    goto err;
> -  }
> -  error = 0;
> -
> - err:
> -  my_net_set_read_timeout(net, old_timeout);
> -  if (fd >= 0)
> -    mysql_file_close(fd, MYF(0));
> -  if (errmsg)
> -  {
> -    sql_print_error("Failed in send_file() %s", errmsg);
> -    DBUG_PRINT("error", ("%s", errmsg));
> -  }
> -  DBUG_RETURN(error);
> -}
> -
> -
> -/*
> -  Adjust the position pointer in the binary log file for all running slaves
> -
> -  SYNOPSIS
> -    adjust_linfo_offsets()
> -    purge_offset	Number of bytes removed from start of log index file
> -
> -  NOTES
> -    - This is called when doing a PURGE when we delete lines from the
> -      index log file
> -
> -  REQUIREMENTS
> -    - Before calling this function, we have to ensure that no threads are
> -      using any binary log file before purge_offset.a
> -
> -  TODO
> -    - Inform the slave threads that they should sync the position
> -      in the binary log file with flush_relay_log_info.
> -      Now they sync is done for next read.
> -*/
> -
> -void adjust_linfo_offsets(my_off_t purge_offset)
> -{
> -  THD *tmp;
> -
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  I_List_iterator<THD> it(threads);
> -
> -  while ((tmp=it++))
> -  {
> -    LOG_INFO* linfo;
> -    if ((linfo = tmp->current_linfo))
> -    {
> -      mysql_mutex_lock(&linfo->lock);
> -      /*
> -	Index file offset can be less that purge offset only if
> -	we just started reading the index file. In that case
> -	we have nothing to adjust
> -      */
> -      if (linfo->index_file_offset < purge_offset)
> -	linfo->fatal = (linfo->index_file_offset != 0);
> -      else
> -	linfo->index_file_offset -= purge_offset;
> -      mysql_mutex_unlock(&linfo->lock);
> -    }
> -  }
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -}
> -
> -
> -bool log_in_use(const char* log_name)
> -{
> -  size_t log_name_len = strlen(log_name) + 1;
> -  THD *tmp;
> -  bool result = 0;
> -
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  I_List_iterator<THD> it(threads);
> -
> -  while ((tmp=it++))
> -  {
> -    LOG_INFO* linfo;
> -    if ((linfo = tmp->current_linfo))
> -    {
> -      mysql_mutex_lock(&linfo->lock);
> -      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
> -                     log_name_len);
> -      mysql_mutex_unlock(&linfo->lock);
> -      if (result)
> -	break;
> -    }
> -  }
> -
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  return result;
> -}
> -
> -bool purge_error_message(THD* thd, int res)
> -{
> -  uint errcode;
> -
> -  if ((errcode= purge_log_get_error_code(res)) != 0)
> -  {
> -    my_message(errcode, ER(errcode), MYF(0));
> -    return TRUE;
> -  }
> -  my_ok(thd);
> -  return FALSE;
> -}
> -
> -
> -/**
> -  Execute a PURGE BINARY LOGS TO <log> command.
> -
> -  @param thd Pointer to THD object for the client thread executing the
> -  statement.
> -
> -  @param to_log Name of the last log to purge.
> -
> -  @retval FALSE success
> -  @retval TRUE failure
> -*/
> -bool purge_master_logs(THD* thd, const char* to_log)
> -{
> -  char search_file_name[FN_REFLEN];
> -  if (!mysql_bin_log.is_open())
> -  {
> -    my_ok(thd);
> -    return FALSE;
> -  }
> -
> -  mysql_bin_log.make_log_name(search_file_name, to_log);
> -  return purge_error_message(thd,
> -			     mysql_bin_log.purge_logs(search_file_name, 0, 1,
> -						      1, NULL));
> -}
> -
> -
> -/**
> -  Execute a PURGE BINARY LOGS BEFORE <date> command.
> -
> -  @param thd Pointer to THD object for the client thread executing the
> -  statement.
> -
> -  @param purge_time Date before which logs should be purged.
> -
> -  @retval FALSE success
> -  @retval TRUE failure
> -*/
> -bool purge_master_logs_before_date(THD* thd, time_t purge_time)
> -{
> -  if (!mysql_bin_log.is_open())
> -  {
> -    my_ok(thd);
> -    return 0;
> -  }
> -  return purge_error_message(thd,
> -                             mysql_bin_log.purge_logs_before_date(purge_time));
> -}
> -
> -int test_for_non_eof_log_read_errors(int error, const char **errmsg)
> -{