List:Commits« Previous MessageNext Message »
From:He Zhenxing Date:September 10 2010 7:27am
Subject:bzr commit into mysql-5.5-bugfixing branch (zhenxing.he:3206) Bug#54649
WL#5385
View as plain text  
#At file:///media/sdb2/hezx/work/mysql/bzr/w5385/5.5-bugfixing/ based on revid:marc.alff@stripped

 3206 He Zhenxing	2010-09-10
      Backport WL#5385 BUG#54649 to 5.5

    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_parse.h
      sql/sql_reload.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-08-18 11:29:04 +0000
+++ b/libmysqld/CMakeLists.txt	2010-09-10 07:27:02 +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 
@@ -70,7 +70,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
            ../sql/sql_binlog.cc ../sql/sql_manager.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
@@ -83,7 +83,7 @@ SET(SQL_EMBEDDED_SOURCES emb_qcache.cc l
            ../sql/sql_alter.cc ../sql/sql_partition_admin.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-09-01 03:38:53 +0000
+++ b/libmysqld/Makefile.am	2010-09-10 07:27:02 +0000
@@ -77,7 +77,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_alter.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 \
 	sql_partition_admin.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)

=== modified file 'mysql-test/lib/v1/mysql-test-run.pl'
--- a/mysql-test/lib/v1/mysql-test-run.pl	2010-08-05 12:53:09 +0000
+++ b/mysql-test/lib/v1/mysql-test-run.pl	2010-09-10 07:27:02 +0000
@@ -3956,7 +3956,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,
@@ -4013,9 +4012,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'}];
@@ -4091,12 +4088,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-09-10 07:27:02 +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-09-10 07:27:02 +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-09-10 07:27:02 +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-09-10 07:27:02 +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-09-10 07:27:02 +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	2010-05-23 20:41:18 +0000
+++ b/mysql-test/suite/rpl_ndb/my.cnf	2010-09-10 07:27:02 +0000
@@ -37,7 +37,6 @@ relay-log=                    slave-rela
 # Cluster only supports row format
 binlog-format=                 row
 
-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-09-10 07:27:02 +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-09-02 22:17:08 +0000
+++ b/sql/CMakeLists.txt	2010-09-10 07:27:02 +0000
@@ -46,14 +46,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 
@@ -61,18 +59,18 @@ SET (SQL_SOURCE
                sql_list.cc sql_load.cc sql_manager.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_partition_admin.cc
                sql_profile.cc event_parse_data.cc sql_alter.cc
-               sql_signal.cc rpl_handler.cc mdl.cc sql_admin.cc
+               sql_signal.cc mdl.cc sql_admin.cc
                transaction.cc sys_vars.cc sql_truncate.cc datadict.cc
                sql_reload.cc
                ${GEN_SOURCES}
@@ -89,7 +87,21 @@ 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_DEPENDENCIES(binlog GenError)
+ADD_LIBRARY(rpl ${RPL_SOURCE})
+SET (MASTER_SOURCE rpl_master.cc)
+ADD_DEPENDENCIES(rpl GenError)
+ADD_LIBRARY(master ${MASTER_SOURCE})
+ADD_DEPENDENCIES(master GenError)
+SET (SLAVE_SOURCE rpl_slave.cc rpl_reporting.cc rpl_mi.cc rpl_rli.cc)
+ADD_LIBRARY(slave ${SLAVE_SOURCE})
+ADD_DEPENDENCIES(slave GenError)
+
 
 IF(WIN32)
   SET(MYSQLD_SOURCE main.cc nt_servc.cc nt_servc.h message.rc)
@@ -131,7 +143,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 sql)
 
 # Provide plugins with minimal set of libraries
 SET(INTERFACE_LIBS ${LIBRT})

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2010-08-18 11:29:04 +0000
+++ b/sql/Makefile.am	2010-09-10 07:27:02 +0000
@@ -68,6 +68,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
@@ -77,9 +79,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@ \
@@ -111,7 +115,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 \
@@ -149,8 +153,6 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
                         sql_truncate.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 \
@@ -158,26 +160,30 @@ 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_view.cc \
+			sql_view.cc \
 			gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
 			tztime.cc my_decimal.cc\
 			sp_head.cc sp_pcontext.cc  sp_rcontext.cc sp.cc \
 			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  \
 			sql_alter.cc sql_partition_admin.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-09-10 07:27:02 +0000
@@ -0,0 +1,5050 @@
+/* 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), changes_to_non_trans_temp_table_flag(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 set_changes_to_non_trans_temp_table()
+  {
+    changes_to_non_trans_temp_table_flag= TRUE;    
+  }
+
+  bool changes_to_non_trans_temp_table()
+  {
+    return (changes_to_non_trans_temp_table_flag);    
+  }
+
+  void reset()
+  {
+    truncate(0);
+    changes_to_non_trans_temp_table_flag= FALSE;
+    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;
+
+  /*
+    This flag indicates if the cache has changes to temporary tables.
+    @TODO This a temporary fix and should be removed after BUG#54562.
+  */
+  bool changes_to_non_trans_temp_table_flag;
+
+  /*
+    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(cache_mngr);
+  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);
+
+  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();
+
+  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);
+
+  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_mode()),
+              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 OPTION_KEEP_LOG is active or;
+        . the format is STMT and a non-trans table was updated or;
+        . the format is MIXED and a temporary non-trans table was
+          updated or;
+        . the format is MIXED, non-trans table was updated and
+          aborting a single statement transaction;
+    */
+
+    if (ending_trans(thd, all) &&
+        ((thd->variables.option_bits & OPTION_KEEP_LOG) ||
+         (trans_has_updated_non_trans_table(thd) &&
+          thd->variables.binlog_format == BINLOG_FORMAT_STMT) ||
+         (cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
+          thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
+         (trans_has_updated_non_trans_table(thd) &&
+          ending_single_stmt_trans(thd,all) &&
+          thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
+    {
+      Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
+      error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
+    }
+    /*
+      Truncate the cache if:
+        . aborting a single or multi-statement transaction or;
+        . the OPTION_KEEP_LOG is not active and;
+        . the format is not STMT or no non-trans table was
+          updated and;
+        . the format is not MIXED or no temporary non-trans table
+          was 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) &&
+              (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
+               thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
+      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 */
+
+  String log_query;
+  if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) ||
+      log_query.append(thd->lex->ident.str, thd->lex->ident.length))
+    DBUG_RETURN(1);
+  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+  Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
+                        TRUE, FALSE, TRUE, errcode);
+  DBUG_RETURN(mysql_bin_log.write(&qinfo));
+}
+
+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)))
+  {
+    String log_query;
+    if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) ||
+        log_query.append(thd->lex->ident.str, thd->lex->ident.length))
+      DBUG_RETURN(1);
+    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+    Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
+                          TRUE, FALSE, TRUE, errcode);
+    DBUG_RETURN(mysql_bin_log.write(&qinfo));
+  }
+  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 = !memcmp(log_name, 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->is_current_stmt_binlog_format_row() ||
+     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 || ending_single_stmt_trans(thd, all));
+}
+
+/**
+  This function checks if 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 single statement transaction, otherwise
+    @c false.
+*/
+bool ending_single_stmt_trans(THD* thd, const bool all)
+{
+  return (!all && !thd->in_multi_stmt_transaction_mode());
+}
+
+/**
+  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;
+  int old_max_allowed_packet= thd->variables.max_allowed_packet;
+  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);
+  thd->variables.max_allowed_packet= old_max_allowed_packet;
+  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),
+   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);
+  my_free(name);
+  name= NULL;
+  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((void *) save_name);
+
+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);
+  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);
+
+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);
+    }
+
+    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)) ||
+	(thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
+         thd->lex->sql_command != SQLCOM_SAVEPOINT &&
+         !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);
+
+      if (thd->lex->stmt_accessed_non_trans_temp_table())
+        cache_data->set_changes_to_non_trans_temp_table();
+
+      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();
+    }
+  }
+
+  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;
+  my_free(name);
+  name= NULL;
+  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(cache_mngr);
+    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_mode())
+      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++;
+  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: %lu",
+                      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_access_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;
+    /*
+      Identifies if a table is changed.
+    */
+    my_bool is_write= FALSE;
+    /*
+      A pointer to a previous table that was changed.
+    */
+    TABLE* prev_write_table= NULL;
+    /*
+      A pointer to a previous table that was accessed.
+    */
+    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 ||
+          table->table->s->table_category == TABLE_CATEGORY_LOG)
+        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;
+
+        my_bool trans= table->table->file->has_transactions();
+
+        if (table->table->s->tmp_table)
+          lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE :
+                                               LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
+        else
+          lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TRANS_TABLE :
+                                               LEX::STMT_WRITES_NON_TRANS_TABLE);
+
+        flags_write_all_set &= flags;
+        flags_write_some_set |= flags;
+        is_write= TRUE;
+
+        prev_write_table= table->table;
+
+      }
+      flags_access_some_set |= flags;
+
+      if (lex->sql_command != SQLCOM_CREATE_TABLE ||
+          (lex->sql_command == SQLCOM_CREATE_TABLE &&
+          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)))
+      {
+        my_bool trans= table->table->file->has_transactions();
+
+        if (table->table->s->tmp_table)
+          lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TEMP_TRANS_TABLE :
+                                               LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
+        else
+          lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TRANS_TABLE :
+                                               LEX::STMT_READS_NON_TRANS_TABLE);
+      }
+
+      if (prev_access_table && prev_access_table->file->ht !=
+          table->table->file->ht)
+        multi_access_engine= TRUE;
+
+      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_access_some_set: 0x%llx", flags_access_some_set));
+    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
+    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
+
+    int error= 0;
+    int unsafe_flags;
+
+    bool multi_stmt_trans= in_multi_stmt_transaction_mode();
+    bool trans_table= trans_has_updated_trans_table(this);
+    bool binlog_direct= variables.binlog_direct_non_trans_update;
+
+    if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct,
+                                  trans_table, tx_isolation))
+      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
+    else if (multi_stmt_trans && trans_table && !binlog_direct &&
+             lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE))
+      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_access_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 &&
+               sqlcom_can_generate_row_events(this))
+      {
+        /*
+          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 &&
+                 sqlcom_can_generate_row_events(this))
+        {
+          /*
+            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 (is_write && (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 = %lu "
+                        "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(m_memory);
+    }
+
+    /**
+       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];
+  };
+
+CPP_UNNAMED_NS_END
+
+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);
+      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(LEX::BINLOG_STMT_UNSAFE_COUNT <=
+              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
+
+  uint32 unsafe_type_flags= binlog_unsafe_warning_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());
+      }
+    }
+  }
+  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 in three places 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:
+
+    1 - sp_head::execute_procedure which prints out warnings for calls to
+    stored procedures.
+
+    2 - sp_head::execute_function which prints out warnings for calls
+    involving functions.
+
+    3 - THD::binlog_query (here) which prints warning for top level
+    statements not covered by the two cases above: i.e., if not insided a
+    procedure and a function.
+
+    Besides, we should not try to print these warnings if it is not
+    possible to write statements to the binary log as it happens when
+    the execution is inside a function, or generaly speaking, when
+    the variables.option_bits & OPTION_BIN_LOG is false.
+    
+  */
+  if ((variables.option_bits & OPTION_BIN_LOG) &&
+      spcont == NULL && !binlog_evt_union.do_union)
+    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);
+      /*
+        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-09-10 07:27:02 +0000
@@ -0,0 +1,266 @@
+#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;
+
+  /* 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)
+
+  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); // binary log write
+  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 ending_single_stmt_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);
+bool sqlcom_can_generate_row_events(const THD *thd);
+
+#endif /* BINLOG_H_INCLUDED */

=== modified file 'sql/field.cc'
--- a/sql/field.cc	2010-08-23 09:56:21 +0000
+++ b/sql/field.cc	2010-09-10 07:27:02 +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-08-12 13:50:23 +0000
+++ b/sql/ha_ndbcluster_binlog.cc	2010-09-10 07:27:02 +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-08-19 08:22:23 +0000
+++ b/sql/ha_partition.cc	2010-09-10 07:27:02 +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-08-25 10:22:34 +0000
+++ b/sql/item_func.cc	2010-09-10 07:27:02 +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-08-30 08:36:02 +0000
+++ b/sql/log.cc	2010-09-10 07:27:02 +0000
@@ -28,15 +28,11 @@
 #include "sql_priv.h"
 #include "log.h"
 #include "sql_base.h"                           // open_log_table
-#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,212 +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), changes_to_non_trans_temp_table_flag(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 set_changes_to_non_trans_temp_table()
-  {
-    changes_to_non_trans_temp_table_flag= TRUE;    
-  }
-
-  bool changes_to_non_trans_temp_table()
-  {
-    return (changes_to_non_trans_temp_table_flag);    
-  }
-
-  void reset()
-  {
-    truncate(0);
-    changes_to_non_trans_temp_table_flag= FALSE;
-    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;
-
-  /*
-    This flag indicates if the cache has changes to temporary tables.
-    @TODO This a temporary fix and should be removed after BUG#54562.
-  */
-  bool changes_to_non_trans_temp_table_flag;
-
-  /*
-    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) {
@@ -1409,3985 +1184,759 @@ 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(cache_mngr);
-  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);
-
-  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 (memcmp(file_info->name, 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.
+  /* 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;
+  }
 
-  @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;
+  next= max_found + 1;
+  sprintf(ext_buf, "%06lu", next);
+  *end++='.';
 
-  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 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))
   {
-    if (cache_mngr->trx_cache.has_incident())
-      error= mysql_bin_log.write_incident(thd, TRUE);
+    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;
+  }
 
-    cache_mngr->reset_cache(&cache_mngr->trx_cache);
+  sprintf(end, "%06lu", next);
 
-    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();
+  /* 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)
-{
-  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);
+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);
 
-  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;
 
-  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_mode()),
-              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);
+  my_free(name);
+  name= NULL;
+  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);
+}
 
-  @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.
+/*
+  Close the log file
 
-  @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)));
+  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.
 
-  /*
-    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);
-  }
+  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
+*/
 
-  if (cache_mngr->trx_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)
   {
-    /* 
-      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);
-  }
+    end_io_cache(&log_file);
 
-  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 OPTION_KEEP_LOG is active or;
-        . the format is STMT and a non-trans table was updated or;
-        . the format is MIXED and a temporary non-trans table was
-          updated or;
-        . the format is MIXED, non-trans table was updated and
-          aborting a single statement transaction;
-    */
+    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 (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) ||
-         (cache_mngr->trx_cache.changes_to_non_trans_temp_table() &&
-          thd->variables.binlog_format == BINLOG_FORMAT_MIXED) ||
-         (trans_has_updated_non_trans_table(thd) &&
-          ending_single_stmt_trans(thd,all) &&
-          thd->variables.binlog_format == BINLOG_FORMAT_MIXED)))
+    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 active and;
-        . the format is not STMT or no non-trans table was
-          updated and;
-        . the format is not MIXED or no temporary non-trans table
-          was 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) &&
-              (!cache_mngr->trx_cache.changes_to_non_trans_temp_table() ||
-               thd->variables.binlog_format != BINLOG_FORMAT_MIXED)))
-      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;
+  my_free(name);
+  name= NULL;
+  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).
-*/
 
-static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
-{
-  DBUG_ENTER("binlog_savepoint_set");
+/*
+  Reopen the log file
+
+  SYNOPSIS
+    reopen_file()
 
-  binlog_trans_log_savepos(thd, (my_off_t*) sv);
-  /* Write it to the binary log */
+  DESCRIPTION
+    Reopen the log file. The method is used during FLUSH LOGS
+    and locks LOCK_log mutex
+*/
 
-  String log_query;
-  if (log_query.append(STRING_WITH_LEN("SAVEPOINT ")) ||
-      log_query.append(thd->lex->ident.str, thd->lex->ident.length))
-    DBUG_RETURN(1);
-  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
-  Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
-                        TRUE, FALSE, TRUE, errcode);
-  DBUG_RETURN(mysql_bin_log.write(&qinfo));
-}
 
-static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
+void MYSQL_QUERY_LOG::reopen_file()
 {
-  DBUG_ENTER("binlog_savepoint_rollback");
+  char *save_name;
 
-  /*
-    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)))
+  DBUG_ENTER("MYSQL_LOG::reopen_file");
+  if (!is_open())
   {
-    String log_query;
-    if (log_query.append(STRING_WITH_LEN("ROLLBACK TO ")) ||
-        log_query.append(thd->lex->ident.str, thd->lex->ident.length))
-      DBUG_RETURN(1);
-    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
-    Query_log_event qinfo(thd, log_query.c_ptr_safe(), log_query.length(),
-                          TRUE, FALSE, TRUE, errcode);
-    DBUG_RETURN(mysql_bin_log.write(&qinfo));
+    DBUG_PRINT("info",("log is closed"));
+    DBUG_VOID_RETURN;
   }
-  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
-  DBUG_RETURN(0);
-}
 
+  mysql_mutex_lock(&LOCK_log);
 
-int check_binlog_magic(IO_CACHE* log, const char** errmsg)
-{
-  char magic[4];
-  DBUG_ASSERT(my_b_tell(log) == 0);
+  save_name= name;
+  name= 0;				// Don't free name
+  close(LOG_CLOSE_TO_BE_OPENED);
 
-  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 (memcmp(file_info->name, 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.
-
-  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
-
-  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
-*/
-
-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);
-  my_free(name);
-  name= NULL;
-  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;
-  my_free(name);
-  name= NULL;
-  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);
-
-  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)
-{
-  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),
-   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);
-  my_free(name);
-  name= NULL;
-  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((void *) save_name);
-
-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);
-  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);
-
-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->is_current_stmt_binlog_format_row() ||
-     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 || ending_single_stmt_trans(thd, all));
-}
-
-/**
-  This function checks if 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 single statement transaction, otherwise
-    @c false.
-*/
-bool ending_single_stmt_trans(THD* thd, const bool all)
-{
-  return (!all && !thd->in_multi_stmt_transaction_mode());
-}
-
-/**
-  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(cache_mngr);
-    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_mode())
-      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++;
-  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);
-    }
-
-    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)) ||
-	(thd->lex->sql_command != SQLCOM_ROLLBACK_TO_SAVEPOINT &&
-         thd->lex->sql_command != SQLCOM_SAVEPOINT &&
-         !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);
-
-      if (thd->lex->stmt_accessed_non_trans_temp_table())
-        cache_data->set_changes_to_non_trans_temp_table();
-
-      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();
-    }
-  }
-
-  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)))
-  {
-    if ((thd->variables.option_bits & OPTION_LOG_OFF)
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-         && (sctx->master_access & SUPER_ACL)
-#endif
-       )
-    {
-      /* No logging */
-      return FALSE;
-    }
-
-    return TRUE;
-  }
-
-  return FALSE;
-}
-
-
-bool general_log_print(THD *thd, enum enum_server_command command,
-                       const char *format, ...)
-{
-  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;
-}
-
-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
+     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
   */
-  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++;
+  open(save_name, log_type, 0, io_cache_type);
+  my_free(save_name);
+
   mysql_mutex_unlock(&LOCK_log);
-  return res;
+
+  DBUG_VOID_RETURN;
 }
 
 
 /*
-  Write the contents of a cache to the binary log.
+  Write a command to traditional general 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()
+
+    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
-    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 given command to to normal (not rotable) log file
 
-  group= (uint)my_b_tell(&log_file);
-  hdr_offs= carry= 0;
+  RETURN
+    FASE - OK
+    TRUE - error occured
+*/
 
-  do
+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())
   {
-    /*
-      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);
+    /* for testing output of timestamp and thread id */
+    DBUG_EXECUTE_IF("reset_log_last_time", last_time= 0;);
 
-      /* assemble both halves */
-      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN - carry);
+    /* Note that my_b_write() assumes it knows the length for this */
+      if (event_time != last_time)
+      {
+        last_time= event_time;
 
-      /* fix end_log_pos */
-      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
-      int4store(&header[LOG_POS_OFFSET], val);
+        localtime_r(&event_time, &start);
 
-      /* write the first half of the split header */
-      if (my_b_write(&log_file, header, carry))
-        return ER_ERROR_ON_WRITE;
+        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);
 
-      /*
-        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 (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;
 
-      /* next event header at ... */
-      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
+      /* command_type, thread_id */
+      length= my_snprintf(buff, 32, "%5ld ", (long) thread_id);
 
-      carry= 0;
-    }
+    if (my_b_write(&log_file, (uchar*) buff, length))
+      goto err;
 
-    /* if there is anything to write, process it. */
+    if (my_b_write(&log_file, (uchar*) command_type, command_type_len))
+      goto err;
 
-    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").
-      */
+    if (my_b_write(&log_file, (uchar*) "\t", 1))
+      goto err;
 
-      while (hdr_offs < length)
-      {
-        /*
-          partial header only? save what we can get, process once
-          we get the rest.
-        */
+    /* sql_text */
+    if (my_b_write(&log_file, (uchar*) sql_text, sql_text_len))
+      goto err;
 
-        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);
+    if (my_b_write(&log_file, (uchar*) "\n", 1) ||
+        flush_io_cache(&log_file))
+      goto err;
+  }
 
-        }
-      }
+  mysql_mutex_unlock(&LOCK_log);
+  return FALSE;
+err:
 
-      /*
-        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;
-    }
+  if (!write_error)
+  {
+    write_error= 1;
+    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+  }
+  mysql_mutex_unlock(&LOCK_log);
+  return TRUE;
+}
 
-    /* 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);
+/*
+  Log a query to the traditional slow log file
 
-  if (sync_log)
-    return flush_and_sync(0);
+  SYNOPSIS
+    write()
 
-  return 0;                                     // All OK
-}
+    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
 
-/*
-  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;
+  DESCRIPTION
 
-    /* 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();
-  }
+   Log a query to the slow log file.
 
-  return error;
-}
+  RETURN
+    FALSE - OK
+    TRUE - error occured
+*/
 
-bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
+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)
 {
-  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)
+  bool error= 0;
+  DBUG_ENTER("MYSQL_QUERY_LOG::write");
+
+  mysql_mutex_lock(&LOCK_log);
+
+  if (!is_open())
   {
-    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(0);
   }
-  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.
+  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;
 
-  @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.
-*/
+    if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
+    {
+      if (current_time != last_time)
+      {
+        last_time= current_time;
+        struct tm start;
+        localtime_r(&current_time, &start);
 
-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);
+        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);
+      }
+    }
 
-  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)
+      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)
     {
-      /*
-        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;
-  my_free(name);
-  name= NULL;
-  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.
 
@@ -5536,14 +2085,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)
@@ -6176,232 +2717,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-08-20 11:22:46 +0000
+++ b/sql/log.h	2010-09-10 07:27:02 +0000
@@ -19,18 +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 ending_single_stmt_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
@@ -145,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
@@ -179,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 };
 
@@ -255,218 +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;
-
-  /* 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)
-
-  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); // binary log write
-  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
 {
@@ -665,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-08-23 22:31:12 +0000
+++ b/sql/log_event.cc	2010-09-10 07:27:02 +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-07-15 13:47:50 +0000
+++ b/sql/log_event.h	2010-09-10 07:27:02 +0000
@@ -1782,8 +1782,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-09-02 18:37:04 +0000
+++ b/sql/mysqld.cc	2010-09-10 07:27:02 +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"
@@ -497,7 +496,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,
@@ -1551,10 +1549,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);
@@ -3555,10 +3549,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);
@@ -5825,9 +5815,6 @@ struct my_option my_long_options[]=
    &master_retry_count, &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.",
-   &rpl_status, &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.",
    &max_binlog_dump_events, &max_binlog_dump_events, 0,
@@ -6043,13 +6030,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;
@@ -6470,9 +6450,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},
@@ -7670,7 +7647,7 @@ PSI_mutex_key key_BINLOG_LOCK_index, key
   key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
   key_LOCK_manager,
   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,
@@ -7709,7 +7686,6 @@ static PSI_mutex_info all_server_mutexes
   { &key_LOCK_global_system_variables, "LOCK_global_system_variables", PSI_FLAG_GLOBAL},
   { &key_LOCK_manager, "LOCK_manager", 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},
@@ -7755,7 +7731,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_rpl_status, key_COND_server_started,
+  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,
@@ -7779,7 +7755,6 @@ static PSI_cond_info all_server_conds[]=
   { &key_COND_cache_status_changed, "Query_cache::COND_cache_status_changed", 0},
   { &key_COND_global_read_lock, "COND_global_read_lock", PSI_FLAG_GLOBAL},
   { &key_COND_manager, "COND_manager", 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-08-30 14:07:40 +0000
+++ b/sql/mysqld.h	2010-09-10 07:27:02 +0000
@@ -175,7 +175,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;
+extern ulong thread_cache_size;
 extern ulong back_log;
 extern char language[FN_REFLEN];
 extern ulong server_id, concurrency;
@@ -230,7 +230,7 @@ extern PSI_mutex_key key_BINLOG_LOCK_ind
   key_LOCK_gdl, key_LOCK_global_read_lock, key_LOCK_global_system_variables,
   key_LOCK_logger, key_LOCK_manager,
   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,
@@ -249,7 +249,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_rpl_status, key_COND_server_started,
+  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-07-23 20:13:36 +0000
+++ b/sql/repl_failsafe.cc	1970-01-01 00:00:00 +0000
@@ -1,645 +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
-};
-
-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.
-*/
-
-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);
-  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);
-}
-
-#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);
-}
-
-
-/**
-  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-07-23 20:13:36 +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;
-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-07-15 19:29:25 +0000
+++ b/sql/rpl_handler.cc	2010-09-10 07:27:02 +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-07-08 21:20:08 +0000
+++ b/sql/rpl_injector.cc	2010-09-10 07:27:02 +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-09-10 07:27:02 +0000
@@ -0,0 +1,1270 @@
+/* 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);
+}
+
+#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);
+  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
+  int old_max_allowed_packet= thd->variables.max_allowed_packet;
+  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);
+  thd->variables.max_allowed_packet= old_max_allowed_packet;
+  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));
+  thd->variables.max_allowed_packet= old_max_allowed_packet;
+
+  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-09-10 07:27:02 +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-07-15 13:47:50 +0000
+++ b/sql/rpl_mi.cc	2010-09-10 07:27:02 +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-07-24 13:31:48 +0000
+++ b/sql/rpl_record.cc	2010-09-10 07:27:02 +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-07-27 10:25:53 +0000
+++ b/sql/rpl_rli.cc	2010-09-10 07:27:02 +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
@@ -1276,4 +1276,32 @@ void Relay_log_info::slave_close_thread_
     thd->mdl_context.release_transactional_locks();
   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-03-31 14:05:33 +0000
+++ b/sql/rpl_rli.h	2010-09-10 07:27:02 +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-07-29 12:32:11 +0000
+++ b/sql/rpl_slave.cc	2010-09-10 07:27:02 +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>
@@ -3028,8 +3026,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
   mysql_mutex_lock(&LOCK_thread_count);
@@ -4213,8 +4209,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,
@@ -4235,7 +4229,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);
     }
@@ -4944,6 +4937,612 @@ 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;
+  char saved_host[HOSTNAME_LENGTH + 1];
+  uint saved_port;
+  char saved_log_name[FN_REFLEN];
+  my_off_t saved_log_pos;
+  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
+  */
+
+  /*
+    Before processing the command, save the previous state.
+  */
+  strmake(saved_host, mi->host, HOSTNAME_LENGTH);
+  saved_port= mi->port;
+  strmake(saved_log_name, mi->master_log_name, FN_REFLEN - 1);
+  saved_log_pos= mi->master_log_pos;
+
+  /*
+    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();
+
+  sql_print_information("'CHANGE MASTER TO executed'. "
+    "Previous state master_host='%s', master_port='%u', master_log_file='%s', "
+    "master_log_pos='%ld'. "
+    "New state master_host='%s', master_port='%u', master_log_file='%s', "
+    "master_log_pos='%ld'.", saved_host, saved_port, saved_log_name,
+    (ulong) saved_log_pos, mi->host, mi->port, mi->master_log_name,
+    (ulong) mi->master_log_pos);
+
+  /*
+    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-03-31 14:05:33 +0000
+++ b/sql/rpl_slave.h	2010-09-10 07:27:02 +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-09-09 12:37:09 +0000
+++ b/sql/set_var.h	2010-09-10 07:27:02 +0000
@@ -171,6 +171,7 @@ protected:
   { return ((uchar*)&global_system_variables) + offset; }
 };
 
+#include "binlog.h"                           /* mysql_bin_log */
 #include "sql_plugin.h"                    /* SHOW_HA_ROWS, SHOW_MY_BOOL */
 
 /****************************************************************************

=== modified file 'sql/sql_binlog.cc'
--- a/sql/sql_binlog.cc	2010-07-15 13:47:50 +0000
+++ b/sql/sql_binlog.cc	2010-09-10 07:27:02 +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-08-30 14:07:40 +0000
+++ b/sql/sql_class.cc	2010-09-10 07:27:02 +0000
@@ -39,7 +39,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"
@@ -3611,1002 +3611,3 @@ void xid_cache_delete(XID_STATE *xid_sta
   my_hash_delete(&xid_cache, (uchar *)xid_state);
   mysql_mutex_unlock(&LOCK_xid_cache);
 }
-
-
-/**
-  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: %lu",
-                      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_access_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;
-    /*
-      Identifies if a table is changed.
-    */
-    my_bool is_write= FALSE;
-    /*
-      A pointer to a previous table that was changed.
-    */
-    TABLE* prev_write_table= NULL;
-    /*
-      A pointer to a previous table that was accessed.
-    */
-    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 ||
-          table->table->s->table_category == TABLE_CATEGORY_LOG)
-        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;
-
-        my_bool trans= table->table->file->has_transactions();
-
-        if (table->table->s->tmp_table)
-          lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TEMP_TRANS_TABLE :
-                                               LEX::STMT_WRITES_TEMP_NON_TRANS_TABLE);
-        else
-          lex->set_stmt_accessed_table(trans ? LEX::STMT_WRITES_TRANS_TABLE :
-                                               LEX::STMT_WRITES_NON_TRANS_TABLE);
-
-        flags_write_all_set &= flags;
-        flags_write_some_set |= flags;
-        is_write= TRUE;
-
-        prev_write_table= table->table;
-
-      }
-      flags_access_some_set |= flags;
-
-      if (lex->sql_command != SQLCOM_CREATE_TABLE ||
-          (lex->sql_command == SQLCOM_CREATE_TABLE &&
-          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE)))
-      {
-        my_bool trans= table->table->file->has_transactions();
-
-        if (table->table->s->tmp_table)
-          lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TEMP_TRANS_TABLE :
-                                               LEX::STMT_READS_TEMP_NON_TRANS_TABLE);
-        else
-          lex->set_stmt_accessed_table(trans ? LEX::STMT_READS_TRANS_TABLE :
-                                               LEX::STMT_READS_NON_TRANS_TABLE);
-      }
-
-      if (prev_access_table && prev_access_table->file->ht !=
-          table->table->file->ht)
-        multi_access_engine= TRUE;
-
-      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_access_some_set: 0x%llx", flags_access_some_set));
-    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
-    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
-
-    int error= 0;
-    int unsafe_flags;
-
-    bool multi_stmt_trans= in_multi_stmt_transaction_mode();
-    bool trans_table= trans_has_updated_trans_table(this);
-    bool binlog_direct= variables.binlog_direct_non_trans_update;
-
-    if (lex->is_mixed_stmt_unsafe(multi_stmt_trans, binlog_direct,
-                                  trans_table, tx_isolation))
-      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
-    else if (multi_stmt_trans && trans_table && !binlog_direct &&
-             lex->stmt_accessed_table(LEX::STMT_WRITES_NON_TRANS_TABLE))
-      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_access_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 &&
-               sqlcom_can_generate_row_events(this))
-      {
-        /*
-          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 &&
-                 sqlcom_can_generate_row_events(this))
-        {
-          /*
-            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 (is_write && (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 = %lu "
-                        "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
-
-/* Declare in unnamed namespace. */
-CPP_UNNAMED_NS_START
-
-  /**
-     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(m_memory);
-    }
-
-    /**
-       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];
-  };
-
-CPP_UNNAMED_NS_END
-
-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);
-      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(LEX::BINLOG_STMT_UNSAFE_COUNT <=
-              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
-
-  uint32 unsafe_type_flags= binlog_unsafe_warning_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());
-      }
-    }
-  }
-  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 in three places 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:
-
-    1 - sp_head::execute_procedure which prints out warnings for calls to
-    stored procedures.
-
-    2 - sp_head::execute_function which prints out warnings for calls
-    involving functions.
-
-    3 - THD::binlog_query (here) which prints warning for top level
-    statements not covered by the two cases above: i.e., if not insided a
-    procedure and a function.
-
-    Besides, we should not try to print these warnings if it is not
-    possible to write statements to the binary log as it happens when
-    the execution is inside a function, or generaly speaking, when
-    the variables.option_bits & OPTION_BIN_LOG is false.
-    
-  */
-  if ((variables.option_bits & OPTION_BIN_LOG) &&
-      spcont == NULL && !binlog_evt_union.do_union)
-    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);
-      /*
-        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-07-19 08:27:53 +0000
+++ b/sql/sql_db.cc	2010-09-10 07:27:02 +0000
@@ -34,6 +34,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-09-01 13:12:42 +0000
+++ b/sql/sql_insert.cc	2010-09-10 07:27:02 +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-08-03 03:49:14 +0000
+++ b/sql/sql_load.cc	2010-09-10 07:27:02 +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-08-25 10:22:34 +0000
+++ b/sql/sql_parse.cc	2010-09-10 07:27:02 +0000
@@ -79,9 +79,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>
@@ -2271,14 +2271,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
@@ -2289,7 +2284,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))

=== modified file 'sql/sql_parse.h'
--- a/sql/sql_parse.h	2010-08-18 11:29:04 +0000
+++ b/sql/sql_parse.h	2010-09-10 07:27:02 +0000
@@ -78,7 +78,6 @@ bool check_host_name(LEX_STRING *str);
 bool check_identifier_name(LEX_STRING *str, uint max_char_length,
                            uint err_code, const char *param_for_err_msg);
 bool mysql_test_parse_for_slave(THD *thd,char *inBuf,uint length);
-bool sqlcom_can_generate_row_events(const THD *thd);
 bool is_update_query(enum enum_sql_command command);
 bool is_log_table_write_query(enum enum_sql_command command);
 bool alloc_query(THD *thd, const char *packet, uint packet_length);

=== modified file 'sql/sql_reload.cc'
--- a/sql/sql_reload.cc	2010-08-13 09:51:48 +0000
+++ b/sql/sql_reload.cc	2010-09-10 07:27:02 +0000
@@ -23,7 +23,9 @@
 #include "sql_base.h"    // close_cached_tables
 #include "sql_db.h"      // my_dbopt_cleanup
 #include "hostname.h"    // hostname_cache_refresh
-#include "sql_repl.h"    // reset_master, reset_slave
+#include "rpl_rli.h"     // rotate_relay_log
+#include "rpl_master.h"  // reset_master
+#include "rpl_slave.h"   // reset_slave
 #include "debug_sync.h"
 
 

=== removed file 'sql/sql_repl.cc'
--- a/sql/sql_repl.cc	2010-07-26 10:52:59 +0000
+++ b/sql/sql_repl.cc	1970-01-01 00:00:00 +0000
@@ -1,2030 +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 = !memcmp(log_name, 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)
-{
-  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
-  int old_max_allowed_packet= thd->variables.max_allowed_packet;
-  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);
-  thd->variables.max_allowed_packet= old_max_allowed_packet;
-  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));
-  thd->variables.max_allowed_packet= old_max_allowed_packet;
-
-  my_message(my_errno, errmsg, MYF(0));
-  DBUG_VOID_RETURN;
-}
-
-
-/**
-  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
-
-*/
-
-
-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 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;
-  char saved_host[HOSTNAME_LENGTH + 1];
-  uint saved_port;
-  char saved_log_name[FN_REFLEN];
-  my_off_t saved_log_pos;
-  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
-  */
-
-  /*
-    Before processing the command, save the previous state.
-  */
-  strmake(saved_host, mi->host, HOSTNAME_LENGTH);
-  saved_port= mi->port;
-  strmake(saved_log_name, mi->master_log_name, FN_REFLEN - 1);
-  saved_log_pos= mi->master_log_pos;
-
-  /*
-    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();
-
-  sql_print_information("'CHANGE MASTER TO executed'. "
-    "Previous state master_host='%s', master_port='%u', master_log_file='%s', "
-    "master_log_pos='%ld'. "
-    "New state master_host='%s', master_port='%u', master_log_file='%s', "
-    "master_log_pos='%ld'.", saved_host, saved_port, saved_log_name,
-    (ulong) saved_log_pos, mi->host, mi->port, mi->master_log_name,
-    (ulong) mi->master_log_pos);
-
-  /*
-    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);
-}
-
-
-/**
-  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 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;
-  const char *errmsg = 0;
-  bool ret = TRUE;
-  IO_CACHE log;
-  File file = -1;
-  MYSQL_BIN_LOG *binary_log= NULL;
-  int old_max_allowed_packet= thd->variables.max_allowed_packet;
-  DBUG_ENTER("mysql_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);
-
-  Format_description_log_event *description_event= new
-    Format_description_log_event(3); /* MySQL 4.0 by default */
-
-  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
-              thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
-
-  /* select wich binary log to use: binlog or relay */
-  if ( thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS )
-  {
-    /*
-      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);
-
-    binary_log= &mysql_bin_log;
-  }
-  else  /* showing relay log contents */
-  {
-    if (!active_mi)
-      DBUG_RETURN(TRUE);
-
-    binary_log= &(active_mi->rli.relay_log);
-  }
-
-  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);
-  thd->variables.max_allowed_packet= old_max_allowed_packet;
-  DBUG_RETURN(ret);
-}
-
-
-/**
-  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);
-}
-
-/**
-   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);
-}
-
-#endif /* HAVE_REPLICATION */

=== removed file 'sql/sql_repl.h'
--- a/sql/sql_repl.h	2010-03-31 14:05:33 +0000
+++ b/sql/sql_repl.h	1970-01-01 00:00:00 +0000
@@ -1,72 +0,0 @@
-/* Copyright (C) 2000-2006 MySQL AB & Sasha
-
-   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 */
-
-#ifndef SQL_REPL_INCLUDED
-#define SQL_REPL_INCLUDED
-
-#include "rpl_filter.h"
-
-#ifdef HAVE_REPLICATION
-#include "slave.h"
-
-typedef struct st_slave_info
-{
-  uint32 server_id;
-  uint32 rpl_recovery_rank, 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 my_bool opt_show_slave_auth_info;
-extern char *master_host, *master_info_file;
-extern bool server_id_supplied;
-
-extern int max_binlog_dump_events;
-extern my_bool opt_sporadic_binlog_dump_fail;
-
-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);
-bool mysql_show_binlog_events(THD* thd);
-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 reset_master(THD* thd);
-bool purge_master_logs(THD* thd, const char* to_log);
-bool purge_master_logs_before_date(THD* thd, time_t purge_time);
-bool log_in_use(const char* log_name);
-void adjust_linfo_offsets(my_off_t purge_offset);
-bool show_binlogs(THD* thd);
-extern int init_master_info(Master_info* mi);
-void kill_zombie_dump_threads(uint32 slave_server_id);
-int check_binlog_magic(IO_CACHE* log, const char** errmsg);
-
-typedef struct st_load_file_info
-{
-  THD* thd;
-  my_off_t last_pos_in_file;
-  bool wrote_create_file, log_delayed;
-} LOAD_FILE_INFO;
-
-int log_loaded_block(IO_CACHE* file);
-int init_replication_sys_vars();
-void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
-
-#endif /* HAVE_REPLICATION */
-
-#endif /* SQL_REPL_INCLUDED */

=== modified file 'sql/sql_servers.h'
--- a/sql/sql_servers.h	2010-03-31 14:05:33 +0000
+++ b/sql/sql_servers.h	2010-09-10 07:27:02 +0000
@@ -17,7 +17,7 @@
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA */
 
 #include "my_global.h"                  /* uint */
-#include "slave.h" // for tables_ok(), rpl_filter
+#include "rpl_slave.h" // for tables_ok(), rpl_filter
 
 class THD;
 typedef struct st_lex_server_options LEX_SERVER_OPTIONS;

=== modified file 'sql/sql_show.cc'
--- a/sql/sql_show.cc	2010-08-30 14:07:40 +0000
+++ b/sql/sql_show.cc	2010-09-10 07:27:02 +0000
@@ -26,7 +26,6 @@
 #include "sql_table.h"                        // filename_to_tablename,
                                               // primary_key_name,
                                               // build_table_filename
-#include "repl_failsafe.h"
 #include "sql_parse.h"             // check_access, check_table_access
 #include "sql_partition.h"         // partition_element
 #include "sql_db.h"     // check_db_dir_existence, load_db_opt_by_name

=== modified file 'sql/sql_yacc.yy'
--- a/sql/sql_yacc.yy	2010-09-01 13:12:42 +0000
+++ b/sql/sql_yacc.yy	2010-09-10 07:27:02 +0000
@@ -44,7 +44,7 @@
 #include "sql_acl.h"                          /* *_ACL */
 #include "password.h"       /* my_make_scrambled_password_323, my_make_scrambled_password */
 #include "sql_class.h"      /* Key_part_spec, enum_filetype, Diag_condition_item_name */
-#include "slave.h"
+#include "rpl_slave.h"
 #include "lex_symbol.h"
 #include "item_create.h"
 #include "sp_head.h"

=== modified file 'sql/structs.h'
--- a/sql/structs.h	2010-03-31 14:05:33 +0000
+++ b/sql/structs.h	2010-09-10 07:27:02 +0000
@@ -358,8 +358,30 @@ public:
     return tmp;
   }
   ~Discrete_intervals_list() { empty(); };
-  bool append(ulonglong start, ulonglong val, ulonglong incr);
-  bool append(Discrete_interval *interval);
+  bool append(ulonglong start, ulonglong val, ulonglong incr)
+  {
+    /* 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);
+      return append(new_interval);
+    }
+    return 0;
+  }
+  
+  bool append(Discrete_interval *new_interval)
+  {
+    if (unlikely(new_interval == NULL))
+      return 1;
+    if (head == NULL)
+      head= current= new_interval;
+    else
+      tail->next= new_interval;
+    tail= new_interval;
+    elements++;
+    return 0;
+  }
   ulonglong minimum()     const { return (head ? head->minimum() : 0); };
   ulonglong maximum()     const { return (head ? tail->maximum() : 0); };
   uint      nb_elements() const { return elements; }

=== modified file 'sql/sys_vars.cc'
--- a/sql/sys_vars.cc	2010-08-30 14:07:40 +0000
+++ b/sql/sys_vars.cc	2010-09-10 07:27:02 +0000
@@ -34,7 +34,7 @@
 
 #include "events.h"
 #include <thr_alarm.h>
-#include "slave.h"
+#include "rpl_slave.h"
 #include "rpl_mi.h"
 #include "transaction.h"
 #include "mysqld.h"
@@ -1534,13 +1534,6 @@ static Sys_var_ulong Sys_div_precincreme
        SESSION_VAR(div_precincrement), CMD_LINE(REQUIRED_ARG),
        VALID_RANGE(0, DECIMAL_MAX_SCALE), DEFAULT(4), BLOCK_SIZE(1));
 
-static Sys_var_ulong Sys_rpl_recovery_rank(
-       "rpl_recovery_rank", "Unused, will be removed",
-       GLOBAL_VAR(rpl_recovery_rank), CMD_LINE(REQUIRED_ARG),
-       VALID_RANGE(0, ULONG_MAX), DEFAULT(0), BLOCK_SIZE(1),
-       NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0), ON_UPDATE(0),
-       DEPRECATED(70000, 0));
-
 static Sys_var_ulong Sys_range_alloc_block_size(
        "range_alloc_block_size",
        "Allocation block size for storing ranges during optimization",


Attachment: [text/bzr-bundle] bzr/zhenxing.he@sun.com-20100910072702-23h8mlixrt5tjf3e.bundle
Thread
bzr commit into mysql-5.5-bugfixing branch (zhenxing.he:3206) Bug#54649WL#5385He Zhenxing10 Sep