List:Commits« Previous MessageNext Message »
From:He Zhenxing Date:April 26 2010 5:01am
Subject:bzr commit into mysql-5.1-rep+2 branch (zhenxing.he:3185) WL#3662
View as plain text  
#At file:///media/sdb2/hezx/work/mysql/bzrwork/rap/5.1-rep%2B2/ based on revid:li-bing.song@stripped

 3185 He Zhenxing	2010-04-26
      WL#3662 Refactoring: Replication Modules
      
      Splitting replication code into libraries for binlog, slave
      and master.
       - add binlog.[cc|h], move BINLOG code from log.cc to binlog.[cc|h]
       - split sql_repl.[cc|h] into sql_master.[cc|h] and sql_slave.[cc|h]
       - add mysql_show_relaylog_events
       - modified Makefile.am/CMakeLists.txt to build the libraries
     @ libmysqld/CMakeLists.txt
        Add binlog.cc
     @ libmysqld/Makefile.am
        Add binlog.cc
     @ sql/Makefile.am
        Add binlog, master, slave libraries
     @ sql/log.cc
        Move binlog related code to binlog.cc
     @ sql/log.h
        Move binlog related code to binlog.cc
     @ sql/sql_parse.cc
        Add function mysql_show_relaylog_events
     @ sql/sql_repl.cc
        Split sql_repl.cc into sql_master.cc and sql_slave.cc
     @ sql/sql_repl.h
        Split sql_repl.h into sql_master.h and sql_slave.h

    D  sql/sql_repl.cc
    A  sql/binlog.cc
    A  sql/binlog.h
    A  sql/sql_master.cc
    A  sql/sql_master.h
    A  sql/sql_slave.cc
    A  sql/sql_slave.h
    M  libmysqld/CMakeLists.txt
    M  libmysqld/Makefile.am
    M  sql/CMakeLists.txt
    M  sql/Makefile.am
    M  sql/log.cc
    M  sql/log.h
    M  sql/slave.h
    M  sql/sql_class.h
    M  sql/sql_db.cc
    M  sql/sql_parse.cc
    M  sql/sql_repl.h
=== modified file 'libmysqld/CMakeLists.txt'
--- a/libmysqld/CMakeLists.txt	2009-11-06 16:35:04 +0000
+++ b/libmysqld/CMakeLists.txt	2010-04-26 05:01:18 +0000
@@ -141,7 +141,7 @@ SET(LIBMYSQLD_SOURCES emb_qcache.cc libm
            ../sql/time.cc ../sql/tztime.cc ../sql/uniques.cc ../sql/unireg.cc
            ../sql/partition_info.cc ../sql/sql_connect.cc 
            ../sql/scheduler.cc ../sql/event_parse_data.cc
-           ../sql/rpl_handler.cc
+           ../sql/rpl_handler.cc ../sql/binlog.cc
            ${GEN_SOURCES}
            ${LIB_SOURCES})
 

=== modified file 'libmysqld/Makefile.am'
--- a/libmysqld/Makefile.am	2009-12-15 20:21:00 +0000
+++ b/libmysqld/Makefile.am	2010-04-26 05:01:18 +0000
@@ -78,7 +78,7 @@ sqlsources = derror.cc field.cc field_co
 	sql_tablespace.cc \
 	rpl_injector.cc my_user.c partition_info.cc \
 	sql_servers.cc event_parse_data.cc \
-	rpl_handler.cc
+	rpl_handler.cc binlog.cc
 
 libmysqld_int_a_SOURCES= $(libmysqld_sources)
 nodist_libmysqld_int_a_SOURCES= $(libmysqlsources) $(sqlsources)

=== modified file 'sql/CMakeLists.txt'
--- a/sql/CMakeLists.txt	2009-11-06 16:35:04 +0000
+++ b/sql/CMakeLists.txt	2010-04-26 05:01:18 +0000
@@ -87,6 +87,14 @@ SET (SQL_SOURCE
                ${PROJECT_SOURCE_DIR}/sql/lex_hash.h)
 ADD_LIBRARY(sql ${SQL_SOURCE})
 
+SET (BINLOG_SOURCE log_event.cc log_event_old.cc rpl_tblmap.cc binlog.cc sql_binlog.cc
+		   rpl_filter.cc rpl_record.cc rpl_record_old.cc rpl_utility.cc)
+ADD_LIBRARY(binlog ${BINLOG_SOURCE})
+SET (MASTER_SOURCE sql_master.cc rpl_injector.cc repl_failsafe.cc)
+ADD_LIBRARY(master ${MASTER_SOURCE})
+SET (SLAVE_SOURCE sql_slave.cc slave.cc rpl_mi.cc rpl_rli.cc rpl_reporting.cc)
+ADD_LIBRARY(slave ${SLAVE_SOURCE})
+
 IF (NOT EXISTS cmake_dummy.cc)
   FILE (WRITE cmake_dummy.cc "")
 ENDIF (NOT EXISTS cmake_dummy.cc)
@@ -95,7 +103,8 @@ ADD_EXECUTABLE(mysqld cmake_dummy.cc)
 SET_TARGET_PROPERTIES(mysqld PROPERTIES OUTPUT_NAME mysqld${MYSQLD_EXE_SUFFIX})
 SET_TARGET_PROPERTIES(mysqld PROPERTIES ENABLE_EXPORTS TRUE)
 
-SET (MYSQLD_CORE_LIBS mysys zlib dbug strings yassl taocrypt vio regex sql)
+SET (MYSQLD_CORE_LIBS mysys zlib dbug strings yassl taocrypt vio regex
+    		      binlog master slave sql)
 TARGET_LINK_LIBRARIES(mysqld ${MYSQLD_CORE_LIBS} ${MYSQLD_STATIC_ENGINE_LIBS})
 TARGET_LINK_LIBRARIES(mysqld ws2_32.lib)
 

=== modified file 'sql/Makefile.am'
--- a/sql/Makefile.am	2009-11-06 16:35:04 +0000
+++ b/sql/Makefile.am	2010-04-26 05:01:18 +0000
@@ -32,14 +32,18 @@ bin_PROGRAMS =		mysql_tzinfo_to_sql
 noinst_LTLIBRARIES=	libndb.la \
 			udf_example.la
 
+pkglib_LTLIBRARIES=	libbinlog.la libmaster.la libslave.la
+
 SUPPORTING_LIBS =	$(top_builddir)/vio/libvio.a \
 			$(top_builddir)/mysys/libmysys.a \
 			$(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 \
+			libbinlog.la libmaster.la libslave.la
 LDADD = $(SUPPORTING_LIBS) @ZLIB_LIBS@ @NDB_SCI_LIBS@
 mysqld_LDADD =		libndb.la \
+			libbinlog.la libmaster.la libslave.la \
 			@MYSQLD_EXTRA_LDFLAGS@ \
 			@pstack_libs@ \
 			@mysql_plugin_libs@ \
@@ -78,7 +82,8 @@ noinst_HEADERS =	item.h item_func.h item
 			event_data_objects.h event_scheduler.h \
 			sql_partition.h partition_info.h partition_element.h \
 			contributors.h sql_servers.h \
-			rpl_handler.h replication.h
+			rpl_handler.h replication.h \
+			binlog.h sql_master.h sql_slave.h rpl_plugin.h
 
 mysqld_SOURCES =	sql_lex.cc sql_handler.cc sql_partition.cc \
 			item.cc item_sum.cc item_buff.cc item_func.cc \
@@ -99,8 +104,6 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			procedure.cc sql_test.cc \
 			log.cc init.cc derror.cc sql_acl.cc \
 			unireg.cc des_key_file.cc \
-			log_event.cc rpl_record.cc \
-			log_event_old.cc rpl_record_old.cc \
 			discover.cc time.cc opt_range.cc opt_sum.cc \
 		   	records.cc filesort.cc handler.cc \
 		        ha_partition.cc \
@@ -108,12 +111,8 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			sql_db.cc sql_table.cc sql_rename.cc sql_crypt.cc \
 			sql_load.cc mf_iocache.cc field_conv.cc sql_show.cc \
 			sql_udf.cc sql_analyse.cc sql_analyse.h sql_cache.cc \
-			slave.cc sql_repl.cc rpl_filter.cc rpl_tblmap.cc \
-			rpl_utility.cc rpl_injector.cc rpl_rli.cc rpl_mi.cc \
-			rpl_reporting.cc \
                         sql_union.cc sql_derived.cc \
 			sql_client.cc \
-			repl_failsafe.h repl_failsafe.cc \
 			sql_olap.cc sql_view.cc \
 			gstream.cc spatial.cc sql_help.cc sql_cursor.cc \
 			tztime.cc my_decimal.cc\
@@ -121,11 +120,20 @@ mysqld_SOURCES =	sql_lex.cc sql_handler.
 			sp_cache.cc parse_file.cc sql_trigger.cc \
                         event_scheduler.cc event_data_objects.cc \
                         event_queue.cc event_db_repository.cc events.cc \
-			sql_plugin.cc sql_binlog.cc \
+			sql_plugin.cc \
 			sql_builtin.cc sql_tablespace.cc partition_info.cc \
 			sql_servers.cc event_parse_data.cc \
 			rpl_handler.cc
 
+libbinlog_la_SOURCES =	log_event.cc log_event_old.cc \
+			binlog.cc sql_binlog.cc \
+			rpl_filter.cc rpl_tblmap.cc \
+			rpl_record.cc rpl_record_old.cc \
+			rpl_utility.cc
+libmaster_la_SOURCES =	sql_master.cc rpl_injector.cc repl_failsafe.cc
+libslave_la_SOURCES = 	sql_slave.cc slave.cc rpl_mi.cc rpl_rli.cc \
+			rpl_reporting.cc
+
 nodist_mysqld_SOURCES =	mini_client_errors.c pack.c client.c my_time.c my_user.c 
 
 libndb_la_CPPFLAGS=	@ndbcluster_includes@

=== added file 'sql/binlog.cc'
--- a/sql/binlog.cc	1970-01-01 00:00:00 +0000
+++ b/sql/binlog.cc	2010-04-26 05:01:18 +0000
@@ -0,0 +1,3835 @@
+/* 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 */
+
+#include "mysql_priv.h"
+#include <my_dir.h>
+#include <mysql/plugin.h>
+#include "binlog.h"
+#include "rpl_filter.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 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 classes to store non-transactional and transactional data
+  before copying it to the binary log.
+*/
+class binlog_cache_data
+{
+public:
+  binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
+  incident(FALSE)
+  {
+    cache_log.end_of_file= max_binlog_cache_size;
+  }
+
+  ~binlog_cache_data()
+  {
+    DBUG_ASSERT(empty());
+    close_cached_file(&cache_log);
+  }
+
+  bool empty() const
+  {
+    return pending() == NULL && my_b_tell(&cache_log) == 0;
+  }
+
+  Rows_log_event *pending() const
+  {
+    return m_pending;
+  }
+
+  void set_pending(Rows_log_event *const pending)
+  {
+    m_pending= pending;
+  }
+
+  void set_incident(void)
+  {
+    incident= TRUE;
+  }
+  
+  bool has_incident(void)
+  {
+    return(incident);
+  }
+
+  void reset()
+  {
+    truncate(0);
+    incident= FALSE;
+    before_stmt_pos= MY_OFF_T_UNDEF;
+    cache_log.end_of_file= max_binlog_cache_size;
+    DBUG_ASSERT(empty());
+  }
+
+  my_off_t get_byte_position() const
+  {
+    return my_b_tell(&cache_log);
+  }
+
+  my_off_t get_prev_position()
+  {
+     return(before_stmt_pos);
+  }
+
+  void set_prev_position(my_off_t pos)
+  {
+     before_stmt_pos= pos;
+  }
+  
+  void restore_prev_position()
+  {
+    truncate(before_stmt_pos);
+  }
+
+  void restore_savepoint(my_off_t pos)
+  {
+    truncate(pos);
+    if (pos < before_stmt_pos)
+      before_stmt_pos= MY_OFF_T_UNDEF;
+  }
+
+  /*
+    Cache to store data before copying it to the binary log.
+  */
+  IO_CACHE cache_log;
+
+private:
+  /*
+    Pending binrows event. This event is the event where the rows are currently
+    written.
+   */
+  Rows_log_event *m_pending;
+
+  /*
+    Binlog position before the start of the current statement.
+  */
+  my_off_t before_stmt_pos;
+ 
+  /*
+    This indicates that some events did not get into the cache and most likely
+    it is corrupted.
+  */ 
+  bool incident;
+
+  /*
+    It truncates the cache to a certain position. This includes deleting the
+    pending event.
+   */
+  void truncate(my_off_t pos)
+  {
+    DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
+    if (pending())
+    {
+      delete pending();
+      set_pending(0);
+    }
+    reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
+    cache_log.end_of_file= max_binlog_cache_size;
+  }
+ 
+  binlog_cache_data& operator=(const binlog_cache_data& info);
+  binlog_cache_data(const binlog_cache_data& info);
+};
+
+class binlog_cache_mngr {
+public:
+  binlog_cache_mngr() {}
+
+  void reset_cache(binlog_cache_data* cache_data)
+  {
+    cache_data->reset();
+  }
+
+  binlog_cache_data* get_binlog_cache_data(bool is_transactional)
+  {
+    return (is_transactional ? &trx_cache : &stmt_cache);
+  }
+
+  IO_CACHE* get_binlog_cache_log(bool is_transactional)
+  {
+    return (is_transactional ? &trx_cache.cache_log : &stmt_cache.cache_log);
+  }
+
+  binlog_cache_data stmt_cache;
+
+  binlog_cache_data trx_cache;
+
+private:
+
+  binlog_cache_mngr& operator=(const binlog_cache_mngr& info);
+  binlog_cache_mngr(const binlog_cache_mngr& info);
+};
+
+
+/*
+  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(pthread_mutex_t *mutex)
+    : m_mutex(mutex)
+  {
+    if (m_mutex)
+      pthread_mutex_lock(mutex);
+  }
+
+  ~Mutex_sentry()
+  {
+    if (m_mutex)
+      pthread_mutex_unlock(m_mutex);
+#ifndef DBUG_OFF
+    m_mutex= 0;
+#endif
+  }
+
+private:
+  pthread_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&);
+};
+
+
+/** 
+  This function checks if a transactional talbe 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 ? my_b_tell (&cache_mngr->trx_cache.cache_log) : 0);
+}
+
+/** 
+  This function checks if a transactional talbe 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, the cache
+  to be used depends on the flag @c is_transactional. 
+
+  Otherswise, we use the trx-cache if either the @c is_transactional
+  is true or the trx-cache is not empty.
+
+  @param thd              The client thread.
+  @param is_transactional The changes are related to a trx-table.
+  @return
+    @c true if a trx-cache should be used, @c false otherwise.
+*/
+bool use_trans_cache(const THD* thd, bool is_transactional)
+{
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+  return
+    (thd->variables.binlog_direct_non_trans_update ? is_transactional :
+    (cache_mngr->trx_cache.empty() && !is_transactional ? FALSE : TRUE));
+}
+
+bool log_in_use(const char* log_name)
+{
+  size_t log_name_len = strlen(log_name) + 1;
+  THD *tmp;
+  bool result = 0;
+
+  pthread_mutex_lock(&LOCK_thread_count);
+  I_List_iterator<THD> it(threads);
+
+  while ((tmp=it++))
+  {
+    LOG_INFO* linfo;
+    if ((linfo = tmp->current_linfo))
+    {
+      pthread_mutex_lock(&linfo->lock);
+      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
+                     log_name_len);
+      pthread_mutex_unlock(&linfo->lock);
+      if (result)
+	break;
+    }
+  }
+
+  pthread_mutex_unlock(&LOCK_thread_count);
+  return result;
+}
+
+
+#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)
+  {
+    (void) my_seek(file, offset, MY_SEEK_SET, MYF(0));
+    if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME)))
+	< 0)
+      goto err;
+    if (!bytes_read)
+      break;					// end of file
+    (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
+    if (my_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 (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
+      my_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 */
+
+/*
+  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;
+
+  pthread_mutex_lock(&LOCK_thread_count);
+  I_List_iterator<THD> it(threads);
+
+  while ((tmp=it++))
+  {
+    LOG_INFO* linfo;
+    if ((linfo = tmp->current_linfo))
+    {
+      pthread_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;
+      pthread_mutex_unlock(&linfo->lock);
+    }
+  }
+  pthread_mutex_unlock(&LOCK_thread_count);
+}
+
+
+/*
+  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.
+*/
+
+int binlog_init(void *p)
+{
+  binlog_hton= (handlerton *)p;
+  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
+  binlog_hton->db_type=DB_TYPE_BINLOG;
+  binlog_hton->savepoint_offset= sizeof(my_off_t);
+  binlog_hton->close_connection= binlog_close_connection;
+  binlog_hton->savepoint_set= binlog_savepoint_set;
+  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
+  binlog_hton->commit= binlog_commit;
+  binlog_hton->rollback= binlog_rollback;
+  binlog_hton->prepare= binlog_prepare;
+  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
+  return 0;
+}
+
+static int binlog_close_connection(handlerton *hton, THD *thd)
+{
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+  DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty());
+  thd_set_ha_data(thd, binlog_hton, NULL);
+  cache_mngr->~binlog_cache_mngr();
+  my_free((uchar*)cache_mngr, MYF(0));
+  return 0;
+}
+
+/**
+  This function flushes a transactional cache upon commit/rollback.
+
+  @param thd        The thread whose transaction should be flushed
+  @param cache_mngr Pointer to the cache data to be flushed
+  @param end_ev     The end event either commit/rollback.
+
+  @return
+    nonzero if an error pops up when flushing the transactional cache.
+*/
+static int
+binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
+                       Log_event *end_ev)
+{
+  DBUG_ENTER("binlog_flush_trx_cache");
+  int error=0;
+  IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log;
+
+  /*
+    This function handles transactional changes and as such
+    this flag equals to true.
+  */
+  bool const is_transactional= TRUE;
+
+  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
+    DBUG_RETURN(1);
+  /*
+    Doing a commit or a rollback including non-transactional tables,
+    i.e., ending a transaction where we might write the transaction
+    cache to the binary log.
+
+    We can always end the statement when ending a transaction since
+    transactions are not allowed inside stored functions. If they
+    were, we would have to ensure that we're not ending a statement
+    inside a stored function.
+  */
+  error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev,
+                             cache_mngr->trx_cache.has_incident());
+  cache_mngr->reset_cache(&cache_mngr->trx_cache);
+
+  /*
+    We need to step the table map version after writing the
+    transaction cache to disk.
+  */
+  mysql_bin_log.update_table_map_version();
+  statistic_increment(binlog_cache_use, &LOCK_status);
+  if (cache_log->disk_writes != 0)
+  {
+    statistic_increment(binlog_cache_disk_use, &LOCK_status);
+    cache_log->disk_writes= 0;
+  }
+
+  DBUG_ASSERT(cache_mngr->trx_cache.empty());
+  DBUG_RETURN(error);
+}
+
+/**
+  This function truncates the transactional cache upon committing or rolling
+  back either a transaction or a statement.
+
+  @param thd        The thread whose transaction should be flushed
+  @param cache_mngr Pointer to the cache data to be flushed
+  @param all        @c true means truncate the transaction, otherwise the
+                    statement must be truncated.
+
+  @return
+    nonzero if an error pops up when truncating the transactional cache.
+*/
+static int
+binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
+{
+  DBUG_ENTER("binlog_truncate_trx_cache");
+  int error=0;
+  /*
+    This function handles transactional changes and as such this flag
+    equals to true.
+  */
+  bool const is_transactional= TRUE;
+
+  DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s",
+                      FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
+                      FLAGSTR(thd->options, 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 (all || !thd->in_multi_stmt_transaction())
+  {
+    if (cache_mngr->trx_cache.has_incident())
+      error= mysql_bin_log.write_incident(thd, TRUE);
+
+    cache_mngr->reset_cache(&cache_mngr->trx_cache);
+
+    thd->clear_binlog_table_maps();
+  }
+  /*
+    If rolling back a statement in a transaction, we truncate the
+    transaction cache to remove the statement.
+  */
+  else
+    cache_mngr->trx_cache.restore_prev_position();
+
+  /*
+    We need to step the table map version on a rollback to ensure that a new
+    table map event is generated instead of the one that was written to the
+    thrown-away transaction cache.
+  */
+  mysql_bin_log.update_table_map_version();
+
+  DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL);
+  DBUG_RETURN(error);
+}
+
+static int binlog_prepare(handlerton *hton, THD *thd, bool all)
+{
+  /*
+    do nothing.
+    just pretend we can do 2pc, so that MySQL won't
+    switch to 1pc.
+    real work will be done in MYSQL_BIN_LOG::log_xid()
+  */
+  return 0;
+}
+
+/**
+  This function flushes the non-transactional to the binary log upon
+  committing or rolling back a statement.
+
+  @param thd        The thread whose transaction should be flushed
+  @param cache_mngr Pointer to the cache data to be flushed
+
+  @return
+    nonzero if an error pops up when flushing the non-transactional cache.
+*/
+static int
+binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+{
+  int error= 0;
+  DBUG_ENTER("binlog_flush_stmt_cache");
+  /*
+    If we are flushing the statement cache, it means that the changes get
+    through otherwise the cache is empty and this routine should not be called.
+  */
+  DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE);
+  /*
+    This function handles non-transactional changes and as such this flag equals
+    to false.
+  */
+  bool const is_transactional= FALSE;
+  IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
+  thd->binlog_flush_pending_rows_event(TRUE, is_transactional);
+  Query_log_event qev(thd, STRING_WITH_LEN("COMMIT"), TRUE, FALSE, TRUE, 0);
+  if ((error= mysql_bin_log.write(thd, cache_log, &qev,
+                                  cache_mngr->stmt_cache.has_incident())))
+    DBUG_RETURN(error);
+  cache_mngr->reset_cache(&cache_mngr->stmt_cache);
+
+  /*
+    We need to step the table map version after writing the
+    transaction cache to disk.
+  */
+  mysql_bin_log.update_table_map_version();
+  statistic_increment(binlog_cache_use, &LOCK_status);
+  if (cache_log->disk_writes != 0)
+  {
+    statistic_increment(binlog_cache_disk_use, &LOCK_status);
+    cache_log->disk_writes= 0;
+  }
+  DBUG_RETURN(error);
+}
+
+/**
+  This function is called once after each statement.
+
+  It has the responsibility to flush the caches to the binary log on commits.
+
+  @param hton  The binlog handlerton.
+  @param thd   The client thread that executes the transaction.
+  @param all   This is @c true if this is a real transaction commit, and
+               @false otherwise.
+
+  @see handlerton::commit
+*/
+static int binlog_commit(handlerton *hton, THD *thd, bool all)
+{
+  int error= 0;
+  DBUG_ENTER("binlog_commit");
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+  bool const in_transaction= thd->in_multi_stmt_transaction();
+
+  DBUG_PRINT("debug",
+             ("all: %d, in_transaction: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
+              all,
+              YESNO(in_transaction),
+              YESNO(thd->transaction.all.modified_non_trans_table),
+              YESNO(thd->transaction.stmt.modified_non_trans_table)));
+
+  if (!cache_mngr->stmt_cache.empty())
+  {
+    binlog_flush_stmt_cache(thd, cache_mngr);
+  }
+
+  if (cache_mngr->trx_cache.empty())
+  {
+    /*
+      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
+    */
+    cache_mngr->reset_cache(&cache_mngr->trx_cache);
+    DBUG_RETURN(0);
+  }
+
+  /*
+    We commit the transaction if:
+     - We are not in a transaction and committing a statement, or
+     - We are in a transaction and a full transaction is committed.
+    Otherwise, we accumulate the changes.
+  */
+  if (!in_transaction || 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())
+  {
+    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 transcation that modified a non-transactional table or;
+        . aborting a statement that modified both transactional and
+         non-transctional tables but which is not in the boundaries of any
+         transaction;
+        . the OPTION_KEEP_LOG is activate.
+    */
+    if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
+        ((all && thd->transaction.all.modified_non_trans_table) ||
+        (!all && thd->transaction.stmt.modified_non_trans_table &&
+        !thd->in_multi_stmt_transaction()) ||
+        (thd->options & OPTION_KEEP_LOG)))
+    {
+      Query_log_event qev(thd, STRING_WITH_LEN("ROLLBACK"), TRUE, FALSE, TRUE, 0);
+      error= binlog_flush_trx_cache(thd, cache_mngr, &qev);
+    }
+    /*
+      Otherwise, we simply truncate the cache as there is no change on
+      non-transactional tables as follows.
+    */
+    else if (all || (!all &&
+                     (!thd->transaction.stmt.modified_non_trans_table ||
+                      !thd->in_multi_stmt_transaction() || 
+                      thd->variables.binlog_format != BINLOG_FORMAT_STMT)))
+      error= binlog_truncate_trx_cache(thd, cache_mngr, all);
+  }
+
+  /* 
+    This is part of the stmt rollback.
+  */
+  if (!all)
+    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); 
+  DBUG_RETURN(error);
+}
+
+/*
+  These functions are placed in this file since they need access to
+  binlog_hton, which has internal linkage.
+*/
+
+int THD::binlog_setup_trx_data()
+{
+  DBUG_ENTER("THD::binlog_setup_trx_data");
+  binlog_cache_mngr *cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+  if (cache_mngr)
+    DBUG_RETURN(0);                             // Already set up
+
+  cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL));
+  if (!cache_mngr ||
+      open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
+                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)) ||
+      open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir,
+                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
+  {
+    my_free((uchar*)cache_mngr, MYF(MY_ALLOW_ZERO_PTR));
+    DBUG_RETURN(1);                      // Didn't manage to set it up
+  }
+  thd_set_ha_data(this, binlog_hton, cache_mngr);
+
+  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
+
+  DBUG_RETURN(0);
+}
+
+/*
+  Function to start a statement and optionally a transaction for the
+  binary log.
+
+  SYNOPSIS
+    binlog_start_trans_and_stmt()
+
+  DESCRIPTION
+
+    This function does three things:
+    - Start a transaction if not in autocommit mode or if a BEGIN
+      statement has been seen.
+
+    - Start a statement transaction to allow us to truncate the cache.
+
+    - Save the currrent binlog position so that we can roll back the
+      statement by truncating the cache.
+
+      We only update the saved position if the old one was undefined,
+      the reason is that there are some cases (e.g., for CREATE-SELECT)
+      where the position is saved twice (e.g., both in
+      select_create::prepare() and THD::binlog_write_table_map()) , but
+      we should use the first. This means that calls to this function
+      can be used to start the statement before the first table map
+      event, to include some extra events.
+ */
+
+void
+THD::binlog_start_trans_and_stmt()
+{
+  binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+  DBUG_ENTER("binlog_start_trans_and_stmt");
+  DBUG_PRINT("enter", ("cache_mngr: %p  cache_mngr->trx_cache.get_prev_position(): %lu",
+                       cache_mngr,
+                       (cache_mngr ? (ulong) cache_mngr->trx_cache.get_prev_position() :
+                        (ulong) 0)));
+
+  if (cache_mngr == NULL ||
+      cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
+  {
+    this->binlog_set_stmt_begin();
+    if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
+      trans_register_ha(this, TRUE, binlog_hton);
+    trans_register_ha(this, FALSE, binlog_hton);
+    /*
+      Mark statement transaction as read/write. We never start
+      a binary log transaction and keep it read-only,
+      therefore it's best to mark the transaction read/write just
+      at the same time we start it.
+      Not necessary to mark the normal transaction read/write
+      since the statement-level flag will be propagated automatically
+      inside ha_commit_trans.
+    */
+    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
+  }
+  DBUG_VOID_RETURN;
+}
+
+void THD::binlog_set_stmt_begin() {
+  binlog_cache_mngr *cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+  /*
+    The call to binlog_trans_log_savepos() might create the cache_mngr
+    structure, if it didn't exist before, so we save the position
+    into an auto variable and then write it into the transaction
+    data for the binary log (i.e., cache_mngr).
+  */
+  my_off_t pos= 0;
+  binlog_trans_log_savepos(this, &pos);
+  cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+  cache_mngr->trx_cache.set_prev_position(pos);
+}
+
+
+/**
+  This function writes a table map to the binary log. 
+  Note that in order to keep the signature uniform with related methods,
+  we use a redundant parameter to indicate whether a transactional table
+  was changed or not.
+ 
+  @param table             a pointer to the table.
+  @param is_transactional  @c true indicates a transactional table,
+                           otherwise @c false a non-transactional.
+  @return
+    nonzero if an error pops up when writing the table map event.
+*/
+int THD::binlog_write_table_map(TABLE *table, bool is_transactional)
+{
+  int error;
+  DBUG_ENTER("THD::binlog_write_table_map");
+  DBUG_PRINT("enter", ("table: 0x%lx  (%s: #%lu)",
+                       (long) table, table->s->table_name.str,
+                       table->s->table_map_id));
+
+  /* Pre-conditions */
+  DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
+  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
+
+  Table_map_log_event
+    the_event(this, table, table->s->table_map_id, is_transactional);
+
+  if (binlog_table_maps == 0)
+    binlog_start_trans_and_stmt();
+
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+  IO_CACHE *file=
+    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
+  if ((error= the_event.write(file)))
+    DBUG_RETURN(error);
+
+  binlog_table_maps++;
+  table->s->table_map_version= mysql_bin_log.table_map_version();
+  DBUG_RETURN(0);
+}
+
+/**
+  This function retrieves a pending row event from a cache which is
+  specified through the parameter @c is_transactional. Respectively, when it
+  is @c true, the pending event is returned from the transactional cache.
+  Otherwise from the non-transactional cache.
+
+  @param is_transactional  @c true indicates a transactional cache,
+                           otherwise @c false a non-transactional.
+  @return
+    The row event if any. 
+*/
+Rows_log_event*
+THD::binlog_get_pending_rows_event(bool is_transactional) const
+{
+  Rows_log_event* rows= NULL;
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+  /*
+    This is less than ideal, but here's the story: If there is no cache_mngr,
+    prepare_pending_rows_event() has never been called (since the cache_mngr
+    is set up there). In that case, we just return NULL.
+   */
+  if (cache_mngr)
+  {
+    binlog_cache_data *cache_data=
+      cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
+
+    rows= cache_data->pending();
+  }
+  return (rows);
+}
+
+/**
+  This function stores a pending row event into a cache which is specified
+  through the parameter @c is_transactional. Respectively, when it is @c
+  true, the pending event is stored into the transactional cache. Otherwise
+  into the non-transactional cache.
+
+  @param evt               a pointer to the row event.
+  @param is_transactional  @c true indicates a transactional cache,
+                           otherwise @c false a non-transactional.
+*/
+void
+THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional)
+{
+  if (thd_get_ha_data(this, binlog_hton) == NULL)
+    binlog_setup_trx_data();
+
+  binlog_cache_mngr *const cache_mngr=
+    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
+
+  DBUG_ASSERT(cache_mngr);
+
+  binlog_cache_data *cache_data=
+    cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
+
+  cache_data->set_pending(ev);
+}
+
+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;
+}
+
+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->main_da.sql_errno())
+  {
+    case ER_TRANS_CACHE_FULL:
+    case ER_ERROR_ON_WRITE:
+    case ER_BINLOG_LOGGING_IMPOSSIBLE:
+      checked= TRUE;
+    break;
+  }
+
+  DBUG_RETURN(checked);
+}
+
+/**
+  @note
+  How do we handle this (unlikely but legal) case:
+  @verbatim
+    [transaction] + [update to non-trans table] + [rollback to savepoint] ?
+  @endverbatim
+  The problem occurs when a savepoint is before the update to the
+  non-transactional table. Then when there's a rollback to the savepoint, if we
+  simply truncate the binlog cache, we lose the part of the binlog cache where
+  the update is. If we want to not lose it, we need to write the SAVEPOINT
+  command and the ROLLBACK TO SAVEPOINT command to the binlog cache. The latter
+  is easy: it's just write at the end of the binlog cache, but the former
+  should be *inserted* to the place where the user called SAVEPOINT. The
+  solution is that when the user calls SAVEPOINT, we write it to the binlog
+  cache (so no need to later insert it). As transactions are never intermixed
+  in the binary log (i.e. they are serialized), we won't have conflicts with
+  savepoint names when using mysqlbinlog or in the slave SQL thread.
+  Then when ROLLBACK TO SAVEPOINT is called, if we updated some
+  non-transactional table, we don't truncate the binlog cache but instead write
+  ROLLBACK TO SAVEPOINT to it; otherwise we truncate the binlog cache (which
+  will chop the SAVEPOINT command from the binlog cache, which is good as in
+  that case there is no need to have it in the binlog).
+*/
+
+static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv)
+{
+  DBUG_ENTER("binlog_savepoint_set");
+
+  binlog_trans_log_savepos(thd, (my_off_t*) sv);
+  /* Write it to the binary log */
+
+  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+  int const error=
+    thd->binlog_query(THD::STMT_QUERY_TYPE,
+                      thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
+                      errcode);
+  DBUG_RETURN(error);
+}
+
+static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
+{
+  DBUG_ENTER("binlog_savepoint_rollback");
+
+  /*
+    Write ROLLBACK TO SAVEPOINT to the binlog cache if we have updated some
+    non-transactional table. Otherwise, truncate the binlog cache starting
+    from the SAVEPOINT command.
+  */
+  if (unlikely(thd->transaction.all.modified_non_trans_table || 
+               (thd->options & OPTION_KEEP_LOG)))
+  {
+    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
+    int error=
+      thd->binlog_query(THD::STMT_QUERY_TYPE,
+                        thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
+                        errcode);
+    DBUG_RETURN(error);
+  }
+  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
+  DBUG_RETURN(0);
+}
+
+
+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;
+}
+
+#ifdef HAVE_REPLICATION
+/*
+  Helper function for SHOW BINLOG/RELAYLOG EVENTS
+ */
+bool show_binlog_events(THD* thd, MYSQL_BIN_LOG *binary_log)
+{
+  Protocol *protocol= thd->protocol;
+  List<Item> field_list;
+  const char *errmsg = 0;
+  bool ret = TRUE;
+  IO_CACHE log;
+  File file = -1;
+  DBUG_ENTER("mysql_show_binlog_events");
+
+  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
+              thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
+
+  Log_event::init_show_field_list(&field_list);
+  if (protocol->send_fields(&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 */
+
+  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;
+    pthread_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;
+    }
+
+    pthread_mutex_lock(&LOCK_thread_count);
+    thd->current_linfo = &linfo;
+    pthread_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;
+
+    pthread_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,(pthread_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,(pthread_mutex_t*) 0,
+                                         description_event)); )
+    {
+      if (event_count >= limit_start &&
+	  ev->net_send(protocol, linfo.log_file_name, pos))
+      {
+	errmsg = "Net error";
+	delete ev;
+	pthread_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";
+      pthread_mutex_unlock(log_lock);
+      goto err;
+    }
+
+    pthread_mutex_unlock(log_lock);
+  }
+
+  ret= FALSE;
+
+err:
+  delete description_event;
+  if (file >= 0)
+  {
+    end_io_cache(&log);
+    (void) my_close(file, MYF(MY_WME));
+  }
+
+  if (errmsg)
+    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
+             "SHOW BINLOG EVENTS", errmsg);
+  else
+    my_eof(thd);
+
+  pthread_mutex_lock(&LOCK_thread_count);
+  thd->current_linfo = 0;
+  pthread_mutex_unlock(&LOCK_thread_count);
+  DBUG_RETURN(ret);
+}
+#endif /* HAVE_REPLICATION */
+
+File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
+{
+  File file;
+  DBUG_ENTER("open_binlog");
+
+  if ((file = my_open(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)
+  {
+    my_close(file,MYF(0));
+    end_io_cache(log);
+  }
+  DBUG_RETURN(-1);
+}
+
+MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
+  :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
+   need_start_event(TRUE), m_table_map_version(0),
+   sync_period_ptr(sync_period),
+   is_relay_log(0), signal_cnt(0),
+   description_event_for_exec(0), description_event_for_queue(0)
+{
+  /*
+    We don't want to initialize locks here as such initialization depends on
+    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
+    called only in main(). Doing initialization here would make it happen
+    before main().
+  */
+  index_file_name[0] = 0;
+  bzero((char*) &index_file, sizeof(index_file));
+  bzero((char*) &purge_index_file, sizeof(purge_index_file));
+}
+
+/* this is called only once */
+
+void MYSQL_BIN_LOG::cleanup()
+{
+  DBUG_ENTER("cleanup");
+  if (inited)
+  {
+    inited= 0;
+    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
+    delete description_event_for_queue;
+    delete description_event_for_exec;
+    (void) pthread_mutex_destroy(&LOCK_log);
+    (void) pthread_mutex_destroy(&LOCK_index);
+    (void) pthread_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;
+  (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
+  (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
+  (void) pthread_cond_init(&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= my_open(index_file_name,
+                              O_RDWR | O_CREAT | O_BINARY ,
+                              MYF(MY_WME))) < 0 ||
+       my_sync(index_file_nr, MYF(MY_WME)) ||
+       init_io_cache(&index_file, index_file_nr,
+                     IO_SIZE, WRITE_CACHE,
+                     my_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 my_create() not my_open().
+    */
+    if (index_file_nr >= 0)
+      my_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", 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) ||
+        my_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", 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) ||
+          my_sync(index_file.file, MYF(MY_WME)))
+        goto err;
+
+#ifdef HAVE_REPLICATION
+      DBUG_EXECUTE_IF("crash_create_after_update_index", 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)
+    my_close(file,MYF(0));
+  end_io_cache(&log_file);
+  end_io_cache(&index_file);
+  safeFree(name);
+  log_state= LOG_CLOSED;
+  DBUG_RETURN(1);
+}
+
+
+int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
+{
+  pthread_mutex_lock(&LOCK_log);
+  int ret = raw_get_current_log(linfo);
+  pthread_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;
+}
+
+/**
+  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)
+    pthread_mutex_lock(&LOCK_index);
+  safe_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)
+    pthread_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)
+    pthread_mutex_lock(&LOCK_index);
+  safe_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)
+    pthread_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.
+  */
+  pthread_mutex_lock(&LOCK_log);
+  pthread_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.
+  */
+  VOID(pthread_mutex_lock(&LOCK_thread_count));
+
+  /* Save variables so that we can reopen the log */
+  save_name=name;
+  name=0;					// Protect against free
+  close(LOG_CLOSE_TO_BE_OPENED);
+
+  /*
+    First delete all old log files and then update the index file.
+    As we first delete the log files and do not use sort of logging,
+    a crash may lead to an inconsistent state where the index has
+    references to non-existent files.
+
+    We need to invert the steps and use the purge_index_file methods
+    in order to make the operation safe.
+  */
+  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
+  {
+    uint errcode= purge_log_get_error_code(err);
+    sql_print_error("Failed to locate old binlog or relay log files");
+    my_message(errcode, ER(errcode), MYF(0));
+    error= 1;
+    goto err;
+  }
+
+  for (;;)
+  {
+    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
+    {
+      if (my_errno == ENOENT) 
+      {
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                            linfo.log_file_name);
+        sql_print_information("Failed to delete file '%s'",
+                              linfo.log_file_name);
+        my_errno= 0;
+        error= 0;
+      }
+      else
+      {
+        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                            ER_BINLOG_PURGE_FATAL_ERR,
+                            "a problem with deleting %s; "
+                            "consider examining correspondence "
+                            "of your binlog index file "
+                            "to the actual binlog files",
+                            linfo.log_file_name);
+        error= 1;
+        goto err;
+      }
+    }
+    if (find_next_log(&linfo, 0))
+      break;
+  }
+
+  /* Start logging with a new file */
+  close(LOG_CLOSE_INDEX);
+  if ((error= my_delete_allow_opened(index_file_name, MYF(0))))	// Reset (open will update)
+  {
+    if (my_errno == ENOENT) 
+    {
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
+                          index_file_name);
+      sql_print_information("Failed to delete file '%s'",
+                            index_file_name);
+      my_errno= 0;
+      error= 0;
+    }
+    else
+    {
+      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                          ER_BINLOG_PURGE_FATAL_ERR,
+                          "a problem with deleting %s; "
+                          "consider examining correspondence "
+                          "of your binlog index file "
+                          "to the actual binlog files",
+                          index_file_name);
+      error= 1;
+      goto err;
+    }
+  }
+  if (!thd->slave_thread)
+    need_start_event=1;
+  if (!open_index_file(index_file_name, 0, FALSE))
+    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
+  my_free((uchar*) save_name, MYF(0));
+
+err:
+  if (error == 1)
+    name= const_cast<char*>(save_name);
+  VOID(pthread_mutex_unlock(&LOCK_thread_count));
+  pthread_mutex_unlock(&LOCK_index);
+  pthread_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));
+
+  pthread_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", abort(););
+
+  pthread_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;
+  pthread_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
+  */
+  pthread_cond_broadcast(&rli->log_space_cond);
+
+  /*
+   * Need to update the log pos because purge logs has been called 
+   * after fetching initially the log pos at the begining of the method.
+   */
+  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
+  {
+    char buff[22];
+    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
+                    error,
+                    llstr(rli->linfo.index_file_offset,buff),
+                    rli->group_relay_log_name,
+                    included);
+    goto err;
+  }
+
+  /* If included was passed, rli->linfo should be the first entry. */
+  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
+
+err:
+  my_free(to_purge_if_included, MYF(0));
+  pthread_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
+                                my_stat() or my_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)
+    pthread_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", 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", 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", abort(););
+
+  if (need_mutex)
+    pthread_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 (!my_stat(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 my_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
+                                my_stat() or my_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");
+
+  pthread_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 (!my_stat(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:
+  pthread_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)
+    pthread_mutex_lock(&LOCK_log);
+  pthread_mutex_lock(&LOCK_index);
+
+  safe_mutex_assert_owner(&LOCK_log);
+  safe_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++;
+    pthread_mutex_lock(&LOCK_prep_xids);
+    while (prepared_xids) {
+      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
+      pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
+    }
+    pthread_mutex_unlock(&LOCK_prep_xids);
+  }
+
+  /* Reuse old name if not binlog and not update log */
+  new_name_ptr= name;
+
+  /*
+    If user hasn't specified an extension, generate a new log name
+    We have to do this here and not in open as we want to store the
+    new file name in the current binary log file.
+  */
+  if (generate_new_name(new_name, name))
+    goto end;
+  new_name_ptr=new_name;
+
+  if (log_type == LOG_BIN)
+  {
+    if (!no_auto_events)
+    {
+      /*
+        We log the whole file name for log file as the user may decide
+        to change base names at some point.
+      */
+      Rotate_log_event r(new_name+dirname_length(new_name),
+                         0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
+      r.write(&log_file);
+      bytes_written += r.data_written;
+    }
+    /*
+      Update needs to be signalled even if there is no rotate event
+      log rotation should give the waiting thread a signal to
+      discover EOF and move on to the next log.
+    */
+    signal_update();
+  }
+  old_name=name;
+  name=0;				// Don't free name
+  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
+
+  /*
+     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
+  */
+
+  /*
+     new_file() is only used for rotation (in FLUSH LOGS or because size >
+     max_binlog_size or max_relay_log_size).
+     If this is a binary log, the Format_description_log_event at the beginning of
+     the new file should have created=0 (to distinguish with the
+     Format_description_log_event written at server startup, which should
+     trigger temp tables deletion on slaves.
+  */
+
+  /* reopen index binlog file, BUG#34582 */
+  if (!open_index_file(index_file_name, 0, FALSE))
+    open(old_name, log_type, new_name_ptr,
+         io_cache_type, no_auto_events, max_size, 1, FALSE);
+  my_free(old_name,MYF(0));
+
+end:
+  if (need_lock)
+    pthread_mutex_unlock(&LOCK_log);
+  pthread_mutex_unlock(&LOCK_index);
+
+  DBUG_VOID_RETURN;
+}
+
+
+bool MYSQL_BIN_LOG::append(Log_event* ev)
+{
+  bool error = 0;
+  pthread_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:
+  pthread_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);
+
+  safe_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;
+  safe_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=my_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 &&
+          thd->transaction.stmt.modified_non_trans_table)
+        cache_data->set_incident();
+      DBUG_RETURN(1);
+    }
+
+    /*
+      We step the table map version if we are writing an event
+      representing the end of a statement.
+
+      In an ideal world, we could avoid stepping the table map version,
+      since we could then reuse the table map that was written earlier
+      in the cache. This does not work since STMT_END_F implies closing
+      all table mappings on the slave side.
+    
+      TODO: Find a solution so that table maps does not have to be
+      written several times within a transaction.
+    */
+    if (pending->get_flags(Rows_log_event::STMT_END_F))
+      ++m_table_map_version;
+
+    delete pending;
+  }
+
+  thd->binlog_set_pending_rows_event(event, is_transactional);
+
+  DBUG_RETURN(error);
+}
+
+/**
+  Write an event to the binary log.
+*/
+
+bool MYSQL_BIN_LOG::write(Log_event *event_info)
+{
+  THD *thd= event_info->thd;
+  bool error= 1;
+  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
+  binlog_cache_data *cache_data= 0;
+
+  if (thd->binlog_evt_union.do_union)
+  {
+    /*
+      In Stored function; Remember that function call caused an update.
+      We will log the function call to the binary log on function exit
+    */
+    thd->binlog_evt_union.unioned_events= TRUE;
+    thd->binlog_evt_union.unioned_events_trans |=
+      event_info->use_trans_cache();
+    DBUG_RETURN(0);
+  }
+
+  /*
+    We only end the statement if we are in a top-level statement.  If
+    we are inside a stored function, we do not end the statement since
+    this will close all tables on the slave.
+  */
+  bool const end_stmt=
+    thd->prelocked_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->options & OPTION_BIN_LOG)) ||
+	(!binlog_filter->db_ok(local_db)))
+      DBUG_RETURN(0);
+#endif /* HAVE_REPLICATION */
+
+#if defined(USING_TRANSACTIONS)
+    IO_CACHE *file= NULL;
+
+    if (event_info->use_direct_logging())
+    {
+      file= &log_file;
+      pthread_mutex_lock(&LOCK_log);
+    }
+    else
+    {
+      if (thd->binlog_setup_trx_data())
+        goto err;
+
+      binlog_cache_mngr *const cache_mngr=
+        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
+
+      bool is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
+      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
+      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
+
+      thd->binlog_start_trans_and_stmt();
+    }
+#endif /* USING_TRANSACTIONS */
+    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:
+      pthread_mutex_unlock(&LOCK_log);
+    }
+
+    if (error)
+    {
+      set_write_error(thd);
+      if (check_write_error(thd) && cache_data &&
+        thd->transaction.stmt.modified_non_trans_table)
+        cache_data->set_incident();
+    }
+  }
+
+  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
+    ++m_table_map_version;
+
+  DBUG_RETURN(error);
+}
+
+void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
+{
+#ifdef HAVE_REPLICATION
+  bool check_purge= false;
+#endif
+  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
+    pthread_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))
+    pthread_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;
+  pthread_mutex_lock(&LOCK_log);
+  res = file_id++;
+  pthread_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
+}
+
+/*
+  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)
+  {
+    error= thd->is_error() ? thd->main_da.sql_errno() : 0;
+
+    /* thd->main_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;
+}
+
+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)
+    pthread_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);
+    }
+    pthread_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 *)");
+  VOID(pthread_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"));
+                        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", 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)
+    {
+      pthread_mutex_lock(&LOCK_prep_xids);
+      prepared_xids++;
+      pthread_mutex_unlock(&LOCK_prep_xids);
+    }
+    else
+      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
+  }
+  VOID(pthread_mutex_unlock(&LOCK_log));
+
+  DBUG_RETURN(0);
+
+err:
+  if (!write_error)
+  {
+    write_error= 1;
+    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+  }
+  VOID(pthread_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" );
+  pthread_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)
+    pthread_cond_wait(&update_cond, &LOCK_log);
+  else
+    ret= pthread_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= my_tell(log_file.file, MYF(0));
+      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
+      my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
+      /*
+        Restore position so that anything we have in the IO_cache is written
+        to the correct position.
+        We need the seek here, as my_pwrite() is not guaranteed to keep the
+        original position on system that doesn't support pwrite().
+      */
+      my_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 (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
+    {
+      write_error= 1;
+      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
+    }
+  }
+  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
+  safeFree(name);
+  DBUG_VOID_RETURN;
+}
+
+
+void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
+{
+  /*
+    We need to take locks, otherwise this may happen:
+    new_file() is called, calls open(old_max_size), then before open() starts,
+    set_max_size() sets max_size to max_size_arg, then open() starts and
+    uses the old_max_size argument, so max_size_arg has been overwritten and
+    it's like if the SET command was never run.
+  */
+  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
+  pthread_mutex_lock(&LOCK_log);
+  if (is_open())
+    max_size= max_size_arg;
+  pthread_mutex_unlock(&LOCK_log);
+  DBUG_VOID_RETURN;
+}
+
+void MYSQL_BIN_LOG::signal_update()
+{
+  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
+  signal_cnt++;
+  pthread_cond_broadcast(&update_cond);
+  DBUG_VOID_RETURN;
+}
+
+/****** 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]);
+
+  pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
+  pthread_cond_init (&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);
+    my_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);
+  pthread_mutex_destroy(&LOCK_prep_xids);
+  pthread_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)
+{
+  pthread_mutex_lock(&LOCK_prep_xids);
+  DBUG_ASSERT(prepared_xids > 0);
+  if (--prepared_xids == 0) {
+    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
+    pthread_cond_signal(&COND_prep_xids);
+  }
+  pthread_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() ||
+      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));
+  hash_free(&xids);
+  return 0;
+
+err2:
+  free_root(&mem_root, MYF(0));
+  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;

=== added file 'sql/binlog.h'
--- a/sql/binlog.h	1970-01-01 00:00:00 +0000
+++ b/sql/binlog.h	2010-04-26 05:01:18 +0000
@@ -0,0 +1,270 @@
+/* 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 BINLOG_H
+#define BINLOG_H
+
+#include "log.h"
+
+class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
+{
+ private:
+  /* LOCK_log and LOCK_index are inited by init_pthread_objects() */
+  pthread_mutex_t LOCK_index;
+  pthread_mutex_t LOCK_prep_xids;
+  pthread_cond_t  COND_prep_xids;
+  pthread_cond_t update_cond;
+  ulonglong bytes_written;
+  IO_CACHE index_file;
+  char index_file_name[FN_REFLEN];
+  /*
+    purge_file is a temp file used in purge_logs so that the index file
+    can be updated before deleting files from disk, yielding better crash
+    recovery. It is created on demand the first time purge_logs is called
+    and then reused for subsequent calls. It is cleaned up in cleanup().
+  */
+  IO_CACHE purge_index_file;
+  char purge_index_file_name[FN_REFLEN];
+  /*
+     The max size before rotation (usable only if log_type == LOG_BIN: binary
+     logs and relay logs).
+     For a binlog, max_size should be max_binlog_size.
+     For a relay log, it should be max_relay_log_size if this is non-zero,
+     max_binlog_size otherwise.
+     max_size is set in init(), and dynamically changed (when one does SET
+     GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
+     fix_max_relay_log_size).
+  */
+  ulong max_size;
+  long prepared_xids; /* for tc log - number of xids to remember */
+  // current file sequence number for load data infile binary logging
+  uint file_id;
+  uint open_count;				// For replication
+  int readers_count;
+  bool need_start_event;
+  /*
+    no_auto_events means we don't want any of these automatic events :
+    Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't
+    want a Rotate_log event to be written to the relay log. When we start a
+    relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
+    In 5.0 it's 0 for relay logs too!
+  */
+  bool no_auto_events;
+
+  ulonglong m_table_map_version;
+
+  /* pointer to the sync period variable, for binlog this will be
+     sync_binlog_period, for relay log this will be
+     sync_relay_log_period
+  */
+  uint *sync_period_ptr;
+  uint sync_counter;
+
+  inline uint get_sync_period()
+  {
+    return *sync_period_ptr;
+  }
+
+  int write_to_file(IO_CACHE *cache);
+  /*
+    This is used to start writing to a new log file. The difference from
+    new_file() is locking. new_file_without_locking() does not acquire
+    LOCK_log.
+  */
+  void new_file_without_locking();
+  void new_file_impl(bool need_lock);
+
+public:
+  MYSQL_LOG::generate_name;
+  MYSQL_LOG::is_open;
+
+  /* This is relay log */
+  bool is_relay_log;
+  ulong signal_cnt;  // update of the counter is checked by heartbeat
+  /*
+    These describe the log's format. This is used only for relay logs.
+    _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
+    necessary to have 2 distinct objects, because the I/O thread may be reading
+    events in a different format from what the SQL thread is reading (consider
+    the case of a master which has been upgraded from 5.0 to 5.1 without doing
+    RESET MASTER, or from 4.x to 5.0).
+  */
+  Format_description_log_event *description_event_for_exec,
+    *description_event_for_queue;
+
+  MYSQL_BIN_LOG(uint *sync_period);
+  /*
+    note that there's no destructor ~MYSQL_BIN_LOG() !
+    The reason is that we don't want it to be automatically called
+    on exit() - but only during the correct shutdown process
+  */
+
+  int open(const char *opt_name);
+  void close();
+  int log_xid(THD *thd, my_xid xid);
+  void unlog(ulong cookie, my_xid xid);
+  int recover(IO_CACHE *log, Format_description_log_event *fdle);
+#if !defined(MYSQL_CLIENT)
+  bool is_table_mapped(TABLE *table) const
+  {
+    return table->s->table_map_version == table_map_version();
+  }
+
+  ulonglong table_map_version() const { return m_table_map_version; }
+  void update_table_map_version() { ++m_table_map_version; }
+
+  int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
+                                       bool is_transactional);
+  int remove_pending_rows_event(THD *thd, bool is_transactional);
+
+#endif /* !defined(MYSQL_CLIENT) */
+  void reset_bytes_written()
+  {
+    bytes_written = 0;
+  }
+  void harvest_bytes_written(ulonglong* counter)
+  {
+#ifndef DBUG_OFF
+    char buf1[22],buf2[22];
+#endif
+    DBUG_ENTER("harvest_bytes_written");
+    (*counter)+=bytes_written;
+    DBUG_PRINT("info",("counter: %s  bytes_written: %s", llstr(*counter,buf1),
+		       llstr(bytes_written,buf2)));
+    bytes_written=0;
+    DBUG_VOID_RETURN;
+  }
+  void set_max_size(ulong max_size_arg);
+  void signal_update();
+  void wait_for_update_relay_log(THD* thd);
+  int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
+  void set_need_start_event() { need_start_event = 1; }
+  void init(bool no_auto_events_arg, ulong max_size);
+  void init_pthread_objects();
+  void cleanup();
+  bool open(const char *log_name,
+            enum_log_type log_type,
+            const char *new_name,
+	    enum cache_type io_cache_type_arg,
+	    bool no_auto_events_arg, ulong max_size,
+            bool null_created,
+            bool need_mutex);
+  bool open_index_file(const char *index_file_name_arg,
+                       const char *log_name, bool need_mutex);
+  /* Use this to start writing a new log file */
+  void new_file();
+
+  bool write(Log_event* event_info);
+  bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
+  bool write_incident(THD *thd, bool lock);
+
+  int  write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
+  void set_write_error(THD *thd);
+  bool check_write_error(THD *thd);
+
+  void start_union_events(THD *thd, query_id_t query_id_param);
+  void stop_union_events(THD *thd);
+  bool is_query_in_union(THD *thd, query_id_t query_id_param);
+
+  /*
+    v stands for vector
+    invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
+  */
+  bool appendv(const char* buf,uint len,...);
+  bool append(Log_event* ev);
+
+  void make_log_name(char* buf, const char* log_ident);
+  bool is_active(const char* log_file_name);
+  int update_log_index(LOG_INFO* linfo, bool need_update_threads);
+  void rotate_and_purge(uint flags);
+  /**
+     Flush binlog cache and synchronize to disk.
+
+     This function flushes events in binlog cache to binary log file,
+     it will do synchronizing according to the setting of system
+     variable 'sync_binlog'. If file is synchronized, @c synced will
+     be set to 1, otherwise 0.
+
+     @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
+
+     @retval 0 Success
+     @retval other Failure
+  */
+  bool flush_and_sync(bool *synced);
+  int purge_logs(const char *to_log, bool included,
+                 bool need_mutex, bool need_update_threads,
+                 ulonglong *decrease_log_space);
+  int purge_logs_before_date(time_t purge_time);
+  int purge_first_log(Relay_log_info* rli, bool included);
+  int set_purge_index_file_name(const char *base_file_name);
+  int open_purge_index_file(bool destroy);
+  bool is_inited_purge_index_file();
+  int close_purge_index_file();
+  int clean_purge_index_file();
+  int sync_purge_index_file();
+  int register_purge_index_entry(const char* entry);
+  int register_create_index_entry(const char* entry);
+  int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
+                        bool need_mutex);
+  bool reset_logs(THD* thd);
+  void close(uint exiting);
+
+  // iterating through the log index file
+  int find_log_pos(LOG_INFO* linfo, const char* log_name,
+		   bool need_mutex);
+  int find_next_log(LOG_INFO* linfo, bool need_mutex);
+  int get_current_log(LOG_INFO* linfo);
+  int raw_get_current_log(LOG_INFO* linfo);
+  uint next_file_id();
+  inline char* get_index_fname() { return index_file_name;}
+  inline char* get_log_fname() { return log_file_name; }
+  inline char* get_name() { return name; }
+  inline pthread_mutex_t* get_log_lock() { return &LOCK_log; }
+  inline IO_CACHE* get_log_file() { return &log_file; }
+
+  inline void lock_index() { pthread_mutex_lock(&LOCK_index);}
+  inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
+  inline IO_CACHE *get_index_file() { return &index_file;}
+  inline uint32 get_open_count() { return open_count; }
+};
+
+enum enum_binlog_format {
+  /*
+    statement-based except for cases where only row-based can work (UUID()
+    etc):
+  */
+  BINLOG_FORMAT_MIXED= 0,
+  BINLOG_FORMAT_STMT= 1, // statement-based
+  BINLOG_FORMAT_ROW= 2, // row_based
+/*
+  This value is last, after the end of binlog_format_typelib: it has no
+  corresponding cell in this typelib. We use this value to be able to know if
+  the user has explicitely specified a binlog format at startup or not.
+*/
+  BINLOG_FORMAT_UNSPEC= 3
+};
+extern TYPELIB binlog_format_typelib;
+
+int query_error_code(THD *thd, bool not_killed);
+
+/* Helper function for SHOW BINLOG/RELAYLOG EVENTS */
+bool show_binlog_events(THD* thd, MYSQL_BIN_LOG *binary_log);
+
+bool rpl_master_has_bug(const Relay_log_info *rli,
+                        uint bug_id, bool report,
+                        bool (*pred)(const void *), const void *param);
+bool rpl_master_erroneous_autoinc(THD* thd);
+
+#endif /* BINLOG_H */

=== modified file 'sql/log.cc'
--- a/sql/log.cc	2010-03-17 11:31:50 +0000
+++ b/sql/log.cc	2010-04-26 05:01:18 +0000
@@ -44,23 +44,11 @@
 #define MAX_LOG_BUFFER_SIZE 1024
 #define MAX_USER_HOST_SIZE 512
 #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
@@ -141,195 +129,6 @@ char *make_default_log_name(char *buff,c
                    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(pthread_mutex_t *mutex)
-    : m_mutex(mutex)
-  {
-    if (m_mutex)
-      pthread_mutex_lock(mutex);
-  }
-
-  ~Mutex_sentry()
-  {
-    if (m_mutex)
-      pthread_mutex_unlock(m_mutex);
-#ifndef DBUG_OFF
-    m_mutex= 0;
-#endif
-  }
-
-private:
-  pthread_mutex_t *m_mutex;
-
-  // It's not allowed to copy this object in any way
-  Mutex_sentry(Mutex_sentry const&);
-  void operator=(Mutex_sentry const&);
-};
-
-/*
-  Helper classes to store non-transactional and transactional data
-  before copying it to the binary log.
-*/
-class binlog_cache_data
-{
-public:
-  binlog_cache_data(): m_pending(0), before_stmt_pos(MY_OFF_T_UNDEF),
-  incident(FALSE)
-  {
-    cache_log.end_of_file= max_binlog_cache_size;
-  }
-
-  ~binlog_cache_data()
-  {
-    DBUG_ASSERT(empty());
-    close_cached_file(&cache_log);
-  }
-
-  bool empty() const
-  {
-    return pending() == NULL && my_b_tell(&cache_log) == 0;
-  }
-
-  Rows_log_event *pending() const
-  {
-    return m_pending;
-  }
-
-  void set_pending(Rows_log_event *const pending)
-  {
-    m_pending= pending;
-  }
-
-  void set_incident(void)
-  {
-    incident= TRUE;
-  }
-  
-  bool has_incident(void)
-  {
-    return(incident);
-  }
-
-  void reset()
-  {
-    truncate(0);
-    incident= FALSE;
-    before_stmt_pos= MY_OFF_T_UNDEF;
-    cache_log.end_of_file= max_binlog_cache_size;
-    DBUG_ASSERT(empty());
-  }
-
-  my_off_t get_byte_position() const
-  {
-    return my_b_tell(&cache_log);
-  }
-
-  my_off_t get_prev_position()
-  {
-     return(before_stmt_pos);
-  }
-
-  void set_prev_position(my_off_t pos)
-  {
-     before_stmt_pos= pos;
-  }
-  
-  void restore_prev_position()
-  {
-    truncate(before_stmt_pos);
-  }
-
-  void restore_savepoint(my_off_t pos)
-  {
-    truncate(pos);
-    if (pos < before_stmt_pos)
-      before_stmt_pos= MY_OFF_T_UNDEF;
-  }
-
-  /*
-    Cache to store data before copying it to the binary log.
-  */
-  IO_CACHE cache_log;
-
-private:
-  /*
-    Pending binrows event. This event is the event where the rows are currently
-    written.
-   */
-  Rows_log_event *m_pending;
-
-  /*
-    Binlog position before the start of the current statement.
-  */
-  my_off_t before_stmt_pos;
- 
-  /*
-    This indicates that some events did not get into the cache and most likely
-    it is corrupted.
-  */ 
-  bool incident;
-
-  /*
-    It truncates the cache to a certain position. This includes deleting the
-    pending event.
-   */
-  void truncate(my_off_t pos)
-  {
-    DBUG_PRINT("info", ("truncating to position %lu", (ulong) pos));
-    if (pending())
-    {
-      delete pending();
-      set_pending(0);
-    }
-    reinit_io_cache(&cache_log, WRITE_CACHE, pos, 0, 0);
-    cache_log.end_of_file= max_binlog_cache_size;
-  }
- 
-  binlog_cache_data& operator=(const binlog_cache_data& info);
-  binlog_cache_data(const binlog_cache_data& info);
-};
-
-class binlog_cache_mngr {
-public:
-  binlog_cache_mngr() {}
-
-  void reset_cache(binlog_cache_data* cache_data)
-  {
-    cache_data->reset();
-  }
-
-  binlog_cache_data* get_binlog_cache_data(bool is_transactional)
-  {
-    return (is_transactional ? &trx_cache : &stmt_cache);
-  }
-
-  IO_CACHE* get_binlog_cache_log(bool is_transactional)
-  {
-    return (is_transactional ? &trx_cache.cache_log : &stmt_cache.cache_log);
-  }
-
-  binlog_cache_data stmt_cache;
-
-  binlog_cache_data trx_cache;
-
-private:
-
-  binlog_cache_mngr& operator=(const binlog_cache_mngr& info);
-  binlog_cache_mngr(const binlog_cache_mngr& info);
-};
-
-handlerton *binlog_hton;
-
 bool LOGGER::is_log_table_enabled(uint log_table_type)
 {
   switch (log_table_type) {
@@ -1381,3923 +1180,776 @@ int LOGGER::set_handlers(uint error_log_
   return 0;
 }
 
- /*
-  Save position of binary log transaction cache.
+#ifdef __NT__
+static int eventSource = 0;
 
-  SYNPOSIS
-    binlog_trans_log_savepos()
+static void setup_windows_event_source()
+{
+  HKEY    hRegKey= NULL;
+  DWORD   dwError= 0;
+  TCHAR   szPath[MAX_PATH];
+  DWORD dwTypes;
 
-    thd      The thread to take the binlog data from
-    pos      Pointer to variable where the position will be stored
+  if (eventSource)               // Ensure that we are only called once
+    return;
+  eventSource= 1;
 
-  DESCRIPTION
+  // Create the event source registry key
+  dwError= RegCreateKey(HKEY_LOCAL_MACHINE,
+                          "SYSTEM\\CurrentControlSet\\Services\\EventLog\\Application\\MySQL", 
+                          &hRegKey);
 
-    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;
-}
+  /* 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));
 
-/*
-  Truncate the binary log transaction cache.
+  /* 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);
 
-  SYNPOSIS
-    binlog_trans_log_truncate()
+  RegCloseKey(hRegKey);
+}
 
-    thd      The thread to take the binlog data from
-    pos      Position to truncate to
+#endif /* __NT__ */
 
-  DESCRIPTION
 
-    Truncate the binary log to the given position. Will not change
-    anything else.
+/**
+  Find a unique filename for 'filename.#'.
 
- */
-static void
-binlog_trans_log_truncate(THD *thd, my_off_t pos)
-{
-  DBUG_ENTER("binlog_trans_log_truncate");
-  DBUG_PRINT("enter", ("pos: %lu", (ulong) pos));
-
-  DBUG_ASSERT(thd_get_ha_data(thd, binlog_hton) != NULL);
-  /* Only true if binlog_trans_log_savepos() wasn't called before */
-  DBUG_ASSERT(pos != ~(my_off_t) 0);
-
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-  cache_mngr->trx_cache.restore_savepoint(pos);
-  DBUG_VOID_RETURN;
-}
+  Set '#' to the number next to the maximum found in the most
+  recent log file extension.
 
+  This function will return nonzero if: (i) the generated name
+  exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
+  or (iii) some other error happened while examining the filesystem.
 
-/*
-  this function is mostly a placeholder.
-  conceptually, binlog initialization (now mostly done in MYSQL_BIN_LOG::open)
-  should be moved here.
+  @return
+    nonzero if not possible to get unique filename.
 */
 
-int binlog_init(void *p)
-{
-  binlog_hton= (handlerton *)p;
-  binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
-  binlog_hton->db_type=DB_TYPE_BINLOG;
-  binlog_hton->savepoint_offset= sizeof(my_off_t);
-  binlog_hton->close_connection= binlog_close_connection;
-  binlog_hton->savepoint_set= binlog_savepoint_set;
-  binlog_hton->savepoint_rollback= binlog_savepoint_rollback;
-  binlog_hton->commit= binlog_commit;
-  binlog_hton->rollback= binlog_rollback;
-  binlog_hton->prepare= binlog_prepare;
-  binlog_hton->flags= HTON_NOT_USER_SELECTABLE | HTON_HIDDEN;
-  return 0;
-}
-
-static int binlog_close_connection(handlerton *hton, THD *thd)
+static int find_uniq_filename(char *name)
 {
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-  DBUG_ASSERT(cache_mngr->trx_cache.empty() && cache_mngr->stmt_cache.empty());
-  thd_set_ha_data(thd, binlog_hton, NULL);
-  cache_mngr->~binlog_cache_mngr();
-  my_free((uchar*)cache_mngr, MYF(0));
-  return 0;
-}
-
-/**
-  This function flushes a transactional cache upon commit/rollback.
-
-  @param thd        The thread whose transaction should be flushed
-  @param cache_mngr Pointer to the cache data to be flushed
-  @param end_ev     The end event either commit/rollback.
+  uint                  i;
+  char                  buff[FN_REFLEN], ext_buf[FN_REFLEN];
+  struct st_my_dir     *dir_info;
+  reg1 struct fileinfo *file_info;
+  ulong                 max_found= 0, next= 0, number= 0;
+  size_t		buf_length, length;
+  char			*start, *end;
+  int                   error= 0;
+  DBUG_ENTER("find_uniq_filename");
 
-  @return
-    nonzero if an error pops up when flushing the transactional cache.
-*/
-static int
-binlog_flush_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr,
-                       Log_event *end_ev)
-{
-  DBUG_ENTER("binlog_flush_trx_cache");
-  int error=0;
-  IO_CACHE *cache_log= &cache_mngr->trx_cache.cache_log;
+  length= dirname_part(buff, name, &buf_length);
+  start=  name + length;
+  end=    strend(start);
 
-  /*
-    This function handles transactional changes and as such
-    this flag equals to true.
-  */
-  bool const is_transactional= TRUE;
+  *end='.';
+  length= (size_t) (end - start + 1);
 
-  if (thd->binlog_flush_pending_rows_event(TRUE, is_transactional))
+  if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))
+  {						// This shouldn't happen
+    strmov(end,".1");				// use name+1
     DBUG_RETURN(1);
-  /*
-    Doing a commit or a rollback including non-transactional tables,
-    i.e., ending a transaction where we might write the transaction
-    cache to the binary log.
-
-    We can always end the statement when ending a transaction since
-    transactions are not allowed inside stored functions. If they
-    were, we would have to ensure that we're not ending a statement
-    inside a stored function.
-  */
-  error= mysql_bin_log.write(thd, &cache_mngr->trx_cache.cache_log, end_ev,
-                             cache_mngr->trx_cache.has_incident());
-  cache_mngr->reset_cache(&cache_mngr->trx_cache);
-
-  /*
-    We need to step the table map version after writing the
-    transaction cache to disk.
-  */
-  mysql_bin_log.update_table_map_version();
-  statistic_increment(binlog_cache_use, &LOCK_status);
-  if (cache_log->disk_writes != 0)
+  }
+  file_info= dir_info->dir_entry;
+  for (i= dir_info->number_off_files ; i-- ; file_info++)
   {
-    statistic_increment(binlog_cache_disk_use, &LOCK_status);
-    cache_log->disk_writes= 0;
+    if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
+	test_if_number(file_info->name+length, &number,0))
+    {
+      set_if_bigger(max_found,(ulong) number);
+    }
   }
+  my_dirend(dir_info);
 
-  DBUG_ASSERT(cache_mngr->trx_cache.empty());
-  DBUG_RETURN(error);
-}
-
-/**
-  This function truncates the transactional cache upon committing or rolling
-  back either a transaction or a statement.
-
-  @param thd        The thread whose transaction should be flushed
-  @param cache_mngr Pointer to the cache data to be flushed
-  @param all        @c true means truncate the transaction, otherwise the
-                    statement must be truncated.
-
-  @return
-    nonzero if an error pops up when truncating the transactional cache.
-*/
-static int
-binlog_truncate_trx_cache(THD *thd, binlog_cache_mngr *cache_mngr, bool all)
-{
-  DBUG_ENTER("binlog_truncate_trx_cache");
-  int error=0;
-  /*
-    This function handles transactional changes and as such this flag
-    equals to true.
-  */
-  bool const is_transactional= TRUE;
-
-  DBUG_PRINT("info", ("thd->options={ %s%s}, transaction: %s",
-                      FLAGSTR(thd->options, OPTION_NOT_AUTOCOMMIT),
-                      FLAGSTR(thd->options, 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 (all || !thd->in_multi_stmt_transaction())
+  /* check if reached the maximum possible extension number */
+  if ((max_found == MAX_LOG_UNIQUE_FN_EXT))
   {
-    if (cache_mngr->trx_cache.has_incident())
-      error= mysql_bin_log.write_incident(thd, TRUE);
+    sql_print_error("Log filename extension number exhausted: %06lu. \
+Please fix this by archiving old logs and \
+updating the index files.", max_found);
+    error= 1;
+    goto end;
+  }
 
-    cache_mngr->reset_cache(&cache_mngr->trx_cache);
+  next= max_found + 1;
+  sprintf(ext_buf, "%06lu", next);
+  *end++='.';
 
-    thd->clear_binlog_table_maps();
+  /* 
+    Check if the generated extension size + the file name exceeds the
+    buffer size used. If one did not check this, then the filename might be
+    truncated, resulting in error.
+   */
+  if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
+  {
+    sql_print_error("Log filename too large: %s%s (%lu). \
+Please fix this by archiving old logs and updating the \
+index files.", name, ext_buf, (strlen(ext_buf) + (end - name)));
+    error= 1;
+    goto end;
   }
-  /*
-    If rolling back a statement in a transaction, we truncate the
-    transaction cache to remove the statement.
-  */
-  else
-    cache_mngr->trx_cache.restore_prev_position();
 
-  /*
-    We need to step the table map version on a rollback to ensure that a new
-    table map event is generated instead of the one that was written to the
-    thrown-away transaction cache.
-  */
-  mysql_bin_log.update_table_map_version();
+  sprintf(end, "%06lu", next);
+
+  /* print warning if reaching the end of available extensions. */
+  if ((next > (MAX_LOG_UNIQUE_FN_EXT - LOG_WARN_UNIQUE_FN_EXT_LEFT)))
+    sql_print_warning("Next log extension: %lu. \
+Remaining log filename extensions: %lu. \
+Please consider archiving some logs.", next, (MAX_LOG_UNIQUE_FN_EXT - next));
 
-  DBUG_ASSERT(thd->binlog_get_pending_rows_event(is_transactional) == NULL);
+end:
   DBUG_RETURN(error);
 }
 
-static int binlog_prepare(handlerton *hton, THD *thd, bool all)
+
+void MYSQL_LOG::init(enum_log_type log_type_arg,
+                     enum cache_type io_cache_type_arg)
 {
-  /*
-    do nothing.
-    just pretend we can do 2pc, so that MySQL won't
-    switch to 1pc.
-    real work will be done in MYSQL_BIN_LOG::log_xid()
-  */
-  return 0;
+  DBUG_ENTER("MYSQL_LOG::init");
+  log_type= log_type_arg;
+  io_cache_type= io_cache_type_arg;
+  DBUG_PRINT("info",("log_type: %d", log_type));
+  DBUG_VOID_RETURN;
 }
 
-/**
-  This function flushes the non-transactional to the binary log upon
-  committing or rolling back a statement.
-
-  @param thd        The thread whose transaction should be flushed
-  @param cache_mngr Pointer to the cache data to be flushed
 
-  @return
-    nonzero if an error pops up when flushing the non-transactional cache.
-*/
-static int
-binlog_flush_stmt_cache(THD *thd, binlog_cache_mngr *cache_mngr)
+bool MYSQL_LOG::init_and_set_log_file_name(const char *log_name,
+                                           const char *new_name,
+                                           enum_log_type log_type_arg,
+                                           enum cache_type io_cache_type_arg)
 {
-  int error= 0;
-  DBUG_ENTER("binlog_flush_stmt_cache");
-  /*
-    If we are flushing the statement cache, it means that the changes get
-    through otherwise the cache is empty and this routine should not be called.
-  */
-  DBUG_ASSERT(cache_mngr->stmt_cache.has_incident() == FALSE);
-  /*
-    This function handles non-transactional changes and as such this flag equals
-    to false.
-  */
-  bool const is_transactional= FALSE;
-  IO_CACHE *cache_log= &cache_mngr->stmt_cache.cache_log;
-  thd->binlog_flush_pending_rows_event(TRUE, is_transactional);
-  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);
+  init(log_type_arg, io_cache_type_arg);
 
-  /*
-    We need to step the table map version after writing the
-    transaction cache to disk.
-  */
-  mysql_bin_log.update_table_map_version();
-  statistic_increment(binlog_cache_use, &LOCK_status);
-  if (cache_log->disk_writes != 0)
-  {
-    statistic_increment(binlog_cache_disk_use, &LOCK_status);
-    cache_log->disk_writes= 0;
-  }
-  DBUG_RETURN(error);
+  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;
 }
 
-/**
-  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);
-  bool const in_transaction= thd->in_multi_stmt_transaction();
+  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(in_transaction),
-              YESNO(thd->transaction.all.modified_non_trans_table),
-              YESNO(thd->transaction.stmt.modified_non_trans_table)));
+  write_error= 0;
 
-  if (!cache_mngr->stmt_cache.empty())
+  if (!(name= my_strdup(log_name, MYF(MY_WME))))
   {
-    binlog_flush_stmt_cache(thd, cache_mngr);
+    name= (char *)log_name; // for the error message
+    goto err;
   }
 
-  if (cache_mngr->trx_cache.empty())
-  {
-    /*
-      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
-    */
-    cache_mngr->reset_cache(&cache_mngr->trx_cache);
-    DBUG_RETURN(0);
-  }
+  if (init_and_set_log_file_name(name, new_name,
+                                 log_type_arg, io_cache_type_arg))
+    goto err;
 
-  /*
-    We commit the transaction if:
-     - We are not in a transaction and committing a statement, or
-     - We are in a transaction and a full transaction is committed.
-    Otherwise, we accumulate the changes.
-  */
-  if (!in_transaction || 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= my_open(log_file_name, open_flags,
+                     MYF(MY_WME | ME_WAITTANG))) < 0 ||
+      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
+                    my_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 __NT__
+			"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)
+    my_close(file, MYF(0));
+  end_io_cache(&log_file);
+  safeFree(name);
+  log_state= LOG_CLOSED;
+  DBUG_RETURN(1);
+}
+
+MYSQL_LOG::MYSQL_LOG()
+  : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
+    log_state(LOG_CLOSED)
+{
   /*
-    This is part of the stmt rollback.
+    We don't want to initialize LOCK_Log here as such initialization depends on
+    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
+    called only in main(). Doing initialization here would make it happen
+    before main().
   */
-  if (!all)
-    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF);
-  DBUG_RETURN(error);
+  bzero((char*) &log_file, sizeof(log_file));
 }
 
-/**
-  This function is called when a transaction or a statement is rolled back.
+void MYSQL_LOG::init_pthread_objects()
+{
+  DBUG_ASSERT(inited == 0);
+  inited= 1;
+  (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
+}
+
+/*
+  Close the log file
 
-  @param hton  The binlog handlerton.
-  @param thd   The client thread that executes the transaction.
-  @param all   This is @c true if this is a real transaction rollback, and
-               @false otherwise.
+  SYNOPSIS
+    close()
+    exiting     Bitmask. For the slow and general logs the only used bit is
+                LOG_CLOSE_TO_BE_OPENED. This is used if we intend to call
+                open at once after close.
 
-  @see handlerton::rollback
+  NOTES
+    One can do an open on the object at once after doing a close.
+    The internal structures are not freed until cleanup() is called
 */
-static int binlog_rollback(handlerton *hton, THD *thd, bool all)
-{
-  DBUG_ENTER("binlog_rollback");
-  int error=0;
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-
-  DBUG_PRINT("debug", ("all: %s, all.modified_non_trans_table: %s, stmt.modified_non_trans_table: %s",
-                       YESNO(all),
-                       YESNO(thd->transaction.all.modified_non_trans_table),
-                       YESNO(thd->transaction.stmt.modified_non_trans_table)));
 
-  /*
-    If an incident event is set we do not flush the content of the statement
-    cache because it may be corrupted.
-  */
-  if (cache_mngr->stmt_cache.has_incident())
-  {
-    mysql_bin_log.write_incident(thd, TRUE);
-    cache_mngr->reset_cache(&cache_mngr->stmt_cache);
-  }
-  else if (!cache_mngr->stmt_cache.empty())
+void MYSQL_LOG::close(uint exiting)
+{					// One can't set log_type here!
+  DBUG_ENTER("MYSQL_LOG::close");
+  DBUG_PRINT("enter",("exiting: %d", (int) exiting));
+  if (log_state == LOG_OPENED)
   {
-    binlog_flush_stmt_cache(thd, cache_mngr);
-  }
+    end_io_cache(&log_file);
 
-  if (cache_mngr->trx_cache.empty())
-  {
-    /* 
-      we're here because cache_log was flushed in MYSQL_BIN_LOG::log_xid()
-    */
-    cache_mngr->reset_cache(&cache_mngr->trx_cache);
-    DBUG_RETURN(0);
-  }
+    if (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
+    {
+      write_error= 1;
+      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
+    }
 
-  if (mysql_bin_log.check_write_error(thd))
-  {
-    /*
-      "all == true" means that a "rollback statement" triggered the error and
-      this function was called. However, this must not happen as a rollback
-      is written directly to the binary log. And in auto-commit mode, a single
-      statement that is rolled back has the flag all == false.
-    */
-    DBUG_ASSERT(!all);
-    /*
-      We reach this point if the effect of a statement did not properly get into
-      a cache and need to be rolled back.
-    */
-    error= binlog_truncate_trx_cache(thd, cache_mngr, all);
-  }
-  else
-  {  
-    /*
-      We flush the cache wrapped in a beging/rollback if:
-        . aborting a transcation that modified a non-transactional table or;
-        . aborting a statement that modified both transactional and
-         non-transctional tables but which is not in the boundaries of any
-         transaction;
-        . the OPTION_KEEP_LOG is activate.
-    */
-    if (thd->variables.binlog_format == BINLOG_FORMAT_STMT &&
-        ((all && thd->transaction.all.modified_non_trans_table) ||
-        (!all && thd->transaction.stmt.modified_non_trans_table &&
-        !thd->in_multi_stmt_transaction()) ||
-        (thd->options & OPTION_KEEP_LOG)))
+    if (my_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);
     }
-    /*
-      Otherwise, we simply truncate the cache as there is no change on
-      non-transactional tables as follows.
-    */
-    else if (all || (!all &&
-                     (!thd->transaction.stmt.modified_non_trans_table ||
-                      !thd->in_multi_stmt_transaction() || 
-                      thd->variables.binlog_format != BINLOG_FORMAT_STMT)))
-      error= binlog_truncate_trx_cache(thd, cache_mngr, all);
   }
 
-  /* 
-    This is part of the stmt rollback.
-  */
-  if (!all)
-    cache_mngr->trx_cache.set_prev_position(MY_OFF_T_UNDEF); 
-  DBUG_RETURN(error);
+  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
+  safeFree(name);
+  DBUG_VOID_RETURN;
 }
 
-void MYSQL_BIN_LOG::set_write_error(THD *thd)
-{
-  DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
-
-  write_error= 1;
-
-  if (check_write_error(thd))
-    DBUG_VOID_RETURN;
-
-  if (my_errno == EFBIG)
-    my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
-  else
-    my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
+/** This is called only once. */
 
+void MYSQL_LOG::cleanup()
+{
+  DBUG_ENTER("cleanup");
+  if (inited)
+  {
+    inited= 0;
+    (void) pthread_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->main_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
 
-  binlog_trans_log_savepos(thd, (my_off_t*) sv);
-  /* Write it to the binary log */
+  SYNOPSIS
+    reopen_file()
+
+  DESCRIPTION
+    Reopen the log file. The method is used during FLUSH LOGS
+    and locks LOCK_log mutex
+*/
 
-  int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
-  int const error=
-    thd->binlog_query(THD::STMT_QUERY_TYPE,
-                      thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
-                      errcode);
-  DBUG_RETURN(error);
-}
 
-static int binlog_savepoint_rollback(handlerton *hton, THD *thd, void *sv)
+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(thd->transaction.all.modified_non_trans_table || 
-               (thd->options & OPTION_KEEP_LOG)))
+  DBUG_ENTER("MYSQL_LOG::reopen_file");
+  if (!is_open())
   {
-    int errcode= query_error_code(thd, thd->killed == THD::NOT_KILLED);
-    int error=
-      thd->binlog_query(THD::STMT_QUERY_TYPE,
-                        thd->query(), thd->query_length(), TRUE, FALSE, FALSE,
-                        errcode);
-    DBUG_RETURN(error);
+    DBUG_PRINT("info",("log is closed"));
+    DBUG_VOID_RETURN;
   }
-  binlog_trans_log_truncate(thd, *(my_off_t*)sv);
-  DBUG_RETURN(0);
-}
 
+  pthread_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;
-}
+  /*
+     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
+  */
 
+  open(save_name, log_type, 0, io_cache_type);
+  my_free(save_name, MYF(0));
 
-File open_binlog(IO_CACHE *log, const char *log_file_name, const char **errmsg)
-{
-  File file;
-  DBUG_ENTER("open_binlog");
-
-  if ((file = my_open(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)
-  {
-    my_close(file,MYF(0));
-    end_io_cache(log);
-  }
-  DBUG_RETURN(-1);
-}
-
-#ifdef __NT__
-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 /* __NT__ */
-
-
-/**
-  Find a unique filename for 'filename.#'.
-
-  Set '#' to the number next to the maximum found in the most
-  recent log file extension.
-
-  This function will return nonzero if: (i) the generated name
-  exceeds FN_REFLEN; (ii) if the number of extensions is exhausted;
-  or (iii) some other error happened while examining the filesystem.
-
-  @return
-    nonzero if not possible to get unique filename.
-*/
-
-static int find_uniq_filename(char *name)
-{
-  uint                  i;
-  char                  buff[FN_REFLEN], ext_buf[FN_REFLEN];
-  struct st_my_dir     *dir_info;
-  reg1 struct fileinfo *file_info;
-  ulong                 max_found= 0, next= 0, number= 0;
-  size_t		buf_length, length;
-  char			*start, *end;
-  int                   error= 0;
-  DBUG_ENTER("find_uniq_filename");
-
-  length= dirname_part(buff, name, &buf_length);
-  start=  name + length;
-  end=    strend(start);
-
-  *end='.';
-  length= (size_t) (end - start + 1);
-
-  if (!(dir_info= my_dir(buff,MYF(MY_DONT_SORT))))
-  {						// This shouldn't happen
-    strmov(end,".1");				// use name+1
-    DBUG_RETURN(1);
-  }
-  file_info= dir_info->dir_entry;
-  for (i= dir_info->number_off_files ; i-- ; file_info++)
-  {
-    if (bcmp((uchar*) file_info->name, (uchar*) start, length) == 0 &&
-	test_if_number(file_info->name+length, &number,0))
-    {
-      set_if_bigger(max_found,(ulong) number);
-    }
-  }
-  my_dirend(dir_info);
-
-  /* check if reached the maximum possible extension number */
-  if ((max_found == MAX_LOG_UNIQUE_FN_EXT))
-  {
-    sql_print_error("Log filename extension number exhausted: %06lu. \
-Please fix this by archiving old logs and \
-updating the index files.", max_found);
-    error= 1;
-    goto end;
-  }
-
-  next= max_found + 1;
-  sprintf(ext_buf, "%06lu", next);
-  *end++='.';
-
-  /* 
-    Check if the generated extension size + the file name exceeds the
-    buffer size used. If one did not check this, then the filename might be
-    truncated, resulting in error.
-   */
-  if (((strlen(ext_buf) + (end - name)) >= FN_REFLEN))
-  {
-    sql_print_error("Log filename too large: %s%s (%lu). \
-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= my_open(log_file_name, open_flags,
-                     MYF(MY_WME | ME_WAITTANG))) < 0 ||
-      init_io_cache(&log_file, file, IO_SIZE, io_cache_type,
-                    my_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 __NT__
-			"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)
-    my_close(file, MYF(0));
-  end_io_cache(&log_file);
-  safeFree(name);
-  log_state= LOG_CLOSED;
-  DBUG_RETURN(1);
-}
-
-MYSQL_LOG::MYSQL_LOG()
-  : name(0), write_error(FALSE), inited(FALSE), log_type(LOG_UNKNOWN),
-    log_state(LOG_CLOSED)
-{
-  /*
-    We don't want to initialize LOCK_Log here as such initialization depends on
-    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
-    called only in main(). Doing initialization here would make it happen
-    before main().
-  */
-  bzero((char*) &log_file, sizeof(log_file));
-}
-
-void MYSQL_LOG::init_pthread_objects()
-{
-  DBUG_ASSERT(inited == 0);
-  inited= 1;
-  (void) pthread_mutex_init(&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 (my_sync(log_file.file, MYF(MY_WME)) && ! write_error)
-    {
-      write_error= 1;
-      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
-    }
-
-    if (my_close(log_file.file, MYF(MY_WME)) && ! write_error)
-    {
-      write_error= 1;
-      sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
-    }
-  }
-
-  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
-  safeFree(name);
-  DBUG_VOID_RETURN;
-}
-
-/** This is called only once. */
-
-void MYSQL_LOG::cleanup()
-{
-  DBUG_ENTER("cleanup");
-  if (inited)
-  {
-    inited= 0;
-    (void) pthread_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;
-  }
-
-  pthread_mutex_lock(&LOCK_log);
-
-  save_name= name;
-  name= 0;				// Don't free name
-  close(LOG_CLOSE_TO_BE_OPENED);
-
-  /*
-     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
-  */
-
-  open(save_name, log_type, 0, io_cache_type);
-  my_free(save_name, MYF(0));
-
-  pthread_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;
-
-  (void) pthread_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;
-  }
-
-  (void) pthread_mutex_unlock(&LOCK_log);
-  return FALSE;
-err:
-
-  if (!write_error)
-  {
-    write_error= 1;
-    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
-  }
-  (void) pthread_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");
-
-  (void) pthread_mutex_lock(&LOCK_log);
-
-  if (!is_open())
-  {
-    (void) pthread_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);
-      }
-    }
-  }
-  (void) pthread_mutex_unlock(&LOCK_log);
-  DBUG_RETURN(error);
-}
-
-
-/**
-  @todo
-  The following should be using fn_format();  We just need to
-  first change fn_format() to cut the file name if it's too long.
-*/
-const char *MYSQL_LOG::generate_name(const char *log_name,
-                                      const char *suffix,
-                                      bool strip_ext, char *buff)
-{
-  if (!log_name || !log_name[0])
-  {
-    strmake(buff, pidfile_name, FN_REFLEN - strlen(suffix) - 1);
-    return (const char *)
-      fn_format(buff, buff, "", suffix, MYF(MY_REPLACE_EXT|MY_REPLACE_DIR));
-  }
-  // get rid of extension if the log is binary to avoid problems
-  if (strip_ext)
-  {
-    char *p= fn_ext(log_name);
-    uint length= (uint) (p - log_name);
-    strmake(buff, log_name, min(length, FN_REFLEN-1));
-    return (const char*)buff;
-  }
-  return log_name;
-}
-
-
-
-MYSQL_BIN_LOG::MYSQL_BIN_LOG(uint *sync_period)
-  :bytes_written(0), prepared_xids(0), file_id(1), open_count(1),
-   need_start_event(TRUE), m_table_map_version(0),
-   sync_period_ptr(sync_period),
-   is_relay_log(0), signal_cnt(0),
-   description_event_for_exec(0), description_event_for_queue(0)
-{
-  /*
-    We don't want to initialize locks here as such initialization depends on
-    safe_mutex (when using safe_mutex) which depends on MY_INIT(), which is
-    called only in main(). Doing initialization here would make it happen
-    before main().
-  */
-  index_file_name[0] = 0;
-  bzero((char*) &index_file, sizeof(index_file));
-  bzero((char*) &purge_index_file, sizeof(purge_index_file));
-}
-
-/* this is called only once */
-
-void MYSQL_BIN_LOG::cleanup()
-{
-  DBUG_ENTER("cleanup");
-  if (inited)
-  {
-    inited= 0;
-    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
-    delete description_event_for_queue;
-    delete description_event_for_exec;
-    (void) pthread_mutex_destroy(&LOCK_log);
-    (void) pthread_mutex_destroy(&LOCK_index);
-    (void) pthread_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;
-  (void) pthread_mutex_init(&LOCK_log, MY_MUTEX_INIT_SLOW);
-  (void) pthread_mutex_init(&LOCK_index, MY_MUTEX_INIT_SLOW);
-  (void) pthread_cond_init(&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= my_open(index_file_name,
-                              O_RDWR | O_CREAT | O_BINARY ,
-                              MYF(MY_WME))) < 0 ||
-       my_sync(index_file_nr, MYF(MY_WME)) ||
-       init_io_cache(&index_file, index_file_nr,
-                     IO_SIZE, WRITE_CACHE,
-                     my_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 my_create() not my_open().
-    */
-    if (index_file_nr >= 0)
-      my_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", 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) ||
-        my_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", 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) ||
-          my_sync(index_file.file, MYF(MY_WME)))
-        goto err;
-
-#ifdef HAVE_REPLICATION
-      DBUG_EXECUTE_IF("crash_create_after_update_index", 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)
-    my_close(file,MYF(0));
-  end_io_cache(&log_file);
-  end_io_cache(&index_file);
-  safeFree(name);
-  log_state= LOG_CLOSED;
-  DBUG_RETURN(1);
-}
-
-
-int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
-{
-  pthread_mutex_lock(&LOCK_log);
-  int ret = raw_get_current_log(linfo);
-  pthread_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)
-  {
-    (void) my_seek(file, offset, MY_SEEK_SET, MYF(0));
-    if ((bytes_read= (int) my_read(file, io_buf, sizeof(io_buf), MYF(MY_WME)))
-	< 0)
-      goto err;
-    if (!bytes_read)
-      break;					// end of file
-    (void) my_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
-    if (my_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 (my_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
-      my_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)
-    pthread_mutex_lock(&LOCK_index);
-  safe_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)
-    pthread_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)
-    pthread_mutex_lock(&LOCK_index);
-  safe_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)
-    pthread_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.
-  */
-  pthread_mutex_lock(&LOCK_log);
-  pthread_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.
-  */
-  VOID(pthread_mutex_lock(&LOCK_thread_count));
-
-  /* Save variables so that we can reopen the log */
-  save_name=name;
-  name=0;					// Protect against free
-  close(LOG_CLOSE_TO_BE_OPENED);
-
-  /*
-    First delete all old log files and then update the index file.
-    As we first delete the log files and do not use sort of logging,
-    a crash may lead to an inconsistent state where the index has
-    references to non-existent files.
-
-    We need to invert the steps and use the purge_index_file methods
-    in order to make the operation safe.
-  */
-  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
-  {
-    uint errcode= purge_log_get_error_code(err);
-    sql_print_error("Failed to locate old binlog or relay log files");
-    my_message(errcode, ER(errcode), MYF(0));
-    error= 1;
-    goto err;
-  }
-
-  for (;;)
-  {
-    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
-    {
-      if (my_errno == ENOENT) 
-      {
-        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
-                            linfo.log_file_name);
-        sql_print_information("Failed to delete file '%s'",
-                              linfo.log_file_name);
-        my_errno= 0;
-        error= 0;
-      }
-      else
-      {
-        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                            ER_BINLOG_PURGE_FATAL_ERR,
-                            "a problem with deleting %s; "
-                            "consider examining correspondence "
-                            "of your binlog index file "
-                            "to the actual binlog files",
-                            linfo.log_file_name);
-        error= 1;
-        goto err;
-      }
-    }
-    if (find_next_log(&linfo, 0))
-      break;
-  }
-
-  /* Start logging with a new file */
-  close(LOG_CLOSE_INDEX);
-  if ((error= my_delete_allow_opened(index_file_name, MYF(0))))	// Reset (open will update)
-  {
-    if (my_errno == ENOENT) 
-    {
-      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
-                          index_file_name);
-      sql_print_information("Failed to delete file '%s'",
-                            index_file_name);
-      my_errno= 0;
-      error= 0;
-    }
-    else
-    {
-      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                          ER_BINLOG_PURGE_FATAL_ERR,
-                          "a problem with deleting %s; "
-                          "consider examining correspondence "
-                          "of your binlog index file "
-                          "to the actual binlog files",
-                          index_file_name);
-      error= 1;
-      goto err;
-    }
-  }
-  if (!thd->slave_thread)
-    need_start_event=1;
-  if (!open_index_file(index_file_name, 0, FALSE))
-    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0, FALSE);
-  my_free((uchar*) save_name, MYF(0));
-
-err:
-  if (error == 1)
-    name= const_cast<char*>(save_name);
-  VOID(pthread_mutex_unlock(&LOCK_thread_count));
-  pthread_mutex_unlock(&LOCK_index);
-  pthread_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));
-
-  pthread_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", abort(););
-
-  pthread_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;
-  pthread_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
-  */
-  pthread_cond_broadcast(&rli->log_space_cond);
-
-  /*
-   * Need to update the log pos because purge logs has been called 
-   * after fetching initially the log pos at the begining of the method.
-   */
-  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
-  {
-    char buff[22];
-    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
-                    error,
-                    llstr(rli->linfo.index_file_offset,buff),
-                    rli->group_relay_log_name,
-                    included);
-    goto err;
-  }
-
-  /* If included was passed, rli->linfo should be the first entry. */
-  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
-
-err:
-  my_free(to_purge_if_included, MYF(0));
-  pthread_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
-                                my_stat() or my_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)
-    pthread_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", 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", 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", abort(););
-
-  if (need_mutex)
-    pthread_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 (!my_stat(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 my_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
-                                my_stat() or my_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");
-
-  pthread_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 (!my_stat(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:
-  pthread_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)
-    pthread_mutex_lock(&LOCK_log);
-  pthread_mutex_lock(&LOCK_index);
-
-  safe_mutex_assert_owner(&LOCK_log);
-  safe_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++;
-    pthread_mutex_lock(&LOCK_prep_xids);
-    while (prepared_xids) {
-      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
-      pthread_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
-    }
-    pthread_mutex_unlock(&LOCK_prep_xids);
-  }
-
-  /* Reuse old name if not binlog and not update log */
-  new_name_ptr= name;
-
-  /*
-    If user hasn't specified an extension, generate a new log name
-    We have to do this here and not in open as we want to store the
-    new file name in the current binary log file.
-  */
-  if (generate_new_name(new_name, name))
-    goto end;
-  new_name_ptr=new_name;
-
-  if (log_type == LOG_BIN)
-  {
-    if (!no_auto_events)
-    {
-      /*
-        We log the whole file name for log file as the user may decide
-        to change base names at some point.
-      */
-      Rotate_log_event r(new_name+dirname_length(new_name),
-                         0, LOG_EVENT_OFFSET, is_relay_log ? Rotate_log_event::RELAY_LOG : 0);
-      r.write(&log_file);
-      bytes_written += r.data_written;
-    }
-    /*
-      Update needs to be signalled even if there is no rotate event
-      log rotation should give the waiting thread a signal to
-      discover EOF and move on to the next log.
-    */
-    signal_update();
-  }
-  old_name=name;
-  name=0;				// Don't free name
-  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
-
-  /*
-     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
-  */
-
-  /*
-     new_file() is only used for rotation (in FLUSH LOGS or because size >
-     max_binlog_size or max_relay_log_size).
-     If this is a binary log, the Format_description_log_event at the beginning of
-     the new file should have created=0 (to distinguish with the
-     Format_description_log_event written at server startup, which should
-     trigger temp tables deletion on slaves.
-  */
-
-  /* reopen index binlog file, BUG#34582 */
-  if (!open_index_file(index_file_name, 0, FALSE))
-    open(old_name, log_type, new_name_ptr,
-         io_cache_type, no_auto_events, max_size, 1, FALSE);
-  my_free(old_name,MYF(0));
-
-end:
-  if (need_lock)
-    pthread_mutex_unlock(&LOCK_log);
-  pthread_mutex_unlock(&LOCK_index);
-
-  DBUG_VOID_RETURN;
-}
-
-
-bool MYSQL_BIN_LOG::append(Log_event* ev)
-{
-  bool error = 0;
-  pthread_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:
-  pthread_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);
-
-  safe_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;
-  safe_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=my_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 talbe 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 ? my_b_tell (&cache_mngr->trx_cache.cache_log) : 0);
-}
-
-/** 
-  This function checks if a transactional talbe 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, the cache
-  to be used depends on the flag @c is_transactional. 
-
-  Otherswise, we use the trx-cache if either the @c is_transactional
-  is true or the trx-cache is not empty.
-
-  @param thd              The client thread.
-  @param is_transactional The changes are related to a trx-table.
-  @return
-    @c true if a trx-cache should be used, @c false otherwise.
-*/
-bool use_trans_cache(const THD* thd, bool is_transactional)
-{
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-
-  return
-    (thd->variables.binlog_direct_non_trans_update ? is_transactional :
-    (cache_mngr->trx_cache.empty() && !is_transactional ? FALSE : TRUE));
-}
-
-/*
-  These functions are placed in this file since they need access to
-  binlog_hton, which has internal linkage.
-*/
-
-int THD::binlog_setup_trx_data()
-{
-  DBUG_ENTER("THD::binlog_setup_trx_data");
-  binlog_cache_mngr *cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-
-  if (cache_mngr)
-    DBUG_RETURN(0);                             // Already set up
-
-  cache_mngr= (binlog_cache_mngr*) my_malloc(sizeof(binlog_cache_mngr), MYF(MY_ZEROFILL));
-  if (!cache_mngr ||
-      open_cached_file(&cache_mngr->stmt_cache.cache_log, mysql_tmpdir,
-                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)) ||
-      open_cached_file(&cache_mngr->trx_cache.cache_log, mysql_tmpdir,
-                       LOG_PREFIX, binlog_cache_size, MYF(MY_WME)))
-  {
-    my_free((uchar*)cache_mngr, MYF(MY_ALLOW_ZERO_PTR));
-    DBUG_RETURN(1);                      // Didn't manage to set it up
-  }
-  thd_set_ha_data(this, binlog_hton, cache_mngr);
-
-  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
-
-  DBUG_RETURN(0);
-}
-
-/*
-  Function to start a statement and optionally a transaction for the
-  binary log.
-
-  SYNOPSIS
-    binlog_start_trans_and_stmt()
-
-  DESCRIPTION
-
-    This function does three things:
-    - Start a transaction if not in autocommit mode or if a BEGIN
-      statement has been seen.
-
-    - Start a statement transaction to allow us to truncate the cache.
-
-    - Save the currrent binlog position so that we can roll back the
-      statement by truncating the cache.
-
-      We only update the saved position if the old one was undefined,
-      the reason is that there are some cases (e.g., for CREATE-SELECT)
-      where the position is saved twice (e.g., both in
-      select_create::prepare() and THD::binlog_write_table_map()) , but
-      we should use the first. This means that calls to this function
-      can be used to start the statement before the first table map
-      event, to include some extra events.
- */
-
-void
-THD::binlog_start_trans_and_stmt()
-{
-  binlog_cache_mngr *cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-  DBUG_ENTER("binlog_start_trans_and_stmt");
-  DBUG_PRINT("enter", ("cache_mngr: %p  cache_mngr->trx_cache.get_prev_position(): %lu",
-                       cache_mngr,
-                       (cache_mngr ? (ulong) cache_mngr->trx_cache.get_prev_position() :
-                        (ulong) 0)));
-
-  if (cache_mngr == NULL ||
-      cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
-  {
-    this->binlog_set_stmt_begin();
-    if (options & (OPTION_NOT_AUTOCOMMIT | OPTION_BEGIN))
-      trans_register_ha(this, TRUE, binlog_hton);
-    trans_register_ha(this, FALSE, binlog_hton);
-    /*
-      Mark statement transaction as read/write. We never start
-      a binary log transaction and keep it read-only,
-      therefore it's best to mark the transaction read/write just
-      at the same time we start it.
-      Not necessary to mark the normal transaction read/write
-      since the statement-level flag will be propagated automatically
-      inside ha_commit_trans.
-    */
-    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
-  }
-  DBUG_VOID_RETURN;
-}
-
-void THD::binlog_set_stmt_begin() {
-  binlog_cache_mngr *cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-
-  /*
-    The call to binlog_trans_log_savepos() might create the cache_mngr
-    structure, if it didn't exist before, so we save the position
-    into an auto variable and then write it into the transaction
-    data for the binary log (i.e., cache_mngr).
-  */
-  my_off_t pos= 0;
-  binlog_trans_log_savepos(this, &pos);
-  cache_mngr= (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-  cache_mngr->trx_cache.set_prev_position(pos);
-}
-
-
-/**
-  This function writes a table map to the binary log. 
-  Note that in order to keep the signature uniform with related methods,
-  we use a redundant parameter to indicate whether a transactional table
-  was changed or not.
- 
-  @param table             a pointer to the table.
-  @param is_transactional  @c true indicates a transactional table,
-                           otherwise @c false a non-transactional.
-  @return
-    nonzero if an error pops up when writing the table map event.
-*/
-int THD::binlog_write_table_map(TABLE *table, bool is_transactional)
-{
-  int error;
-  DBUG_ENTER("THD::binlog_write_table_map");
-  DBUG_PRINT("enter", ("table: 0x%lx  (%s: #%lu)",
-                       (long) table, table->s->table_name.str,
-                       table->s->table_map_id));
-
-  /* Pre-conditions */
-  DBUG_ASSERT(is_current_stmt_binlog_format_row() && mysql_bin_log.is_open());
-  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
-
-  Table_map_log_event
-    the_event(this, table, table->s->table_map_id, is_transactional);
-
-  if (binlog_table_maps == 0)
-    binlog_start_trans_and_stmt();
-
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-
-  IO_CACHE *file=
-    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
-  if ((error= the_event.write(file)))
-    DBUG_RETURN(error);
-
-  binlog_table_maps++;
-  table->s->table_map_version= mysql_bin_log.table_map_version();
-  DBUG_RETURN(0);
-}
-
-/**
-  This function retrieves a pending row event from a cache which is
-  specified through the parameter @c is_transactional. Respectively, when it
-  is @c true, the pending event is returned from the transactional cache.
-  Otherwise from the non-transactional cache.
-
-  @param is_transactional  @c true indicates a transactional cache,
-                           otherwise @c false a non-transactional.
-  @return
-    The row event if any. 
-*/
-Rows_log_event*
-THD::binlog_get_pending_rows_event(bool is_transactional) const
-{
-  Rows_log_event* rows= NULL;
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-
-  /*
-    This is less than ideal, but here's the story: If there is no cache_mngr,
-    prepare_pending_rows_event() has never been called (since the cache_mngr
-    is set up there). In that case, we just return NULL.
-   */
-  if (cache_mngr)
-  {
-    binlog_cache_data *cache_data=
-      cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
-
-    rows= cache_data->pending();
-  }
-  return (rows);
-}
-
-/**
-  This function stores a pending row event into a cache which is specified
-  through the parameter @c is_transactional. Respectively, when it is @c
-  true, the pending event is stored into the transactional cache. Otherwise
-  into the non-transactional cache.
-
-  @param evt               a pointer to the row event.
-  @param is_transactional  @c true indicates a transactional cache,
-                           otherwise @c false a non-transactional.
-*/
-void
-THD::binlog_set_pending_rows_event(Rows_log_event* ev, bool is_transactional)
-{
-  if (thd_get_ha_data(this, binlog_hton) == NULL)
-    binlog_setup_trx_data();
-
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
-
-  DBUG_ASSERT(cache_mngr);
-
-  binlog_cache_data *cache_data=
-    cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
-
-  cache_data->set_pending(ev);
-}
-
-
-/**
-  This function removes the pending rows event, discarding any outstanding
-  rows. If there is no pending rows event available, this is effectively a
-  no-op.
-
-  @param thd               a pointer to the user thread.
-  @param is_transactional  @c true indicates a transactional cache,
-                           otherwise @c false a non-transactional.
-*/
-int
-MYSQL_BIN_LOG::remove_pending_rows_event(THD *thd, bool is_transactional)
-{
-  DBUG_ENTER("MYSQL_BIN_LOG::remove_pending_rows_event");
-
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-
-  DBUG_ASSERT(cache_mngr);
-
-  binlog_cache_data *cache_data=
-    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
-
-  if (Rows_log_event* pending= cache_data->pending())
-  {
-    delete pending;
-    cache_data->set_pending(NULL);
-  }
-
-  DBUG_RETURN(0);
-}
-
-/*
-  Moves the last bunch of rows from the pending Rows event to a cache (either
-  transactional cache if is_transaction is @c true, or the non-transactional
-  cache otherwise. Sets a new pending event.
-
-  @param thd               a pointer to the user thread.
-  @param evt               a pointer to the row event.
-  @param is_transactional  @c true indicates a transactional cache,
-                           otherwise @c false a non-transactional.
-*/
-int
-MYSQL_BIN_LOG::flush_and_set_pending_rows_event(THD *thd,
-                                                Rows_log_event* event,
-                                                bool is_transactional)
-{
-  DBUG_ENTER("MYSQL_BIN_LOG::flush_and_set_pending_rows_event(event)");
-  DBUG_ASSERT(mysql_bin_log.is_open());
-  DBUG_PRINT("enter", ("event: 0x%lx", (long) event));
-
-  int error= 0;
-  binlog_cache_mngr *const cache_mngr=
-    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-
-  DBUG_ASSERT(cache_mngr);
-
-  binlog_cache_data *cache_data=
-    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
-
-  DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long) cache_data->pending()));
-
-  if (Rows_log_event* pending= cache_data->pending())
-  {
-    IO_CACHE *file= &cache_data->cache_log;
-
-    /*
-      Write pending event to the cache.
-    */
-    if (pending->write(file))
-    {
-      set_write_error(thd);
-      if (check_write_error(thd) && cache_data &&
-          thd->transaction.stmt.modified_non_trans_table)
-        cache_data->set_incident();
-      DBUG_RETURN(1);
-    }
-
-    /*
-      We step the table map version if we are writing an event
-      representing the end of a statement.
-
-      In an ideal world, we could avoid stepping the table map version,
-      since we could then reuse the table map that was written earlier
-      in the cache. This does not work since STMT_END_F implies closing
-      all table mappings on the slave side.
-    
-      TODO: Find a solution so that table maps does not have to be
-      written several times within a transaction.
-    */
-    if (pending->get_flags(Rows_log_event::STMT_END_F))
-      ++m_table_map_version;
-
-    delete pending;
-  }
-
-  thd->binlog_set_pending_rows_event(event, is_transactional);
-
-  DBUG_RETURN(error);
-}
-
-/**
-  Write an event to the binary log.
-*/
-
-bool MYSQL_BIN_LOG::write(Log_event *event_info)
-{
-  THD *thd= event_info->thd;
-  bool error= 1;
-  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
-  binlog_cache_data *cache_data= 0;
-
-  if (thd->binlog_evt_union.do_union)
-  {
-    /*
-      In Stored function; Remember that function call caused an update.
-      We will log the function call to the binary log on function exit
-    */
-    thd->binlog_evt_union.unioned_events= TRUE;
-    thd->binlog_evt_union.unioned_events_trans |=
-      event_info->use_trans_cache();
-    DBUG_RETURN(0);
-  }
-
-  /*
-    We only end the statement if we are in a top-level statement.  If
-    we are inside a stored function, we do not end the statement since
-    this will close all tables on the slave.
-  */
-  bool const end_stmt=
-    thd->prelocked_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->options & OPTION_BIN_LOG)) ||
-	(!binlog_filter->db_ok(local_db)))
-      DBUG_RETURN(0);
-#endif /* HAVE_REPLICATION */
-
-#if defined(USING_TRANSACTIONS)
-    IO_CACHE *file= NULL;
-
-    if (event_info->use_direct_logging())
-    {
-      file= &log_file;
-      pthread_mutex_lock(&LOCK_log);
-    }
-    else
-    {
-      if (thd->binlog_setup_trx_data())
-        goto err;
-
-      binlog_cache_mngr *const cache_mngr=
-        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
-
-      bool is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
-      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
-      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
-
-      thd->binlog_start_trans_and_stmt();
-    }
-#endif /* USING_TRANSACTIONS */
-    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:
-      pthread_mutex_unlock(&LOCK_log);
-    }
-
-    if (error)
-    {
-      set_write_error(thd);
-      if (check_write_error(thd) && cache_data &&
-        thd->transaction.stmt.modified_non_trans_table)
-        cache_data->set_incident();
-    }
-  }
-
-  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
-    ++m_table_map_version;
-
-  DBUG_RETURN(error);
-}
-
-
-int error_log_print(enum loglevel level, const char *format,
-                    va_list args)
-{
-  return logger.error_log_print(level, format, args);
-}
-
-
-bool slow_log_print(THD *thd, const char *query, uint query_length,
-                    ulonglong current_utime)
-{
-  return logger.slow_log_print(thd, query, query_length, current_utime);
-}
-
-
-bool LOGGER::log_command(THD *thd, enum enum_server_command command)
-{
-#ifndef NO_EMBEDDED_ACCESS_CHECKS
-  Security_context *sctx= thd->security_ctx;
-#endif
-  /*
-    Log command if we have at least one log event handler enabled and want
-    to log this king of commands
-  */
-  if (*general_log_handler_list && (what_to_log & (1L << (uint) command)))
-  {
-    if ((thd->options & 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))
-    pthread_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))
-    pthread_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;
-  pthread_mutex_lock(&LOCK_log);
-  res = file_id++;
   pthread_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;
+
+  (void) pthread_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;
+  }
 
-        }
-      }
+  (void) pthread_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);
+  }
+  (void) pthread_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)
-  {
-    error= thd->is_error() ? thd->main_da.sql_errno() : 0;
+  DESCRIPTION
 
-    /* thd->main_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)
-    pthread_mutex_lock(&LOCK_log);
-  error= ev.write(&log_file);
-  if (lock)
+  bool error= 0;
+  DBUG_ENTER("MYSQL_QUERY_LOG::write");
+
+  (void) pthread_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);
-    }
-    pthread_mutex_unlock(&LOCK_log);
+    (void) pthread_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 *)");
-  VOID(pthread_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);
 
-  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)
+        /* 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)
     {
-      /*
-        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"));
-                        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", abort(););
-      if (cache->error)				// Error on read
+      if (!(specialflag & SPECIAL_SHORT_LOG_FORMAT))
       {
-        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
-        write_error=1;				// Don't give more errors
-        goto err;
+        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 (RUN_HOOK(binlog_storage, after_flush,
-                   (thd, log_file_name, log_file.pos_in_file, synced)))
+    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)
       {
-        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)
-    {
-      pthread_mutex_lock(&LOCK_prep_xids);
-      prepared_xids++;
-      pthread_mutex_unlock(&LOCK_prep_xids);
     }
-    else
-      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
   }
-  VOID(pthread_mutex_unlock(&LOCK_log));
+  (void) pthread_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));
   }
-  VOID(pthread_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).
-*/
+/**
+  Move all data up in a file in an filename index file.
 
-void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
-{
-  const char *old_msg;
-  DBUG_ENTER("wait_for_update_relay_log");
+    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.
 
-  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" );
-  pthread_cond_wait(&update_cond, &LOCK_log);
-  thd->exit_cond(old_msg);
-  DBUG_VOID_RETURN;
-}
+  @param index_file			File to move
+  @param offset			Move everything from here to beginning
 
-/**
-  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.
+    File will be truncated to be 'offset' shorter or filled up with newlines
+
+  @retval
+    0	ok
 */
 
-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)
-    pthread_cond_wait(&update_cond, &LOCK_log);
-  else
-    ret= pthread_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
-*/
+int error_log_print(enum loglevel level, const char *format,
+                    va_list args)
+{
+  return logger.error_log_print(level, format, args);
+}
 
-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= my_tell(log_file.file, MYF(0));
-      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
-      my_pwrite(log_file.file, &flags, 1, offset, MYF(0));
-      /*
-        Restore position so that anything we have in the IO_cache is written
-        to the correct position.
-        We need the seek here, as my_pwrite() is not guaranteed to keep the
-        original position on system that doesn't support pwrite().
-      */
-      my_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
-    }
+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);
+}
 
-    /* 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 (my_close(index_file.file, MYF(0)) < 0 && ! write_error)
+    if ((thd->options & OPTION_LOG_OFF)
+#ifndef NO_EMBEDDED_ACCESS_CHECKS
+         && (sctx->master_access & SUPER_ACL)
+#endif
+       )
     {
-      write_error= 1;
-      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
+      /* No logging */
+      return FALSE;
     }
+
+    return TRUE;
   }
-  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED : LOG_CLOSED;
-  safeFree(name);
-  DBUG_VOID_RETURN;
+
+  return FALSE;
 }
 
 
-void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
+bool general_log_print(THD *thd, enum enum_server_command command,
+                       const char *format, ...)
 {
-  /*
-    We need to take locks, otherwise this may happen:
-    new_file() is called, calls open(old_max_size), then before open() starts,
-    set_max_size() sets max_size to max_size_arg, then open() starts and
-    uses the old_max_size argument, so max_size_arg has been overwritten and
-    it's like if the SET command was never run.
-  */
-  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
-  pthread_mutex_lock(&LOCK_log);
-  if (is_open())
-    max_size= max_size_arg;
-  pthread_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.
 
@@ -5417,14 +2069,6 @@ bool flush_error_log()
    return result;
 }
 
-void MYSQL_BIN_LOG::signal_update()
-{
-  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
-  signal_cnt++;
-  pthread_cond_broadcast(&update_cond);
-  DBUG_VOID_RETURN;
-}
-
 #ifdef __NT__
 static void print_buffer_to_nt_eventlog(enum loglevel level, char *buff,
                                         size_t length, size_t buffLen)
@@ -6058,230 +2702,3 @@ int TC_LOG::using_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]);
-
-  pthread_mutex_init(&LOCK_prep_xids, MY_MUTEX_INIT_FAST);
-  pthread_cond_init (&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);
-    my_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);
-  pthread_mutex_destroy(&LOCK_prep_xids);
-  pthread_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)
-{
-  pthread_mutex_lock(&LOCK_prep_xids);
-  DBUG_ASSERT(prepared_xids > 0);
-  if (--prepared_xids == 0) {
-    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
-    pthread_cond_signal(&COND_prep_xids);
-  }
-  pthread_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() ||
-      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));
-  hash_free(&xids);
-  return 0;
-
-err2:
-  free_root(&mem_root, MYF(0));
-  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-02-13 09:42:41 +0000
+++ b/sql/log.h	2010-04-26 05:01:18 +0000
@@ -244,228 +244,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() */
-  pthread_mutex_t LOCK_index;
-  pthread_mutex_t LOCK_prep_xids;
-  pthread_cond_t  COND_prep_xids;
-  pthread_cond_t update_cond;
-  ulonglong bytes_written;
-  IO_CACHE index_file;
-  char index_file_name[FN_REFLEN];
-  /*
-    purge_file is a temp file used in purge_logs so that the index file
-    can be updated before deleting files from disk, yielding better crash
-    recovery. It is created on demand the first time purge_logs is called
-    and then reused for subsequent calls. It is cleaned up in cleanup().
-  */
-  IO_CACHE purge_index_file;
-  char purge_index_file_name[FN_REFLEN];
-  /*
-     The max size before rotation (usable only if log_type == LOG_BIN: binary
-     logs and relay logs).
-     For a binlog, max_size should be max_binlog_size.
-     For a relay log, it should be max_relay_log_size if this is non-zero,
-     max_binlog_size otherwise.
-     max_size is set in init(), and dynamically changed (when one does SET
-     GLOBAL MAX_BINLOG_SIZE|MAX_RELAY_LOG_SIZE) by fix_max_binlog_size and
-     fix_max_relay_log_size).
-  */
-  ulong max_size;
-  long prepared_xids; /* for tc log - number of xids to remember */
-  // current file sequence number for load data infile binary logging
-  uint file_id;
-  uint open_count;				// For replication
-  int readers_count;
-  bool need_start_event;
-  /*
-    no_auto_events means we don't want any of these automatic events :
-    Start/Rotate/Stop. That is, in 4.x when we rotate a relay log, we don't
-    want a Rotate_log event to be written to the relay log. When we start a
-    relay log etc. So in 4.x this is 1 for relay logs, 0 for binlogs.
-    In 5.0 it's 0 for relay logs too!
-  */
-  bool no_auto_events;
-
-  ulonglong m_table_map_version;
-
-  /* pointer to the sync period variable, for binlog this will be
-     sync_binlog_period, for relay log this will be
-     sync_relay_log_period
-  */
-  uint *sync_period_ptr;
-  uint sync_counter;
-
-  inline uint get_sync_period()
-  {
-    return *sync_period_ptr;
-  }
-
-  int write_to_file(IO_CACHE *cache);
-  /*
-    This is used to start writing to a new log file. The difference from
-    new_file() is locking. new_file_without_locking() does not acquire
-    LOCK_log.
-  */
-  void new_file_without_locking();
-  void new_file_impl(bool need_lock);
-
-public:
-  MYSQL_LOG::generate_name;
-  MYSQL_LOG::is_open;
-
-  /* This is relay log */
-  bool is_relay_log;
-  ulong signal_cnt;  // update of the counter is checked by heartbeat
-  /*
-    These describe the log's format. This is used only for relay logs.
-    _for_exec is used by the SQL thread, _for_queue by the I/O thread. It's
-    necessary to have 2 distinct objects, because the I/O thread may be reading
-    events in a different format from what the SQL thread is reading (consider
-    the case of a master which has been upgraded from 5.0 to 5.1 without doing
-    RESET MASTER, or from 4.x to 5.0).
-  */
-  Format_description_log_event *description_event_for_exec,
-    *description_event_for_queue;
-
-  MYSQL_BIN_LOG(uint *sync_period);
-  /*
-    note that there's no destructor ~MYSQL_BIN_LOG() !
-    The reason is that we don't want it to be automatically called
-    on exit() - but only during the correct shutdown process
-  */
-
-  int open(const char *opt_name);
-  void close();
-  int log_xid(THD *thd, my_xid xid);
-  void unlog(ulong cookie, my_xid xid);
-  int recover(IO_CACHE *log, Format_description_log_event *fdle);
-#if !defined(MYSQL_CLIENT)
-  bool is_table_mapped(TABLE *table) const
-  {
-    return table->s->table_map_version == table_map_version();
-  }
-
-  ulonglong table_map_version() const { return m_table_map_version; }
-  void update_table_map_version() { ++m_table_map_version; }
-
-  int flush_and_set_pending_rows_event(THD *thd, Rows_log_event* event,
-                                       bool is_transactional);
-  int remove_pending_rows_event(THD *thd, bool is_transactional);
-
-#endif /* !defined(MYSQL_CLIENT) */
-  void reset_bytes_written()
-  {
-    bytes_written = 0;
-  }
-  void harvest_bytes_written(ulonglong* counter)
-  {
-#ifndef DBUG_OFF
-    char buf1[22],buf2[22];
-#endif
-    DBUG_ENTER("harvest_bytes_written");
-    (*counter)+=bytes_written;
-    DBUG_PRINT("info",("counter: %s  bytes_written: %s", llstr(*counter,buf1),
-		       llstr(bytes_written,buf2)));
-    bytes_written=0;
-    DBUG_VOID_RETURN;
-  }
-  void set_max_size(ulong max_size_arg);
-  void signal_update();
-  void wait_for_update_relay_log(THD* thd);
-  int  wait_for_update_bin_log(THD* thd, const struct timespec * timeout);
-  void set_need_start_event() { need_start_event = 1; }
-  void init(bool no_auto_events_arg, ulong max_size);
-  void init_pthread_objects();
-  void cleanup();
-  bool open(const char *log_name,
-            enum_log_type log_type,
-            const char *new_name,
-	    enum cache_type io_cache_type_arg,
-	    bool no_auto_events_arg, ulong max_size,
-            bool null_created,
-            bool need_mutex);
-  bool open_index_file(const char *index_file_name_arg,
-                       const char *log_name, bool need_mutex);
-  /* Use this to start writing a new log file */
-  void new_file();
-
-  bool write(Log_event* event_info);
-  bool write(THD *thd, IO_CACHE *cache, Log_event *commit_event, bool incident);
-  bool write_incident(THD *thd, bool lock);
-
-  int  write_cache(IO_CACHE *cache, bool lock_log, bool flush_and_sync);
-  void set_write_error(THD *thd);
-  bool check_write_error(THD *thd);
-
-  void start_union_events(THD *thd, query_id_t query_id_param);
-  void stop_union_events(THD *thd);
-  bool is_query_in_union(THD *thd, query_id_t query_id_param);
-
-  /*
-    v stands for vector
-    invoked as appendv(buf1,len1,buf2,len2,...,bufn,lenn,0)
-  */
-  bool appendv(const char* buf,uint len,...);
-  bool append(Log_event* ev);
-
-  void make_log_name(char* buf, const char* log_ident);
-  bool is_active(const char* log_file_name);
-  int update_log_index(LOG_INFO* linfo, bool need_update_threads);
-  void rotate_and_purge(uint flags);
-  /**
-     Flush binlog cache and synchronize to disk.
-
-     This function flushes events in binlog cache to binary log file,
-     it will do synchronizing according to the setting of system
-     variable 'sync_binlog'. If file is synchronized, @c synced will
-     be set to 1, otherwise 0.
-
-     @param[out] synced if not NULL, set to 1 if file is synchronized, otherwise 0
-
-     @retval 0 Success
-     @retval other Failure
-  */
-  bool flush_and_sync(bool *synced);
-  int purge_logs(const char *to_log, bool included,
-                 bool need_mutex, bool need_update_threads,
-                 ulonglong *decrease_log_space);
-  int purge_logs_before_date(time_t purge_time);
-  int purge_first_log(Relay_log_info* rli, bool included);
-  int set_purge_index_file_name(const char *base_file_name);
-  int open_purge_index_file(bool destroy);
-  bool is_inited_purge_index_file();
-  int close_purge_index_file();
-  int clean_purge_index_file();
-  int sync_purge_index_file();
-  int register_purge_index_entry(const char* entry);
-  int register_create_index_entry(const char* entry);
-  int purge_index_entry(THD *thd, ulonglong *decrease_log_space,
-                        bool need_mutex);
-  bool reset_logs(THD* thd);
-  void close(uint exiting);
-
-  // iterating through the log index file
-  int find_log_pos(LOG_INFO* linfo, const char* log_name,
-		   bool need_mutex);
-  int find_next_log(LOG_INFO* linfo, bool need_mutex);
-  int get_current_log(LOG_INFO* linfo);
-  int raw_get_current_log(LOG_INFO* linfo);
-  uint next_file_id();
-  inline char* get_index_fname() { return index_file_name;}
-  inline char* get_log_fname() { return log_file_name; }
-  inline char* get_name() { return name; }
-  inline pthread_mutex_t* get_log_lock() { return &LOCK_log; }
-  inline IO_CACHE* get_log_file() { return &log_file; }
-
-  inline void lock_index() { pthread_mutex_lock(&LOCK_index);}
-  inline void unlock_index() { pthread_mutex_unlock(&LOCK_index);}
-  inline IO_CACHE *get_index_file() { return &index_file;}
-  inline uint32 get_open_count() { return open_count; }
-};
-
 class Log_event_handler
 {
 public:
@@ -629,24 +407,6 @@ public:
   }
 };
 
-enum enum_binlog_format {
-  /*
-    statement-based except for cases where only row-based can work (UUID()
-    etc):
-  */
-  BINLOG_FORMAT_MIXED= 0,
-  BINLOG_FORMAT_STMT= 1, // statement-based
-  BINLOG_FORMAT_ROW= 2, // row_based
-/*
-  This value is last, after the end of binlog_format_typelib: it has no
-  corresponding cell in this typelib. We use this value to be able to know if
-  the user has explicitely specified a binlog format at startup or not.
-*/
-  BINLOG_FORMAT_UNSPEC= 3
-};
-extern TYPELIB binlog_format_typelib;
-
-int query_error_code(THD *thd, bool not_killed);
 uint purge_log_get_error_code(int res);
 
 #endif /* LOG_H */

=== modified file 'sql/slave.h'
--- a/sql/slave.h	2010-02-12 23:30:44 +0000
+++ b/sql/slave.h	2010-04-26 05:01:18 +0000
@@ -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"

=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h	2010-03-17 11:31:50 +0000
+++ b/sql/sql_class.h	2010-04-26 05:01:18 +0000
@@ -24,6 +24,7 @@
 #endif
 
 #include "log.h"
+#include "binlog.h"
 #include "rpl_tblmap.h"
 #include "replication.h"
 

=== modified file 'sql/sql_db.cc'
--- a/sql/sql_db.cc	2010-02-12 23:30:44 +0000
+++ b/sql/sql_db.cc	2010-04-26 05:01:18 +0000
@@ -23,6 +23,7 @@
 #include <my_dir.h>
 #include <m_ctype.h>
 #include "log.h"
+#include "binlog.h"
 #ifdef __WIN__
 #include <direct.h>
 #endif

=== added file 'sql/sql_master.cc'
--- a/sql/sql_master.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sql_master.cc	2010-04-26 05:01:18 +0000
@@ -0,0 +1,1191 @@
+/* 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_master.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
+
+/*
+    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 = my_open(fname, O_RDONLY, MYF(0))) < 0)
+  {
+    errmsg = "on open of file";
+    goto err;
+  }
+
+  while ((long) (bytes= my_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)
+    (void) my_close(fd, MYF(0));
+  if (errmsg)
+  {
+    sql_print_error("Failed in send_file() %s", errmsg);
+    DBUG_PRINT("error", ("%s", errmsg));
+  }
+  DBUG_RETURN(error);
+}
+
+
+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*) 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;
+  pthread_mutex_t *log_lock;
+  bool binlog_can_be_corrupted= FALSE;
+#ifndef DBUG_OFF
+  int left_events = max_binlog_dump_events;
+#endif
+  DBUG_ENTER("mysql_binlog_send");
+  DBUG_PRINT("enter",("log_ident: '%s'  pos: %ld", log_ident, (long) pos));
+
+  bzero((char*) &log,sizeof(log));
+  /* 
+     heartbeat_period from @master_heartbeat_period user variable
+  */
+  ulonglong heartbeat_period= get_heartbeat_period(thd);
+  struct timespec heartbeat_buf;
+  struct event_coordinates coord_buf;
+  struct timespec *heartbeat_ts= NULL;
+  struct event_coordinates *coord= NULL;
+  if (heartbeat_period != LL(0))
+  {
+    heartbeat_ts= &heartbeat_buf;
+    set_timespec_nsec(*heartbeat_ts, 0);
+    coord= &coord_buf;
+    coord->file_name= log_file_name; // initialization basing on what slave remembers
+    coord->pos= pos;
+  }
+  sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)",
+                        thd->server_id, log_ident, (ulong)pos);
+  if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
+  {
+    errmsg= "Failed to run hook 'transmit_start'";
+    my_errno= ER_UNKNOWN_ERROR;
+    goto err;
+  }
+
+#ifndef DBUG_OFF
+  if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
+  {
+    errmsg = "Master failed COM_BINLOG_DUMP to test if slave can recover";
+    my_errno= ER_UNKNOWN_ERROR;
+    goto err;
+  }
+#endif
+
+  if (!mysql_bin_log.is_open())
+  {
+    errmsg = "Binary log is not open";
+    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
+    goto err;
+  }
+  if (!server_id_supplied)
+  {
+    errmsg = "Misconfigured master - server id was not set";
+    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
+    goto err;
+  }
+
+  name=search_file_name;
+  if (log_ident[0])
+    mysql_bin_log.make_log_name(search_file_name, log_ident);
+  else
+    name=0;					// Find first log
+
+  linfo.index_file_offset = 0;
+
+  if (mysql_bin_log.find_log_pos(&linfo, name, 1))
+  {
+    errmsg = "Could not find first log file name in binary log index file";
+    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
+    goto err;
+  }
+
+  pthread_mutex_lock(&LOCK_thread_count);
+  thd->current_linfo = &linfo;
+  pthread_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.
+	*/
+
+	pthread_mutex_lock(log_lock);
+	switch (error= Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0)) {
+	case 0:
+	  /* we read successfully, so we'll need to send it to the slave */
+	  pthread_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)
+	  {
+	    pthread_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 != LL(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 != LL(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;
+                pthread_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);
+          pthread_mutex_unlock(log_lock);
+        }
+        break;
+            
+        default:
+	  pthread_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);
+      (void) my_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);
+  (void)my_close(file, MYF(MY_WME));
+
+  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
+  my_eof(thd);
+  thd_proc_info(thd, "Waiting to finalize termination");
+  pthread_mutex_lock(&LOCK_thread_count);
+  thd->current_linfo = 0;
+  pthread_mutex_unlock(&LOCK_thread_count);
+  DBUG_VOID_RETURN;
+
+err:
+  thd_proc_info(thd, "Waiting to finalize termination");
+  end_io_cache(&log);
+  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
+  /*
+    Exclude  iteration through thread list
+    this is needed for purge_logs() - it will iterate through
+    thread list and update thd->current_linfo->index_file_offset
+    this mutex will make sure that it never tried to update our linfo
+    after we return from this stack frame
+  */
+  pthread_mutex_lock(&LOCK_thread_count);
+  thd->current_linfo = 0;
+  pthread_mutex_unlock(&LOCK_thread_count);
+  if (file >= 0)
+    (void) my_close(file, MYF(MY_WME));
+
+  my_message(my_errno, errmsg, MYF(0));
+  DBUG_VOID_RETURN;
+}
+
+/*
+  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 (pthread_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)
+{
+  pthread_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)
+    {
+      pthread_mutex_lock(&tmp->LOCK_thd_data);	// Lock from delete
+      break;
+    }
+  }
+  pthread_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);
+    pthread_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) ||
+/*      RUN_HOOK(rpl_master, reset, (thd)) || */
+      RUN_HOOK(binlog_transmit, after_reset_master, (thd, 0 /* flags */)))
+    return 1;
+  return 0;
+}
+
+/**
+  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)
+{
+  DBUG_ENTER("mysql_show_relaylog_events");
+  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS);
+  ha_binlog_wait(thd);
+  DBUG_RETURN(show_binlog_events(thd, &mysql_bin_log));
+}
+
+/**
+  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_fields(&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_fields(&field_list,
+                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
+    DBUG_RETURN(TRUE);
+  
+  pthread_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
+  pthread_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= my_open(fname, O_RDONLY | O_SHARE | O_BINARY,
+                         MYF(0))) >= 0)
+      {
+        file_length= (ulonglong) my_seek(file, 0L, MY_SEEK_END, MYF(0));
+        my_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_SYNC_POINT("debug_lock.created_file_event",10);
+    }
+  }
+  DBUG_RETURN(0);
+}
+
+class sys_var_sync_binlog_period :public sys_var_long_ptr
+{
+public:
+  sys_var_sync_binlog_period(sys_var_chain *chain, const char *name_arg, 
+                             ulong *value_ptr)
+    :sys_var_long_ptr(chain, name_arg,value_ptr) {}
+  bool update(THD *thd, set_var *var);
+};
+
+static sys_var_chain vars = { NULL, NULL };
+static sys_var_uint_ptr sys_sync_binlog_period(&vars, "sync_binlog",
+                                              &sync_binlog_period);
+
+int init_master_sys_vars()
+{
+  if (mysql_add_sys_var_chain(vars.first, my_long_options))
+  {
+    /* should not happen */
+    fprintf(stderr, "failed to initialize replication master system variables");
+    unireg_abort(1);
+  }
+  return 0;
+}

=== added file 'sql/sql_master.h'
--- a/sql/sql_master.h	1970-01-01 00:00:00 +0000
+++ b/sql/sql_master.h	2010-04-26 05:01:18 +0000
@@ -0,0 +1,62 @@
+/* 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 */
+
+
+#ifndef RPL_MASTER_H
+#define RPL_MASTER_H
+
+#include <mysql_priv.h>
+#include <my_global.h>
+#include <my_pthread.h>
+#include "binlog.h"
+#include "rpl_filter.h"
+#include "rpl_handler.h"
+
+#ifdef HAVE_REPLICATION
+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 int max_binlog_dump_events;
+extern my_bool opt_sporadic_binlog_dump_fail;
+
+bool mysql_show_binlog_events(THD* thd);
+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);
+void kill_zombie_dump_threads(uint32 slave_server_id);
+
+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_master_sys_vars();
+
+#endif /* HAVE_REPLICATION */
+#endif /* RPL_MASTER_H */

=== modified file 'sql/sql_parse.cc'
--- a/sql/sql_parse.cc	2010-03-03 14:43:35 +0000
+++ b/sql/sql_parse.cc	2010-04-26 05:01:18 +0000
@@ -2260,7 +2260,13 @@ mysql_execute_command(THD *thd)
     res = show_slave_hosts(thd);
     break;
   }
-  case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
+  case SQLCOM_SHOW_RELAYLOG_EVENTS:
+  {
+    if (check_global_access(thd, REPL_SLAVE_ACL))
+      goto error;
+    res = mysql_show_relaylog_events(thd);
+    break;
+  }
   case SQLCOM_SHOW_BINLOG_EVENTS:
   {
     if (check_global_access(thd, REPL_SLAVE_ACL))

=== removed file 'sql/sql_repl.cc'
--- a/sql/sql_repl.cc	2010-03-03 14:43:35 +0000
+++ b/sql/sql_repl.cc	1970-01-01 00:00:00 +0000
@@ -1,2134 +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 */
-
-#include "mysql_priv.h"
-#ifdef HAVE_REPLICATION
-
-#include "rpl_mi.h"
-#include "sql_repl.h"
-#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
-
-/*
-    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 = my_open(fname, O_RDONLY, MYF(0))) < 0)
-  {
-    errmsg = "on open of file";
-    goto err;
-  }
-
-  while ((long) (bytes= my_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)
-    (void) my_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;
-
-  pthread_mutex_lock(&LOCK_thread_count);
-  I_List_iterator<THD> it(threads);
-
-  while ((tmp=it++))
-  {
-    LOG_INFO* linfo;
-    if ((linfo = tmp->current_linfo))
-    {
-      pthread_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;
-      pthread_mutex_unlock(&linfo->lock);
-    }
-  }
-  pthread_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;
-
-  pthread_mutex_lock(&LOCK_thread_count);
-  I_List_iterator<THD> it(threads);
-
-  while ((tmp=it++))
-  {
-    LOG_INFO* linfo;
-    if ((linfo = tmp->current_linfo))
-    {
-      pthread_mutex_lock(&linfo->lock);
-      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
-                     log_name_len);
-      pthread_mutex_unlock(&linfo->lock);
-      if (result)
-	break;
-    }
-  }
-
-  pthread_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*) 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;
-  pthread_mutex_t *log_lock;
-  bool binlog_can_be_corrupted= FALSE;
-#ifndef DBUG_OFF
-  int left_events = max_binlog_dump_events;
-#endif
-  DBUG_ENTER("mysql_binlog_send");
-  DBUG_PRINT("enter",("log_ident: '%s'  pos: %ld", log_ident, (long) pos));
-
-  bzero((char*) &log,sizeof(log));
-  /* 
-     heartbeat_period from @master_heartbeat_period user variable
-  */
-  ulonglong heartbeat_period= get_heartbeat_period(thd);
-  struct timespec heartbeat_buf;
-  struct event_coordinates coord_buf;
-  struct timespec *heartbeat_ts= NULL;
-  struct event_coordinates *coord= NULL;
-  if (heartbeat_period != LL(0))
-  {
-    heartbeat_ts= &heartbeat_buf;
-    set_timespec_nsec(*heartbeat_ts, 0);
-    coord= &coord_buf;
-    coord->file_name= log_file_name; // initialization basing on what slave remembers
-    coord->pos= pos;
-  }
-  sql_print_information("Start binlog_dump to slave_server(%d), pos(%s, %lu)",
-                        thd->server_id, log_ident, (ulong)pos);
-  if (RUN_HOOK(binlog_transmit, transmit_start, (thd, flags, log_ident, pos)))
-  {
-    errmsg= "Failed to run hook 'transmit_start'";
-    my_errno= ER_UNKNOWN_ERROR;
-    goto err;
-  }
-
-#ifndef DBUG_OFF
-  if (opt_sporadic_binlog_dump_fail && (binlog_dump_count++ % 2))
-  {
-    errmsg = "Master failed COM_BINLOG_DUMP to test if slave can recover";
-    my_errno= ER_UNKNOWN_ERROR;
-    goto err;
-  }
-#endif
-
-  if (!mysql_bin_log.is_open())
-  {
-    errmsg = "Binary log is not open";
-    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
-    goto err;
-  }
-  if (!server_id_supplied)
-  {
-    errmsg = "Misconfigured master - server id was not set";
-    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
-    goto err;
-  }
-
-  name=search_file_name;
-  if (log_ident[0])
-    mysql_bin_log.make_log_name(search_file_name, log_ident);
-  else
-    name=0;					// Find first log
-
-  linfo.index_file_offset = 0;
-
-  if (mysql_bin_log.find_log_pos(&linfo, name, 1))
-  {
-    errmsg = "Could not find first log file name in binary log index file";
-    my_errno= ER_MASTER_FATAL_ERROR_READING_BINLOG;
-    goto err;
-  }
-
-  pthread_mutex_lock(&LOCK_thread_count);
-  thd->current_linfo = &linfo;
-  pthread_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.
-	*/
-
-	pthread_mutex_lock(log_lock);
-	switch (error= Log_event::read_log_event(&log, packet, (pthread_mutex_t*) 0)) {
-	case 0:
-	  /* we read successfully, so we'll need to send it to the slave */
-	  pthread_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)
-	  {
-	    pthread_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 != LL(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 != LL(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;
-                pthread_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);
-          pthread_mutex_unlock(log_lock);
-        }
-        break;
-            
-        default:
-	  pthread_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);
-      (void) my_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);
-  (void)my_close(file, MYF(MY_WME));
-
-  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
-  my_eof(thd);
-  thd_proc_info(thd, "Waiting to finalize termination");
-  pthread_mutex_lock(&LOCK_thread_count);
-  thd->current_linfo = 0;
-  pthread_mutex_unlock(&LOCK_thread_count);
-  DBUG_VOID_RETURN;
-
-err:
-  thd_proc_info(thd, "Waiting to finalize termination");
-  end_io_cache(&log);
-  RUN_HOOK(binlog_transmit, transmit_stop, (thd, flags));
-  /*
-    Exclude  iteration through thread list
-    this is needed for purge_logs() - it will iterate through
-    thread list and update thd->current_linfo->index_file_offset
-    this mutex will make sure that it never tried to update our linfo
-    after we return from this stack frame
-  */
-  pthread_mutex_lock(&LOCK_thread_count);
-  thd->current_linfo = 0;
-  pthread_mutex_unlock(&LOCK_thread_count);
-  if (file >= 0)
-    (void) my_close(file, MYF(MY_WME));
-
-  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->main_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,0,0,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)
-      {
-        pthread_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));
-        }
-
-        pthread_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->main_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,0,0,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 (my_stat(fname, &stat_area, MYF(0)) && my_delete(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 (my_stat(fname, &stat_area, MYF(0)) && my_delete(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 (pthread_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)
-{
-  pthread_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)
-    {
-      pthread_mutex_lock(&tmp->LOCK_thd_data);	// Lock from delete
-      break;
-    }
-  }
-  pthread_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);
-    pthread_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;
-  DBUG_ENTER("change_master");
-
-  lock_slave_threads(mi);
-  init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
-  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
-  if (thread_mask) // We refuse if any slave thread is running
-  {
-    my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
-    ret= TRUE;
-    goto err;
-  }
-
-  thd_proc_info(thd, "Changing master");
-  /* 
-    We need to check if there is an empty master_host. Otherwise
-    change master succeeds, a master.info file is created containing 
-    empty master_host string and when issuing: start slave; an error
-    is thrown stating that the server is not configured as slave.
-    (See BUG#28796).
-  */
-  if(lex_mi->host && !*lex_mi->host) 
-  {
-    my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST");
-    unlock_slave_threads(mi);
-    DBUG_RETURN(TRUE);
-  }
-  // TODO: see if needs re-write
-  if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
-		       thread_mask))
-  {
-    my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
-    ret= TRUE;
-    goto err;
-  }
-
-  /*
-    Data lock not needed since we have already stopped the running threads,
-    and we have the hold on the run locks which will keep all threads that
-    could possibly modify the data structures from running
-  */
-
-  /*
-    If the user specified host or port without binlog or position,
-    reset binlog's name to FIRST and position to 4.
-  */
-
-  if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
-  {
-    mi->master_log_name[0] = 0;
-    mi->master_log_pos= BIN_LOG_HEADER_SIZE;
-  }
-
-  if (lex_mi->log_file_name)
-    strmake(mi->master_log_name, lex_mi->log_file_name,
-	    sizeof(mi->master_log_name)-1);
-  if (lex_mi->pos)
-  {
-    mi->master_log_pos= lex_mi->pos;
-  }
-  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
-
-  if (lex_mi->host)
-    strmake(mi->host, lex_mi->host, sizeof(mi->host)-1);
-  if (lex_mi->user)
-    strmake(mi->user, lex_mi->user, sizeof(mi->user)-1);
-  if (lex_mi->password)
-    strmake(mi->password, lex_mi->password, sizeof(mi->password)-1);
-  if (lex_mi->port)
-    mi->port = lex_mi->port;
-  if (lex_mi->connect_retry)
-    mi->connect_retry = lex_mi->connect_retry;
-  if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
-    mi->heartbeat_period = lex_mi->heartbeat_period;
-  else
-    mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
-                                      (slave_net_timeout/2.0));
-  mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd
-  /*
-    reset the last time server_id list if the current CHANGE MASTER 
-    is mentioning IGNORE_SERVER_IDS= (...)
-  */
-  if (lex_mi->repl_ignore_server_ids_opt == LEX_MASTER_INFO::LEX_MI_ENABLE)
-    reset_dynamic(&mi->ignore_server_ids);
-  for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++)
-  {
-    ulong s_id;
-    get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i);
-    if (s_id == ::server_id && replicate_same_server_id)
-    {
-      my_error(ER_SLAVE_IGNORE_SERVER_IDS, MYF(0), s_id);
-      ret= TRUE;
-      goto err;
-    }
-    else
-    {
-      if (bsearch((const ulong *) &s_id,
-                  mi->ignore_server_ids.buffer,
-                  mi->ignore_server_ids.elements, sizeof(ulong),
-                  (int (*) (const void*, const void*))
-                  change_master_server_id_cmp) == NULL)
-        insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id);
-    }
-  }
-  sort_dynamic(&mi->ignore_server_ids, (qsort_cmp) change_master_server_id_cmp);
-
-  if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
-    mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
-
-  if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
-    mi->ssl_verify_server_cert=
-      (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
-
-  if (lex_mi->ssl_ca)
-    strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
-  if (lex_mi->ssl_capath)
-    strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1);
-  if (lex_mi->ssl_cert)
-    strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1);
-  if (lex_mi->ssl_cipher)
-    strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1);
-  if (lex_mi->ssl_key)
-    strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1);
-#ifndef HAVE_OPENSSL
-  if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
-      lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ||
-      lex_mi->ssl_verify_server_cert )
-    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
-                 ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS));
-#endif
-
-  if (lex_mi->relay_log_name)
-  {
-    need_relay_log_purge= 0;
-    char relay_log_name[FN_REFLEN];
-    mi->rli.relay_log.make_log_name(relay_log_name, lex_mi->relay_log_name);
-    strmake(mi->rli.group_relay_log_name, relay_log_name,
-	    sizeof(mi->rli.group_relay_log_name)-1);
-    strmake(mi->rli.event_relay_log_name, relay_log_name,
-	    sizeof(mi->rli.event_relay_log_name)-1);
-  }
-
-  if (lex_mi->relay_log_pos)
-  {
-    need_relay_log_purge= 0;
-    mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos;
-  }
-
-  /*
-    If user did specify neither host nor port nor any log name nor any log
-    pos, i.e. he specified only user/password/master_connect_retry, he probably
-    wants replication to resume from where it had left, i.e. from the
-    coordinates of the **SQL** thread (imagine the case where the I/O is ahead
-    of the SQL; restarting from the coordinates of the I/O would lose some
-    events which is probably unwanted when you are just doing minor changes
-    like changing master_connect_retry).
-    A side-effect is that if only the I/O thread was started, this thread may
-    restart from ''/4 after the CHANGE MASTER. That's a minor problem (it is a
-    much more unlikely situation than the one we are fixing here).
-    Note: coordinates of the SQL thread must be read here, before the
-    'if (need_relay_log_purge)' block which resets them.
-  */
-  if (!lex_mi->host && !lex_mi->port &&
-      !lex_mi->log_file_name && !lex_mi->pos &&
-      need_relay_log_purge)
-   {
-     /*
-       Sometimes mi->rli.master_log_pos == 0 (it happens when the SQL thread is
-       not initialized), so we use a max().
-       What happens to mi->rli.master_log_pos during the initialization stages
-       of replication is not 100% clear, so we guard against problems using
-       max().
-      */
-     mi->master_log_pos = max(BIN_LOG_HEADER_SIZE,
-			      mi->rli.group_master_log_pos);
-     strmake(mi->master_log_name, mi->rli.group_master_log_name,
-             sizeof(mi->master_log_name)-1);
-  }
-  /*
-    Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never
-    a slave before).
-  */
-  if (flush_master_info(mi, 0))
-  {
-    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;
-
-  pthread_mutex_lock(&mi->rli.data_lock);
-  mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
-  /* Clear the errors, for a clean start */
-  mi->rli.clear_error();
-  mi->rli.clear_until_condition();
-  /*
-    If we don't write new coordinates to disk now, then old will remain in
-    relay-log.info until START SLAVE is issued; but if mysqld is shutdown
-    before START SLAVE, then old will remain in relay-log.info, and will be the
-    in-memory value at restart (thus causing errors, as the old relay log does
-    not exist anymore).
-  */
-  flush_relay_log_info(&mi->rli);
-  pthread_cond_broadcast(&mi->data_cond);
-  pthread_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;
-  DBUG_ENTER("mysql_show_binlog_events");
-
-  Log_event::init_show_field_list(&field_list);
-  if (protocol->send_fields(&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;
-    pthread_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;
-    }
-
-    pthread_mutex_lock(&LOCK_thread_count);
-    thd->current_linfo = &linfo;
-    pthread_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;
-
-    pthread_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,(pthread_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,(pthread_mutex_t*) 0,
-                                         description_event)); )
-    {
-      if (event_count >= limit_start &&
-	  ev->net_send(protocol, linfo.log_file_name, pos))
-      {
-	errmsg = "Net error";
-	delete ev;
-	pthread_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";
-      pthread_mutex_unlock(log_lock);
-      goto err;
-    }
-
-    pthread_mutex_unlock(log_lock);
-  }
-
-  ret= FALSE;
-
-err:
-  delete description_event;
-  if (file >= 0)
-  {
-    end_io_cache(&log);
-    (void) my_close(file, MYF(MY_WME));
-  }
-
-  if (errmsg)
-    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
-             "SHOW BINLOG EVENTS", errmsg);
-  else
-    my_eof(thd);
-
-  pthread_mutex_lock(&LOCK_thread_count);
-  thd->current_linfo = 0;
-  pthread_mutex_unlock(&LOCK_thread_count);
-  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_fields(&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_fields(&field_list,
-                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
-    DBUG_RETURN(TRUE);
-  
-  pthread_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
-  pthread_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= my_open(fname, O_RDONLY | O_SHARE | O_BINARY,
-                         MYF(0))) >= 0)
-      {
-        file_length= (ulonglong) my_seek(file, 0L, MY_SEEK_END, MYF(0));
-        my_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_SYNC_POINT("debug_lock.created_file_event",10);
-    }
-  }
-  DBUG_RETURN(0);
-}
-
-/*
-  Replication System Variables
-*/
-
-class sys_var_slave_skip_counter :public sys_var
-{
-public:
-  sys_var_slave_skip_counter(sys_var_chain *chain, const char *name_arg)
-    :sys_var(name_arg)
-  { chain_sys_var(chain); }
-  bool check(THD *thd, set_var *var);
-  bool update(THD *thd, set_var *var);
-  bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
-  /*
-    We can't retrieve the value of this, so we don't have to define
-    type() or value_ptr()
-  */
-};
-
-class sys_var_sync_binlog_period :public sys_var_long_ptr
-{
-public:
-  sys_var_sync_binlog_period(sys_var_chain *chain, const char *name_arg, 
-                             ulong *value_ptr)
-    :sys_var_long_ptr(chain, name_arg,value_ptr) {}
-  bool update(THD *thd, set_var *var);
-};
-
-static void fix_slave_net_timeout(THD *thd, enum_var_type type)
-{
-  DBUG_ENTER("fix_slave_net_timeout");
-#ifdef HAVE_REPLICATION
-  pthread_mutex_lock(&LOCK_active_mi);
-  DBUG_PRINT("info",("slave_net_timeout=%lu mi->heartbeat_period=%.3f",
-                     slave_net_timeout,
-                     (active_mi? active_mi->heartbeat_period : 0.0)));
-  if (active_mi && slave_net_timeout < active_mi->heartbeat_period)
-    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
-                        ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE,
-                        "The currect value for master_heartbeat_period"
-                        " exceeds the new value of `slave_net_timeout' sec."
-                        " A sensible value for the period should be"
-                        " less than the timeout.");
-  pthread_mutex_unlock(&LOCK_active_mi);
-#endif
-  DBUG_VOID_RETURN;
-}
-
-static sys_var_chain vars = { NULL, NULL };
-
-static sys_var_const    sys_log_slave_updates(&vars, "log_slave_updates",
-                                              OPT_GLOBAL, SHOW_MY_BOOL,
-                                              (uchar*) &opt_log_slave_updates);
-static sys_var_const    sys_relay_log(&vars, "relay_log",
-                                      OPT_GLOBAL, SHOW_CHAR_PTR,
-                                      (uchar*) &opt_relay_logname);
-static sys_var_const    sys_relay_log_index(&vars, "relay_log_index",
-                                      OPT_GLOBAL, SHOW_CHAR_PTR,
-                                      (uchar*) &opt_relaylog_index_name);
-static sys_var_const    sys_relay_log_info_file(&vars, "relay_log_info_file",
-                                      OPT_GLOBAL, SHOW_CHAR_PTR,
-                                      (uchar*) &relay_log_info_file);
-static sys_var_bool_ptr	sys_relay_log_purge(&vars, "relay_log_purge",
-					    &relay_log_purge);
-static sys_var_bool_ptr sys_relay_log_recovery(&vars, "relay_log_recovery",
-                                               &relay_log_recovery);
-static sys_var_uint_ptr sys_sync_binlog_period(&vars, "sync_binlog",
-                                              &sync_binlog_period);
-static sys_var_uint_ptr sys_sync_relaylog_period(&vars, "sync_relay_log",
-                                                &sync_relaylog_period);
-static sys_var_uint_ptr sys_sync_relayloginfo_period(&vars, "sync_relay_log_info",
-                                                    &sync_relayloginfo_period);
-static sys_var_uint_ptr sys_sync_masterinfo_period(&vars, "sync_master_info",
-                                                  &sync_masterinfo_period);
-static sys_var_const    sys_relay_log_space_limit(&vars,
-                                                  "relay_log_space_limit",
-                                                  OPT_GLOBAL, SHOW_LONGLONG,
-                                                  (uchar*)
-                                                  &relay_log_space_limit);
-static sys_var_const    sys_slave_load_tmpdir(&vars, "slave_load_tmpdir",
-                                              OPT_GLOBAL, SHOW_CHAR_PTR,
-                                              (uchar*) &slave_load_tmpdir);
-static sys_var_long_ptr	sys_slave_net_timeout(&vars, "slave_net_timeout",
-					      &slave_net_timeout,
-                                              fix_slave_net_timeout);
-static sys_var_const    sys_slave_skip_errors(&vars, "slave_skip_errors",
-                                              OPT_GLOBAL, SHOW_CHAR,
-                                              (uchar*) slave_skip_error_names);
-static sys_var_long_ptr	sys_slave_trans_retries(&vars, "slave_transaction_retries",
-						&slave_trans_retries);
-static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter");
-
-
-bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
-{
-  int result= 0;
-  pthread_mutex_lock(&LOCK_active_mi);
-  pthread_mutex_lock(&active_mi->rli.run_lock);
-  if (active_mi->rli.slave_running)
-  {
-    my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
-    result=1;
-  }
-  pthread_mutex_unlock(&active_mi->rli.run_lock);
-  pthread_mutex_unlock(&LOCK_active_mi);
-  var->save_result.ulong_value= (ulong) var->value->val_int();
-  return result;
-}
-
-
-bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
-{
-  pthread_mutex_lock(&LOCK_active_mi);
-  pthread_mutex_lock(&active_mi->rli.run_lock);
-  /*
-    The following test should normally never be true as we test this
-    in the check function;  To be safe against multiple
-    SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
-  */
-  if (!active_mi->rli.slave_running)
-  {
-    pthread_mutex_lock(&active_mi->rli.data_lock);
-    active_mi->rli.slave_skip_counter= var->save_result.ulong_value;
-    pthread_mutex_unlock(&active_mi->rli.data_lock);
-  }
-  pthread_mutex_unlock(&active_mi->rli.run_lock);
-  pthread_mutex_unlock(&LOCK_active_mi);
-  return 0;
-}
-
-
-int init_replication_sys_vars()
-{
-  if (mysql_add_sys_var_chain(vars.first, my_long_options))
-  {
-    /* should not happen */
-    fprintf(stderr, "failed to initialize replication system variables");
-    unireg_abort(1);
-  }
-  return 0;
-}
-
-
-#endif /* HAVE_REPLICATION */

=== modified file 'sql/sql_repl.h'
--- a/sql/sql_repl.h	2009-09-23 21:32:31 +0000
+++ b/sql/sql_repl.h	2010-04-26 05:01:18 +0000
@@ -16,55 +16,16 @@
 #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;
+#include "sql_slave.h"
+#include "sql_master.h"
 
-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
+inline int init_replication_sys_vars()
 {
-  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();
+  return (init_master_sys_vars() ||
+          init_slave_sys_vars());
+}
 
 #endif /* HAVE_REPLICATION */
 

=== added file 'sql/sql_slave.cc'
--- a/sql/sql_slave.cc	1970-01-01 00:00:00 +0000
+++ b/sql/sql_slave.cc	2010-04-26 05:01:18 +0000
@@ -0,0 +1,738 @@
+/* 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_slave.h"
+
+#ifdef HAVE_REPLICATION
+
+/**
+  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->main_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,0,0,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)
+      {
+        pthread_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));
+        }
+
+        pthread_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->main_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,0,0,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 (my_stat(fname, &stat_area, MYF(0)) && my_delete(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 (my_stat(fname, &stat_area, MYF(0)) && my_delete(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);
+}
+
+/**
+  Execute a CHANGE MASTER statement.
+
+  @param thd Pointer to THD object for the client thread executing the
+  statement.
+
+  @param mi Pointer to Master_info object belonging to the slave's IO
+  thread.
+
+  @retval FALSE success
+  @retval TRUE error
+*/
+bool change_master(THD* thd, Master_info* mi)
+{
+  int thread_mask;
+  const char* errmsg= 0;
+  bool need_relay_log_purge= 1;
+  bool ret= FALSE;
+  DBUG_ENTER("change_master");
+
+  lock_slave_threads(mi);
+  init_thread_mask(&thread_mask,mi,0 /*not inverse*/);
+  LEX_MASTER_INFO* lex_mi= &thd->lex->mi;
+  if (thread_mask) // We refuse if any slave thread is running
+  {
+    my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
+    ret= TRUE;
+    goto err;
+  }
+
+  thd_proc_info(thd, "Changing master");
+  /* 
+    We need to check if there is an empty master_host. Otherwise
+    change master succeeds, a master.info file is created containing 
+    empty master_host string and when issuing: start slave; an error
+    is thrown stating that the server is not configured as slave.
+    (See BUG#28796).
+  */
+  if(lex_mi->host && !*lex_mi->host) 
+  {
+    my_error(ER_WRONG_ARGUMENTS, MYF(0), "MASTER_HOST");
+    unlock_slave_threads(mi);
+    DBUG_RETURN(TRUE);
+  }
+  // TODO: see if needs re-write
+  if (init_master_info(mi, master_info_file, relay_log_info_file, 0,
+		       thread_mask))
+  {
+    my_message(ER_MASTER_INFO, ER(ER_MASTER_INFO), MYF(0));
+    ret= TRUE;
+    goto err;
+  }
+
+  /*
+    Data lock not needed since we have already stopped the running threads,
+    and we have the hold on the run locks which will keep all threads that
+    could possibly modify the data structures from running
+  */
+
+  /*
+    If the user specified host or port without binlog or position,
+    reset binlog's name to FIRST and position to 4.
+  */
+
+  if ((lex_mi->host || lex_mi->port) && !lex_mi->log_file_name && !lex_mi->pos)
+  {
+    mi->master_log_name[0] = 0;
+    mi->master_log_pos= BIN_LOG_HEADER_SIZE;
+  }
+
+  if (lex_mi->log_file_name)
+    strmake(mi->master_log_name, lex_mi->log_file_name,
+	    sizeof(mi->master_log_name)-1);
+  if (lex_mi->pos)
+  {
+    mi->master_log_pos= lex_mi->pos;
+  }
+  DBUG_PRINT("info", ("master_log_pos: %lu", (ulong) mi->master_log_pos));
+
+  if (lex_mi->host)
+    strmake(mi->host, lex_mi->host, sizeof(mi->host)-1);
+  if (lex_mi->user)
+    strmake(mi->user, lex_mi->user, sizeof(mi->user)-1);
+  if (lex_mi->password)
+    strmake(mi->password, lex_mi->password, sizeof(mi->password)-1);
+  if (lex_mi->port)
+    mi->port = lex_mi->port;
+  if (lex_mi->connect_retry)
+    mi->connect_retry = lex_mi->connect_retry;
+  if (lex_mi->heartbeat_opt != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+    mi->heartbeat_period = lex_mi->heartbeat_period;
+  else
+    mi->heartbeat_period= (float) min(SLAVE_MAX_HEARTBEAT_PERIOD,
+                                      (slave_net_timeout/2.0));
+  mi->received_heartbeats= LL(0); // counter lives until master is CHANGEd
+  /*
+    reset the last time server_id list if the current CHANGE MASTER 
+    is mentioning IGNORE_SERVER_IDS= (...)
+  */
+  if (lex_mi->repl_ignore_server_ids_opt == LEX_MASTER_INFO::LEX_MI_ENABLE)
+    reset_dynamic(&mi->ignore_server_ids);
+  for (uint i= 0; i < lex_mi->repl_ignore_server_ids.elements; i++)
+  {
+    ulong s_id;
+    get_dynamic(&lex_mi->repl_ignore_server_ids, (uchar*) &s_id, i);
+    if (s_id == ::server_id && replicate_same_server_id)
+    {
+      my_error(ER_SLAVE_IGNORE_SERVER_IDS, MYF(0), s_id);
+      ret= TRUE;
+      goto err;
+    }
+    else
+    {
+      if (bsearch((const ulong *) &s_id,
+                  mi->ignore_server_ids.buffer,
+                  mi->ignore_server_ids.elements, sizeof(ulong),
+                  (int (*) (const void*, const void*))
+                  change_master_server_id_cmp) == NULL)
+        insert_dynamic(&mi->ignore_server_ids, (uchar*) &s_id);
+    }
+  }
+  sort_dynamic(&mi->ignore_server_ids, (qsort_cmp) change_master_server_id_cmp);
+
+  if (lex_mi->ssl != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+    mi->ssl= (lex_mi->ssl == LEX_MASTER_INFO::LEX_MI_ENABLE);
+
+  if (lex_mi->ssl_verify_server_cert != LEX_MASTER_INFO::LEX_MI_UNCHANGED)
+    mi->ssl_verify_server_cert=
+      (lex_mi->ssl_verify_server_cert == LEX_MASTER_INFO::LEX_MI_ENABLE);
+
+  if (lex_mi->ssl_ca)
+    strmake(mi->ssl_ca, lex_mi->ssl_ca, sizeof(mi->ssl_ca)-1);
+  if (lex_mi->ssl_capath)
+    strmake(mi->ssl_capath, lex_mi->ssl_capath, sizeof(mi->ssl_capath)-1);
+  if (lex_mi->ssl_cert)
+    strmake(mi->ssl_cert, lex_mi->ssl_cert, sizeof(mi->ssl_cert)-1);
+  if (lex_mi->ssl_cipher)
+    strmake(mi->ssl_cipher, lex_mi->ssl_cipher, sizeof(mi->ssl_cipher)-1);
+  if (lex_mi->ssl_key)
+    strmake(mi->ssl_key, lex_mi->ssl_key, sizeof(mi->ssl_key)-1);
+#ifndef HAVE_OPENSSL
+  if (lex_mi->ssl || lex_mi->ssl_ca || lex_mi->ssl_capath ||
+      lex_mi->ssl_cert || lex_mi->ssl_cipher || lex_mi->ssl_key ||
+      lex_mi->ssl_verify_server_cert )
+    push_warning(thd, MYSQL_ERROR::WARN_LEVEL_NOTE,
+                 ER_SLAVE_IGNORED_SSL_PARAMS, ER(ER_SLAVE_IGNORED_SSL_PARAMS));
+#endif
+
+  if (lex_mi->relay_log_name)
+  {
+    need_relay_log_purge= 0;
+    char relay_log_name[FN_REFLEN];
+    mi->rli.relay_log.make_log_name(relay_log_name, lex_mi->relay_log_name);
+    strmake(mi->rli.group_relay_log_name, relay_log_name,
+	    sizeof(mi->rli.group_relay_log_name)-1);
+    strmake(mi->rli.event_relay_log_name, relay_log_name,
+	    sizeof(mi->rli.event_relay_log_name)-1);
+  }
+
+  if (lex_mi->relay_log_pos)
+  {
+    need_relay_log_purge= 0;
+    mi->rli.group_relay_log_pos= mi->rli.event_relay_log_pos= lex_mi->relay_log_pos;
+  }
+
+  /*
+    If user did specify neither host nor port nor any log name nor any log
+    pos, i.e. he specified only user/password/master_connect_retry, he probably
+    wants replication to resume from where it had left, i.e. from the
+    coordinates of the **SQL** thread (imagine the case where the I/O is ahead
+    of the SQL; restarting from the coordinates of the I/O would lose some
+    events which is probably unwanted when you are just doing minor changes
+    like changing master_connect_retry).
+    A side-effect is that if only the I/O thread was started, this thread may
+    restart from ''/4 after the CHANGE MASTER. That's a minor problem (it is a
+    much more unlikely situation than the one we are fixing here).
+    Note: coordinates of the SQL thread must be read here, before the
+    'if (need_relay_log_purge)' block which resets them.
+  */
+  if (!lex_mi->host && !lex_mi->port &&
+      !lex_mi->log_file_name && !lex_mi->pos &&
+      need_relay_log_purge)
+   {
+     /*
+       Sometimes mi->rli.master_log_pos == 0 (it happens when the SQL thread is
+       not initialized), so we use a max().
+       What happens to mi->rli.master_log_pos during the initialization stages
+       of replication is not 100% clear, so we guard against problems using
+       max().
+      */
+     mi->master_log_pos = max(BIN_LOG_HEADER_SIZE,
+			      mi->rli.group_master_log_pos);
+     strmake(mi->master_log_name, mi->rli.group_master_log_name,
+             sizeof(mi->master_log_name)-1);
+  }
+  /*
+    Relay log's IO_CACHE may not be inited, if rli->inited==0 (server was never
+    a slave before).
+  */
+  if (flush_master_info(mi, 0))
+  {
+    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;
+
+  pthread_mutex_lock(&mi->rli.data_lock);
+  mi->rli.abort_pos_wait++; /* for MASTER_POS_WAIT() to abort */
+  /* Clear the errors, for a clean start */
+  mi->rli.clear_error();
+  mi->rli.clear_until_condition();
+  /*
+    If we don't write new coordinates to disk now, then old will remain in
+    relay-log.info until START SLAVE is issued; but if mysqld is shutdown
+    before START SLAVE, then old will remain in relay-log.info, and will be the
+    in-memory value at restart (thus causing errors, as the old relay log does
+    not exist anymore).
+  */
+  flush_relay_log_info(&mi->rli);
+  pthread_cond_broadcast(&mi->data_cond);
+  pthread_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);
+}
+
+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 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)
+{
+  DBUG_ENTER("mysql_show_relaylog_events");
+  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
+  if (!active_mi)
+    DBUG_RETURN(TRUE);
+  DBUG_RETURN(show_binlog_events(thd, &(active_mi->rli.relay_log)));
+}
+
+/*
+  Replication System Variables
+*/
+
+class sys_var_slave_skip_counter :public sys_var
+{
+public:
+  sys_var_slave_skip_counter(sys_var_chain *chain, const char *name_arg)
+    :sys_var(name_arg)
+  { chain_sys_var(chain); }
+  bool check(THD *thd, set_var *var);
+  bool update(THD *thd, set_var *var);
+  bool check_type(enum_var_type type) { return type != OPT_GLOBAL; }
+  /*
+    We can't retrieve the value of this, so we don't have to define
+    type() or value_ptr()
+  */
+};
+
+static void fix_slave_net_timeout(THD *thd, enum_var_type type)
+{
+  DBUG_ENTER("fix_slave_net_timeout");
+#ifdef HAVE_REPLICATION
+  pthread_mutex_lock(&LOCK_active_mi);
+  DBUG_PRINT("info",("slave_net_timeout=%lu mi->heartbeat_period=%.3f",
+                     slave_net_timeout,
+                     (active_mi? active_mi->heartbeat_period : 0.0)));
+  if (active_mi && slave_net_timeout < active_mi->heartbeat_period)
+    push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
+                        ER_SLAVE_HEARTBEAT_VALUE_OUT_OF_RANGE,
+                        "The currect value for master_heartbeat_period"
+                        " exceeds the new value of `slave_net_timeout' sec."
+                        " A sensible value for the period should be"
+                        " less than the timeout.");
+  pthread_mutex_unlock(&LOCK_active_mi);
+#endif
+  DBUG_VOID_RETURN;
+}
+
+static sys_var_chain vars = { NULL, NULL };
+static sys_var_const    sys_log_slave_updates(&vars, "log_slave_updates",
+                                              OPT_GLOBAL, SHOW_MY_BOOL,
+                                              (uchar*) &opt_log_slave_updates);
+static sys_var_const    sys_relay_log(&vars, "relay_log",
+                                      OPT_GLOBAL, SHOW_CHAR_PTR,
+                                      (uchar*) &opt_relay_logname);
+static sys_var_const    sys_relay_log_index(&vars, "relay_log_index",
+                                      OPT_GLOBAL, SHOW_CHAR_PTR,
+                                      (uchar*) &opt_relaylog_index_name);
+static sys_var_const    sys_relay_log_info_file(&vars, "relay_log_info_file",
+                                      OPT_GLOBAL, SHOW_CHAR_PTR,
+                                      (uchar*) &relay_log_info_file);
+static sys_var_bool_ptr	sys_relay_log_purge(&vars, "relay_log_purge",
+					    &relay_log_purge);
+static sys_var_bool_ptr sys_relay_log_recovery(&vars, "relay_log_recovery",
+                                               &relay_log_recovery);
+static sys_var_uint_ptr sys_sync_relaylog_period(&vars, "sync_relay_log",
+                                                &sync_relaylog_period);
+static sys_var_uint_ptr sys_sync_relayloginfo_period(&vars, "sync_relay_log_info",
+                                                    &sync_relayloginfo_period);
+static sys_var_uint_ptr sys_sync_masterinfo_period(&vars, "sync_master_info",
+                                                  &sync_masterinfo_period);
+static sys_var_const    sys_relay_log_space_limit(&vars,
+                                                  "relay_log_space_limit",
+                                                  OPT_GLOBAL, SHOW_LONGLONG,
+                                                  (uchar*)
+                                                  &relay_log_space_limit);
+static sys_var_const    sys_slave_load_tmpdir(&vars, "slave_load_tmpdir",
+                                              OPT_GLOBAL, SHOW_CHAR_PTR,
+                                              (uchar*) &slave_load_tmpdir);
+static sys_var_long_ptr	sys_slave_net_timeout(&vars, "slave_net_timeout",
+					      &slave_net_timeout,
+                                              fix_slave_net_timeout);
+static sys_var_const    sys_slave_skip_errors(&vars, "slave_skip_errors",
+                                              OPT_GLOBAL, SHOW_CHAR,
+                                              (uchar*) slave_skip_error_names);
+static sys_var_long_ptr	sys_slave_trans_retries(&vars, "slave_transaction_retries",
+						&slave_trans_retries);
+static sys_var_slave_skip_counter sys_slave_skip_counter(&vars, "sql_slave_skip_counter");
+
+bool sys_var_slave_skip_counter::check(THD *thd, set_var *var)
+{
+  int result= 0;
+  pthread_mutex_lock(&LOCK_active_mi);
+  pthread_mutex_lock(&active_mi->rli.run_lock);
+  if (active_mi->rli.slave_running)
+  {
+    my_message(ER_SLAVE_MUST_STOP, ER(ER_SLAVE_MUST_STOP), MYF(0));
+    result=1;
+  }
+  pthread_mutex_unlock(&active_mi->rli.run_lock);
+  pthread_mutex_unlock(&LOCK_active_mi);
+  var->save_result.ulong_value= (ulong) var->value->val_int();
+  return result;
+}
+
+
+bool sys_var_slave_skip_counter::update(THD *thd, set_var *var)
+{
+  pthread_mutex_lock(&LOCK_active_mi);
+  pthread_mutex_lock(&active_mi->rli.run_lock);
+  /*
+    The following test should normally never be true as we test this
+    in the check function;  To be safe against multiple
+    SQL_SLAVE_SKIP_COUNTER request, we do the check anyway
+  */
+  if (!active_mi->rli.slave_running)
+  {
+    pthread_mutex_lock(&active_mi->rli.data_lock);
+    active_mi->rli.slave_skip_counter= var->save_result.ulong_value;
+    pthread_mutex_unlock(&active_mi->rli.data_lock);
+  }
+  pthread_mutex_unlock(&active_mi->rli.run_lock);
+  pthread_mutex_unlock(&LOCK_active_mi);
+  return 0;
+}
+
+int init_slave_sys_vars()
+{
+  if (mysql_add_sys_var_chain(vars.first, my_long_options))
+  {
+    /* should not happen */
+    fprintf(stderr, "failed to initialize replication slave system variables");
+    unireg_abort(1);
+  }
+  return 0;
+}
+#endif /* HAVE_REPLICATION */

=== added file 'sql/sql_slave.h'
--- a/sql/sql_slave.h	1970-01-01 00:00:00 +0000
+++ b/sql/sql_slave.h	2010-04-26 05:01:18 +0000
@@ -0,0 +1,48 @@
+/* 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 */
+
+
+#ifndef RPL_SLAVE_H
+#define RPL_SLAVE_H
+
+#include <mysql_priv.h>
+#include <my_global.h>
+#include <my_pthread.h>
+#include <my_dir.h>
+#include "binlog.h"
+#include "slave.h"
+#include "rpl_rli.h"
+#include "rpl_mi.h"
+#include "rpl_filter.h"
+#include "rpl_handler.h"
+
+#ifdef HAVE_REPLICATION
+
+extern my_bool opt_show_slave_auth_info;
+extern char *master_host, *master_info_file;
+
+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);
+extern int init_master_info(Master_info* mi);
+int check_binlog_magic(IO_CACHE* log, const char** errmsg);
+bool mysql_show_relaylog_events(THD* thd);
+int init_slave_sys_vars();
+
+#endif /* HAVE_REPLICATION */
+#endif /* RPL_SLAVE_H */


Attachment: [text/bzr-bundle] bzr/zhenxing.he@sun.com-20100426050118-hq4k7hsa1xfxwy7n.bundle
Thread
bzr commit into mysql-5.1-rep+2 branch (zhenxing.he:3185) WL#3662He Zhenxing26 Apr