List:Commits« Previous MessageNext Message »
From:Luís Soares Date:May 13 2010 2:04pm
Subject:Re: bzr commit into mysql-trunk-bugfixing branch (zhenxing.he:3037)
WL#5385
View as plain text  
Hi Zhenxing,

  I am mostly ok with the incremental changes.
  I was a bit skeptical about moving the 
decide_logging_format into binlog.cc, but I guess it
makes sense to keep it a bit disconnected from the rest
of the server core.

  I was also a bit skeptical about splitting the
mysql_show_binlog_events, but I guess there is a need
for it.

  I did not build this, I guess that your changes are good
for both: cmake and autotools...

  Patch approved. 

  Now we "just" need to break down the inter-module 
dependencies...

Regards,
Luís

  

On Thu, 2010-05-13 at 05:54 +0000, He Zhenxing wrote:
> #At file:///media/sdb2/hezx/work/mysql/bzrwork/w3662/trunk-bugfixing/ based on
> revid:zhenxing.he@stripped
> 
>  3037 He Zhenxing	2010-05-13
>       WL#5385 Refactoring: Split replication into libraries
>       
>       Incremental patch based on previous patch.
>       
>       - orgnized functions in binlog.cc
>       - removed sql_repl.h, added master.h move code to slave.h and
>         master.h correspondly
>       - split mysql_show_binlog_events, add mysql_show_relaylog_events
>         and show_binlog_events.
>      @ sql/Makefile.am
>         Added master.h
>      @ sql/binlog.cc
>         moved binlog related code from sql_class.cc to binlog.cc
>      @ sql/master.h
>         Added master.h
>      @ sql/rpl_rli.cc
>         added mysql_show_relaylog_events
>      @ sql/rpl_rli.h
>         moved some relay log related functions delaration here  from slave.h
>      @ sql/slave.h
>         moved slave related declarations from sql_repl.h
>      @ sql/sql_class.cc
>         Moved binlog related code to binlog.cc
>         Moved definition of Discrete_intervals_list::append to structs.h
>      @ sql/sql_parse.cc
>         use mysql_show_relaylog_events for SHOW RELAYLOG EVENTS command
>      @ sql/structs.h
>         Moved definition of Discrete_intervals_list::append from sql_class.cc
> 
>     removed:
>       sql/sql_repl.h
>     added:
>       sql/master.h
>     modified:
>       sql/Makefile.am
>       sql/binlog.cc
>       sql/binlog.h
>       sql/log.h
>       sql/master.cc
>       sql/mysqld.cc
>       sql/repl_failsafe.cc
>       sql/rpl_handler.cc
>       sql/rpl_rli.cc
>       sql/rpl_rli.h
>       sql/slave.cc
>       sql/slave.h
>       sql/sql_class.cc
>       sql/sql_load.cc
>       sql/sql_parse.cc
>       sql/structs.h
> === modified file 'sql/Makefile.am'
> --- a/sql/Makefile.am	2010-05-08 02:34:04 +0000
> +++ b/sql/Makefile.am	2010-05-13 05:54:26 +0000
> @@ -109,7 +109,7 @@ noinst_HEADERS =	item.h item_func.h item
>  			sql_derived.h sql_load.h sql_handler.h init.h \
>  			derror.h sql_union.h des_key_file.h sql_binlog.h \
>  			discover.h sql_manager.h sql_do.h \
> -			sql_repl.h slave.h rpl_filter.h rpl_injector.h \
> +			sql_repl.h slave.h master.h  rpl_filter.h rpl_injector.h \
>  			log_event.h rpl_record.h sql_const.h \
>  			log_event_old.h rpl_record_old.h \
>  			sql_sort.h sql_cache.h set_var.h sys_vars_shared.h \
> 
> === modified file 'sql/binlog.cc'
> --- a/sql/binlog.cc	2010-05-08 02:34:04 +0000
> +++ b/sql/binlog.cc	2010-05-13 05:54:26 +0000
> @@ -20,7 +20,6 @@
>  #include "log_event.h"
>  #include "rpl_filter.h"
>  #include "rpl_rli.h"
> -#include "sql_repl.h"
>  #include "sql_plugin.h"
>  #include "rpl_handler.h"
>  
> @@ -31,6 +30,10 @@ handlerton *binlog_hton;
>  
>  MYSQL_BIN_LOG mysql_bin_log(&sync_binlog_period);
>  
> +static bool purge_error_message(THD* thd, int res);
> +static void adjust_linfo_offsets(my_off_t purge_offset);
> +static bool log_in_use(const char* log_name);
> +
>  static int binlog_init(void *p);
>  static int binlog_close_connection(handlerton *hton, THD *thd);
>  static int binlog_savepoint_set(handlerton *hton, THD *thd, void *sv);
> @@ -295,7 +298,7 @@ binlog_trans_log_truncate(THD *thd, my_o
>    should be moved here.
>  */
>  
> -int binlog_init(void *p)
> +static int binlog_init(void *p)
>  {
>    binlog_hton= (handlerton *)p;
>    binlog_hton->state=opt_bin_log ? SHOW_OPTION_YES : SHOW_OPTION_NO;
> @@ -655,23 +658,6 @@ static int binlog_rollback(handlerton *h
>    DBUG_RETURN(error);
>  }
>  
> -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;
> -}
> -
>  /**
>    @note
>    How do we handle this (unlikely but legal) case:
> @@ -735,6 +721,97 @@ static int binlog_savepoint_rollback(han
>  }
>  
> 
> +/*
> +  Adjust the position pointer in the binary log file for all running slaves
> +
> +  SYNOPSIS
> +    adjust_linfo_offsets()
> +    purge_offset	Number of bytes removed from start of log index file
> +
> +  NOTES
> +    - This is called when doing a PURGE when we delete lines from the
> +      index log file
> +
> +  REQUIREMENTS
> +    - Before calling this function, we have to ensure that no threads are
> +      using any binary log file before purge_offset.a
> +
> +  TODO
> +    - Inform the slave threads that they should sync the position
> +      in the binary log file with flush_relay_log_info.
> +      Now they sync is done for next read.
> +*/
> +
> +static void adjust_linfo_offsets(my_off_t purge_offset)
> +{
> +  THD *tmp;
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  I_List_iterator<THD> it(threads);
> +
> +  while ((tmp=it++))
> +  {
> +    LOG_INFO* linfo;
> +    if ((linfo = tmp->current_linfo))
> +    {
> +      mysql_mutex_lock(&linfo->lock);
> +      /*
> +	Index file offset can be less that purge offset only if
> +	we just started reading the index file. In that case
> +	we have nothing to adjust
> +      */
> +      if (linfo->index_file_offset < purge_offset)
> +	linfo->fatal = (linfo->index_file_offset != 0);
> +      else
> +	linfo->index_file_offset -= purge_offset;
> +      mysql_mutex_unlock(&linfo->lock);
> +    }
> +  }
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +}
> +
> +
> +static bool log_in_use(const char* log_name)
> +{
> +  size_t log_name_len = strlen(log_name) + 1;
> +  THD *tmp;
> +  bool result = 0;
> +
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  I_List_iterator<THD> it(threads);
> +
> +  while ((tmp=it++))
> +  {
> +    LOG_INFO* linfo;
> +    if ((linfo = tmp->current_linfo))
> +    {
> +      mysql_mutex_lock(&linfo->lock);
> +      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
> +                     log_name_len);
> +      mysql_mutex_unlock(&linfo->lock);
> +      if (result)
> +	break;
> +    }
> +  }
> +
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  return result;
> +}
> +
> +static bool purge_error_message(THD* thd, int res)
> +{
> +  uint errcode;
> +
> +  if ((errcode= purge_log_get_error_code(res)) != 0)
> +  {
> +    my_message(errcode, ER(errcode), MYF(0));
> +    return TRUE;
> +  }
> +  my_ok(thd);
> +  return FALSE;
> +}
> +
> +
>  int check_binlog_magic(IO_CACHE* log, const char** errmsg)
>  {
>    char magic[4];
> @@ -791,3000 +868,4229 @@ err:
>    DBUG_RETURN(-1);
>  }
>  
> -bool MYSQL_BIN_LOG::check_write_error(THD *thd)
> +/** 
> +  This function checks if a transactional table was updated by the
> +  current transaction.
> +
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a transactional table was updated, @c false otherwise.
> +*/
> +bool
> +trans_has_updated_trans_table(const THD* thd)
>  {
> -  DBUG_ENTER("MYSQL_BIN_LOG::check_write_error");
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
>  
> -  bool checked= FALSE;
> +  return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
> +}
>  
> -  if (!thd->is_error())
> -    DBUG_RETURN(checked);
> +/** 
> +  This function checks if a transactional table was updated by the
> +  current statement.
>  
> -  switch (thd->stmt_da->sql_errno())
> +  @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())
>    {
> -    case ER_TRANS_CACHE_FULL:
> -    case ER_ERROR_ON_WRITE:
> -    case ER_BINLOG_LOGGING_IMPOSSIBLE:
> -      checked= TRUE;
> -    break;
> +    if (ha_info->is_trx_read_write() && ha_info->ht() != binlog_hton)
> +      return (TRUE);
>    }
> -
> -  DBUG_RETURN(checked);
> +  return (FALSE);
>  }
>  
> -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 function checks if either a trx-cache or a non-trx-cache should
> +  be used. If @c bin_log_direct_non_trans_update is active or the format
> +  is either MIXED or ROW, the cache to be used depends on the flag @c
> +  is_transactional. 
>  
> -/* this is called only once */
> +  On the other hand, if binlog_format is STMT or direct option is
> +  OFF, the trx-cache should be used if and only if the statement is
> +  transactional or the trx-cache is not empty. Otherwise, the
> +  non-trx-cache should be used.
>  
> -void MYSQL_BIN_LOG::cleanup()
> +  @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)
>  {
> -  DBUG_ENTER("cleanup");
> -  if (inited)
> -  {
> -    inited= 0;
> -    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
> -    delete description_event_for_queue;
> -    delete description_event_for_exec;
> -    mysql_mutex_destroy(&LOCK_log);
> -    mysql_mutex_destroy(&LOCK_index);
> -    mysql_cond_destroy(&update_cond);
> -  }
> -  DBUG_VOID_RETURN;
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +  return
> +    ((thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
> +     thd->variables.binlog_direct_non_trans_update) ? is_transactional :
> +     (is_transactional || !cache_mngr->trx_cache.empty()));
>  }
>  
> +/**
> +  This function checks if a transaction, either a multi-statement
> +  or a single statement transaction is about to commit or not.
>  
> -/* Init binlog-specific vars */
> -void MYSQL_BIN_LOG::init(bool no_auto_events_arg, ulong max_size_arg)
> +  @param thd The client thread that executed the current statement.
> +  @param all Committing a transaction (i.e. TRUE) or a statement
> +             (i.e. FALSE).
> +  @return
> +    @c true if committing a transaction, otherwise @c false.
> +*/
> +bool ending_trans(THD* thd, const bool all)
>  {
> -  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;
> +  return (all || (!all && !thd->in_multi_stmt_transaction()));
>  }
>  
> +/**
> +  This function checks if a non-transactional table was updated by
> +  the current transaction.
>  
> -void MYSQL_BIN_LOG::init_pthread_objects()
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a non-transactional table was updated, @c false
> +    otherwise.
> +*/
> +bool trans_has_updated_non_trans_table(const THD* thd)
>  {
> -  DBUG_ASSERT(inited == 0);
> -  inited= 1;
> -  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> -  mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
> -  mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0);
> +  return (thd->transaction.all.modified_non_trans_table ||
> +          thd->transaction.stmt.modified_non_trans_table);
>  }
>  
> +/**
> +  This function checks if a non-transactional table was updated by the
> +  current statement.
>  
> -bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
> -                                    const char *log_name, bool need_mutex)
> +  @param thd The client thread that executed the current statement.
> +  @return
> +    @c true if a non-transactional table was updated, @c false otherwise.
> +*/
> +bool stmt_has_updated_non_trans_table(const THD* thd)
>  {
> -  File index_file_nr= -1;
> -  DBUG_ASSERT(!my_b_inited(&index_file));
> +  return (thd->transaction.stmt.modified_non_trans_table);
> +}
>  
> -  /*
> -    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)
> +#ifndef EMBEDDED_LIBRARY
> +/**
> +  Execute a PURGE BINARY LOGS TO <log> command.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @param to_log Name of the last log to purge.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool purge_master_logs(THD* thd, const char* to_log)
> +{
> +  char search_file_name[FN_REFLEN];
> +  if (!mysql_bin_log.is_open())
>    {
> -    index_file_name_arg= log_name;    // Use same basename for index file
> -    opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
> +    my_ok(thd);
> +    return FALSE;
>    }
> -  fn_format(index_file_name, index_file_name_arg, mysql_data_home,
> -            ".index", opt);
> -  if ((index_file_nr= mysql_file_open(key_file_binlog_index,
> -                                      index_file_name,
> -                                      O_RDWR | O_CREAT | O_BINARY,
> -                                      MYF(MY_WME))) < 0 ||
> -       mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
> -       init_io_cache(&index_file, index_file_nr,
> -                     IO_SIZE, WRITE_CACHE,
> -                     mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
> -                                     0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
> -      DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
> +
> +  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())
>    {
> -    /*
> -      TODO: all operations creating/deleting the index file or a log, should
> -      call my_sync_dir() or my_sync_dir_by_file() to be durable.
> -      TODO: file creation should be done with mysql_file_create()
> -      not mysql_file_open().
> -    */
> -    if (index_file_nr >= 0)
> -      mysql_file_close(index_file_nr, MYF(0));
> -    return TRUE;
> +    my_ok(thd);
> +    return 0;
>    }
> +  return purge_error_message(thd,
> +                             mysql_bin_log.purge_logs_before_date(purge_time));
> +}
> +#endif /* EMBEDDED_LIBRARY */
>  
> -#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.
> -  */
> +/*
> +  Helper function to get the error code of the query to be binlogged.
> + */
> +int query_error_code(THD *thd, bool not_killed)
> +{
> +  int error;
> +  
> +  if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
> +  {
> +    error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
>  
> -  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))
> +    /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or
> +       ER_QUERY_INTERRUPTED, So here we need to make sure that error
> +       is not set to these errors when specified not_killed by the
> +       caller.
> +    */
> +    if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED)
> +      error= 0;
> +  }
> +  else
>    {
> -    sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
> -                    "file.");
> -    return TRUE;
> +    /* killed status for DELAYED INSERT thread should never be used */
> +    DBUG_ASSERT(!(thd->system_thread & SYSTEM_THREAD_DELAYED_INSERT));
> +    error= thd->killed_errno();
>    }
> -#endif
>  
> -  return FALSE;
> +  return error;
>  }
>  
> 
>  /**
> -  Open a (new) binlog file.
> +  Move all data up in a file in an filename index 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.
> +    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
> -  @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;
> +#ifdef HAVE_REPLICATION
>  
> -  DBUG_ENTER("MYSQL_BIN_LOG::open");
> -  DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
> +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");
>  
> -  if (init_and_set_log_file_name(log_name, new_name, log_type_arg,
> -                                 io_cache_type_arg))
> +  for (;; offset+= bytes_read)
>    {
> -    sql_print_error("MSYQL_BIN_LOG::open failed to generate new file name.");
> -    DBUG_RETURN(1);
> +    mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0));
> +    if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf),
> +                                           MYF(MY_WME)))
> +	< 0)
> +      goto err;
> +    if (!bytes_read)
> +      break;					// end of file
> +    mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
> +    if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
> +      goto err;
>    }
> +  /* The following will either truncate the file or fill the end with \n' */
> +  if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
> +      mysql_file_sync(file, MYF(MY_WME)))
> +    goto err;
>  
> -#ifdef HAVE_REPLICATION
> -  if (open_purge_index_file(TRUE) ||
> -      register_create_index_entry(log_file_name) ||
> -      sync_purge_index_file() ||
> -      DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
> -    DBUG_RETURN(1);
> -  }
> -  DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_ABORT(););
> -#endif
> +  /* Reset data in old index cache */
> +  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
> +  DBUG_RETURN(0);
>  
> -  write_error= 0;
> +err:
> +  DBUG_RETURN(1);
> +}
>  
> -  /* 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 */
> +/**
> +   Load data's io cache specific hook to be executed
> +   before a chunk of data is being read into the cache's buffer
> +   The fuction instantianates and writes into the binlog
> +   replication events along LOAD DATA processing.
> +   
> +   @param file  pointer to io-cache
> +   @retval 0 success
> +   @retval 1 failure
> +*/
> +int log_loaded_block(IO_CACHE* file)
> +{
> +  DBUG_ENTER("log_loaded_block");
> +  LOAD_FILE_INFO *lf_info;
> +  uint block_len;
> +  /* buffer contains position where we started last read */
> +  uchar* buffer= (uchar*) my_b_get_buffer_start(file);
> +  uint max_event_size= current_thd->variables.max_allowed_packet;
> +  lf_info= (LOAD_FILE_INFO*) file->arg;
> +  if (lf_info->thd->is_current_stmt_binlog_format_row())
> +    DBUG_RETURN(0);
> +  if (lf_info->last_pos_in_file != HA_POS_ERROR &&
> +      lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
> +    DBUG_RETURN(0);
> +  
> +  for (block_len= (uint) (my_b_get_bytes_in_buffer(file)); block_len > 0;
> +       buffer += min(block_len, max_event_size),
> +       block_len -= min(block_len, max_event_size))
> +  {
> +    lf_info->last_pos_in_file= my_b_get_pos_in_file(file);
> +    if (lf_info->wrote_create_file)
> +    {
> +      Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
> +                               min(block_len, max_event_size),
> +                               lf_info->log_delayed);
> +      if (mysql_bin_log.write(&a))
> +        DBUG_RETURN(1);
> +    }
> +    else
> +    {
> +      Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
> +                                   buffer,
> +                                   min(block_len, max_event_size),
> +                                   lf_info->log_delayed);
> +      if (mysql_bin_log.write(&b))
> +        DBUG_RETURN(1);
> +      lf_info->wrote_create_file= 1;
> +    }
>    }
> +  DBUG_RETURN(0);
> +}
>  
> -  init(no_auto_events_arg, max_size_arg);
> +/* Helper function for SHOW BINLOG/RELAYLOG EVENTS */
> +bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log)
> +{
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  const char *errmsg = 0;
> +  bool ret = TRUE;
> +  IO_CACHE log;
> +  File file = -1;
> +  DBUG_ENTER("show_binlog_events");
> +
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
> +              thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
> +
> +  Format_description_log_event *description_event= new
> +    Format_description_log_event(3); /* MySQL 4.0 by default */
> +
> +  if (binary_log->is_open())
> +  {
> +    LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
> +    SELECT_LEX_UNIT *unit= &thd->lex->unit;
> +    ha_rows event_count, limit_start, limit_end;
> +    my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
> +    char search_file_name[FN_REFLEN], *name;
> +    const char *log_file_name = lex_mi->log_file_name;
> +    mysql_mutex_t *log_lock = binary_log->get_log_lock();
> +    LOG_INFO linfo;
> +    Log_event* ev;
> +
> +    unit->set_limit(thd->lex->current_select);
> +    limit_start= unit->offset_limit_cnt;
> +    limit_end= unit->select_limit_cnt;
> +
> +    name= search_file_name;
> +    if (log_file_name)
> +      binary_log->make_log_name(search_file_name, log_file_name);
> +    else
> +      name=0;					// Find first log
>  
> -  open_count++;
> +    linfo.index_file_offset = 0;
>  
> -  DBUG_ASSERT(log_type == LOG_BIN);
> +    if (binary_log->find_log_pos(&linfo, name, 1))
> +    {
> +      errmsg = "Could not find target log";
> +      goto err;
> +    }
>  
> -  {
> -    bool write_file_name_to_index_file=0;
> +    mysql_mutex_lock(&LOCK_thread_count);
> +    thd->current_linfo = &linfo;
> +    mysql_mutex_unlock(&LOCK_thread_count);
>  
> -    if (!my_b_filelength(&log_file))
> +    if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
> +      goto err;
> +
> +    /*
> +      to account binlog event header size
> +    */
> +    thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER;
> +
> +    mysql_mutex_lock(log_lock);
> +
> +    /*
> +      open_binlog() sought to position 4.
> +      Read the first event in case it's a Format_description_log_event, to
> +      know the format. If there's no such event, we are 3.23 or 4.x. This
> +      code, like before, can't read 3.23 binlogs.
> +      This code will fail on a mixed relay log (one which has Format_desc then
> +      Rotate then Format_desc).
> +    */
> +    ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event);
> +    if (ev)
>      {
> -      /*
> -	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 (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
> +      {
> +        delete description_event;
> +        description_event= (Format_description_log_event*) ev;
> +      }
> +      else
> +        delete ev;
>      }
>  
> -    if (need_start_event && !no_auto_events)
> +    my_b_seek(&log, pos);
> +
> +    if (!description_event->is_valid())
>      {
> -      /*
> -        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;
> +      errmsg="Invalid Format_description event; could be out of memory";
> +      goto err;
>      }
> -    if (description_event_for_queue &&
> -        description_event_for_queue->binlog_version>=4)
> +
> +    for (event_count = 0;
> +         (ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
> +                                         description_event)); )
>      {
> -      /*
> -        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 (event_count >= limit_start &&
> +	  ev->net_send(protocol, linfo.log_file_name, pos))
> +      {
> +	errmsg = "Net error";
> +	delete ev;
> +        mysql_mutex_unlock(log_lock);
> +	goto err;
> +      }
>  
> -      if (description_event_for_queue->write(&log_file))
> -        goto err;
> -      bytes_written+= description_event_for_queue->data_written;
> +      pos = my_b_tell(&log);
> +      delete ev;
> +
> +      if (++event_count >= limit_end)
> +	break;
>      }
> -    if (flush_io_cache(&log_file) ||
> -        mysql_file_sync(log_file.file, MYF(MY_WME)))
> -      goto err;
>  
> -    if (write_file_name_to_index_file)
> +    if (event_count < limit_end && log.error)
>      {
> -#ifdef HAVE_REPLICATION
> -      DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_ABORT(););
> -#endif
> -
> -      DBUG_ASSERT(my_b_inited(&index_file) != 0);
> -      reinit_io_cache(&index_file, WRITE_CACHE,
> -                      my_b_filelength(&index_file), 0, 0);
> -      /*
> -        As this is a new log file, we write the file name to the index
> -        file. As every time we write to the index file, we sync it.
> -      */
> -      if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
> -          my_b_write(&index_file, (uchar*) log_file_name,
> -                     strlen(log_file_name)) ||
> -          my_b_write(&index_file, (uchar*) "\n", 1) ||
> -          flush_io_cache(&index_file) ||
> -          mysql_file_sync(index_file.file, MYF(MY_WME)))
> -        goto err;
> -
> -#ifdef HAVE_REPLICATION
> -      DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_ABORT(););
> -#endif
> +      errmsg = "Wrong offset or I/O error";
> +      mysql_mutex_unlock(log_lock);
> +      goto err;
>      }
> -  }
> -  log_state= LOG_OPENED;
>  
> -#ifdef HAVE_REPLICATION
> -  close_purge_index_file();
> -#endif
> +    mysql_mutex_unlock(log_lock);
> +  }
>  
> -  DBUG_RETURN(0);
> +  ret= FALSE;
>  
>  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);
> +  delete description_event;
>    if (file >= 0)
> -    mysql_file_close(file, MYF(0));
> -  end_io_cache(&log_file);
> -  end_io_cache(&index_file);
> -  safeFree(name);
> -  log_state= LOG_CLOSED;
> -  DBUG_RETURN(1);
> -}
> -
> +  {
> +    end_io_cache(&log);
> +    mysql_file_close(file, MYF(MY_WME));
> +  }
>  
> -int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
> -{
> -  mysql_mutex_lock(&LOCK_log);
> -  int ret = raw_get_current_log(linfo);
> -  mysql_mutex_unlock(&LOCK_log);
> -  return ret;
> -}
> +  if (errmsg)
> +    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
> +             "SHOW BINLOG EVENTS", errmsg);
> +  else
> +    my_eof(thd);
>  
> -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;
> +  mysql_mutex_lock(&LOCK_thread_count);
> +  thd->current_linfo = 0;
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  DBUG_RETURN(ret);
>  }
>  
>  /**
> -  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
> +  Execute a SHOW BINLOG EVENTS statement.
>  
> -  @note
> -    File will be truncated to be 'offset' shorter or filled up with newlines
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
>  
> -  @retval
> -    0	ok
> +  @retval FALSE success
> +  @retval TRUE failure
>  */
> -
> -#ifdef HAVE_REPLICATION
> -
> -static bool copy_up_file_and_fill(IO_CACHE *index_file, my_off_t offset)
> +bool mysql_show_binlog_events(THD* thd)
>  {
> -  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");
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  DBUG_ENTER("mysql_show_binlog_events");
>  
> -  for (;; offset+= bytes_read)
> -  {
> -    mysql_file_seek(file, offset, MY_SEEK_SET, MYF(0));
> -    if ((bytes_read= (int) mysql_file_read(file, io_buf, sizeof(io_buf),
> -                                           MYF(MY_WME)))
> -	< 0)
> -      goto err;
> -    if (!bytes_read)
> -      break;					// end of file
> -    mysql_file_seek(file, offset-init_offset, MY_SEEK_SET, MYF(0));
> -    if (mysql_file_write(file, io_buf, bytes_read, MYF(MY_WME | MY_NABP)))
> -      goto err;
> -  }
> -  /* The following will either truncate the file or fill the end with \n' */
> -  if (mysql_file_chsize(file, offset - init_offset, '\n', MYF(MY_WME)) ||
> -      mysql_file_sync(file, MYF(MY_WME)))
> -    goto err;
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS);
>  
> -  /* Reset data in old index cache */
> -  reinit_io_cache(index_file, READ_CACHE, (my_off_t) 0, 0, 1);
> -  DBUG_RETURN(0);
> +  Log_event::init_show_field_list(&field_list);
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
>  
> -err:
> -  DBUG_RETURN(1);
> +  /*
> +    Wait for handlers to insert any pending information
> +    into the binlog.  For e.g. ndb which updates the binlog asynchronously
> +    this is needed so that the uses sees all its own commands in the binlog
> +  */
> +  ha_binlog_wait(thd);
> +  
> +  DBUG_RETURN(show_binlog_events(thd, &mysql_bin_log));
>  }
>  
>  #endif /* HAVE_REPLICATION */
>  
> -/**
> -  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)
> +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)
>  {
> -  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
> +    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().
>    */
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_index);
> -  mysql_mutex_assert_owner(&LOCK_index);
> +  index_file_name[0] = 0;
> +  bzero((char*) &index_file, sizeof(index_file));
> +  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> +}
>  
> -  /* 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);
> +/* this is called only once */
>  
> -  for (;;)
> +void MYSQL_BIN_LOG::cleanup()
> +{
> +  DBUG_ENTER("cleanup");
> +  if (inited)
>    {
> -    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;
> -    }
> +    inited= 0;
> +    close(LOG_CLOSE_INDEX|LOG_CLOSE_STOP_EVENT);
> +    delete description_event_for_queue;
> +    delete description_event_for_exec;
> +    mysql_mutex_destroy(&LOCK_log);
> +    mysql_mutex_destroy(&LOCK_index);
> +    mysql_cond_destroy(&update_cond);
>    }
> -
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> +  DBUG_VOID_RETURN;
>  }
>  
> 
> -/**
> -  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
> +/* 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;
> +}
>  
> -  @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
> -*/
> +void MYSQL_BIN_LOG::init_pthread_objects()
> +{
> +  DBUG_ASSERT(inited == 0);
> +  inited= 1;
> +  mysql_mutex_init(key_LOG_LOCK_log, &LOCK_log, MY_MUTEX_INIT_SLOW);
> +  mysql_mutex_init(key_BINLOG_LOCK_index, &LOCK_index, MY_MUTEX_INIT_SLOW);
> +  mysql_cond_init(key_BINLOG_update_cond, &update_cond, 0);
> +}
>  
> -int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
> +
> +bool MYSQL_BIN_LOG::open_index_file(const char *index_file_name_arg,
> +                                    const char *log_name, bool need_mutex)
>  {
> -  int error= 0;
> -  uint length;
> -  char *fname= linfo->log_file_name;
> +  File index_file_nr= -1;
> +  DBUG_ASSERT(!my_b_inited(&index_file));
>  
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_index);
> -  mysql_mutex_assert_owner(&LOCK_index);
> +  /*
> +    First open of this class instance
> +    Create an index file that will hold all file names uses for logging.
> +    Add new entries to the end of it.
> +  */
> +  myf opt= MY_UNPACK_FILENAME;
> +  if (!index_file_name_arg)
> +  {
> +    index_file_name_arg= log_name;    // Use same basename for index file
> +    opt= MY_UNPACK_FILENAME | MY_REPLACE_EXT;
> +  }
> +  fn_format(index_file_name, index_file_name_arg, mysql_data_home,
> +            ".index", opt);
> +  if ((index_file_nr= mysql_file_open(key_file_binlog_index,
> +                                      index_file_name,
> +                                      O_RDWR | O_CREAT | O_BINARY,
> +                                      MYF(MY_WME))) < 0 ||
> +       mysql_file_sync(index_file_nr, MYF(MY_WME)) ||
> +       init_io_cache(&index_file, index_file_nr,
> +                     IO_SIZE, WRITE_CACHE,
> +                     mysql_file_seek(index_file_nr, 0L, MY_SEEK_END, MYF(0)),
> +                                     0, MYF(MY_WME | MY_WAIT_IF_FULL)) ||
> +      DBUG_EVALUATE_IF("fault_injection_openning_index", 1, 0))
> +  {
> +    /*
> +      TODO: all operations creating/deleting the index file or a log, should
> +      call my_sync_dir() or my_sync_dir_by_file() to be durable.
> +      TODO: file creation should be done with mysql_file_create()
> +      not mysql_file_open().
> +    */
> +    if (index_file_nr >= 0)
> +      mysql_file_close(index_file_nr, MYF(0));
> +    return TRUE;
> +  }
>  
> -  /* 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);
> +#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.
> +  */
>  
> -  linfo->index_file_start_offset= linfo->index_file_offset;
> -  if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
> +  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))
>    {
> -    error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
> -    goto err;
> +    sql_print_error("MYSQL_BIN_LOG::open_index_file failed to sync the index "
> +                    "file.");
> +    return TRUE;
>    }
> -  fname[length-1]=0;				// kill \n
> -  linfo->index_file_offset = my_b_tell(&index_file);
> +#endif
>  
> -err:
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_index);
> -  return error;
> +  return FALSE;
>  }
>  
> 
>  /**
> -  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
> +  Open a (new) binlog file.
>  
> -  @note
> -    If not called from slave thread, write start event to new log
> +  - 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
> +    1	error
>  */
>  
> -bool MYSQL_BIN_LOG::reset_logs(THD* thd)
> +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)
>  {
> -  LOG_INFO linfo;
> -  bool error=0;
> -  int err;
> -  const char* save_name;
> -  DBUG_ENTER("reset_logs");
> -
> -  ha_reset_logs(thd);
> -  /*
> -    We need to get both locks to be sure that no one is trying to
> -    write to the index log file.
> -  */
> -  mysql_mutex_lock(&LOCK_log);
> -  mysql_mutex_lock(&LOCK_index);
> +  File file= -1;
>  
> -  /*
> -    The following mutex is needed to ensure that no threads call
> -    'delete thd' as we would then risk missing a 'rollback' from this
> -    thread. If the transaction involved MyISAM tables, it should go
> -    into binlog even on rollback.
> -  */
> -  mysql_mutex_lock(&LOCK_thread_count);
> +  DBUG_ENTER("MYSQL_BIN_LOG::open");
> +  DBUG_PRINT("enter",("log_type: %d",(int) log_type_arg));
>  
> -  /* Save variables so that we can reopen the log */
> -  save_name=name;
> -  name=0;					// Protect against free
> -  close(LOG_CLOSE_TO_BE_OPENED);
> +  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);
> +  }
>  
> -  /*
> -    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.
> +#ifdef HAVE_REPLICATION
> +  if (open_purge_index_file(TRUE) ||
> +      register_create_index_entry(log_file_name) ||
> +      sync_purge_index_file() ||
> +      DBUG_EVALUATE_IF("fault_injection_registering_index", 1, 0))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::open failed to sync the index file.");
> +    DBUG_RETURN(1);
> +  }
> +  DBUG_EXECUTE_IF("crash_create_non_critical_before_update_index", DBUG_ABORT(););
> +#endif
>  
> -    We need to invert the steps and use the purge_index_file methods
> -    in order to make the operation safe.
> -  */
> +  write_error= 0;
>  
> -  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
> +  /* open the main log file */
> +  if (MYSQL_LOG::open(log_name, log_type_arg, new_name,
> +                      io_cache_type_arg))
>    {
> -    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;
> +#ifdef HAVE_REPLICATION
> +    close_purge_index_file();
> +#endif
> +    DBUG_RETURN(1);                            /* all warnings issued */
>    }
>  
> -  for (;;)
> +  init(no_auto_events_arg, max_size_arg);
> +
> +  open_count++;
> +
> +  DBUG_ASSERT(log_type == LOG_BIN);
> +
>    {
> -    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
> +    bool write_file_name_to_index_file=0;
> +
> +    if (!my_b_filelength(&log_file))
>      {
> -      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;
> +      /*
> +	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 (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) 
> +    if (need_start_event && !no_auto_events)
>      {
> -      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
> +      /*
> +        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)
>      {
> -      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;
> +      /*
> +        This is a relay log written to by the I/O slave thread.
> +        Write the event so that others can later know the format of this relay
> +        log.
> +        Note that this event is very close to the original event from the
> +        master (it has binlog version of the master, event types of the
> +        master), so this is suitable to parse the next relay log's event. It
> +        has been produced by
> +        Format_description_log_event::Format_description_log_event(char* buf,).
> +        Why don't we want to write the description_event_for_queue if this
> +        event is for format<4 (3.23 or 4.x): this is because in that case, the
> +        description_event_for_queue describes the data received from the
> +        master, but not the data written to the relay log (*conversion*),
> +        which is in format 4 (slave's).
> +      */
> +      /*
> +        Set 'created' to 0, so that in next relay logs this event does not
> +        trigger cleaning actions on the slave in
> +        Format_description_log_event::apply_event_impl().
> +      */
> +      description_event_for_queue->created= 0;
> +      /* Don't set log_pos in event header */
> +      description_event_for_queue->set_artificial_event();
> +
> +      if (description_event_for_queue->write(&log_file))
> +        goto err;
> +      bytes_written+= description_event_for_queue->data_written;
> +    }
> +    if (flush_io_cache(&log_file) ||
> +        mysql_file_sync(log_file.file, MYF(MY_WME)))
>        goto err;
> +
> +    if (write_file_name_to_index_file)
> +    {
> +#ifdef HAVE_REPLICATION
> +      DBUG_EXECUTE_IF("crash_create_critical_before_update_index", DBUG_ABORT(););
> +#endif
> +
> +      DBUG_ASSERT(my_b_inited(&index_file) != 0);
> +      reinit_io_cache(&index_file, WRITE_CACHE,
> +                      my_b_filelength(&index_file), 0, 0);
> +      /*
> +        As this is a new log file, we write the file name to the index
> +        file. As every time we write to the index file, we sync it.
> +      */
> +      if (DBUG_EVALUATE_IF("fault_injection_updating_index", 1, 0) ||
> +          my_b_write(&index_file, (uchar*) log_file_name,
> +                     strlen(log_file_name)) ||
> +          my_b_write(&index_file, (uchar*) "\n", 1) ||
> +          flush_io_cache(&index_file) ||
> +          mysql_file_sync(index_file.file, MYF(MY_WME)))
> +        goto err;
> +
> +#ifdef HAVE_REPLICATION
> +      DBUG_EXECUTE_IF("crash_create_after_update_index", DBUG_ABORT(););
> +#endif
>      }
>    }
> -  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));
> +  log_state= LOG_OPENED;
> +
> +#ifdef HAVE_REPLICATION
> +  close_purge_index_file();
> +#endif
> +
> +  DBUG_RETURN(0);
>  
>  err:
> -  if (error == 1)
> -    name= const_cast<char*>(save_name);
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  mysql_mutex_unlock(&LOCK_index);
> +#ifdef HAVE_REPLICATION
> +  if (is_inited_purge_index_file())
> +    purge_index_entry(NULL, NULL, need_mutex);
> +  close_purge_index_file();
> +#endif
> +  sql_print_error("Could not use %s for logging (error %d). \
> +Turning logging off for the whole duration of the MySQL server process. \
> +To turn it on again: fix the cause, \
> +shutdown the MySQL server and restart it.", name, errno);
> +  if (file >= 0)
> +    mysql_file_close(file, MYF(0));
> +  end_io_cache(&log_file);
> +  end_io_cache(&index_file);
> +  safeFree(name);
> +  log_state= LOG_CLOSED;
> +  DBUG_RETURN(1);
> +}
> +
> +
> +int MYSQL_BIN_LOG::get_current_log(LOG_INFO* linfo)
> +{
> +  mysql_mutex_lock(&LOCK_log);
> +  int ret = raw_get_current_log(linfo);
>    mysql_mutex_unlock(&LOCK_log);
> -  DBUG_RETURN(error);
> +  return ret;
> +}
> +
> +int MYSQL_BIN_LOG::raw_get_current_log(LOG_INFO* linfo)
> +{
> +  strmake(linfo->log_file_name, log_file_name,
> sizeof(linfo->log_file_name)-1);
> +  linfo->pos = my_b_tell(&log_file);
> +  return 0;
>  }
>  
> +bool MYSQL_BIN_LOG::check_write_error(THD *thd)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::check_write_error");
>  
> -/**
> -  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.
> +  bool checked= FALSE;
>  
> -  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
> +  if (!thd->is_error())
> +    DBUG_RETURN(checked);
>  
> -  @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).
> +  switch (thd->stmt_da->sql_errno())
> +  {
> +    case ER_TRANS_CACHE_FULL:
> +    case ER_ERROR_ON_WRITE:
> +    case ER_BINLOG_LOGGING_IMPOSSIBLE:
> +      checked= TRUE;
> +    break;
> +  }
> +
> +  DBUG_RETURN(checked);
> +}
> +
> +void MYSQL_BIN_LOG::set_write_error(THD *thd)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_write_error");
> +
> +  write_error= 1;
> +
> +  if (check_write_error(thd))
> +    DBUG_VOID_RETURN;
> +
> +  if (my_errno == EFBIG)
> +    my_message(ER_TRANS_CACHE_FULL, ER(ER_TRANS_CACHE_FULL), MYF(MY_WME));
> +  else
> +    my_error(ER_ERROR_ON_WRITE, MYF(MY_WME), name, errno);
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +/**
> +  Find the position in the log-index-file for the given log name.
> +
> +  @param linfo		Store here the found log file name and position to
> +                       the NEXT log file name in the index file.
> +  @param log_name	Filename to find in the index file.
> +                       Is a null pointer if we want to read the first entry
> +  @param need_lock	Set this to 1 if the parent doesn't already have a
> +                       lock on LOCK_index
>  
>    @note
> -    - 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).
> +    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_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 MYSQL_BIN_LOG::find_log_pos(LOG_INFO *linfo, const char *log_name,
> +			    bool need_lock)
>  {
> -  int error;
> -  char *to_purge_if_included= NULL;
> -  DBUG_ENTER("purge_first_log");
> -
> -  DBUG_ASSERT(is_open());
> -  DBUG_ASSERT(rli->slave_running == 1);
> -  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
> -
> -  mysql_mutex_lock(&LOCK_index);
> -  to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
> +  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"));
>  
>    /*
> -    Read the next log file name from the index file and pass it back to
> -    the caller.
> +    Mutex needed because we need to make sure the file pointer does not
> +    move from under our feet
>    */
> -  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;
> -  }
> +  if (need_lock)
> +    mysql_mutex_lock(&LOCK_index);
> +  mysql_mutex_assert_owner(&LOCK_index);
>  
> -  /*
> -    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);
> +  /* 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);
>  
> -  /*
> -    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)
> +  for (;;)
>    {
> -    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
> -    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
> -            sizeof(rli->group_relay_log_name)-1);
> -    rli->notify_group_relay_log_name_update();
> -  }
> -
> -  /* Store where we are in the new file for the execution thread */
> -  flush_relay_log_info(rli);
> -
> -  DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_ABORT(););
> -
> -  mysql_mutex_lock(&rli->log_space_lock);
> -  rli->relay_log.purge_logs(to_purge_if_included, included,
> -                            0, 0, &rli->log_space_total);
> -  // Tell the I/O thread to take the relay_log_space_limit into account
> -  rli->ignore_log_space_limit= 0;
> -  mysql_mutex_unlock(&rli->log_space_lock);
> +    uint length;
> +    my_off_t offset= my_b_tell(&index_file);
>  
> -  /*
> -    Ok to broadcast after the critical region as there is no risk of
> -    the mutex being destroyed by this thread later - this helps save
> -    context switches
> -  */
> -  mysql_cond_broadcast(&rli->log_space_cond);
> +    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;
> +    }
>  
> -  /*
> -   * 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 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 included was passed, rli->linfo should be the first entry. */
> -  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
> -
> -err:
> -  my_free(to_purge_if_included, MYF(0));
> -  mysql_mutex_unlock(&LOCK_index);
> +  if (need_lock)
> +    mysql_mutex_unlock(&LOCK_index);
>    DBUG_RETURN(error);
>  }
>  
> -/**
> -  Update log index_file.
> -*/
> -
> -int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
> -{
> -  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
> -    return LOG_INFO_IO;
> -
> -  // now update offsets in index file for running threads
> -  if (need_update_threads)
> -    adjust_linfo_offsets(log_info->index_file_start_offset);
> -  return 0;
> -}
>  
>  /**
> -  Remove all logs before the given log from disk and from the index file.
> +  Find the position in the log-index-file for the given log name.
>  
> -  @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
> +  @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
> -    If any of the logs before the deleted one is in use,
> -    only purge logs up to this one.
> +    - 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		to_log not found
> -    LOG_INFO_EMFILE             too many files opened
> -    LOG_INFO_FATAL              if any other than ENOENT error from
> -                                mysql_file_stat() or mysql_file_delete()
> +    LOG_INFO_EOF	        End of log-index-file found
> +  @retval
> +    LOG_INFO_IO		Got IO error while reading file
>  */
>  
> -int MYSQL_BIN_LOG::purge_logs(const char *to_log, 
> -                          bool included,
> -                          bool need_mutex, 
> -                          bool need_update_threads, 
> -                          ulonglong *decrease_log_space)
> +int MYSQL_BIN_LOG::find_next_log(LOG_INFO* linfo, bool need_lock)
>  {
>    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));
> +  uint length;
> +  char *fname= linfo->log_file_name;
>  
> -  if (need_mutex)
> +  if (need_lock)
>      mysql_mutex_lock(&LOCK_index);
> -  if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) 
> -  {
> -    sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
> -                    "listed in the index.", to_log);
> -    goto err;
> -  }
> -
> -  if ((error= open_purge_index_file(TRUE)))
> -  {
> -    sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
> -    goto err;
> -  }
> -
> -  /*
> -    File name exists in index file; delete until we find this file
> -    or a file that is used.
> -  */
> -  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> -    goto err;
> -  while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
> -         !is_active(log_info.log_file_name) &&
> -         !log_in_use(log_info.log_file_name))
> -  {
> -    if ((error= register_purge_index_entry(log_info.log_file_name)))
> -    {
> -      sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register
> file.",
> -                      log_info.log_file_name);
> -      goto err;
> -    }
> -
> -    if (find_next_log(&log_info, 0) || exit_loop)
> -      break;
> -  }
> -
> -  DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_ABORT(););
> +  mysql_mutex_assert_owner(&LOCK_index);
>  
> -  if ((error= sync_purge_index_file()))
> -  {
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
> -    goto err;
> -  }
> +  /* 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);
>  
> -  /* We know how many files to delete. Update index file. */
> -  if ((error=update_log_index(&log_info, need_update_threads)))
> +  linfo->index_file_start_offset= linfo->index_file_offset;
> +  if ((length=my_b_gets(&index_file, fname, FN_REFLEN)) <= 1)
>    {
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
> +    error = !index_file.error ? LOG_INFO_EOF : LOG_INFO_IO;
>      goto err;
>    }
> -
> -  DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_ABORT(););
> +  fname[length-1]=0;				// kill \n
> +  linfo->index_file_offset = my_b_tell(&index_file);
>  
>  err:
> -  /* Read each entry from purge_index_file and delete the file. */
> -  if (is_inited_purge_index_file() &&
> -      (error= purge_index_entry(thd, decrease_log_space, FALSE)))
> -    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
> -                    " that would be purged.");
> -  close_purge_index_file();
> -
> -  DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_ABORT(););
> -
> -  if (need_mutex)
> +  if (need_lock)
>      mysql_mutex_unlock(&LOCK_index);
> -  DBUG_RETURN(error);
> +  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;
> +/**
> +  Delete all logs refered to in the index file.
> +  Start writing to a new log file.
>  
> -  DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
> +  The new index file will only contain this file.
>  
> -  if (destroy)
> -    close_purge_index_file();
> +  @param thd		Thread
>  
> -  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);
> -}
> +  @note
> +    If not called from slave thread, write start event to new log
>  
> -int MYSQL_BIN_LOG::close_purge_index_file()
> +  @retval
> +    0	ok
> +  @retval
> +    1   error
> +*/
> +
> +bool MYSQL_BIN_LOG::reset_logs(THD* thd)
>  {
> -  int error= 0;
> +  LOG_INFO linfo;
> +  bool error=0;
> +  int err;
> +  const char* save_name;
> +  DBUG_ENTER("reset_logs");
>  
> -  DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
> +  ha_reset_logs(thd);
> +  /*
> +    We need to get both locks to be sure that no one is trying to
> +    write to the index log file.
> +  */
> +  mysql_mutex_lock(&LOCK_log);
> +  mysql_mutex_lock(&LOCK_index);
>  
> -  if (my_b_inited(&purge_index_file))
> -  {
> +  /*
> +    The following mutex is needed to ensure that no threads call
> +    'delete thd' as we would then risk missing a 'rollback' from this
> +    thread. If the transaction involved MyISAM tables, it should go
> +    into binlog even on rollback.
> +  */
> +  mysql_mutex_lock(&LOCK_thread_count);
> +
> +  /* Save variables so that we can reopen the log */
> +  save_name=name;
> +  name=0;					// Protect against free
> +  close(LOG_CLOSE_TO_BE_OPENED);
> +
> +  /*
> +    First delete all old log files and then update the index file.
> +    As we first delete the log files and do not use sort of logging,
> +    a crash may lead to an inconsistent state where the index has
> +    references to non-existent files.
> +
> +    We need to invert the steps and use the purge_index_file methods
> +    in order to make the operation safe.
> +  */
> +
> +  if ((err= find_log_pos(&linfo, NullS, 0)) != 0)
> +  {
> +    uint errcode= purge_log_get_error_code(err);
> +    sql_print_error("Failed to locate old binlog or relay log files");
> +    my_message(errcode, ER(errcode), MYF(0));
> +    error= 1;
> +    goto err;
> +  }
> +
> +  for (;;)
> +  {
> +    if ((error= my_delete_allow_opened(linfo.log_file_name, MYF(0))) != 0)
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                            ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                            linfo.log_file_name);
> +        sql_print_information("Failed to delete file '%s'",
> +                              linfo.log_file_name);
> +        my_errno= 0;
> +        error= 0;
> +      }
> +      else
> +      {
> +        push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                            ER_BINLOG_PURGE_FATAL_ERR,
> +                            "a problem with deleting %s; "
> +                            "consider examining correspondence "
> +                            "of your binlog index file "
> +                            "to the actual binlog files",
> +                            linfo.log_file_name);
> +        error= 1;
> +        goto err;
> +      }
> +    }
> +    if (find_next_log(&linfo, 0))
> +      break;
> +  }
> +
> +  /* Start logging with a new file */
> +  close(LOG_CLOSE_INDEX);
> +  if ((error= my_delete_allow_opened(index_file_name, MYF(0))))	// Reset (open will
> update)
> +  {
> +    if (my_errno == ENOENT) 
> +    {
> +      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                          ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                          index_file_name);
> +      sql_print_information("Failed to delete file '%s'",
> +                            index_file_name);
> +      my_errno= 0;
> +      error= 0;
> +    }
> +    else
> +    {
> +      push_warning_printf(current_thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                          ER_BINLOG_PURGE_FATAL_ERR,
> +                          "a problem with deleting %s; "
> +                          "consider examining correspondence "
> +                          "of your binlog index file "
> +                          "to the actual binlog files",
> +                          index_file_name);
> +      error= 1;
> +      goto err;
> +    }
> +  }
> +  if (!thd->slave_thread)
> +    need_start_event=1;
> +  if (!open_index_file(index_file_name, 0, FALSE))
> +    open(save_name, log_type, 0, io_cache_type, no_auto_events, max_size, 0,
> FALSE);
> +  my_free((uchar*) save_name, MYF(0));
> +
> +err:
> +  if (error == 1)
> +    name= const_cast<char*>(save_name);
> +  mysql_mutex_unlock(&LOCK_thread_count);
> +  mysql_mutex_unlock(&LOCK_index);
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_RETURN(error);
> +}
> +
> +
> +/**
> +  Delete relay log files prior to rli->group_relay_log_name
> +  (i.e. all logs which are not involved in a non-finished group
> +  (transaction)), remove them from the index file and start on next
> +  relay log.
> +
> +  IMPLEMENTATION
> +  - Protects index file with LOCK_index
> +  - Delete relevant relay log files
> +  - Copy all file names after these ones to the front of the index file
> +  - If the OS has truncate, truncate the file, else fill it with \n'
> +  - Read the next file name from the index file and store in rli->linfo
> +
> +  @param rli	       Relay log information
> +  @param included     If false, all relay logs that are strictly before
> +                      rli->group_relay_log_name are deleted ; if true, the
> +                      latter is deleted too (i.e. all relay logs
> +                      read by the SQL slave thread are deleted).
> +
> +  @note
> +    - This is only called from the slave-execute thread when it has read
> +    all commands from a relay log and want to switch to a new relay log.
> +    - When this happens, we can be in an active transaction as
> +    a transaction can span over two relay logs
> +    (although it is always written as a single block to the master's binary
> +    log, hence cannot span over two master's binary logs).
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF	        End of log-index-file found
> +  @retval
> +    LOG_INFO_SEEK	Could not allocate IO cache
> +  @retval
> +    LOG_INFO_IO		Got IO error while reading file
> +*/
> +
> +#ifdef HAVE_REPLICATION
> +
> +int MYSQL_BIN_LOG::purge_first_log(Relay_log_info* rli, bool included)
> +{
> +  int error;
> +  char *to_purge_if_included= NULL;
> +  DBUG_ENTER("purge_first_log");
> +
> +  DBUG_ASSERT(is_open());
> +  DBUG_ASSERT(rli->slave_running == 1);
> +  DBUG_ASSERT(!strcmp(rli->linfo.log_file_name,rli->event_relay_log_name));
> +
> +  mysql_mutex_lock(&LOCK_index);
> +  to_purge_if_included= my_strdup(rli->group_relay_log_name, MYF(0));
> +
> +  /*
> +    Read the next log file name from the index file and pass it back to
> +    the caller.
> +  */
> +  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)) || 
> +     (error=find_next_log(&rli->linfo, 0)))
> +  {
> +    char buff[22];
> +    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> +                    error,
> +                    llstr(rli->linfo.index_file_offset,buff),
> +                    rli->event_relay_log_name,
> +                    included);
> +    goto err;
> +  }
> +
> +  /*
> +    Reset rli's coordinates to the current log.
> +  */
> +  rli->event_relay_log_pos= BIN_LOG_HEADER_SIZE;
> +  strmake(rli->event_relay_log_name,rli->linfo.log_file_name,
> +	  sizeof(rli->event_relay_log_name)-1);
> +
> +  /*
> +    If we removed the rli->group_relay_log_name file,
> +    we must update the rli->group* coordinates, otherwise do not touch it as the
> +    group's execution is not finished (e.g. COMMIT not executed)
> +  */
> +  if (included)
> +  {
> +    rli->group_relay_log_pos = BIN_LOG_HEADER_SIZE;
> +    strmake(rli->group_relay_log_name,rli->linfo.log_file_name,
> +            sizeof(rli->group_relay_log_name)-1);
> +    rli->notify_group_relay_log_name_update();
> +  }
> +
> +  /* Store where we are in the new file for the execution thread */
> +  flush_relay_log_info(rli);
> +
> +  DBUG_EXECUTE_IF("crash_before_purge_logs", DBUG_ABORT(););
> +
> +  mysql_mutex_lock(&rli->log_space_lock);
> +  rli->relay_log.purge_logs(to_purge_if_included, included,
> +                            0, 0, &rli->log_space_total);
> +  // Tell the I/O thread to take the relay_log_space_limit into account
> +  rli->ignore_log_space_limit= 0;
> +  mysql_mutex_unlock(&rli->log_space_lock);
> +
> +  /*
> +    Ok to broadcast after the critical region as there is no risk of
> +    the mutex being destroyed by this thread later - this helps save
> +    context switches
> +  */
> +  mysql_cond_broadcast(&rli->log_space_cond);
> +
> +  /*
> +   * Need to update the log pos because purge logs has been called 
> +   * after fetching initially the log pos at the begining of the method.
> +   */
> +  if((error=find_log_pos(&rli->linfo, rli->event_relay_log_name, 0)))
> +  {
> +    char buff[22];
> +    sql_print_error("next log error: %d  offset: %s  log: %s included: %d",
> +                    error,
> +                    llstr(rli->linfo.index_file_offset,buff),
> +                    rli->group_relay_log_name,
> +                    included);
> +    goto err;
> +  }
> +
> +  /* If included was passed, rli->linfo should be the first entry. */
> +  DBUG_ASSERT(!included || rli->linfo.index_file_start_offset == 0);
> +
> +err:
> +  my_free(to_purge_if_included, MYF(0));
> +  mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Update log index_file.
> +*/
> +
> +int MYSQL_BIN_LOG::update_log_index(LOG_INFO* log_info, bool need_update_threads)
> +{
> +  if (copy_up_file_and_fill(&index_file, log_info->index_file_start_offset))
> +    return LOG_INFO_IO;
> +
> +  // now update offsets in index file for running threads
> +  if (need_update_threads)
> +    adjust_linfo_offsets(log_info->index_file_start_offset);
> +  return 0;
> +}
> +
> +/**
> +  Remove all logs before the given log from disk and from the index file.
> +
> +  @param to_log	      Delete all log file name before this file.
> +  @param included            If true, to_log is deleted too.
> +  @param need_mutex
> +  @param need_update_threads If we want to update the log coordinates of
> +                             all threads. False for relay logs, true otherwise.
> +  @param freed_log_space     If not null, decrement this variable of
> +                             the amount of log space freed
> +
> +  @note
> +    If any of the logs before the deleted one is in use,
> +    only purge logs up to this one.
> +
> +  @retval
> +    0			ok
> +  @retval
> +    LOG_INFO_EOF		to_log not found
> +    LOG_INFO_EMFILE             too many files opened
> +    LOG_INFO_FATAL              if any other than ENOENT error from
> +                                mysql_file_stat() or mysql_file_delete()
> +*/
> +
> +int MYSQL_BIN_LOG::purge_logs(const char *to_log, 
> +                          bool included,
> +                          bool need_mutex, 
> +                          bool need_update_threads, 
> +                          ulonglong *decrease_log_space)
> +{
> +  int error= 0;
> +  bool exit_loop= 0;
> +  LOG_INFO log_info;
> +  THD *thd= current_thd;
> +  DBUG_ENTER("purge_logs");
> +  DBUG_PRINT("info",("to_log= %s",to_log));
> +
> +  if (need_mutex)
> +    mysql_mutex_lock(&LOCK_index);
> +  if ((error=find_log_pos(&log_info, to_log, 0 /*no mutex*/))) 
> +  {
> +    sql_print_error("MYSQL_BIN_LOG::purge_logs was called with file %s not "
> +                    "listed in the index.", to_log);
> +    goto err;
> +  }
> +
> +  if ((error= open_purge_index_file(TRUE)))
> +  {
> +    sql_print_error("MYSQL_BIN_LOG::purge_logs failed to sync the index file.");
> +    goto err;
> +  }
> +
> +  /*
> +    File name exists in index file; delete until we find this file
> +    or a file that is used.
> +  */
> +  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> +    goto err;
> +  while ((strcmp(to_log,log_info.log_file_name) || (exit_loop=included)) &&
> +         !is_active(log_info.log_file_name) &&
> +         !log_in_use(log_info.log_file_name))
> +  {
> +    if ((error= register_purge_index_entry(log_info.log_file_name)))
> +    {
> +      sql_print_error("MYSQL_BIN_LOG::purge_logs failed to copy %s to register
> file.",
> +                      log_info.log_file_name);
> +      goto err;
> +    }
> +
> +    if (find_next_log(&log_info, 0) || exit_loop)
> +      break;
> +  }
> +
> +  DBUG_EXECUTE_IF("crash_purge_before_update_index", DBUG_ABORT(););
> +
> +  if ((error= sync_purge_index_file()))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to flush register file.");
> +    goto err;
> +  }
> +
> +  /* We know how many files to delete. Update index file. */
> +  if ((error=update_log_index(&log_info, need_update_threads)))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to update the index file");
> +    goto err;
> +  }
> +
> +  DBUG_EXECUTE_IF("crash_purge_critical_after_update_index", DBUG_ABORT(););
> +
> +err:
> +  /* Read each entry from purge_index_file and delete the file. */
> +  if (is_inited_purge_index_file() &&
> +      (error= purge_index_entry(thd, decrease_log_space, FALSE)))
> +    sql_print_error("MSYQL_BIN_LOG::purge_logs failed to process registered files"
> +                    " that would be purged.");
> +  close_purge_index_file();
> +
> +  DBUG_EXECUTE_IF("crash_purge_non_critical_after_update_index", DBUG_ABORT(););
> +
> +  if (need_mutex)
> +    mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::set_purge_index_file_name(const char *base_file_name)
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_purge_index_file_name");
> +  if (fn_format(purge_index_file_name, base_file_name, mysql_data_home,
> +                ".~rec~", MYF(MY_UNPACK_FILENAME | MY_SAFE_PATH |
> +                              MY_REPLACE_EXT)) == NULL)
> +  {
> +    error= 1;
> +    sql_print_error("MYSQL_BIN_LOG::set_purge_index_file_name failed to set "
> +                      "file name.");
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::open_purge_index_file(bool destroy)
> +{
> +  int error= 0;
> +  File file= -1;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::open_purge_index_file");
> +
> +  if (destroy)
> +    close_purge_index_file();
> +
> +  if (!my_b_inited(&purge_index_file))
> +  {
> +    if ((file= my_open(purge_index_file_name, O_RDWR | O_CREAT | O_BINARY,
> +                       MYF(MY_WME | ME_WAITTANG))) < 0  ||
> +        init_io_cache(&purge_index_file, file, IO_SIZE,
> +                      (destroy ? WRITE_CACHE : READ_CACHE),
> +                      0, 0, MYF(MY_WME | MY_NABP | MY_WAIT_IF_FULL)))
> +    {
> +      error= 1;
> +      sql_print_error("MYSQL_BIN_LOG::open_purge_index_file failed to open register
> "
> +                      " file.");
> +    }
> +  }
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::close_purge_index_file()
> +{
> +  int error= 0;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::close_purge_index_file");
> +
> +  if (my_b_inited(&purge_index_file))
> +  {
>      end_io_cache(&purge_index_file);
>      error= my_close(purge_index_file.file, MYF(0));
>    }
> -  my_delete(purge_index_file_name, MYF(0));
> -  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> +  my_delete(purge_index_file_name, MYF(0));
> +  bzero((char*) &purge_index_file, sizeof(purge_index_file));
> +
> +  DBUG_RETURN(error);
> +}
> +
> +bool MYSQL_BIN_LOG::is_inited_purge_index_file()
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
> +  DBUG_RETURN (my_b_inited(&purge_index_file));
> +}
> +
> +int MYSQL_BIN_LOG::sync_purge_index_file()
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::sync_purge_index_file");
> +
> +  if ((error= flush_io_cache(&purge_index_file)) ||
> +      (error= my_sync(purge_index_file.file, MYF(MY_WME))))
> +    DBUG_RETURN(error);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
> +{
> +  int error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
> +
> +  if ((error=my_b_write(&purge_index_file, (const uchar*)entry, strlen(entry)))
> ||
> +      (error=my_b_write(&purge_index_file, (const uchar*)"\n", 1)))
> +    DBUG_RETURN (error);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
> +{
> +  DBUG_ENTER("MYSQL_BIN_LOG::register_create_index_entry");
> +  DBUG_RETURN(register_purge_index_entry(entry));
> +}
> +
> +int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> +                                     bool need_mutex)
> +{
> +  MY_STAT s;
> +  int error= 0;
> +  LOG_INFO log_info;
> +  LOG_INFO check_log_info;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
> +
> +  DBUG_ASSERT(my_b_inited(&purge_index_file));
> +
> +  if ((error=reinit_io_cache(&purge_index_file, READ_CACHE, 0, 0, 0)))
> +  {
> +    sql_print_error("MSYQL_BIN_LOG::purge_index_entry failed to reinit register file
> "
> +                    "for read");
> +    goto err;
> +  }
> +
> +  for (;;)
> +  {
> +    uint length;
> +
> +    if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
> +                          FN_REFLEN)) <= 1)
> +    {
> +      if (purge_index_file.error)
> +      {
> +        error= purge_index_file.error;
> +        sql_print_error("MSYQL_BIN_LOG::purge_index_entry error %d reading from "
> +                        "register file.", error);
> +        goto err;
> +      }
> +
> +      /* Reached EOF */
> +      break;
> +    }
> +
> +    /* Get rid of the trailing '\n' */
> +    log_info.log_file_name[length-1]= 0;
> +
> +    if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0)))
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        /*
> +          It's not fatal if we can't stat a log file that does not exist;
> +          If we could not stat, we won't delete.
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                              log_info.log_file_name);
> +        }
> +        sql_print_information("Failed to execute mysql_file_stat on file '%s'",
> +			      log_info.log_file_name);
> +        my_errno= 0;
> +      }
> +      else
> +      {
> +        /*
> +          Other than ENOENT are fatal
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_BINLOG_PURGE_FATAL_ERR,
> +                              "a problem with getting info on being purged %s; "
> +                              "consider examining correspondence "
> +                              "of your binlog index file "
> +                              "to the actual binlog files",
> +                              log_info.log_file_name);
> +        }
> +        else
> +        {
> +          sql_print_information("Failed to delete log file '%s'; "
> +                                "consider examining correspondence "
> +                                "of your binlog index file "
> +                                "to the actual binlog files",
> +                                log_info.log_file_name);
> +        }
> +        error= LOG_INFO_FATAL;
> +        goto err;
> +      }
> +    }
> +    else
> +    {
> +      if ((error= find_log_pos(&check_log_info, log_info.log_file_name,
> need_mutex)))
> +      {
> +        if (error != LOG_INFO_EOF)
> +        {
> +          if (thd)
> +          {
> +            push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                ER_BINLOG_PURGE_FATAL_ERR,
> +                                "a problem with deleting %s and "
> +                                "reading the binlog index file",
> +                                log_info.log_file_name);
> +          }
> +          else
> +          {
> +            sql_print_information("Failed to delete file '%s' and "
> +                                  "read the binlog index file",
> +                                  log_info.log_file_name);
> +          }
> +          goto err;
> +        }
> +           
> +        error= 0;
> +        if (!need_mutex)
> +        {
> +          /*
> +            This is to avoid triggering an error in NDB.
> +          */
> +          ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
> +        }
> +
> +        DBUG_PRINT("info",("purging %s",log_info.log_file_name));
> +        if (!my_delete(log_info.log_file_name, MYF(0)))
> +        {
> +          if (decrease_log_space)
> +            *decrease_log_space-= s.st_size;
> +        }
> +        else
> +        {
> +          if (my_errno == ENOENT)
> +          {
> +            if (thd)
> +            {
> +              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                  ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> +                                  log_info.log_file_name);
> +            }
> +            sql_print_information("Failed to delete file '%s'",
> +                                  log_info.log_file_name);
> +            my_errno= 0;
> +          }
> +          else
> +          {
> +            if (thd)
> +            {
> +              push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                                  ER_BINLOG_PURGE_FATAL_ERR,
> +                                  "a problem with deleting %s; "
> +                                  "consider examining correspondence "
> +                                  "of your binlog index file "
> +                                  "to the actual binlog files",
> +                                  log_info.log_file_name);
> +            }
> +            else
> +            {
> +              sql_print_information("Failed to delete file '%s'; "
> +                                    "consider examining correspondence "
> +                                    "of your binlog index file "
> +                                    "to the actual binlog files",
> +                                    log_info.log_file_name);
> +            }
> +            if (my_errno == EMFILE)
> +            {
> +              DBUG_PRINT("info",
> +                         ("my_errno: %d, set ret = LOG_INFO_EMFILE", my_errno));
> +              error= LOG_INFO_EMFILE;
> +              goto err;
> +            }
> +            error= LOG_INFO_FATAL;
> +            goto err;
> +          }
> +        }
> +      }
> +    }
> +  }
> +
> +err:
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Remove all logs before the given file date from disk and from the
> +  index file.
> +
> +  @param thd		Thread pointer
> +  @param purge_time	Delete all log files before given date.
> +
> +  @note
> +    If any of the logs before the deleted one is in use,
> +    only purge logs up to this one.
> +
> +  @retval
> +    0				ok
> +  @retval
> +    LOG_INFO_PURGE_NO_ROTATE	Binary file that can't be rotated
> +    LOG_INFO_FATAL              if any other than ENOENT error from
> +                                mysql_file_stat() or mysql_file_delete()
> +*/
> +
> +int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
> +{
> +  int error;
> +  char to_log[FN_REFLEN];
> +  LOG_INFO log_info;
> +  MY_STAT stat_area;
> +  THD *thd= current_thd;
> +  
> +  DBUG_ENTER("purge_logs_before_date");
> +
> +  mysql_mutex_lock(&LOCK_index);
> +  to_log[0]= 0;
> +
> +  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> +    goto err;
> +
> +  while (strcmp(log_file_name, log_info.log_file_name) &&
> +	 !is_active(log_info.log_file_name) &&
> +         !log_in_use(log_info.log_file_name))
> +  {
> +    if (!mysql_file_stat(key_file_binlog,
> +                         log_info.log_file_name, &stat_area, MYF(0)))
> +    {
> +      if (my_errno == ENOENT) 
> +      {
> +        /*
> +          It's not fatal if we can't stat a log file that does not exist.
> +        */
> +        my_errno= 0;
> +      }
> +      else
> +      {
> +        /*
> +          Other than ENOENT are fatal
> +        */
> +        if (thd)
> +        {
> +          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> +                              ER_BINLOG_PURGE_FATAL_ERR,
> +                              "a problem with getting info on being purged %s; "
> +                              "consider examining correspondence "
> +                              "of your binlog index file "
> +                              "to the actual binlog files",
> +                              log_info.log_file_name);
> +        }
> +        else
> +        {
> +          sql_print_information("Failed to delete log file '%s'",
> +                                log_info.log_file_name);
> +        }
> +        error= LOG_INFO_FATAL;
> +        goto err;
> +      }
> +    }
> +    else
> +    {
> +      if (stat_area.st_mtime < purge_time) 
> +        strmake(to_log, 
> +                log_info.log_file_name, 
> +                sizeof(log_info.log_file_name) - 1);
> +      else
> +        break;
> +    }
> +    if (find_next_log(&log_info, 0))
> +      break;
> +  }
> +
> +  error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
> +
> +err:
> +  mysql_mutex_unlock(&LOCK_index);
> +  DBUG_RETURN(error);
> +}
> +#endif /* HAVE_REPLICATION */
> +
> +
> +/**
> +  Create a new log file name.
> +
> +  @param buf		buf of at least FN_REFLEN where new name is stored
> +
> +  @note
> +    If file name will be longer then FN_REFLEN it will be truncated
> +*/
> +
> +void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
> +{
> +  uint dir_len = dirname_length(log_file_name); 
> +  if (dir_len >= FN_REFLEN)
> +    dir_len=FN_REFLEN-1;
> +  strnmov(buf, log_file_name, dir_len);
> +  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
> +}
> +
> +
> +/**
> +  Check if we are writing/reading to the given log file.
> +*/
> +
> +bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
> +{
> +  return !strcmp(log_file_name, log_file_name_arg);
> +}
> +
> +
> +/*
> +  Wrappers around new_file_impl to avoid using argument
> +  to control locking. The argument 1) less readable 2) breaks
> +  incapsulation 3) allows external access to the class without
> +  a lock (which is not possible with private new_file_without_locking
> +  method).
> +*/
> +
> +void MYSQL_BIN_LOG::new_file()
> +{
> +  new_file_impl(1);
> +}
> +
> +
> +void MYSQL_BIN_LOG::new_file_without_locking()
> +{
> +  new_file_impl(0);
> +}
> +
> +
> +/**
> +  Start writing to a new log file or reopen the old file.
> +
> +  @param need_lock		Set to 1 if caller has not locked LOCK_log
> +
> +  @note
> +    The new file name is stored last in the index file
> +*/
> +
> +void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
> +{
> +  char new_name[FN_REFLEN], *new_name_ptr, *old_name;
> +
> +  DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
> +  if (!is_open())
> +  {
> +    DBUG_PRINT("info",("log is closed"));
> +    DBUG_VOID_RETURN;
> +  }
> +
> +  if (need_lock)
> +    mysql_mutex_lock(&LOCK_log);
> +  mysql_mutex_lock(&LOCK_index);
> +
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  mysql_mutex_assert_owner(&LOCK_index);
> +
> +  /*
> +    if binlog is used as tc log, be sure all xids are "unlogged",
> +    so that on recover we only need to scan one - latest - binlog file
> +    for prepared xids. As this is expected to be a rare event,
> +    simple wait strategy is enough. We're locking LOCK_log to be sure no
> +    new Xid_log_event's are added to the log (and prepared_xids is not
> +    increased), and waiting on COND_prep_xids for late threads to
> +    catch up.
> +  */
> +  if (prepared_xids)
> +  {
> +    tc_log_page_waits++;
> +    mysql_mutex_lock(&LOCK_prep_xids);
> +    while (prepared_xids) {
> +      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> +      mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
> +    }
> +    mysql_mutex_unlock(&LOCK_prep_xids);
> +  }
> +
> +  /* Reuse old name if not binlog and not update log */
> +  new_name_ptr= name;
> +
> +  /*
> +    If user hasn't specified an extension, generate a new log name
> +    We have to do this here and not in open as we want to store the
> +    new file name in the current binary log file.
> +  */
> +  if (generate_new_name(new_name, name))
> +    goto end;
> +  new_name_ptr=new_name;
> +
> +  if (log_type == LOG_BIN)
> +  {
> +    if (!no_auto_events)
> +    {
> +      /*
> +        We log the whole file name for log file as the user may decide
> +        to change base names at some point.
> +      */
> +      Rotate_log_event r(new_name+dirname_length(new_name),
> +                         0, LOG_EVENT_OFFSET, is_relay_log ?
> Rotate_log_event::RELAY_LOG : 0);
> +      r.write(&log_file);
> +      bytes_written += r.data_written;
> +    }
> +    /*
> +      Update needs to be signalled even if there is no rotate event
> +      log rotation should give the waiting thread a signal to
> +      discover EOF and move on to the next log.
> +    */
> +    signal_update();
> +  }
> +  old_name=name;
> +  name=0;				// Don't free name
> +  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
> +
> +  /*
> +     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
> +  */
> +
> +  /*
> +     new_file() is only used for rotation (in FLUSH LOGS or because size >
> +     max_binlog_size or max_relay_log_size).
> +     If this is a binary log, the Format_description_log_event at the beginning of
> +     the new file should have created=0 (to distinguish with the
> +     Format_description_log_event written at server startup, which should
> +     trigger temp tables deletion on slaves.
> +  */
> +
> +  /* reopen index binlog file, BUG#34582 */
> +  if (!open_index_file(index_file_name, 0, FALSE))
> +    open(old_name, log_type, new_name_ptr,
> +         io_cache_type, no_auto_events, max_size, 1, FALSE);
> +  my_free(old_name,MYF(0));
> +
> +end:
> +  if (need_lock)
> +    mysql_mutex_unlock(&LOCK_log);
> +  mysql_mutex_unlock(&LOCK_index);
> +
> +  DBUG_VOID_RETURN;
> +}
> +
> +
> +bool MYSQL_BIN_LOG::append(Log_event* ev)
> +{
> +  bool error = 0;
> +  mysql_mutex_lock(&LOCK_log);
> +  DBUG_ENTER("MYSQL_BIN_LOG::append");
> +
> +  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> +  /*
> +    Log_event::write() is smart enough to use my_b_write() or
> +    my_b_append() depending on the kind of cache we have.
> +  */
> +  if (ev->write(&log_file))
> +  {
> +    error=1;
> +    goto err;
> +  }
> +  bytes_written+= ev->data_written;
> +  DBUG_PRINT("info",("max_size: %lu",max_size));
> +  if (flush_and_sync(0))
> +    goto err;
> +  if ((uint) my_b_append_tell(&log_file) > max_size)
> +    new_file_without_locking();
> +
> +err:
> +  mysql_mutex_unlock(&LOCK_log);
> +  signal_update();				// Safe as we don't call close
> +  DBUG_RETURN(error);
> +}
> +
> +
> +bool MYSQL_BIN_LOG::appendv(const char* buf, uint len,...)
> +{
> +  bool error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::appendv");
> +  va_list(args);
> +  va_start(args,len);
> +
> +  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> +
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  do
> +  {
> +    if (my_b_append(&log_file,(uchar*) buf,len))
> +    {
> +      error= 1;
> +      goto err;
> +    }
> +    bytes_written += len;
> +  } while ((buf=va_arg(args,const char*)) && (len=va_arg(args,uint)));
> +  DBUG_PRINT("info",("max_size: %lu",max_size));
> +  if (flush_and_sync(0))
> +    goto err;
> +  if ((uint) my_b_append_tell(&log_file) > max_size)
> +    new_file_without_locking();
>  
> +err:
> +  if (!error)
> +    signal_update();
>    DBUG_RETURN(error);
>  }
>  
> -bool MYSQL_BIN_LOG::is_inited_purge_index_file()
> +bool MYSQL_BIN_LOG::flush_and_sync(bool *synced)
>  {
> -  DBUG_ENTER("MYSQL_BIN_LOG::is_inited_purge_index_file");
> -  DBUG_RETURN (my_b_inited(&purge_index_file));
> +  int err=0, fd=log_file.file;
> +  if (synced)
> +    *synced= 0;
> +  mysql_mutex_assert_owner(&LOCK_log);
> +  if (flush_io_cache(&log_file))
> +    return 1;
> +  uint sync_period= get_sync_period();
> +  if (sync_period && ++sync_counter >= sync_period)
> +  {
> +    sync_counter= 0;
> +    err= mysql_file_sync(fd, MYF(MY_WME));
> +    if (synced)
> +      *synced= 1;
> +  }
> +  return err;
>  }
>  
> -int MYSQL_BIN_LOG::sync_purge_index_file()
> +void MYSQL_BIN_LOG::start_union_events(THD *thd, query_id_t query_id_param)
>  {
> -  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_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;
> +}
>  
> -  DBUG_RETURN(error);
> +void MYSQL_BIN_LOG::stop_union_events(THD *thd)
> +{
> +  DBUG_ASSERT(thd->binlog_evt_union.do_union);
> +  thd->binlog_evt_union.do_union= FALSE;
>  }
>  
> -int MYSQL_BIN_LOG::register_purge_index_entry(const char *entry)
> +bool MYSQL_BIN_LOG::is_query_in_union(THD *thd, query_id_t query_id_param)
>  {
> -  int error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::register_purge_index_entry");
> +  return (thd->binlog_evt_union.do_union && 
> +          query_id_param >= thd->binlog_evt_union.first_query_id);
> +}
>  
> -  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);
> -}
> +/**
> +  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.
>  
> -int MYSQL_BIN_LOG::register_create_index_entry(const char *entry)
> +  @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::register_create_index_entry");
> -  DBUG_RETURN(register_purge_index_entry(entry));
> +  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);
>  }
>  
> -int MYSQL_BIN_LOG::purge_index_entry(THD *thd, ulonglong *decrease_log_space,
> -                                     bool need_mutex)
> +/*
> +  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)
>  {
> -  MY_STAT s;
> +  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;
> -  LOG_INFO log_info;
> -  LOG_INFO check_log_info;
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
>  
> -  DBUG_ENTER("MYSQL_BIN_LOG:purge_index_entry");
> +  DBUG_ASSERT(cache_mngr);
>  
> -  DBUG_ASSERT(my_b_inited(&purge_index_file));
> +  binlog_cache_data *cache_data=
> +    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
>  
> -  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;
> -  }
> +  DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long)
> cache_data->pending()));
>  
> -  for (;;)
> +  if (Rows_log_event* pending= cache_data->pending())
>    {
> -    uint length;
> +    IO_CACHE *file= &cache_data->cache_log;
>  
> -    if ((length=my_b_gets(&purge_index_file, log_info.log_file_name,
> -                          FN_REFLEN)) <= 1)
> +    /*
> +      Write pending event to the cache.
> +    */
> +    if (pending->write(file))
>      {
> -      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;
> +      set_write_error(thd);
> +      if (check_write_error(thd) && cache_data &&
> +          stmt_has_updated_non_trans_table(thd))
> +        cache_data->set_incident();
> +      DBUG_RETURN(1);
>      }
>  
> -    /* Get rid of the trailing '\n' */
> -    log_info.log_file_name[length-1]= 0;
> +    /*
> +      We step the table map version if we are writing an event
> +      representing the end of a statement.
>  
> -    if (!mysql_file_stat(key_file_binlog, log_info.log_file_name, &s, MYF(0)))
> -    {
> -      if (my_errno == ENOENT) 
> -      {
> -        /*
> -          It's not fatal if we can't stat a log file that does not exist;
> -          If we could not stat, we won't delete.
> -        */
> -        if (thd)
> -        {
> -          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                              ER_LOG_PURGE_NO_FILE, ER(ER_LOG_PURGE_NO_FILE),
> -                              log_info.log_file_name);
> -        }
> -        sql_print_information("Failed to execute mysql_file_stat on file '%s'",
> -			      log_info.log_file_name);
> -        my_errno= 0;
> -      }
> -      else
> -      {
> -        /*
> -          Other than ENOENT are fatal
> -        */
> -        if (thd)
> -        {
> -          push_warning_printf(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
> -                              ER_BINLOG_PURGE_FATAL_ERR,
> -                              "a problem with getting info on being purged %s; "
> -                              "consider examining correspondence "
> -                              "of your binlog index file "
> -                              "to the actual binlog files",
> -                              log_info.log_file_name);
> -        }
> -        else
> -        {
> -          sql_print_information("Failed to delete log file '%s'; "
> -                                "consider examining correspondence "
> -                                "of your binlog index file "
> -                                "to the actual binlog files",
> -                                log_info.log_file_name);
> -        }
> -        error= LOG_INFO_FATAL;
> -        goto err;
> -      }
> +      In an ideal world, we could avoid stepping the table map version,
> +      since we could then reuse the table map that was written earlier
> +      in the cache. This does not work since STMT_END_F implies closing
> +      all table mappings on the slave side.
> +    
> +      TODO: Find a solution so that table maps does not have to be
> +      written several times within a transaction.
> +    */
> +    if (pending->get_flags(Rows_log_event::STMT_END_F))
> +      ++m_table_map_version;
> +
> +    delete pending;
> +  }
> +
> +  thd->binlog_set_pending_rows_event(event, is_transactional);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +/**
> +  Write an event to the binary log.
> +*/
> +
> +bool MYSQL_BIN_LOG::write(Log_event *event_info)
> +{
> +  THD *thd= event_info->thd;
> +  bool error= 1;
> +  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
> +  binlog_cache_data *cache_data= 0;
> +
> +  if (thd->binlog_evt_union.do_union)
> +  {
> +    /*
> +      In Stored function; Remember that function call caused an update.
> +      We will log the function call to the binary log on function exit
> +    */
> +    thd->binlog_evt_union.unioned_events= TRUE;
> +    thd->binlog_evt_union.unioned_events_trans |=
> +      event_info->use_trans_cache();
> +    DBUG_RETURN(0);
> +  }
> +
> +  /*
> +    We only end the statement if we are in a top-level statement.  If
> +    we are inside a stored function, we do not end the statement since
> +    this will close all tables on the slave.
> +  */
> +  bool const end_stmt=
> +    thd->locked_tables_mode && thd->lex->requires_prelocking();
> +  if (thd->binlog_flush_pending_rows_event(end_stmt,
> +                                           event_info->use_trans_cache()))
> +    DBUG_RETURN(error);
> +
> +  /*
> +     In most cases this is only called if 'is_open()' is true; in fact this is
> +     mostly called if is_open() *was* true a few instructions before, but it
> +     could have changed since.
> +  */
> +  if (likely(is_open()))
> +  {
> +#ifdef HAVE_REPLICATION
> +    /*
> +      In the future we need to add to the following if tests like
> +      "do the involved tables match (to be implemented)
> +      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
> +    */
> +    const char *local_db= event_info->get_db();
> +    if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
> +	!binlog_filter->db_ok(local_db))
> +      DBUG_RETURN(0);
> +#endif /* HAVE_REPLICATION */
> +
> +    IO_CACHE *file= NULL;
> +
> +    if (event_info->use_direct_logging())
> +    {
> +      file= &log_file;
> +      mysql_mutex_lock(&LOCK_log);
>      }
>      else
>      {
> -      if ((error= find_log_pos(&check_log_info, log_info.log_file_name,
> need_mutex)))
> +      if (thd->binlog_setup_trx_data())
> +        goto err;
> +
> +      binlog_cache_mngr *const cache_mngr=
> +        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +
> +      bool is_trans_cache= use_trans_cache(thd, event_info->use_trans_cache());
> +      file= cache_mngr->get_binlog_cache_log(is_trans_cache);
> +      cache_data= cache_mngr->get_binlog_cache_data(is_trans_cache);
> +
> +      thd->binlog_start_trans_and_stmt();
> +    }
> +    DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
> +
> +    /*
> +       No check for auto events flag here - this write method should
> +       never be called if auto-events are enabled.
> +
> +       Write first log events which describe the 'run environment'
> +       of the SQL command. If row-based binlogging, Insert_id, Rand
> +       and other kind of "setting context" events are not needed.
> +    */
> +    if (thd)
> +    {
> +      if (!thd->is_current_stmt_binlog_format_row())
>        {
> -        if (error != LOG_INFO_EOF)
> +        if (thd->stmt_depends_on_first_successful_insert_id_in_prev_stmt)
>          {
> -          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;
> +          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;
>          }
> -           
> -        error= 0;
> -        if (!need_mutex)
> +        if (thd->auto_inc_intervals_in_cur_stmt_for_binlog.nb_elements() > 0)
>          {
> -          /*
> -            This is to avoid triggering an error in NDB.
> -          */
> -          ha_binlog_index_purge_file(current_thd, log_info.log_file_name);
> +          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;
>          }
> -
> -        DBUG_PRINT("info",("purging %s",log_info.log_file_name));
> -        if (!my_delete(log_info.log_file_name, MYF(0)))
> +        if (thd->rand_used)
>          {
> -          if (decrease_log_space)
> -            *decrease_log_space-= s.st_size;
> +          Rand_log_event e(thd,thd->rand_saved_seed1,thd->rand_saved_seed2);
> +          if (e.write(file))
> +            goto err;
>          }
> -        else
> +        if (thd->user_var_events.elements)
>          {
> -          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
> +          for (uint i= 0; i < thd->user_var_events.elements; i++)
>            {
> -            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;
> +            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;
> -            }
> -            error= LOG_INFO_FATAL;
> -            goto err;
>            }
>          }
>        }
>      }
> -  }
> -
> -err:
> -  DBUG_RETURN(error);
> -}
>  
> -/**
> -  Remove all logs before the given file date from disk and from the
> -  index file.
> -
> -  @param thd		Thread pointer
> -  @param purge_time	Delete all log files before given date.
> -
> -  @note
> -    If any of the logs before the deleted one is in use,
> -    only purge logs up to this one.
> -
> -  @retval
> -    0				ok
> -  @retval
> -    LOG_INFO_PURGE_NO_ROTATE	Binary file that can't be rotated
> -    LOG_INFO_FATAL              if any other than ENOENT error from
> -                                mysql_file_stat() or mysql_file_delete()
> -*/
> -
> -int MYSQL_BIN_LOG::purge_logs_before_date(time_t purge_time)
> -{
> -  int error;
> -  char to_log[FN_REFLEN];
> -  LOG_INFO log_info;
> -  MY_STAT stat_area;
> -  THD *thd= current_thd;
> -  
> -  DBUG_ENTER("purge_logs_before_date");
> -
> -  mysql_mutex_lock(&LOCK_index);
> -  to_log[0]= 0;
> +    /*
> +      Write the event.
> +    */
> +    if (event_info->write(file) ||
> +        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
> +      goto err;
>  
> -  if ((error=find_log_pos(&log_info, NullS, 0 /*no mutex*/)))
> -    goto err;
> +    error= 0;
>  
> -  while (strcmp(log_file_name, log_info.log_file_name) &&
> -	 !is_active(log_info.log_file_name) &&
> -         !log_in_use(log_info.log_file_name))
> -  {
> -    if (!mysql_file_stat(key_file_binlog,
> -                         log_info.log_file_name, &stat_area, MYF(0)))
> +err:
> +    if (event_info->use_direct_logging())
>      {
> -      if (my_errno == ENOENT) 
> -      {
> -        /*
> -          It's not fatal if we can't stat a log file that does not exist.
> -        */
> -        my_errno= 0;
> -      }
> -      else
> +      if (!error)
>        {
> -        /*
> -          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
> +        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_information("Failed to delete log file '%s'",
> -                                log_info.log_file_name);
> +          sql_print_error("Failed to run 'after_flush' hooks");
> +          goto unlock;
>          }
> -        error= LOG_INFO_FATAL;
> -        goto err;
> +        signal_update();
> +        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
>        }
> +unlock:
> +      mysql_mutex_unlock(&LOCK_log);
>      }
> -    else
> +
> +    if (error)
>      {
> -      if (stat_area.st_mtime < purge_time) 
> -        strmake(to_log, 
> -                log_info.log_file_name, 
> -                sizeof(log_info.log_file_name) - 1);
> -      else
> -        break;
> +      set_write_error(thd);
> +      if (check_write_error(thd) && cache_data &&
> +          stmt_has_updated_non_trans_table(thd))
> +        cache_data->set_incident();
>      }
> -    if (find_next_log(&log_info, 0))
> -      break;
>    }
>  
> -  error= (to_log[0] ? purge_logs(to_log, 1, 0, 1, (ulonglong *) 0) : 0);
> +  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
> +    ++m_table_map_version;
>  
> -err:
> -  mysql_mutex_unlock(&LOCK_index);
>    DBUG_RETURN(error);
>  }
> -#endif /* HAVE_REPLICATION */
> -
> -
> -/**
> -  Create a new log file name.
> -
> -  @param buf		buf of at least FN_REFLEN where new name is stored
> -
> -  @note
> -    If file name will be longer then FN_REFLEN it will be truncated
> -*/
> -
> -void MYSQL_BIN_LOG::make_log_name(char* buf, const char* log_ident)
> -{
> -  uint dir_len = dirname_length(log_file_name); 
> -  if (dir_len >= FN_REFLEN)
> -    dir_len=FN_REFLEN-1;
> -  strnmov(buf, log_file_name, dir_len);
> -  strmake(buf+dir_len, log_ident, FN_REFLEN - dir_len -1);
> -}
> -
>  
> -/**
> -  Check if we are writing/reading to the given log file.
> -*/
>  
> -bool MYSQL_BIN_LOG::is_active(const char *log_file_name_arg)
> +void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
>  {
> -  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).
> -*/
> +#ifdef HAVE_REPLICATION
> +  bool check_purge= false;
> +#endif
> +  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> +    mysql_mutex_lock(&LOCK_log);
> +  if ((flags & RP_FORCE_ROTATE) ||
> +      (my_b_tell(&log_file) >= (my_off_t) max_size))
> +  {
> +    new_file_without_locking();
> +#ifdef HAVE_REPLICATION
> +    check_purge= true;
> +#endif
> +  }
> +  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> +    mysql_mutex_unlock(&LOCK_log);
>  
> -void MYSQL_BIN_LOG::new_file()
> -{
> -  new_file_impl(1);
> +#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
>  }
>  
> -
> -void MYSQL_BIN_LOG::new_file_without_locking()
> +uint MYSQL_BIN_LOG::next_file_id()
>  {
> -  new_file_impl(0);
> +  uint res;
> +  mysql_mutex_lock(&LOCK_log);
> +  res = file_id++;
> +  mysql_mutex_unlock(&LOCK_log);
> +  return res;
>  }
>  
> 
> -/**
> -  Start writing to a new log file or reopen the old file.
> +/*
> +  Write the contents of a cache to the binary log.
>  
> -  @param need_lock		Set to 1 if caller has not locked LOCK_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
>  
> -  @note
> -    The new file name is stored last in the index file
> -*/
> +  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.
> + */
>  
> -void MYSQL_BIN_LOG::new_file_impl(bool need_lock)
> +int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
>  {
> -  char new_name[FN_REFLEN], *new_name_ptr, *old_name;
> -
> -  DBUG_ENTER("MYSQL_BIN_LOG::new_file_impl");
> -  if (!is_open())
> -  {
> -    DBUG_PRINT("info",("log is closed"));
> -    DBUG_VOID_RETURN;
> -  }
> -
> -  if (need_lock)
> -    mysql_mutex_lock(&LOCK_log);
> -  mysql_mutex_lock(&LOCK_index);
> +  Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
>  
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  mysql_mutex_assert_owner(&LOCK_index);
> +  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];
>  
>    /*
> -    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.
> +    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.
>    */
> -  if (prepared_xids)
> -  {
> -    tc_log_page_waits++;
> -    mysql_mutex_lock(&LOCK_prep_xids);
> -    while (prepared_xids) {
> -      DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> -      mysql_cond_wait(&COND_prep_xids, &LOCK_prep_xids);
> -    }
> -    mysql_mutex_unlock(&LOCK_prep_xids);
> -  }
> -
> -  /* Reuse old name if not binlog and not update log */
> -  new_name_ptr= name;
>  
> -  /*
> -    If user hasn't specified an extension, generate a new log name
> -    We have to do this here and not in open as we want to store the
> -    new file name in the current binary log file.
> -  */
> -  if (generate_new_name(new_name, name))
> -    goto end;
> -  new_name_ptr=new_name;
> +  group= (uint)my_b_tell(&log_file);
> +  hdr_offs= carry= 0;
>  
> -  if (log_type == LOG_BIN)
> +  do
>    {
> -    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.
> +      if we only got a partial header in the last iteration,
> +      get the other half now and process a full header.
>      */
> -    signal_update();
> -  }
> -  old_name=name;
> -  name=0;				// Don't free name
> -  close(LOG_CLOSE_TO_BE_OPENED | LOG_CLOSE_INDEX);
> -
> -  /*
> -     Note that at this point, log_state != LOG_CLOSED (important for is_open()).
> -  */
> -
> -  /*
> -     new_file() is only used for rotation (in FLUSH LOGS or because size >
> -     max_binlog_size or max_relay_log_size).
> -     If this is a binary log, the Format_description_log_event at the beginning of
> -     the new file should have created=0 (to distinguish with the
> -     Format_description_log_event written at server startup, which should
> -     trigger temp tables deletion on slaves.
> -  */
> -
> -  /* reopen index binlog file, BUG#34582 */
> -  if (!open_index_file(index_file_name, 0, FALSE))
> -    open(old_name, log_type, new_name_ptr,
> -         io_cache_type, no_auto_events, max_size, 1, FALSE);
> -  my_free(old_name,MYF(0));
> -
> -end:
> -  if (need_lock)
> -    mysql_mutex_unlock(&LOCK_log);
> -  mysql_mutex_unlock(&LOCK_index);
> -
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -bool MYSQL_BIN_LOG::append(Log_event* ev)
> -{
> -  bool error = 0;
> -  mysql_mutex_lock(&LOCK_log);
> -  DBUG_ENTER("MYSQL_BIN_LOG::append");
> +    if (unlikely(carry > 0))
> +    {
> +      DBUG_ASSERT(carry < LOG_EVENT_HEADER_LEN);
>  
> -  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();
> +      /* assemble both halves */
> +      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN -
> carry);
>  
> -err:
> -  mysql_mutex_unlock(&LOCK_log);
> -  signal_update();				// Safe as we don't call close
> -  DBUG_RETURN(error);
> -}
> +      /* 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;
>  
> -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);
> +      /*
> +        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);
>  
> -  DBUG_ASSERT(log_file.type == SEQ_READ_APPEND);
> +      /* next event header at ... */
> +      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
>  
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  do
> -  {
> -    if (my_b_append(&log_file,(uchar*) buf,len))
> -    {
> -      error= 1;
> -      goto err;
> +      carry= 0;
>      }
> -    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);
> -}
> +    /* if there is anything to write, process it. */
>  
> -bool MYSQL_BIN_LOG::flush_and_sync(bool *synced)
> -{
> -  int err=0, fd=log_file.file;
> -  if (synced)
> -    *synced= 0;
> -  mysql_mutex_assert_owner(&LOCK_log);
> -  if (flush_io_cache(&log_file))
> -    return 1;
> -  uint sync_period= get_sync_period();
> -  if (sync_period && ++sync_counter >= sync_period)
> -  {
> -    sync_counter= 0;
> -    err= mysql_file_sync(fd, MYF(MY_WME));
> -    if (synced)
> -      *synced= 1;
> -  }
> -  return err;
> -}
> +    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").
> +      */
>  
> -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;
> -}
> +      while (hdr_offs < length)
> +      {
> +        /*
> +          partial header only? save what we can get, process once
> +          we get the rest.
> +        */
>  
> -void MYSQL_BIN_LOG::stop_union_events(THD *thd)
> -{
> -  DBUG_ASSERT(thd->binlog_evt_union.do_union);
> -  thd->binlog_evt_union.do_union= FALSE;
> -}
> +        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 */
>  
> -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);
> -}
> +          uchar *log_pos= (uchar *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
>  
> -/** 
> -  This function checks if a transactional table was updated by the
> -  current transaction.
> +          /* fix end_log_pos */
> +          val= uint4korr(log_pos) + group;
> +          int4store(log_pos, val);
>  
> -  @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);
> +          /* next event header at ... */
> +          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
> +          hdr_offs += uint4korr(log_pos);
>  
> -  return (cache_mngr ? !cache_mngr->trx_cache.empty() : 0);
> -}
> +        }
> +      }
>  
> -/** 
> -  This function checks if a transactional table was updated by the
> -  current statement.
> +      /*
> +        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;
> +    }
>  
> -  @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;
> +    /* 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)));
>  
> -  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);
> -}
> +  DBUG_ASSERT(carry == 0);
>  
> -/** 
> -  This function checks if either a trx-cache or a non-trx-cache should
> -  be used. If @c bin_log_direct_non_trans_update is active or the format
> -  is either MIXED or ROW, the cache to be used depends on the flag @c
> -  is_transactional. 
> +  if (sync_log)
> +    return flush_and_sync(0);
>  
> -  On the other hand, if binlog_format is STMT or direct option is
> -  OFF, the trx-cache should be used if and only if the statement is
> -  transactional or the trx-cache is not empty. Otherwise, the
> -  non-trx-cache should be used.
> +  return 0;                                     // All OK
> +}
>  
> -  @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)
> +bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
>  {
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> -
> -  return
> -    ((thd->variables.binlog_format != BINLOG_FORMAT_STMT ||
> -     thd->variables.binlog_direct_non_trans_update) ? is_transactional :
> -     (is_transactional || !cache_mngr->trx_cache.empty()));
> +  uint error= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
> +  LEX_STRING const write_error_msg=
> +    { C_STRING_WITH_LEN("error writing to the binary log") };
> +  Incident incident= INCIDENT_LOST_EVENTS;
> +  Incident_log_event ev(thd, incident, write_error_msg);
> +  if (lock)
> +    mysql_mutex_lock(&LOCK_log);
> +  error= ev.write(&log_file);
> +  if (lock)
> +  {
> +    if (!error && !(error= flush_and_sync(0)))
> +    {
> +      signal_update();
> +      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> +    }
> +    mysql_mutex_unlock(&LOCK_log);
> +  }
> +  DBUG_RETURN(error);
>  }
>  
>  /**
> -  This function checks if a transaction, either a multi-statement
> -  or a single statement transaction is about to commit or not.
> +  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 The client thread that executed the current statement.
> -  @param all Committing a transaction (i.e. TRUE) or a statement
> -             (i.e. FALSE).
> -  @return
> -    @c true if committing a transaction, otherwise @c false.
> +  @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 ending_trans(THD* thd, const bool all)
> +
> +bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
> +                          bool incident)
>  {
> -  return (all || (!all && !thd->in_multi_stmt_transaction()));
> -}
> +  DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
> +  mysql_mutex_lock(&LOCK_log);
>  
> -/**
> -  This function checks if a non-transactional table was updated by
> -  the current transaction.
> +  DBUG_ASSERT(is_open());
> +  if (likely(is_open()))                       // Should always be true
> +  {
> +    /*
> +      We only bother to write to the binary log if there is anything
> +      to write.
> +     */
> +    if (my_b_tell(cache) > 0)
> +    {
> +      /*
> +        Log "BEGIN" at the beginning of every transaction.  Here, a
> +        transaction is either a BEGIN..COMMIT block or a single
> +        statement in autocommit mode.
> +      */
> +      Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
> +      if (qinfo.write(&log_file))
> +        goto err;
> +      DBUG_EXECUTE_IF("crash_before_writing_xid",
> +                      {
> +                        if ((write_error= write_cache(cache, false, true)))
> +                          DBUG_PRINT("info", ("error writing binlog cache: %d",
> +                                               write_error));
> +                        DBUG_PRINT("info", ("crashing before writing xid"));
> +                        DBUG_ABORT();
> +                      });
>  
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a non-transactional table was updated, @c false
> -    otherwise.
> -*/
> -bool trans_has_updated_non_trans_table(const THD* thd)
> -{
> -  return (thd->transaction.all.modified_non_trans_table ||
> -          thd->transaction.stmt.modified_non_trans_table);
> -}
> +      if ((write_error= write_cache(cache, false, false)))
> +        goto err;
>  
> -/**
> -  This function checks if a non-transactional table was updated by the
> -  current statement.
> +      if (commit_event && commit_event->write(&log_file))
> +        goto err;
>  
> -  @param thd The client thread that executed the current statement.
> -  @return
> -    @c true if a non-transactional table was updated, @c false otherwise.
> -*/
> -bool stmt_has_updated_non_trans_table(const THD* thd)
> -{
> -  return (thd->transaction.stmt.modified_non_trans_table);
> -}
> +      if (incident && write_incident(thd, FALSE))
> +        goto err;
>  
> -/*
> -  These functions are placed in this file since they need access to
> -  binlog_hton, which has internal linkage.
> -*/
> +      bool synced= 0;
> +      if (flush_and_sync(&synced))
> +        goto err;
> +      DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
> +      if (cache->error)				// Error on read
> +      {
> +        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
> +        write_error=1;				// Don't give more errors
> +        goto err;
> +      }
>  
> -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 (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;
> +      }
>  
> -  if (cache_mngr)
> -    DBUG_RETURN(0);                             // Already set up
> +      signal_update();
> +    }
>  
> -  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
> +    /*
> +      if commit_event is Xid_log_event, increase the number of
> +      prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
> +      if there're prepared xids in it - see the comment in new_file() for
> +      an explanation.
> +      If the commit_event is not Xid_log_event (then it's a Query_log_event)
> +      rotate binlog, if necessary.
> +    */
> +    if (commit_event && commit_event->get_type_code() == XID_EVENT)
> +    {
> +      mysql_mutex_lock(&LOCK_prep_xids);
> +      prepared_xids++;
> +      mysql_mutex_unlock(&LOCK_prep_xids);
> +    }
> +    else
> +      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
>    }
> -  thd_set_ha_data(this, binlog_hton, cache_mngr);
> -
> -  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
> +  mysql_mutex_unlock(&LOCK_log);
>  
>    DBUG_RETURN(0);
> -}
> -
> -/*
> -  Function to start a statement and optionally a transaction for the
> -  binary log.
>  
> -  SYNOPSIS
> -    binlog_start_trans_and_stmt()
> -
> -  DESCRIPTION
> +err:
> +  if (!write_error)
> +  {
> +    write_error= 1;
> +    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> +  }
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_RETURN(1);
> +}
>  
> -    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.
> +/**
> +  Wait until we get a signal that the relay log has been updated.
>  
> -    - Save the currrent binlog position so that we can roll back the
> -      statement by truncating the cache.
> +  @param thd		Thread variable
>  
> -      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.
> - */
> +  @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
> -THD::binlog_start_trans_and_stmt()
> +void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
>  {
> -  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)));
> +  const char *old_msg;
> +  DBUG_ENTER("wait_for_update_relay_log");
>  
> -  if (cache_mngr == NULL ||
> -      cache_mngr->trx_cache.get_prev_position() == MY_OFF_T_UNDEF)
> -  {
> -    this->binlog_set_stmt_begin();
> -    if (in_multi_stmt_transaction())
> -      trans_register_ha(this, TRUE, binlog_hton);
> -    trans_register_ha(this, FALSE, binlog_hton);
> -    /*
> -      Mark statement transaction as read/write. We never start
> -      a binary log transaction and keep it read-only,
> -      therefore it's best to mark the transaction read/write just
> -      at the same time we start it.
> -      Not necessary to mark the normal transaction read/write
> -      since the statement-level flag will be propagated automatically
> -      inside ha_commit_trans.
> -    */
> -    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
> -  }
> +  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> +                           "Slave has read all relay log; "
> +                           "waiting for the slave I/O "
> +                           "thread to update it" );
> +  mysql_cond_wait(&update_cond, &LOCK_log);
> +  thd->exit_cond(old_msg);
>    DBUG_VOID_RETURN;
>  }
>  
> -void THD::binlog_set_stmt_begin() {
> -  binlog_cache_mngr *cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +/**
> +  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.
> +*/
>  
> -  /*
> -    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);
> +int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
> +                                           const struct timespec *timeout)
> +{
> +  int ret= 0;
> +  const char* old_msg = thd->proc_info;
> +  DBUG_ENTER("wait_for_update_bin_log");
> +  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> +                           "Master has sent all binlog to slave; "
> +                           "waiting for binlog to be updated");
> +  if (!timeout)
> +    mysql_cond_wait(&update_cond, &LOCK_log);
> +  else
> +    ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
> +                              const_cast<struct timespec *>(timeout));
> +  DBUG_RETURN(ret);
>  }
>  
> 
>  /**
> -  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));
> +  Close the log file.
>  
> -  /* Pre-conditions */
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -  DBUG_ASSERT(table->s->table_map_id != ULONG_MAX);
> +  @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
>  
> -  Table_map_log_event
> -    the_event(this, table, table->s->table_map_id, is_transactional);
> +  @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 */
>  
> -  if (binlog_table_maps == 0)
> -    binlog_start_trans_and_stmt();
> +    /* don't pwrite in a file opened with O_APPEND - it doesn't work */
> +    if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
> +    {
> +      my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
> +      my_off_t org_position= mysql_file_tell(log_file.file, MYF(0));
> +      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
> +      mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
> +      /*
> +        Restore position so that anything we have in the IO_cache is written
> +        to the correct position.
> +        We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the
> +        original position on system that doesn't support pwrite().
> +      */
> +      mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
> +    }
>  
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
> +    /* this will cleanup IO_CACHE, sync and close the file */
> +    MYSQL_LOG::close(exiting);
> +  }
>  
> -  IO_CACHE *file=
> -    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
> -  if ((error= the_event.write(file)))
> -    DBUG_RETURN(error);
> +  /*
> +    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.
> +  */
>  
> -  binlog_table_maps++;
> -  table->s->table_map_version= mysql_bin_log.table_map_version();
> -  DBUG_RETURN(0);
> +  if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
> +  {
> +    end_io_cache(&index_file);
> +    if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error)
> +    {
> +      write_error= 1;
> +      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
> +    }
> +  }
> +  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> +  safeFree(name);
> +  DBUG_VOID_RETURN;
>  }
>  
> -/**
> -  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
> +void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
>  {
> -  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);
> +    We need to take locks, otherwise this may happen:
> +    new_file() is called, calls open(old_max_size), then before open() starts,
> +    set_max_size() sets max_size to max_size_arg, then open() starts and
> +    uses the old_max_size argument, so max_size_arg has been overwritten and
> +    it's like if the SET command was never run.
> +  */
> +  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
> +  mysql_mutex_lock(&LOCK_log);
> +  if (is_open())
> +    max_size= max_size_arg;
> +  mysql_mutex_unlock(&LOCK_log);
> +  DBUG_VOID_RETURN;
>  }
>  
> -/**
> -  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)
> +void MYSQL_BIN_LOG::signal_update()
>  {
> -  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);
> +  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
> +  signal_cnt++;
> +  mysql_cond_broadcast(&update_cond);
> +  DBUG_VOID_RETURN;
>  }
>  
> +/****** transaction coordinator log for 2pc - binlog() based solution ******/
>  
>  /**
> -  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.
> +  @todo
> +  keep in-memory list of prepared transactions
> +  (add to list in log(), remove on unlog())
> +  and copy it to the new binlog if rotated
> +  but let's check the behaviour of tc_log_page_waits first!
>  */
> -int
> -MYSQL_BIN_LOG::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);
> +int MYSQL_BIN_LOG::open(const char *opt_name)
> +{
> +  LOG_INFO log_info;
> +  int      error= 1;
>  
> -  DBUG_ASSERT(cache_mngr);
> +  DBUG_ASSERT(total_ha_2pc > 1);
> +  DBUG_ASSERT(opt_name && opt_name[0]);
>  
> -  binlog_cache_data *cache_data=
> -    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> +  mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
> +                   &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
> +  mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
>  
> -  if (Rows_log_event* pending= cache_data->pending())
> +  if (!my_b_inited(&index_file))
>    {
> -    delete pending;
> -    cache_data->set_pending(NULL);
> +    /* There was a failure to open the index file, can't open the binlog */
> +    cleanup();
> +    return 1;
>    }
>  
> -  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));
> +  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;
> +  }
>  
> -  int error= 0;
> -  binlog_cache_mngr *const cache_mngr=
> -    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  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;
> +  }
>  
> -  DBUG_ASSERT(cache_mngr);
> +  {
> +    const char *errmsg;
> +    IO_CACHE    log;
> +    File        file;
> +    Log_event  *ev=0;
> +    Format_description_log_event fdle(BINLOG_VERSION);
> +    char        log_name[FN_REFLEN];
>  
> -  binlog_cache_data *cache_data=
> -    cache_mngr->get_binlog_cache_data(use_trans_cache(thd, is_transactional));
> +    if (! fdle.is_valid())
> +      goto err;
>  
> -  DBUG_PRINT("info", ("cache_mngr->pending(): 0x%lx", (long)
> cache_data->pending()));
> +    do
> +    {
> +      strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
> +    } while (!(error= find_next_log(&log_info, 1)));
>  
> -  if (Rows_log_event* pending= cache_data->pending())
> -  {
> -    IO_CACHE *file= &cache_data->cache_log;
> +    if (error !=  LOG_INFO_EOF)
> +    {
> +      sql_print_error("find_log_pos() failed (error: %d)", error);
> +      goto err;
> +    }
>  
> -    /*
> -      Write pending event to the cache.
> -    */
> -    if (pending->write(file))
> +    if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
>      {
> -      set_write_error(thd);
> -      if (check_write_error(thd) && cache_data &&
> -          stmt_has_updated_non_trans_table(thd))
> -        cache_data->set_incident();
> -      DBUG_RETURN(1);
> +      sql_print_error("%s", errmsg);
> +      goto err;
>      }
>  
> -    /*
> -      We step the table map version if we are writing an event
> -      representing the end of a statement.
> +    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;
>  
> -      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 ev;
> +    end_io_cache(&log);
> +    mysql_file_close(file, MYF(MY_WME));
>  
> -    delete pending;
> +    if (error)
> +      goto err;
>    }
>  
> -  thd->binlog_set_pending_rows_event(event, is_transactional);
> +err:
> +  return error;
> +}
>  
> -  DBUG_RETURN(error);
> +/** This is called on shutdown, after ha_panic. */
> +void MYSQL_BIN_LOG::close()
> +{
> +  DBUG_ASSERT(prepared_xids==0);
> +  mysql_mutex_destroy(&LOCK_prep_xids);
> +  mysql_cond_destroy(&COND_prep_xids);
>  }
>  
>  /**
> -  Write an event to the binary log.
> -*/
> +  @todo
> +  group commit
>  
> -bool MYSQL_BIN_LOG::write(Log_event *event_info)
> +  @retval
> +    0    error
> +  @retval
> +    1    success
> +*/
> +int MYSQL_BIN_LOG::log_xid(THD *thd, my_xid xid)
>  {
> -  THD *thd= event_info->thd;
> -  bool error= 1;
> -  DBUG_ENTER("MYSQL_BIN_LOG::write(Log_event *)");
> -  binlog_cache_data *cache_data= 0;
> +  DBUG_ENTER("MYSQL_BIN_LOG::log_xid");
> +  Xid_log_event xle(thd, xid);
> +  binlog_cache_mngr *cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  /*
> +    We always commit the entire transaction when writing an XID. Also
> +    note that the return value is inverted.
> +   */
> +  DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) &&
> +              !binlog_flush_trx_cache(thd, cache_mngr, &xle));
> +}
>  
> -  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);
> +void MYSQL_BIN_LOG::unlog(ulong cookie, my_xid xid)
> +{
> +  mysql_mutex_lock(&LOCK_prep_xids);
> +  DBUG_ASSERT(prepared_xids > 0);
> +  if (--prepared_xids == 0) {
> +    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> +    mysql_cond_signal(&COND_prep_xids);
>    }
> +  mysql_mutex_unlock(&LOCK_prep_xids);
> +  rotate_and_purge(0);     // as ::write() did not rotate
> +}
>  
> -  /*
> -    We only end the statement if we are in a top-level statement.  If
> -    we are inside a stored function, we do not end the statement since
> -    this will close all tables on the slave.
> -  */
> -  bool const end_stmt=
> -    thd->locked_tables_mode && thd->lex->requires_prelocking();
> -  if (thd->binlog_flush_pending_rows_event(end_stmt,
> -                                           event_info->use_trans_cache()))
> -    DBUG_RETURN(error);
> +int MYSQL_BIN_LOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
> +{
> +  Log_event  *ev;
> +  HASH xids;
> +  MEM_ROOT mem_root;
>  
> -  /*
> -     In most cases this is only called if 'is_open()' is true; in fact this is
> -     mostly called if is_open() *was* true a few instructions before, but it
> -     could have changed since.
> -  */
> -  if (likely(is_open()))
> -  {
> -#ifdef HAVE_REPLICATION
> -    /*
> -      In the future we need to add to the following if tests like
> -      "do the involved tables match (to be implemented)
> -      binlog_[wild_]{do|ignore}_table?" (WL#1049)"
> -    */
> -    const char *local_db= event_info->get_db();
> -    if ((thd && !(thd->variables.option_bits & OPTION_BIN_LOG)) ||
> -	!binlog_filter->db_ok(local_db))
> -      DBUG_RETURN(0);
> -#endif /* HAVE_REPLICATION */
> +  if (! fdle->is_valid() ||
> +      my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
> +                   sizeof(my_xid), 0, 0, MYF(0)))
> +    goto err1;
>  
> -    IO_CACHE *file= NULL;
> +  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
>  
> -    if (event_info->use_direct_logging())
> +  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)
>      {
> -      file= &log_file;
> -      mysql_mutex_lock(&LOCK_log);
> +      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;
>      }
> -    else
> -    {
> -      if (thd->binlog_setup_trx_data())
> -        goto err;
> +    delete ev;
> +  }
>  
> -      binlog_cache_mngr *const cache_mngr=
> -        (binlog_cache_mngr*) thd_get_ha_data(thd, binlog_hton);
> +  if (ha_recover(&xids))
> +    goto err2;
>  
> -      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);
> +  free_root(&mem_root, MYF(0));
> +  my_hash_free(&xids);
> +  return 0;
>  
> -      thd->binlog_start_trans_and_stmt();
> -    }
> -    DBUG_PRINT("info",("event type: %d",event_info->get_type_code()));
> +err2:
> +  free_root(&mem_root, MYF(0));
> +  my_hash_free(&xids);
> +err1:
> +  sql_print_error("Crash recovery failed. Either correct the problem "
> +                  "(if it's, for example, out of memory error) and restart, "
> +                  "or delete (or rename) binary log and start mysqld with "
> +                  "--tc-heuristic-recover={commit|rollback}");
> +  return 1;
> +}
>  
> -    /*
> -       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);
> +/*
> +  These functions are placed in this file since they need access to
> +  binlog_hton, which has internal linkage.
> +*/
>  
> -            /* 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;
> +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);
>  
> -            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;
> -          }
> -        }
> -      }
> -    }
> +  if (cache_mngr)
> +    DBUG_RETURN(0);                             // Already set up
>  
> -    /*
> -      Write the event.
> -    */
> -    if (event_info->write(file) ||
> -        DBUG_EVALUATE_IF("injecting_fault_writing", 1, 0))
> -      goto err;
> +  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);
>  
> -    error= 0;
> +  cache_mngr= new (thd_get_ha_data(this, binlog_hton)) binlog_cache_mngr;
>  
> -err:
> -    if (event_info->use_direct_logging())
> -    {
> -      if (!error)
> -      {
> -        bool synced;
> -        if ((error= flush_and_sync(&synced)))
> -          goto unlock;
> +  DBUG_RETURN(0);
> +}
>  
> -        if ((error= RUN_HOOK(binlog_storage, after_flush,
> -                 (thd, log_file_name, file->pos_in_file, synced))))
> -        {
> -          sql_print_error("Failed to run 'after_flush' hooks");
> -          goto unlock;
> -        }
> -        signal_update();
> -        rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> -      }
> -unlock:
> -      mysql_mutex_unlock(&LOCK_log);
> -    }
> +/*
> +  Function to start a statement and optionally a transaction for the
> +  binary log.
>  
> -    if (error)
> -    {
> -      set_write_error(thd);
> -      if (check_write_error(thd) && cache_data &&
> -          stmt_has_updated_non_trans_table(thd))
> -        cache_data->set_incident();
> -    }
> -  }
> +  SYNOPSIS
> +    binlog_start_trans_and_stmt()
>  
> -  if (event_info->flags & LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F)
> -    ++m_table_map_version;
> +  DESCRIPTION
>  
> -  DBUG_RETURN(error);
> -}
> +    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.
>  
> -void MYSQL_BIN_LOG::rotate_and_purge(uint flags)
> +    - 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()
>  {
> -#ifdef HAVE_REPLICATION
> -  bool check_purge= false;
> -#endif
> -  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> -    mysql_mutex_lock(&LOCK_log);
> -  if ((flags & RP_FORCE_ROTATE) ||
> -      (my_b_tell(&log_file) >= (my_off_t) max_size))
> +  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)
>    {
> -    new_file_without_locking();
> -#ifdef HAVE_REPLICATION
> -    check_purge= true;
> -#endif
> +    this->binlog_set_stmt_begin();
> +    if (in_multi_stmt_transaction())
> +      trans_register_ha(this, TRUE, binlog_hton);
> +    trans_register_ha(this, FALSE, binlog_hton);
> +    /*
> +      Mark statement transaction as read/write. We never start
> +      a binary log transaction and keep it read-only,
> +      therefore it's best to mark the transaction read/write just
> +      at the same time we start it.
> +      Not necessary to mark the normal transaction read/write
> +      since the statement-level flag will be propagated automatically
> +      inside ha_commit_trans.
> +    */
> +    ha_data[binlog_hton->slot].ha_info[0].set_trx_read_write();
>    }
> -  if (!(flags & RP_LOCK_LOG_IS_ALREADY_LOCKED))
> -    mysql_mutex_unlock(&LOCK_log);
> +  DBUG_VOID_RETURN;
> +}
> +
> +void THD::binlog_set_stmt_begin() {
> +  binlog_cache_mngr *cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
>  
> -#ifdef HAVE_REPLICATION
>    /*
> -    NOTE: Run purge_logs wo/ holding LOCK_log
> -          as it otherwise will deadlock in ndbcluster_binlog_index_purge_file
> +    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).
>    */
> -  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
> +  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);
>  }
>  
> -uint MYSQL_BIN_LOG::next_file_id()
> +
> +/**
> +  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)
>  {
> -  uint res;
> -  mysql_mutex_lock(&LOCK_log);
> -  res = file_id++;
> -  mysql_mutex_unlock(&LOCK_log);
> -  return res;
> -}
> +  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);
>  
> -/*
> -  Write the contents of a cache to the binary log.
> +  Table_map_log_event
> +    the_event(this, table, table->s->table_map_id, is_transactional);
>  
> -  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
> +  if (binlog_table_maps == 0)
> +    binlog_start_trans_and_stmt();
>  
> -  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.
> - */
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
>  
> -int MYSQL_BIN_LOG::write_cache(IO_CACHE *cache, bool lock_log, bool sync_log)
> -{
> -  Mutex_sentry sentry(lock_log ? &LOCK_log : NULL);
> +  IO_CACHE *file=
> +    cache_mngr->get_binlog_cache_log(use_trans_cache(this, is_transactional));
> +  if ((error= the_event.write(file)))
> +    DBUG_RETURN(error);
>  
> -  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];
> +  binlog_table_maps++;
> +  table->s->table_map_version= mysql_bin_log.table_map_version();
> +  DBUG_RETURN(0);
> +}
>  
> -  /*
> -    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.
> -  */
> +/**
> +  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.
>  
> -  group= (uint)my_b_tell(&log_file);
> -  hdr_offs= carry= 0;
> +  @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);
>  
> -  do
> +  /*
> +    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)
>    {
> -    /*
> -      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);
> +    binlog_cache_data *cache_data=
> +      cache_mngr->get_binlog_cache_data(use_trans_cache(this,
> is_transactional));
>  
> -      /* assemble both halves */
> -      memcpy(&header[carry], (char *)cache->read_pos, LOG_EVENT_HEADER_LEN -
> carry);
> +    rows= cache_data->pending();
> +  }
> +  return (rows);
> +}
>  
> -      /* fix end_log_pos */
> -      val= uint4korr(&header[LOG_POS_OFFSET]) + group;
> -      int4store(&header[LOG_POS_OFFSET], val);
> +/**
> +  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.
>  
> -      /* write the first half of the split header */
> -      if (my_b_write(&log_file, header, carry))
> -        return ER_ERROR_ON_WRITE;
> +  @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();
>  
> -      /*
> -        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);
> +  binlog_cache_mngr *const cache_mngr=
> +    (binlog_cache_mngr*) thd_get_ha_data(this, binlog_hton);
>  
> -      /* next event header at ... */
> -      hdr_offs = uint4korr(&header[EVENT_LEN_OFFSET]) - carry;
> +  DBUG_ASSERT(cache_mngr);
>  
> -      carry= 0;
> -    }
> +  binlog_cache_data *cache_data=
> +    cache_mngr->get_binlog_cache_data(use_trans_cache(this, is_transactional));
>  
> -    /* if there is anything to write, process it. */
> +  cache_data->set_pending(ev);
> +}
>  
> -    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").
> -      */
> +/**
> +  Decide on logging format to use for the statement and issue errors
> +  or warnings as needed.  The decision depends on the following
> +  parameters:
>  
> -      while (hdr_offs < length)
> -      {
> -        /*
> -          partial header only? save what we can get, process once
> -          we get the rest.
> -        */
> +  - The logging mode, i.e., the value of binlog_format.  Can be
> +    statement, mixed, or row.
> +
> +  - The type of statement.  There are three types of statements:
> +    "normal" safe statements; unsafe statements; and row injections.
> +    An unsafe statement is one that, if logged in statement format,
> +    might produce different results when replayed on the slave (e.g.,
> +    INSERT DELAYED).  A row injection is either a BINLOG statement, or
> +    a row event executed by the slave's SQL thread.
> +
> +  - The capabilities of tables modified by the statement.  The
> +    *capabilities vector* for a table is a set of flags associated
> +    with the table.  Currently, it only includes two flags: *row
> +    capability flag* and *statement capability flag*.
> +
> +    The row capability flag is set if and only if the engine can
> +    handle row-based logging. The statement capability flag is set if
> +    and only if the table can handle statement-based logging.
>  
> -        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 */
> +  Decision table for logging format
> +  ---------------------------------
>  
> -          uchar *log_pos= (uchar *)cache->read_pos + hdr_offs + LOG_POS_OFFSET;
> +  The following table summarizes how the format and generated
> +  warning/error depends on the tables' capabilities, the statement
> +  type, and the current binlog_format.
>  
> -          /* fix end_log_pos */
> -          val= uint4korr(log_pos) + group;
> -          int4store(log_pos, val);
> +     Row capable        N NNNNNNNNN YYYYYYYYY YYYYYYYYY
> +     Statement capable  N YYYYYYYYY NNNNNNNNN YYYYYYYYY
>  
> -          /* next event header at ... */
> -          log_pos= (uchar *)cache->read_pos + hdr_offs + EVENT_LEN_OFFSET;
> -          hdr_offs += uint4korr(log_pos);
> +     Statement type     * SSSUUUIII SSSUUUIII SSSUUUIII
>  
> -        }
> -      }
> +     binlog_format      * SMRSMRSMR SMRSMRSMR SMRSMRSMR
>  
> -      /*
> -        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;
> -    }
> +     Logged format      - SS-S----- -RR-RR-RR SRRSRR-RR
> +     Warning/Error      1 --2732444 5--5--6-- ---7--6--
>  
> -    /* 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)));
> +  Legend
> +  ------
>  
> -  DBUG_ASSERT(carry == 0);
> +  Row capable:    N - Some table not row-capable, Y - All tables row-capable
> +  Stmt capable:   N - Some table not stmt-capable, Y - All tables stmt-capable
> +  Statement type: (S)afe, (U)nsafe, or Row (I)njection
> +  binlog_format:  (S)TATEMENT, (M)IXED, or (R)OW
> +  Logged format:  (S)tatement or (R)ow
> +  Warning/Error:  Warnings and error messages are as follows:
>  
> -  if (sync_log)
> -    return flush_and_sync(0);
> +  1. Error: Cannot execute statement: binlogging impossible since both
> +     row-incapable engines and statement-incapable engines are
> +     involved.
>  
> -  return 0;                                     // All OK
> -}
> +  2. Error: Cannot execute statement: binlogging impossible since
> +     BINLOG_FORMAT = ROW and at least one table uses a storage engine
> +     limited to statement-logging.
>  
> -/*
> -  Helper function to get the error code of the query to be binlogged.
> - */
> -int query_error_code(THD *thd, bool not_killed)
> -{
> -  int error;
> -  
> -  if (not_killed || (thd->killed == THD::KILL_BAD_DATA))
> -  {
> -    error= thd->is_error() ? thd->stmt_da->sql_errno() : 0;
> +  3. Error: Cannot execute statement: binlogging of unsafe statement
> +     is impossible when storage engine is limited to statement-logging
> +     and BINLOG_FORMAT = MIXED.
>  
> -    /* thd->stmt_da->sql_errno() might be ER_SERVER_SHUTDOWN or
> -       ER_QUERY_INTERRUPTED, So here we need to make sure that error
> -       is not set to these errors when specified not_killed by the
> -       caller.
> -    */
> -    if (error == ER_SERVER_SHUTDOWN || error == ER_QUERY_INTERRUPTED)
> -      error= 0;
> -  }
> -  else
> -  {
> -    /* killed status for DELAYED INSERT thread should never be used */
> -    DBUG_ASSERT(!(thd->system_thread & SYSTEM_THREAD_DELAYED_INSERT));
> -    error= thd->killed_errno();
> -  }
> +  4. Error: Cannot execute row injection: binlogging impossible since
> +     at least one table uses a storage engine limited to
> +     statement-logging.
>  
> -  return error;
> -}
> +  5. Error: Cannot execute statement: binlogging impossible since
> +     BINLOG_FORMAT = STATEMENT and at least one table uses a storage
> +     engine limited to row-logging.
>  
> -bool MYSQL_BIN_LOG::write_incident(THD *thd, bool lock)
> -{
> -  uint error= 0;
> -  DBUG_ENTER("MYSQL_BIN_LOG::write_incident");
> -  LEX_STRING const write_error_msg=
> -    { C_STRING_WITH_LEN("error writing to the binary log") };
> -  Incident incident= INCIDENT_LOST_EVENTS;
> -  Incident_log_event ev(thd, incident, write_error_msg);
> -  if (lock)
> -    mysql_mutex_lock(&LOCK_log);
> -  error= ev.write(&log_file);
> -  if (lock)
> -  {
> -    if (!error && !(error= flush_and_sync(0)))
> -    {
> -      signal_update();
> -      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> -    }
> -    mysql_mutex_unlock(&LOCK_log);
> -  }
> -  DBUG_RETURN(error);
> -}
> +  6. Error: Cannot execute row injection: binlogging impossible since
> +     BINLOG_FORMAT = STATEMENT.
>  
> -/**
> -  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.
> +  7. Warning: Unsafe statement binlogged in statement format since
> +     BINLOG_FORMAT = STATEMENT.
>  
> -  @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.
> +  In addition, we can produce the following error (not depending on
> +  the variables of the decision diagram):
>  
> -  @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.
> +  8. Error: Cannot execute statement: binlogging impossible since more
> +     than one engine is involved and at least one engine is
> +     self-logging.
> +
> +  For each error case above, the statement is prevented from being
> +  logged, we report an error, and roll back the statement.  For
> +  warnings, we set the thd->binlog_flags variable: the warning will be
> +  printed only if the statement is successfully logged.
> +
> +  @see THD::binlog_query
> +
> +  @param[in] thd    Client thread
> +  @param[in] tables Tables involved in the query
> +
> +  @retval 0 No error; statement can be logged.
> +  @retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
>  */
>  
> -bool MYSQL_BIN_LOG::write(THD *thd, IO_CACHE *cache, Log_event *commit_event,
> -                          bool incident)
> +int THD::decide_logging_format(TABLE_LIST *tables)
>  {
> -  DBUG_ENTER("MYSQL_BIN_LOG::write(THD *, IO_CACHE *, Log_event *)");
> -  mysql_mutex_lock(&LOCK_log);
> +  DBUG_ENTER("THD::decide_logging_format");
> +  DBUG_PRINT("info", ("query: %s", query()));
> +  DBUG_PRINT("info", ("variables.binlog_format: %u",
> +                      variables.binlog_format));
> +  DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
> +                      lex->get_stmt_unsafe_flags()));
>  
> -  DBUG_ASSERT(is_open());
> -  if (likely(is_open()))                       // Should always be true
> +  /*
> +    We should not decide logging format if the binlog is closed or
> +    binlogging is off, or if the statement is filtered out from the
> +    binlog by filtering rules.
> +  */
> +  if (mysql_bin_log.is_open() && (variables.option_bits &
> OPTION_BIN_LOG) &&
> +      !(variables.binlog_format == BINLOG_FORMAT_STMT &&
> +        !binlog_filter->db_ok(db)))
>    {
>      /*
> -      We only bother to write to the binary log if there is anything
> -      to write.
> -     */
> -    if (my_b_tell(cache) > 0)
> +      Compute one bit field with the union of all the engine
> +      capabilities, and one with the intersection of all the engine
> +      capabilities.
> +    */
> +    handler::Table_flags flags_write_some_set= 0;
> +    handler::Table_flags flags_some_set= 0;
> +    handler::Table_flags flags_write_all_set=
> +      HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
> +
> +    /* 
> +       If different types of engines are about to be updated.
> +       For example: Innodb and Falcon; Innodb and MyIsam.
> +    */
> +    my_bool multi_write_engine= FALSE;
> +    /*
> +       If different types of engines are about to be accessed 
> +       and any of them is about to be updated. For example:
> +       Innodb and Falcon; Innodb and MyIsam.
> +    */
> +    my_bool multi_access_engine= FALSE;
> +    /*
> +       If non-transactional and transactional engines are about
> +       to be accessed and any of them is about to be updated.
> +       For example: Innodb and MyIsam.
> +    */
> +    my_bool trans_non_trans_access_engines= FALSE;
> +    /*
> +       If all engines that are about to be updated are
> +       transactional.
> +    */
> +    my_bool all_trans_write_engines= TRUE;
> +    TABLE* prev_write_table= NULL;
> +    TABLE* prev_access_table= NULL;
> +
> +#ifndef DBUG_OFF
> +    {
> +      static const char *prelocked_mode_name[] = {
> +        "NON_PRELOCKED",
> +        "PRELOCKED",
> +        "PRELOCKED_UNDER_LOCK_TABLES",
> +      };
> +      DBUG_PRINT("debug", ("prelocked_mode: %s",
> +                           prelocked_mode_name[locked_tables_mode]));
> +    }
> +#endif
> +
> +    /*
> +      Get the capabilities vector for all involved storage engines and
> +      mask out the flags for the binary log.
> +    */
> +    for (TABLE_LIST *table= tables; table; table= table->next_global)
>      {
> +      if (table->placeholder())
> +        continue;
> +      if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
> +        lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
> +      handler::Table_flags const flags=
> table->table->file->ha_table_flags();
> +      DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
> +                          table->table_name, flags));
> +      if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
> +      {
> +        if (prev_write_table && prev_write_table->file->ht !=
> +            table->table->file->ht)
> +          multi_write_engine= TRUE;
> +        /*
> +          Every temporary table must be always written to the binary
> +          log in transaction boundaries and as such we artificially
> +          classify them as transactional.
> +
> +          Indirectly, this avoids classifying a temporary table created
> +          on a non-transactional engine as unsafe when it is modified
> +          after any transactional table:
> +
> +          BEGIN;
> +            INSERT INTO innodb_t VALUES (1);
> +            INSERT INTO myisam_t_temp VALUES (1);
> +          COMMIT;
> +
> +          BINARY LOG:
> +
> +          BEGIN;
> +            INSERT INTO innodb_t VALUES (1);
> +            INSERT INTO myisam_t_temp VALUES (1);
> +          COMMIT;
> +        */
> +        all_trans_write_engines= all_trans_write_engines &&
> +                                 (table->table->file->has_transactions()
> ||
> +                                  table->table->s->tmp_table);
> +        prev_write_table= table->table;
> +        flags_write_all_set &= flags;
> +        flags_write_some_set |= flags;
> +      }
> +      flags_some_set |= flags;
>        /*
> -        Log "BEGIN" at the beginning of every transaction.  Here, a
> -        transaction is either a BEGIN..COMMIT block or a single
> -        statement in autocommit mode.
> -      */
> -      Query_log_event qinfo(thd, STRING_WITH_LEN("BEGIN"), TRUE, FALSE, TRUE, 0);
> -      if (qinfo.write(&log_file))
> -        goto err;
> -      DBUG_EXECUTE_IF("crash_before_writing_xid",
> -                      {
> -                        if ((write_error= write_cache(cache, false, true)))
> -                          DBUG_PRINT("info", ("error writing binlog cache: %d",
> -                                               write_error));
> -                        DBUG_PRINT("info", ("crashing before writing xid"));
> -                        DBUG_ABORT();
> -                      });
> +        The mixture of non-transactional and transactional tables must
> +        identified and classified as unsafe. However, a temporary table
> +        must be always handled as a transactional table. Based on that,
> +        we have the following statements classified as mixed and by
> +        consequence as unsafe:
>  
> -      if ((write_error= write_cache(cache, false, false)))
> -        goto err;
> +        1: INSERT INTO myisam_t SELECT * FROM innodb_t;
>  
> -      if (commit_event && commit_event->write(&log_file))
> -        goto err;
> +        2: INSERT INTO innodb_t SELECT * FROM myisam_t;
>  
> -      if (incident && write_incident(thd, FALSE))
> -        goto err;
> +        3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
>  
> -      bool synced= 0;
> -      if (flush_and_sync(&synced))
> -        goto err;
> -      DBUG_EXECUTE_IF("half_binlogged_transaction", DBUG_ABORT(););
> -      if (cache->error)				// Error on read
> -      {
> -        sql_print_error(ER(ER_ERROR_ON_READ), cache->file_name, errno);
> -        write_error=1;				// Don't give more errors
> -        goto err;
> -      }
> +        4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
>  
> -      if (RUN_HOOK(binlog_storage, after_flush,
> -                   (thd, log_file_name, log_file.pos_in_file, synced)))
> +        5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> +
> +        The following statements are not considered mixed and as such
> +        are safe:
> +
> +        1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
> +
> +        2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
> +      */
> +      if (!trans_non_trans_access_engines && prev_access_table &&
> +          (lex->sql_command != SQLCOM_CREATE_TABLE ||
> +          (lex->sql_command == SQLCOM_CREATE_TABLE &&
> +          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
>        {
> -        sql_print_error("Failed to run 'after_flush' hooks");
> -        write_error=1;
> -        goto err;
> +        my_bool prev_trans;
> +        my_bool act_trans;
> +        if (prev_access_table->s->tmp_table ||
> table->table->s->tmp_table)
> +        {
> +          prev_trans= prev_access_table->s->tmp_table ? TRUE :
> +                     prev_access_table->file->has_transactions();
> +          act_trans= table->table->s->tmp_table ? TRUE :
> +                    table->table->file->has_transactions();
> +        }
> +        else
> +        {
> +          prev_trans= prev_access_table->file->has_transactions();
> +          act_trans= table->table->file->has_transactions();
> +        }
> +        trans_non_trans_access_engines= (prev_trans != act_trans);
> +        multi_access_engine= TRUE;
>        }
> -
> -      signal_update();
> +      thread_temporary_used |= table->table->s->tmp_table;
> +      prev_access_table= table->table;
>      }
>  
> +    DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
> +    DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
> +    DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
> +    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
> +    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
> +    DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
> +                        trans_non_trans_access_engines));
> +
> +    int error= 0;
> +    int unsafe_flags;
> +
>      /*
> -      if commit_event is Xid_log_event, increase the number of
> -      prepared_xids (it's decreasd in ::unlog()). Binlog cannot be rotated
> -      if there're prepared xids in it - see the comment in new_file() for
> -      an explanation.
> -      If the commit_event is not Xid_log_event (then it's a Query_log_event)
> -      rotate binlog, if necessary.
> -    */
> -    if (commit_event && commit_event->get_type_code() == XID_EVENT)
> -    {
> -      mysql_mutex_lock(&LOCK_prep_xids);
> -      prepared_xids++;
> -      mysql_mutex_unlock(&LOCK_prep_xids);
> -    }
> -    else
> -      rotate_and_purge(RP_LOCK_LOG_IS_ALREADY_LOCKED);
> -  }
> -  mysql_mutex_unlock(&LOCK_log);
> +      Set the statement as unsafe if:
>  
> -  DBUG_RETURN(0);
> +      . it is a mixed statement, i.e. access transactional and non-transactional
> +      tables, and update any of them;
>  
> -err:
> -  if (!write_error)
> -  {
> -    write_error= 1;
> -    sql_print_error(ER(ER_ERROR_ON_WRITE), name, errno);
> -  }
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_RETURN(1);
> -}
> +      or:
>  
> +      . an early statement updated a transactional table;
> +      . and, the current statement updates a non-transactional table.
>  
> -/**
> -  Wait until we get a signal that the relay log has been updated.
> +      Any mixed statement is classified as unsafe to ensure that mixed mode is
> +      completely safe. Consider the following example to understand why we
> +      decided to do this:
>  
> -  @param thd		Thread variable
> +      Note that mixed statements such as
>  
> -  @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).
> -*/
> +      1: INSERT INTO myisam_t SELECT * FROM innodb_t;
>  
> -void MYSQL_BIN_LOG::wait_for_update_relay_log(THD* thd)
> -{
> -  const char *old_msg;
> -  DBUG_ENTER("wait_for_update_relay_log");
> +      2: INSERT INTO innodb_t SELECT * FROM myisam_t;
>  
> -  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> -                           "Slave has read all relay log; "
> -                           "waiting for the slave I/O "
> -                           "thread to update it" );
> -  mysql_cond_wait(&update_cond, &LOCK_log);
> -  thd->exit_cond(old_msg);
> -  DBUG_VOID_RETURN;
> -}
> +      3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
>  
> -/**
> -  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.
> -*/
> +      4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> +
> +      5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
>  
> -int MYSQL_BIN_LOG::wait_for_update_bin_log(THD* thd,
> -                                           const struct timespec *timeout)
> -{
> -  int ret= 0;
> -  const char* old_msg = thd->proc_info;
> -  DBUG_ENTER("wait_for_update_bin_log");
> -  old_msg= thd->enter_cond(&update_cond, &LOCK_log,
> -                           "Master has sent all binlog to slave; "
> -                           "waiting for binlog to be updated");
> -  if (!timeout)
> -    mysql_cond_wait(&update_cond, &LOCK_log);
> -  else
> -    ret= mysql_cond_timedwait(&update_cond, &LOCK_log,
> -                              const_cast<struct timespec *>(timeout));
> -  DBUG_RETURN(ret);
> -}
> +      are classified as unsafe to ensure that in mixed mode the execution is
> +      completely safe and equivalent to the row mode. Consider the following
> +      statements and sessions (connections) to understand the reason:
>  
> +      con1: INSERT INTO innodb_t VALUES (1);
> +      con1: INSERT INTO innodb_t VALUES (100);
>  
> -/**
> -  Close the log file.
> +      con1: BEGIN
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
>  
> -  @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
> +      The point is that the concurrent statements may be written into the binary
> log
> +      in a way different from the execution. For example,
>  
> -  @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
> -*/
> +      BINARY LOG:
>  
> -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 */
> +      con2: BEGIN;
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con2: COMMIT;
> +      con1: BEGIN
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
>  
> -    /* don't pwrite in a file opened with O_APPEND - it doesn't work */
> -    if (log_file.type == WRITE_CACHE && log_type == LOG_BIN)
> +      ....
> +
> +      or
> +
> +      BINARY LOG:
> +
> +      con1: BEGIN
> +      con1: INSERT INTO innodb_t VALUES (200);
> +      con1: COMMIT;
> +      con2: BEGIN;
> +      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> +      con2: COMMIT;
> +
> +      Clearly, this may become a problem in STMT mode and setting the statement
> +      as unsafe will make rows to be written into the binary log in MIXED mode
> +      and as such the problem will not stand.
> +
> +      In STMT mode, although such statement is classified as unsafe, i.e.
> +
> +      INSERT INTO myisam_t SELECT * FROM innodb_t;
> +
> +      there is no enough information to avoid writing it outside the boundaries
> +      of a transaction. This is not a problem if we are considering snapshot
> +      isolation level but if we have pure repeatable read or serializable the
> +      lock history on the slave will be different from the master.
> +    */
> +    if (trans_non_trans_access_engines)
> +      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
> +    else if (trans_has_updated_trans_table(this) &&
> !all_trans_write_engines)
> +      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
> +
> +    /*
> +      If more than one engine is involved in the statement and at
> +      least one is doing it's own logging (is *self-logging*), the
> +      statement cannot be logged atomically, so we generate an error
> +      rather than allowing the binlog to become corrupt.
> +    */
> +    if (multi_write_engine &&
> +        (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
> +      my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
> +               MYF(0));
> +    else if (multi_access_engine && flags_some_set &
> HA_HAS_OWN_BINLOGGING)
> +     
> lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
> +
> +    /* both statement-only and row-only engines involved */
> +    if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE))
> == 0)
>      {
> -      my_off_t offset= BIN_LOG_HEADER_SIZE + FLAGS_OFFSET;
> -      my_off_t org_position= mysql_file_tell(log_file.file, MYF(0));
> -      uchar flags= 0;            // clearing LOG_EVENT_BINLOG_IN_USE_F
> -      mysql_file_pwrite(log_file.file, &flags, 1, offset, MYF(0));
>        /*
> -        Restore position so that anything we have in the IO_cache is written
> -        to the correct position.
> -        We need the seek here, as mysql_file_pwrite() is not guaranteed to keep the
> -        original position on system that doesn't support pwrite().
> +        1. Error: Binary logging impossible since both row-incapable
> +           engines and statement-incapable engines are involved
>        */
> -      mysql_file_seek(log_file.file, org_position, MY_SEEK_SET, MYF(0));
> +      my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
>      }
> -
> -    /* this will cleanup IO_CACHE, sync and close the file */
> -    MYSQL_LOG::close(exiting);
> -  }
> -
> -  /*
> -    The following test is needed even if is_open() is not set, as we may have
> -    called a not complete close earlier and the index file is still open.
> -  */
> -
> -  if ((exiting & LOG_CLOSE_INDEX) && my_b_inited(&index_file))
> -  {
> -    end_io_cache(&index_file);
> -    if (mysql_file_close(index_file.file, MYF(0)) < 0 && ! write_error)
> +    /* statement-only engines involved */
> +    else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
>      {
> -      write_error= 1;
> -      sql_print_error(ER(ER_ERROR_ON_WRITE), index_file_name, errno);
> +      if (lex->is_stmt_row_injection())
> +      {
> +        /*
> +          4. Error: Cannot execute row injection since table uses
> +             storage engine limited to statement-logging
> +        */
> +        my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
> +      }
> +      else if (variables.binlog_format == BINLOG_FORMAT_ROW)
> +      {
> +        /*
> +          2. Error: Cannot modify table that uses a storage engine
> +             limited to statement-logging when BINLOG_FORMAT = ROW
> +        */
> +        my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
> +      }
> +      else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> +      {
> +        /*
> +          3. Error: Cannot execute statement: binlogging of unsafe
> +             statement is impossible when storage engine is limited to
> +             statement-logging and BINLOG_FORMAT = MIXED.
> +        */
> +        for (int unsafe_type= 0;
> +             unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> +             unsafe_type++)
> +          if (unsafe_flags & (1 << unsafe_type))
> +            my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
> +                     ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +      }
> +      /* log in statement format! */
> +    }
> +    /* no statement-only engines */
> +    else
> +    {
> +      /* binlog_format = STATEMENT */
> +      if (variables.binlog_format == BINLOG_FORMAT_STMT)
> +      {
> +        if (lex->is_stmt_row_injection())
> +        {
> +          /*
> +            6. Error: Cannot execute row injection since
> +               BINLOG_FORMAT = STATEMENT
> +          */
> +          my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
> +        }
> +        else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> +        {
> +          /*
> +            5. Error: Cannot modify table that uses a storage engine
> +               limited to row-logging when binlog_format = STATEMENT
> +          */
> +          my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
> +        }
> +        else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> +        {
> +          /*
> +            7. Warning: Unsafe statement logged as statement due to
> +               binlog_format = STATEMENT
> +          */
> +          binlog_unsafe_warning_flags|= unsafe_flags;
> +          DBUG_PRINT("info", ("Scheduling warning to be issued by "
> +                              "binlog_query: '%s'",
> +                              ER(ER_BINLOG_UNSAFE_STATEMENT)));
> +          DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
> +                              binlog_unsafe_warning_flags));
> +        }
> +        /* log in statement format! */
> +      }
> +      /* No statement-only engines and binlog_format != STATEMENT.
> +         I.e., nothing prevents us from row logging if needed. */
> +      else
> +      {
> +        if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
> +            || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> +        {
> +          /* log in row format! */
> +          set_current_stmt_binlog_format_row_if_mixed();
> +        }
> +      }
>      }
> -  }
> -  log_state= (exiting & LOG_CLOSE_TO_BE_OPENED) ? LOG_TO_BE_OPENED :
> LOG_CLOSED;
> -  safeFree(name);
> -  DBUG_VOID_RETURN;
> -}
>  
> +    if (error) {
> +      DBUG_PRINT("info", ("decision: no logging since an error was generated"));
> +      DBUG_RETURN(-1);
> +    }
> +    DBUG_PRINT("info", ("decision: logging in %s format",
> +                        is_current_stmt_binlog_format_row() ?
> +                        "ROW" : "STATEMENT"));
> +  }
> +#ifndef DBUG_OFF
> +  else
> +    DBUG_PRINT("info", ("decision: no logging since "
> +                        "mysql_bin_log.is_open() = %d "
> +                        "and (options & OPTION_BIN_LOG) = 0x%llx "
> +                        "and binlog_format = %u "
> +                        "and binlog_filter->db_ok(db) = %d",
> +                        mysql_bin_log.is_open(),
> +                        (variables.option_bits & OPTION_BIN_LOG),
> +                        variables.binlog_format,
> +                        binlog_filter->db_ok(db)));
> +#endif
>  
> -void MYSQL_BIN_LOG::set_max_size(ulong max_size_arg)
> -{
> -  /*
> -    We need to take locks, otherwise this may happen:
> -    new_file() is called, calls open(old_max_size), then before open() starts,
> -    set_max_size() sets max_size to max_size_arg, then open() starts and
> -    uses the old_max_size argument, so max_size_arg has been overwritten and
> -    it's like if the SET command was never run.
> -  */
> -  DBUG_ENTER("MYSQL_BIN_LOG::set_max_size");
> -  mysql_mutex_lock(&LOCK_log);
> -  if (is_open())
> -    max_size= max_size_arg;
> -  mysql_mutex_unlock(&LOCK_log);
> -  DBUG_VOID_RETURN;
> +  DBUG_RETURN(0);
>  }
>  
> 
> -void MYSQL_BIN_LOG::signal_update()
> -{
> -  DBUG_ENTER("MYSQL_BIN_LOG::signal_update");
> -  signal_cnt++;
> -  mysql_cond_broadcast(&update_cond);
> -  DBUG_VOID_RETURN;
> -}
> +/*
> +  Implementation of interface to write rows to the binary log through the
> +  thread.  The thread is responsible for writing the rows it has
> +  inserted/updated/deleted.
> +*/
>  
> -/****** transaction coordinator log for 2pc - binlog() based solution ******/
> -#define TC_LOG_BINLOG MYSQL_BIN_LOG
> +#ifndef MYSQL_CLIENT
>  
> -/**
> -  @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!
> -*/
> +/*
> +  Template member function for ensuring that there is an rows log
> +  event of the apropriate type before proceeding.
> +
> +  PRE CONDITION:
> +    - Events of type 'RowEventT' have the type code 'type_code'.
> +    
> +  POST CONDITION:
> +    If a non-NULL pointer is returned, the pending event for thread 'thd' will
> +    be an event of type 'RowEventT' (which have the type code 'type_code')
> +    will either empty or have enough space to hold 'needed' bytes.  In
> +    addition, the columns bitmap will be correct for the row, meaning that
> +    the pending event will be flushed if the columns in the event differ from
> +    the columns suppled to the function.
> +
> +  RETURNS
> +    If no error, a non-NULL pending event (either one which already existed or
> +    the newly created one).
> +    If error, NULL.
> + */
>  
> -int TC_LOG_BINLOG::open(const char *opt_name)
> +template <class RowsEventT> Rows_log_event* 
> +THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
> +                                       MY_BITMAP const* cols,
> +                                       size_t colcnt,
> +                                       size_t needed,
> +                                       bool is_transactional,
> +				       RowsEventT *hint __attribute__((unused)))
>  {
> -  LOG_INFO log_info;
> -  int      error= 1;
> +  DBUG_ENTER("binlog_prepare_pending_rows_event");
> +  /* Pre-conditions */
> +  DBUG_ASSERT(table->s->table_map_id != ~0UL);
>  
> -  DBUG_ASSERT(total_ha_2pc > 1);
> -  DBUG_ASSERT(opt_name && opt_name[0]);
> +  /* Fetch the type code for the RowsEventT template parameter */
> +  int const type_code= RowsEventT::TYPE_CODE;
>  
> -  mysql_mutex_init(key_BINLOG_LOCK_prep_xids,
> -                   &LOCK_prep_xids, MY_MUTEX_INIT_FAST);
> -  mysql_cond_init(key_BINLOG_COND_prep_xids, &COND_prep_xids, 0);
> +  /*
> +    There is no good place to set up the transactional data, so we
> +    have to do it here.
> +  */
> +  if (binlog_setup_trx_data())
> +    DBUG_RETURN(NULL);
> +
> +  Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
> +
> +  if (unlikely(pending && !pending->is_valid()))
> +    DBUG_RETURN(NULL);
> +
> +  /*
> +    Check if the current event is non-NULL and a write-rows
> +    event. Also check if the table provided is mapped: if it is not,
> +    then we have switched to writing to a new table.
> +    If there is no pending event, we need to create one. If there is a pending
> +    event, but it's not about the same table id, or not of the same type
> +    (between Write, Update and Delete), or not the same affected columns, or
> +    going to be too big, flush this event to disk and create a new pending
> +    event.
> +  */
> +  if (!pending ||
> +      pending->server_id != serv_id || 
> +      pending->get_table_id() != table->s->table_map_id ||
> +      pending->get_type_code() != type_code || 
> +      pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 
> +      pending->get_width() != colcnt ||
> +      !bitmap_cmp(pending->get_cols(), cols)) 
> +  {
> +    /* Create a new RowsEventT... */
> +    Rows_log_event* const
> +	ev= new RowsEventT(this, table, table->s->table_map_id, cols,
> +                           is_transactional);
> +    if (unlikely(!ev))
> +      DBUG_RETURN(NULL);
> +    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
> +    /*
> +      flush the pending event and replace it with the newly created
> +      event...
> +    */
> +    if (unlikely(
> +        mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
> +                                                       is_transactional)))
> +    {
> +      delete ev;
> +      DBUG_RETURN(NULL);
> +    }
>  
> -  if (!my_b_inited(&index_file))
> -  {
> -    /* There was a failure to open the index file, can't open the binlog */
> -    cleanup();
> -    return 1;
> +    DBUG_RETURN(ev);               /* This is the new pending event */
>    }
> +  DBUG_RETURN(pending);        /* This is the current pending event */
> +}
>  
> -  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;
> -  }
> +#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
> +/*
> +  Instantiate the versions we need, we have -fno-implicit-template as
> +  compiling option.
> +*/
> +template Rows_log_event*
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t, size_t, bool,
> +				       Write_rows_log_event*);
> +
> +template Rows_log_event*
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t colcnt, size_t, bool,
> +				       Delete_rows_log_event *);
> +
> +template Rows_log_event* 
> +THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> +				       size_t colcnt, size_t, bool,
> +				       Update_rows_log_event *);
> +#endif
>  
> -  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;
> -  }
> +namespace {
> +  /**
> +     Class to handle temporary allocation of memory for row data.
> +
> +     The responsibilities of the class is to provide memory for
> +     packing one or two rows of packed data (depending on what
> +     constructor is called).
> +
> +     In order to make the allocation more efficient for "simple" rows,
> +     i.e., rows that do not contain any blobs, a pointer to the
> +     allocated memory is of memory is stored in the table structure
> +     for simple rows.  If memory for a table containing a blob field
> +     is requested, only memory for that is allocated, and subsequently
> +     released when the object is destroyed.
>  
> -  {
> -    const char *errmsg;
> -    IO_CACHE    log;
> -    File        file;
> -    Log_event  *ev=0;
> -    Format_description_log_event fdle(BINLOG_VERSION);
> -    char        log_name[FN_REFLEN];
> +   */
> +  class Row_data_memory {
> +  public:
> +    /**
> +      Build an object to keep track of a block-local piece of memory
> +      for storing a row of data.
>  
> -    if (! fdle.is_valid())
> -      goto err;
> +      @param table
> +      Table where the pre-allocated memory is stored.
>  
> -    do
> +      @param length
> +      Length of data that is needed, if the record contain blobs.
> +     */
> +    Row_data_memory(TABLE *table, size_t const len1)
> +      : m_memory(0)
>      {
> -      strmake(log_name, log_info.log_file_name, sizeof(log_name)-1);
> -    } while (!(error= find_next_log(&log_info, 1)));
> +#ifndef DBUG_OFF
> +      m_alloc_checked= FALSE;
> +#endif
> +      allocate_memory(table, len1);
> +      m_ptr[0]= has_memory() ? m_memory : 0;
> +      m_ptr[1]= 0;
> +    }
>  
> -    if (error !=  LOG_INFO_EOF)
> +    Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
> +      : m_memory(0)
>      {
> -      sql_print_error("find_log_pos() failed (error: %d)", error);
> -      goto err;
> +#ifndef DBUG_OFF
> +      m_alloc_checked= FALSE;
> +#endif
> +      allocate_memory(table, len1 + len2);
> +      m_ptr[0]= has_memory() ? m_memory        : 0;
> +      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
>      }
>  
> -    if ((file= open_binlog(&log, log_name, &errmsg)) < 0)
> +    ~Row_data_memory()
>      {
> -      sql_print_error("%s", errmsg);
> -      goto err;
> +      if (m_memory != 0 && m_release_memory_on_destruction)
> +        my_free((uchar*) m_memory, MYF(MY_WME));
> +    }
> +
> +    /**
> +       Is there memory allocated?
> +
> +       @retval true There is memory allocated
> +       @retval false Memory allocation failed
> +     */
> +    bool has_memory() const {
> +#ifndef DBUG_OFF
> +      m_alloc_checked= TRUE;
> +#endif
> +      return m_memory != 0;
> +    }
> +
> +    uchar *slot(uint s)
> +    {
> +      DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
> +      DBUG_ASSERT(m_ptr[s] != 0);
> +      DBUG_ASSERT(m_alloc_checked == TRUE);
> +      return m_ptr[s];
> +    }
> +
> +  private:
> +    void allocate_memory(TABLE *const table, size_t const total_length)
> +    {
> +      if (table->s->blob_fields == 0)
> +      {
> +        /*
> +          The maximum length of a packed record is less than this
> +          length. We use this value instead of the supplied length
> +          when allocating memory for records, since we don't know how
> +          the memory will be used in future allocations.
> +
> +          Since table->s->reclength is for unpacked records, we have
> +          to add two bytes for each field, which can potentially be
> +          added to hold the length of a packed field.
> +        */
> +        size_t const maxlen= table->s->reclength + 2 *
> table->s->fields;
> +
> +        /*
> +          Allocate memory for two records if memory hasn't been
> +          allocated. We allocate memory for two records so that it can
> +          be used when processing update rows as well.
> +        */
> +        if (table->write_row_record == 0)
> +          table->write_row_record=
> +            (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
> +        m_memory= table->write_row_record;
> +        m_release_memory_on_destruction= FALSE;
> +      }
> +      else
> +      {
> +        m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
> +        m_release_memory_on_destruction= TRUE;
> +      }
>      }
>  
> -    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;
> +#ifndef DBUG_OFF
> +    mutable bool m_alloc_checked;
> +#endif
> +    bool m_release_memory_on_destruction;
> +    uchar *m_memory;
> +    uchar *m_ptr[2];
> +  };
> +}
> +
> +
> +int THD::binlog_write_row(TABLE* table, bool is_trans, 
> +                          MY_BITMAP const* cols, size_t colcnt, 
> +                          uchar const *record) 
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +
> +  /*
> +    Pack records into format for transfer. We are allocating more
> +    memory than needed, but that doesn't matter.
> +  */
> +  Row_data_memory memory(table, max_row_length(table, record));
> +  if (!memory.has_memory())
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  uchar *row_data= memory.slot(0);
>  
> -    delete ev;
> -    end_io_cache(&log);
> -    mysql_file_close(file, MYF(MY_WME));
> +  size_t const len= pack_row(table, cols, row_data, record);
>  
> -    if (error)
> -      goto err;
> -  }
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +                                      len, is_trans,
> +                                      static_cast<Write_rows_log_event*>(0));
>  
> -err:
> -  return error;
> -}
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
>  
> -/** This is called on shutdown, after ha_panic. */
> -void TC_LOG_BINLOG::close()
> -{
> -  DBUG_ASSERT(prepared_xids==0);
> -  mysql_mutex_destroy(&LOCK_prep_xids);
> -  mysql_cond_destroy(&COND_prep_xids);
> +  return ev->add_row_data(row_data, len);
>  }
>  
> -/**
> -  @todo
> -  group commit
> +int THD::binlog_update_row(TABLE* table, bool is_trans,
> +                           MY_BITMAP const* cols, size_t colcnt,
> +                           const uchar *before_record,
> +                           const uchar *after_record)
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> +
> +  size_t const before_maxlen = max_row_length(table, before_record);
> +  size_t const after_maxlen  = max_row_length(table, after_record);
> +
> +  Row_data_memory row_data(table, before_maxlen, after_maxlen);
> +  if (!row_data.has_memory())
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  uchar *before_row= row_data.slot(0);
> +  uchar *after_row= row_data.slot(1);
> +
> +  size_t const before_size= pack_row(table, cols, before_row,
> +                                        before_record);
> +  size_t const after_size= pack_row(table, cols, after_row,
> +                                       after_record);
>  
> -  @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.
> +    Don't print debug messages when running valgrind since they can
> +    trigger false warnings.
>     */
> -  DBUG_RETURN(!binlog_flush_stmt_cache(thd, cache_mngr) &&
> -              !binlog_flush_trx_cache(thd, cache_mngr, &xle));
> -}
> +#ifndef HAVE_purify
> +  DBUG_DUMP("before_record", before_record, table->s->reclength);
> +  DBUG_DUMP("after_record",  after_record, table->s->reclength);
> +  DBUG_DUMP("before_row",    before_row, before_size);
> +  DBUG_DUMP("after_row",     after_row, after_size);
> +#endif
>  
> -void TC_LOG_BINLOG::unlog(ulong cookie, my_xid xid)
> -{
> -  mysql_mutex_lock(&LOCK_prep_xids);
> -  DBUG_ASSERT(prepared_xids > 0);
> -  if (--prepared_xids == 0) {
> -    DBUG_PRINT("info", ("prepared_xids=%lu", prepared_xids));
> -    mysql_cond_signal(&COND_prep_xids);
> -  }
> -  mysql_mutex_unlock(&LOCK_prep_xids);
> -  rotate_and_purge(0);     // as ::write() did not rotate
> -}
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +				      before_size + after_size, is_trans,
> +				      static_cast<Update_rows_log_event*>(0));
>  
> -int TC_LOG_BINLOG::recover(IO_CACHE *log, Format_description_log_event *fdle)
> -{
> -  Log_event  *ev;
> -  HASH xids;
> -  MEM_ROOT mem_root;
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
>  
> -  if (! fdle->is_valid() ||
> -      my_hash_init(&xids, &my_charset_bin, TC_LOG_PAGE_SIZE/3, 0,
> -                   sizeof(my_xid), 0, 0, MYF(0)))
> -    goto err1;
> +  return
> +    ev->add_row_data(before_row, before_size) ||
> +    ev->add_row_data(after_row, after_size);
> +}
>  
> -  init_alloc_root(&mem_root, TC_LOG_PAGE_SIZE, TC_LOG_PAGE_SIZE);
> +int THD::binlog_delete_row(TABLE* table, bool is_trans, 
> +                           MY_BITMAP const* cols, size_t colcnt,
> +                           uchar const *record)
> +{ 
> +  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
>  
> -  fdle->flags&= ~LOG_EVENT_BINLOG_IN_USE_F; // abort on the first error
> +  /* 
> +     Pack records into format for transfer. We are allocating more
> +     memory than needed, but that doesn't matter.
> +  */
> +  Row_data_memory memory(table, max_row_length(table, record));
> +  if (unlikely(!memory.has_memory()))
> +    return HA_ERR_OUT_OF_MEM;
>  
> -  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;
> -  }
> +  uchar *row_data= memory.slot(0);
>  
> -  if (ha_recover(&xids))
> -    goto err2;
> +  size_t const len= pack_row(table, cols, row_data, record);
>  
> -  free_root(&mem_root, MYF(0));
> -  my_hash_free(&xids);
> -  return 0;
> +  Rows_log_event* const ev=
> +    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> +				      len, is_trans,
> +				      static_cast<Delete_rows_log_event*>(0));
>  
> -err2:
> -  free_root(&mem_root, MYF(0));
> -  my_hash_free(&xids);
> -err1:
> -  sql_print_error("Crash recovery failed. Either correct the problem "
> -                  "(if it's, for example, out of memory error) and restart, "
> -                  "or delete (or rename) binary log and start mysqld with "
> -                  "--tc-heuristic-recover={commit|rollback}");
> -  return 1;
> +  if (unlikely(ev == 0))
> +    return HA_ERR_OUT_OF_MEM;
> +
> +  return ev->add_row_data(row_data, len);
>  }
>  
> -/*
> -  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
> +int THD::binlog_remove_pending_rows_event(bool clear_maps,
> +                                          bool is_transactional)
> +{
> +  DBUG_ENTER("THD::binlog_remove_pending_rows_event");
>  
> -  NOTES
> -    - This is called when doing a PURGE when we delete lines from the
> -      index log file
> +  if (!mysql_bin_log.is_open())
> +    DBUG_RETURN(0);
>  
> -  REQUIREMENTS
> -    - Before calling this function, we have to ensure that no threads are
> -      using any binary log file before purge_offset.a
> +  mysql_bin_log.remove_pending_rows_event(this, is_transactional);
>  
> -  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.
> -*/
> +  if (clear_maps)
> +    binlog_table_maps= 0;
>  
> -void adjust_linfo_offsets(my_off_t purge_offset)
> -{
> -  THD *tmp;
> +  DBUG_RETURN(0);
> +}
>  
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  I_List_iterator<THD> it(threads);
> +int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
> +{
> +  DBUG_ENTER("THD::binlog_flush_pending_rows_event");
> +  /*
> +    We shall flush the pending event even if we are not in row-based
> +    mode: it might be the case that we left row-based mode before
> +    flushing anything (e.g., if we have explicitly locked tables).
> +   */
> +  if (!mysql_bin_log.is_open())
> +    DBUG_RETURN(0);
>  
> -  while ((tmp=it++))
> +  /*
> +    Mark the event as the last event of a statement if the stmt_end
> +    flag is set.
> +  */
> +  int error= 0;
> +  if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
>    {
> -    LOG_INFO* linfo;
> -    if ((linfo = tmp->current_linfo))
> +    if (stmt_end)
>      {
> -      mysql_mutex_lock(&linfo->lock);
> -      /*
> -	Index file offset can be less that purge offset only if
> -	we just started reading the index file. In that case
> -	we have nothing to adjust
> -      */
> -      if (linfo->index_file_offset < purge_offset)
> -	linfo->fatal = (linfo->index_file_offset != 0);
> -      else
> -	linfo->index_file_offset -= purge_offset;
> -      mysql_mutex_unlock(&linfo->lock);
> +      pending->set_flags(Rows_log_event::STMT_END_F);
> +      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> +      binlog_table_maps= 0;
>      }
> +
> +    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
> +                                                          is_transactional);
>    }
> -  mysql_mutex_unlock(&LOCK_thread_count);
> +
> +  DBUG_RETURN(error);
> +}
> +
> +
> +#if !defined(DBUG_OFF) && !defined(_lint)
> +static const char *
> +show_query_type(THD::enum_binlog_query_type qtype)
> +{
> +  switch (qtype) {
> +  case THD::ROW_QUERY_TYPE:
> +    return "ROW";
> +  case THD::STMT_QUERY_TYPE:
> +    return "STMT";
> +  case THD::QUERY_TYPE_COUNT:
> +  default:
> +    DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
> +  }
> +  static char buf[64];
> +  sprintf(buf, "UNKNOWN#%d", qtype);
> +  return buf;
>  }
> +#endif
>  
> 
> -bool log_in_use(const char* log_name)
> +/**
> +  Auxiliary method used by @c binlog_query() to raise warnings.
> +
> +  The type of warning and the type of unsafeness is stored in
> +  THD::binlog_unsafe_warning_flags.
> +*/
> +void THD::issue_unsafe_warnings()
>  {
> -  size_t log_name_len = strlen(log_name) + 1;
> -  THD *tmp;
> -  bool result = 0;
> +  DBUG_ENTER("issue_unsafe_warnings");
> +  /*
> +    Ensure that binlog_unsafe_warning_flags is big enough to hold all
> +    bits.  This is actually a constant expression.
> +  */
> +  DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
> +              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
>  
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  I_List_iterator<THD> it(threads);
> +  uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
>  
> -  while ((tmp=it++))
> +  /*
> +    Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
> +    warnings that have been printed already.
> +  */
> +  unsafe_type_flags &= (LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS ^
> +                        (unsafe_type_flags >>
> LEX::BINLOG_STMT_UNSAFE_COUNT));
> +  /* If all warnings have been printed already, return. */
> +  if (unsafe_type_flags == 0)
> +    DBUG_VOID_RETURN;
> +
> +  DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
> +
> +  /*
> +    For each unsafe_type, check if the statement is unsafe in this way
> +    and issue a warning.
> +  */
> +  for (int unsafe_type=0;
> +       unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> +       unsafe_type++)
>    {
> -    LOG_INFO* linfo;
> -    if ((linfo = tmp->current_linfo))
> +    if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
>      {
> -      mysql_mutex_lock(&linfo->lock);
> -      result = !bcmp((uchar*) log_name, (uchar*) linfo->log_file_name,
> -                     log_name_len);
> -      mysql_mutex_unlock(&linfo->lock);
> -      if (result)
> -	break;
> +      push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
> +                          ER_BINLOG_UNSAFE_STATEMENT,
> +                          ER(ER_BINLOG_UNSAFE_STATEMENT),
> +                          ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +      if (global_system_variables.log_warnings)
> +      {
> +        char buf[MYSQL_ERRMSG_SIZE * 2];
> +        sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
> +                ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> +        sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
> +      }
>      }
>    }
> -
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  return result;
> +  /*
> +    Mark these unsafe types as already printed, to avoid printing
> +    warnings for them again.
> +  */
> +  binlog_unsafe_warning_flags|=
> +    unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
> +  DBUG_VOID_RETURN;
>  }
>  
> -#ifndef EMBEDDED_LIBRARY
> -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;
> -}
> +/**
> +  Log the current query.
>  
> +  The query will be logged in either row format or statement format
> +  depending on the value of @c current_stmt_binlog_format_row field and
> +  the value of the @c qtype parameter.
>  
> -/**
> -  Execute a PURGE BINARY LOGS TO <log> command.
> +  This function must be called:
>  
> -  @param thd Pointer to THD object for the client thread executing the
> -  statement.
> +  - After the all calls to ha_*_row() functions have been issued.
>  
> -  @param to_log Name of the last log to purge.
> +  - After any writes to system tables. Rationale: if system tables
> +    were written after a call to this function, and the master crashes
> +    after the call to this function and before writing the system
> +    tables, then the master and slave get out of sync.
>  
> -  @retval FALSE success
> -  @retval TRUE failure
> +  - Before tables are unlocked and closed.
> +
> +  @see decide_logging_format
> +
> +  @retval 0 Success
> +
> +  @retval nonzero If there is a failure when writing the query (e.g.,
> +  write failure), then the error code is returned.
>  */
> -bool purge_master_logs(THD* thd, const char* to_log)
> +int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
> +                      ulong query_len, bool is_trans, bool direct, 
> +                      bool suppress_use, int errcode)
>  {
> -  char search_file_name[FN_REFLEN];
> -  if (!mysql_bin_log.is_open())
> -  {
> -    my_ok(thd);
> -    return FALSE;
> -  }
> +  DBUG_ENTER("THD::binlog_query");
> +  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
> +                       show_query_type(qtype), query_arg));
> +  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
>  
> -  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));
> -}
> +  /*
> +    If we are not in prelocked mode, mysql_unlock_tables() will be
> +    called after this binlog_query(), so we have to flush the pending
> +    rows event with the STMT_END_F set to unlock all tables at the
> +    slave side as well.
>  
> +    If we are in prelocked mode, the flushing will be done inside the
> +    top-most close_thread_tables().
> +  */
> +  if (this->locked_tables_mode <= LTM_LOCK_TABLES)
> +    if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
> +      DBUG_RETURN(error);
>  
> -/**
> -  Execute a PURGE BINARY LOGS BEFORE <date> command.
> +  /*
> +    Warnings for unsafe statements logged in statement format are
> +    printed here instead of in decide_logging_format().  This is
> +    because the warnings should be printed only if the statement is
> +    actually logged. When executing decide_logging_format(), we cannot
> +    know for sure if the statement will be logged.
> +  */
> +  if (sql_log_bin_toplevel)
> +    issue_unsafe_warnings();
>  
> -  @param thd Pointer to THD object for the client thread executing the
> -  statement.
> +  switch (qtype) {
> +    /*
> +      ROW_QUERY_TYPE means that the statement may be logged either in
> +      row format or in statement format.  If
> +      current_stmt_binlog_format is row, it means that the
> +      statement has already been logged in row format and hence shall
> +      not be logged again.
> +    */
> +  case THD::ROW_QUERY_TYPE:
> +    DBUG_PRINT("debug",
> +               ("is_current_stmt_binlog_format_row: %d",
> +                is_current_stmt_binlog_format_row()));
> +    if (is_current_stmt_binlog_format_row())
> +      DBUG_RETURN(0);
> +    /* Fall through */
>  
> -  @param purge_time Date before which logs should be purged.
> +    /*
> +      STMT_QUERY_TYPE means that the query must be logged in statement
> +      format; it cannot be logged in row format.  This is typically
> +      used by DDL statements.  It is an error to use this query type
> +      if current_stmt_binlog_format_row is row.
> +
> +      @todo Currently there are places that call this method with
> +      STMT_QUERY_TYPE and current_stmt_binlog_format is row.  Fix those
> +      places and add assert to ensure correct behavior. /Sven
> +    */
> +  case THD::STMT_QUERY_TYPE:
> +    /*
> +      The MYSQL_LOG::write() function will set the STMT_END_F flag and
> +      flush the pending rows event if necessary.
> +    */
> +    {
> +      Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
> +                            suppress_use, errcode);
> +      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> +      /*
> +        Binlog table maps will be irrelevant after a Query_log_event
> +        (they are just removed on the slave side) so after the query
> +        log event is written to the binary log, we pretend that no
> +        table maps were written.
> +       */
> +      int error= mysql_bin_log.write(&qinfo);
> +      binlog_table_maps= 0;
> +      DBUG_RETURN(error);
> +    }
> +    break;
>  
> -  @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;
> +  case THD::QUERY_TYPE_COUNT:
> +  default:
> +    DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
>    }
> -  return purge_error_message(thd,
> -                             mysql_bin_log.purge_logs_before_date(purge_time));
> +  DBUG_RETURN(0);
>  }
> -#endif /* EMBEDDED_LIBRARY */
> +
> +#endif /* !defined(MYSQL_CLIENT) */
>  
>  #ifdef INNODB_COMPATIBILITY_HOOKS
>  /**
> 
> === modified file 'sql/binlog.h'
> --- a/sql/binlog.h	2010-05-08 02:34:04 +0000
> +++ b/sql/binlog.h	2010-05-13 05:54:26 +0000
> @@ -23,13 +23,6 @@ class Relay_log_info;
>  
>  class Format_description_log_event;
>  
> -bool trans_has_updated_trans_table(const THD* thd);
> -bool stmt_has_updated_trans_table(const THD *thd);
> -bool use_trans_cache(const THD* thd, bool is_transactional);
> -bool ending_trans(THD* thd, const bool all);
> -bool trans_has_updated_non_trans_table(const THD* thd);
> -bool stmt_has_updated_non_trans_table(const THD* thd);
> -
>  class MYSQL_BIN_LOG: public TC_LOG, private MYSQL_LOG
>  {
>   private:
> @@ -253,6 +246,28 @@ public:
>    inline uint32 get_open_count() { return open_count; }
>  };
>  
> +typedef struct st_load_file_info
> +{
> +  THD* thd;
> +  my_off_t last_pos_in_file;
> +  bool wrote_create_file, log_delayed;
> +} LOAD_FILE_INFO;
> +
>  extern MYSQL_PLUGIN_IMPORT MYSQL_BIN_LOG mysql_bin_log;
>  
> +bool trans_has_updated_trans_table(const THD* thd);
> +bool stmt_has_updated_trans_table(const THD *thd);
> +bool use_trans_cache(const THD* thd, bool is_transactional);
> +bool ending_trans(THD* thd, const bool all);
> +bool trans_has_updated_non_trans_table(const THD* thd);
> +bool stmt_has_updated_non_trans_table(const THD* thd);
> +
> +int log_loaded_block(IO_CACHE* file);
> +File open_binlog(IO_CACHE *log, const char *log_file_name,
> +                 const char **errmsg);
> +int check_binlog_magic(IO_CACHE* log, const char** errmsg);
> +bool purge_master_logs(THD* thd, const char* to_log);
> +bool purge_master_logs_before_date(THD* thd, time_t purge_time);
> +bool show_binlog_events(THD *thd, MYSQL_BIN_LOG *binary_log);
> +
>  #endif /* BINLOG_H_INCLUDED */
> 
> === modified file 'sql/log.h'
> --- a/sql/log.h	2010-05-08 02:34:04 +0000
> +++ b/sql/log.h	2010-05-13 05:54:26 +0000
> @@ -436,9 +436,6 @@ bool general_log_write(THD *thd, enum en
>  void sql_perror(const char *message);
>  bool flush_error_log();
>  
> -File open_binlog(IO_CACHE *log, const char *log_file_name,
> -                 const char **errmsg);
> -
>  char *make_log_name(char *buff, const char *name, const char* log_ext);
>  
>  extern LOGGER logger;
> 
> === modified file 'sql/master.cc'
> --- a/sql/master.cc	2010-05-08 02:34:04 +0000
> +++ b/sql/master.cc	2010-05-13 05:54:26 +0000
> @@ -19,7 +19,6 @@
>  #include "sql_parse.h"                          // check_access
>  #ifdef HAVE_REPLICATION
>  
> -#include "sql_repl.h"
>  #include "sql_acl.h"                            // SUPER_ACL
>  #include "log_event.h"
>  #include "rpl_filter.h"
> @@ -925,182 +924,6 @@ int cmp_master_pos(const char* log_file_
>  
> 
>  /**
> -  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_result_set_metadata(&field_list,
> -                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> -    DBUG_RETURN(TRUE);
> -
> -  Format_description_log_event *description_event= new
> -    Format_description_log_event(3); /* MySQL 4.0 by default */
> -
> -  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS ||
> -              thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
> -
> -  /* select wich binary log to use: binlog or relay */
> -  if ( thd->lex->sql_command == SQLCOM_SHOW_BINLOG_EVENTS )
> -  {
> -    /*
> -      Wait for handlers to insert any pending information
> -      into the binlog.  For e.g. ndb which updates the binlog asynchronously
> -      this is needed so that the uses sees all its own commands in the binlog
> -    */
> -    ha_binlog_wait(thd);
> -
> -    binary_log= &mysql_bin_log;
> -  }
> -  else  /* showing relay log contents */
> -  {
> -    if (!active_mi)
> -      DBUG_RETURN(TRUE);
> -
> -    binary_log= &(active_mi->rli.relay_log);
> -  }
> -
> -  if (binary_log->is_open())
> -  {
> -    LEX_MASTER_INFO *lex_mi= &thd->lex->mi;
> -    SELECT_LEX_UNIT *unit= &thd->lex->unit;
> -    ha_rows event_count, limit_start, limit_end;
> -    my_off_t pos = max(BIN_LOG_HEADER_SIZE, lex_mi->pos); // user-friendly
> -    char search_file_name[FN_REFLEN], *name;
> -    const char *log_file_name = lex_mi->log_file_name;
> -    mysql_mutex_t *log_lock = binary_log->get_log_lock();
> -    LOG_INFO linfo;
> -    Log_event* ev;
> -
> -    unit->set_limit(thd->lex->current_select);
> -    limit_start= unit->offset_limit_cnt;
> -    limit_end= unit->select_limit_cnt;
> -
> -    name= search_file_name;
> -    if (log_file_name)
> -      binary_log->make_log_name(search_file_name, log_file_name);
> -    else
> -      name=0;					// Find first log
> -
> -    linfo.index_file_offset = 0;
> -
> -    if (binary_log->find_log_pos(&linfo, name, 1))
> -    {
> -      errmsg = "Could not find target log";
> -      goto err;
> -    }
> -
> -    mysql_mutex_lock(&LOCK_thread_count);
> -    thd->current_linfo = &linfo;
> -    mysql_mutex_unlock(&LOCK_thread_count);
> -
> -    if ((file=open_binlog(&log, linfo.log_file_name, &errmsg)) < 0)
> -      goto err;
> -
> -    /*
> -      to account binlog event header size
> -    */
> -    thd->variables.max_allowed_packet += MAX_LOG_EVENT_HEADER;
> -
> -    mysql_mutex_lock(log_lock);
> -
> -    /*
> -      open_binlog() sought to position 4.
> -      Read the first event in case it's a Format_description_log_event, to
> -      know the format. If there's no such event, we are 3.23 or 4.x. This
> -      code, like before, can't read 3.23 binlogs.
> -      This code will fail on a mixed relay log (one which has Format_desc then
> -      Rotate then Format_desc).
> -    */
> -    ev= Log_event::read_log_event(&log, (mysql_mutex_t*)0, description_event);
> -    if (ev)
> -    {
> -      if (ev->get_type_code() == FORMAT_DESCRIPTION_EVENT)
> -      {
> -        delete description_event;
> -        description_event= (Format_description_log_event*) ev;
> -      }
> -      else
> -        delete ev;
> -    }
> -
> -    my_b_seek(&log, pos);
> -
> -    if (!description_event->is_valid())
> -    {
> -      errmsg="Invalid Format_description event; could be out of memory";
> -      goto err;
> -    }
> -
> -    for (event_count = 0;
> -         (ev = Log_event::read_log_event(&log, (mysql_mutex_t*) 0,
> -                                         description_event)); )
> -    {
> -      if (event_count >= limit_start &&
> -	  ev->net_send(protocol, linfo.log_file_name, pos))
> -      {
> -	errmsg = "Net error";
> -	delete ev;
> -        mysql_mutex_unlock(log_lock);
> -	goto err;
> -      }
> -
> -      pos = my_b_tell(&log);
> -      delete ev;
> -
> -      if (++event_count >= limit_end)
> -	break;
> -    }
> -
> -    if (event_count < limit_end && log.error)
> -    {
> -      errmsg = "Wrong offset or I/O error";
> -      mysql_mutex_unlock(log_lock);
> -      goto err;
> -    }
> -
> -    mysql_mutex_unlock(log_lock);
> -  }
> -
> -  ret= FALSE;
> -
> -err:
> -  delete description_event;
> -  if (file >= 0)
> -  {
> -    end_io_cache(&log);
> -    mysql_file_close(file, MYF(MY_WME));
> -  }
> -
> -  if (errmsg)
> -    my_error(ER_ERROR_WHEN_EXECUTING_COMMAND, MYF(0),
> -             "SHOW BINLOG EVENTS", errmsg);
> -  else
> -    my_eof(thd);
> -
> -  mysql_mutex_lock(&LOCK_thread_count);
> -  thd->current_linfo = 0;
> -  mysql_mutex_unlock(&LOCK_thread_count);
> -  DBUG_RETURN(ret);
> -}
> -
> -
> -/**
>    Execute a SHOW MASTER STATUS statement.
>  
>    @param thd Pointer to THD object for the client thread executing the
> @@ -1225,56 +1048,4 @@ err:
>    DBUG_RETURN(TRUE);
>  }
>  
> -/**
> -   Load data's io cache specific hook to be executed
> -   before a chunk of data is being read into the cache's buffer
> -   The fuction instantianates and writes into the binlog
> -   replication events along LOAD DATA processing.
> -   
> -   @param file  pointer to io-cache
> -   @retval 0 success
> -   @retval 1 failure
> -*/
> -int log_loaded_block(IO_CACHE* file)
> -{
> -  DBUG_ENTER("log_loaded_block");
> -  LOAD_FILE_INFO *lf_info;
> -  uint block_len;
> -  /* buffer contains position where we started last read */
> -  uchar* buffer= (uchar*) my_b_get_buffer_start(file);
> -  uint max_event_size= current_thd->variables.max_allowed_packet;
> -  lf_info= (LOAD_FILE_INFO*) file->arg;
> -  if (lf_info->thd->is_current_stmt_binlog_format_row())
> -    DBUG_RETURN(0);
> -  if (lf_info->last_pos_in_file != HA_POS_ERROR &&
> -      lf_info->last_pos_in_file >= my_b_get_pos_in_file(file))
> -    DBUG_RETURN(0);
> -  
> -  for (block_len= (uint) (my_b_get_bytes_in_buffer(file)); block_len > 0;
> -       buffer += min(block_len, max_event_size),
> -       block_len -= min(block_len, max_event_size))
> -  {
> -    lf_info->last_pos_in_file= my_b_get_pos_in_file(file);
> -    if (lf_info->wrote_create_file)
> -    {
> -      Append_block_log_event a(lf_info->thd, lf_info->thd->db, buffer,
> -                               min(block_len, max_event_size),
> -                               lf_info->log_delayed);
> -      if (mysql_bin_log.write(&a))
> -        DBUG_RETURN(1);
> -    }
> -    else
> -    {
> -      Begin_load_query_log_event b(lf_info->thd, lf_info->thd->db,
> -                                   buffer,
> -                                   min(block_len, max_event_size),
> -                                   lf_info->log_delayed);
> -      if (mysql_bin_log.write(&b))
> -        DBUG_RETURN(1);
> -      lf_info->wrote_create_file= 1;
> -    }
> -  }
> -  DBUG_RETURN(0);
> -}
> -
>  #endif /* HAVE_REPLICATION */
> 
> === added file 'sql/master.h'
> --- a/sql/master.h	1970-01-01 00:00:00 +0000
> +++ b/sql/master.h	2010-05-13 05:54:26 +0000
> @@ -0,0 +1,28 @@
> +#ifndef MASTER_H_INCLUDED
> +/* Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; version 2 of the License.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program; if not, write to the Free Software
> +   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> +
> +
> +#define MASTER_H_INCLUDED
> +extern bool server_id_supplied;
> +extern int max_binlog_dump_events;
> +extern my_bool opt_sporadic_binlog_dump_fail;
> +
> +bool mysql_show_binlog_events(THD* thd);
> +bool show_binlogs(THD* thd);
> +void kill_zombie_dump_threads(uint32 slave_server_id);
> +void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
> +int reset_master(THD* thd);
> +#endif /* MASTER_H_INCLUDED */
> 
> === modified file 'sql/mysqld.cc'
> --- a/sql/mysqld.cc	2010-04-19 08:27:46 +0000
> +++ b/sql/mysqld.cc	2010-05-13 05:54:26 +0000
> @@ -54,8 +54,8 @@
>  #include <my_dir.h>
>  #include <my_bit.h>
>  #include "slave.h"
> +#include "master.h"
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
>  #include "rpl_filter.h"
>  #include "repl_failsafe.h"
>  #include <my_stacktrace.h>
> 
> === modified file 'sql/repl_failsafe.cc'
> --- a/sql/repl_failsafe.cc	2010-03-31 14:05:33 +0000
> +++ b/sql/repl_failsafe.cc	2010-05-13 05:54:26 +0000
> @@ -29,7 +29,6 @@
>  
>  #include "repl_failsafe.h"
>  #include "sql_acl.h"                            // REPL_SLAVE_ACL
> -#include "sql_repl.h"
>  #include "slave.h"
>  #include "rpl_mi.h"
>  #include "rpl_filter.h"
> 
> === modified file 'sql/rpl_handler.cc'
> --- a/sql/rpl_handler.cc	2010-03-31 14:05:33 +0000
> +++ b/sql/rpl_handler.cc	2010-05-13 05:54:26 +0000
> @@ -17,7 +17,6 @@
>  #include "unireg.h"
>  
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
>  #include "log_event.h"
>  #include "rpl_filter.h"
>  #include <my_dir.h>
> 
> === modified file 'sql/rpl_rli.cc'
> --- a/sql/rpl_rli.cc	2010-03-31 14:05:33 +0000
> +++ b/sql/rpl_rli.cc	2010-05-13 05:54:26 +0000
> @@ -19,10 +19,10 @@
>  #include "rpl_rli.h"
>  #include "sql_base.h"                        // close_thread_tables
>  #include <my_dir.h>    // For MY_STAT
> -#include "sql_repl.h"  // For check_binlog_magic
>  #include "log_event.h" // Format_description_log_event, Log_event,
>                         // FORMAT_DESCRIPTION_LOG_EVENT, ROTATE_EVENT,
>                         // PREFIX_SQL_LOAD
> +#include "slave.h"
>  #include "rpl_utility.h"
>  #include "transaction.h"
>  #include "sql_parse.h"                          // end_trans, ROLLBACK
> @@ -1261,4 +1261,32 @@ void Relay_log_info::slave_close_thread_
>    close_thread_tables(thd);
>    clear_tables_to_lock();
>  }
> +/**
> +  Execute a SHOW RELAYLOG EVENTS statement.
> +
> +  @param thd Pointer to THD object for the client thread executing the
> +  statement.
> +
> +  @retval FALSE success
> +  @retval TRUE failure
> +*/
> +bool mysql_show_relaylog_events(THD* thd)
> +{
> +  Protocol *protocol= thd->protocol;
> +  List<Item> field_list;
> +  DBUG_ENTER("mysql_show_relaylog_events");
> +
> +  DBUG_ASSERT(thd->lex->sql_command == SQLCOM_SHOW_RELAYLOG_EVENTS);
> +
> +  Log_event::init_show_field_list(&field_list);
> +  if (protocol->send_result_set_metadata(&field_list,
> +                            Protocol::SEND_NUM_ROWS | Protocol::SEND_EOF))
> +    DBUG_RETURN(TRUE);
> +
> +  if (!active_mi)
> +    DBUG_RETURN(TRUE);
> +  
> +  DBUG_RETURN(show_binlog_events(thd, &active_mi->rli.relay_log));
> +}
> +
>  #endif
> 
> === modified file 'sql/rpl_rli.h'
> --- a/sql/rpl_rli.h	2010-05-08 02:34:04 +0000
> +++ b/sql/rpl_rli.h	2010-05-13 05:54:26 +0000
> @@ -450,6 +450,15 @@ private:
>  
>  // Defined in rpl_rli.cc
>  int init_relay_log_info(Relay_log_info* rli, const char* info_fname);
> +bool flush_relay_log_info(Relay_log_info* rli);
> +void end_relay_log_info(Relay_log_info* rli);
> +int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
> +		       bool need_data_lock, const char** errmsg,
> +                       bool look_for_description_event);
>  
> +int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
> +		     const char** errmsg);
> +void rotate_relay_log(Master_info* mi);
> +bool mysql_show_relaylog_events(THD* thd);
>  
>  #endif /* RPL_RLI_H */
> 
> === modified file 'sql/slave.cc'
> --- a/sql/slave.cc	2010-05-08 02:34:04 +0000
> +++ b/sql/slave.cc	2010-05-13 05:54:26 +0000
> @@ -31,7 +31,6 @@
>  #include "sql_table.h"                         // mysql_rm_table
>  #include "rpl_mi.h"
>  #include "rpl_rli.h"
> -#include "sql_repl.h"
>  #include "rpl_filter.h"
>  #include "repl_failsafe.h"
>  #include "transaction.h"
> 
> === modified file 'sql/slave.h'
> --- a/sql/slave.h	2010-05-08 02:34:04 +0000
> +++ b/sql/slave.h	2010-05-13 05:54:26 +0000
> @@ -49,6 +49,20 @@
>  class Relay_log_info;
>  class Master_info;
>  
> +extern bool server_id_supplied;
> +extern my_bool opt_show_slave_auth_info;
> +
> +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;
> +
>  
>  /*****************************************************************************
>  
> @@ -145,10 +159,15 @@ extern ulonglong relay_log_space_limit;
>  */
>  #define SLAVE_FORCE_ALL 4
>  
> +int start_slave(THD* thd, Master_info* mi, bool net_report);
> +int stop_slave(THD* thd, Master_info* mi, bool net_report);
> +bool change_master(THD* thd, Master_info* mi);
> +int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
> +		   const char* log_file_name2, ulonglong log_pos2);
> +int reset_slave(THD *thd, Master_info* mi);
>  int init_slave();
>  int init_recovery(Master_info* mi, const char** errmsg);
>  void init_slave_skip_errors(const char* arg);
> -bool flush_relay_log_info(Relay_log_info* rli);
>  int register_slave_on_master(MYSQL* mysql);
>  int terminate_slave_threads(Master_info* mi, int thread_mask,
>  			     bool skip_lock = 0);
> @@ -194,19 +213,11 @@ void end_slave(); /* release slave threa
>  void close_active_mi(); /* clean up slave threads data */
>  void clear_until_condition(Relay_log_info* rli);
>  void clear_slave_error(Relay_log_info* rli);
> -void end_relay_log_info(Relay_log_info* rli);
>  void lock_slave_threads(Master_info* mi);
>  void unlock_slave_threads(Master_info* mi);
>  void init_thread_mask(int* mask,Master_info* mi,bool inverse);
> -int init_relay_log_pos(Relay_log_info* rli,const char* log,ulonglong pos,
> -		       bool need_data_lock, const char** errmsg,
> -                       bool look_for_description_event);
> -
> -int purge_relay_logs(Relay_log_info* rli, THD *thd, bool just_reset,
> -		     const char** errmsg);
>  void set_slave_thread_options(THD* thd);
>  void set_slave_thread_default_charset(THD *thd, Relay_log_info const *rli);
> -void rotate_relay_log(Master_info* mi);
>  int apply_event_and_update_pos(Log_event* ev, THD* thd, Relay_log_info* rli);
>  
>  pthread_handler_t handle_slave_io(void *arg);
> 
> === modified file 'sql/sql_class.cc'
> --- a/sql/sql_class.cc	2010-04-29 10:43:54 +0000
> +++ b/sql/sql_class.cc	2010-05-13 05:54:26 +0000
> @@ -3480,610 +3480,6 @@ void xid_cache_delete(XID_STATE *xid_sta
>  }
>  
> 
> -/**
> -  Decide on logging format to use for the statement and issue errors
> -  or warnings as needed.  The decision depends on the following
> -  parameters:
> -
> -  - The logging mode, i.e., the value of binlog_format.  Can be
> -    statement, mixed, or row.
> -
> -  - The type of statement.  There are three types of statements:
> -    "normal" safe statements; unsafe statements; and row injections.
> -    An unsafe statement is one that, if logged in statement format,
> -    might produce different results when replayed on the slave (e.g.,
> -    INSERT DELAYED).  A row injection is either a BINLOG statement, or
> -    a row event executed by the slave's SQL thread.
> -
> -  - The capabilities of tables modified by the statement.  The
> -    *capabilities vector* for a table is a set of flags associated
> -    with the table.  Currently, it only includes two flags: *row
> -    capability flag* and *statement capability flag*.
> -
> -    The row capability flag is set if and only if the engine can
> -    handle row-based logging. The statement capability flag is set if
> -    and only if the table can handle statement-based logging.
> -
> -  Decision table for logging format
> -  ---------------------------------
> -
> -  The following table summarizes how the format and generated
> -  warning/error depends on the tables' capabilities, the statement
> -  type, and the current binlog_format.
> -
> -     Row capable        N NNNNNNNNN YYYYYYYYY YYYYYYYYY
> -     Statement capable  N YYYYYYYYY NNNNNNNNN YYYYYYYYY
> -
> -     Statement type     * SSSUUUIII SSSUUUIII SSSUUUIII
> -
> -     binlog_format      * SMRSMRSMR SMRSMRSMR SMRSMRSMR
> -
> -     Logged format      - SS-S----- -RR-RR-RR SRRSRR-RR
> -     Warning/Error      1 --2732444 5--5--6-- ---7--6--
> -
> -  Legend
> -  ------
> -
> -  Row capable:    N - Some table not row-capable, Y - All tables row-capable
> -  Stmt capable:   N - Some table not stmt-capable, Y - All tables stmt-capable
> -  Statement type: (S)afe, (U)nsafe, or Row (I)njection
> -  binlog_format:  (S)TATEMENT, (M)IXED, or (R)OW
> -  Logged format:  (S)tatement or (R)ow
> -  Warning/Error:  Warnings and error messages are as follows:
> -
> -  1. Error: Cannot execute statement: binlogging impossible since both
> -     row-incapable engines and statement-incapable engines are
> -     involved.
> -
> -  2. Error: Cannot execute statement: binlogging impossible since
> -     BINLOG_FORMAT = ROW and at least one table uses a storage engine
> -     limited to statement-logging.
> -
> -  3. Error: Cannot execute statement: binlogging of unsafe statement
> -     is impossible when storage engine is limited to statement-logging
> -     and BINLOG_FORMAT = MIXED.
> -
> -  4. Error: Cannot execute row injection: binlogging impossible since
> -     at least one table uses a storage engine limited to
> -     statement-logging.
> -
> -  5. Error: Cannot execute statement: binlogging impossible since
> -     BINLOG_FORMAT = STATEMENT and at least one table uses a storage
> -     engine limited to row-logging.
> -
> -  6. Error: Cannot execute row injection: binlogging impossible since
> -     BINLOG_FORMAT = STATEMENT.
> -
> -  7. Warning: Unsafe statement binlogged in statement format since
> -     BINLOG_FORMAT = STATEMENT.
> -
> -  In addition, we can produce the following error (not depending on
> -  the variables of the decision diagram):
> -
> -  8. Error: Cannot execute statement: binlogging impossible since more
> -     than one engine is involved and at least one engine is
> -     self-logging.
> -
> -  For each error case above, the statement is prevented from being
> -  logged, we report an error, and roll back the statement.  For
> -  warnings, we set the thd->binlog_flags variable: the warning will be
> -  printed only if the statement is successfully logged.
> -
> -  @see THD::binlog_query
> -
> -  @param[in] thd    Client thread
> -  @param[in] tables Tables involved in the query
> -
> -  @retval 0 No error; statement can be logged.
> -  @retval -1 One of the error conditions above applies (1, 2, 4, 5, or 6).
> -*/
> -
> -int THD::decide_logging_format(TABLE_LIST *tables)
> -{
> -  DBUG_ENTER("THD::decide_logging_format");
> -  DBUG_PRINT("info", ("query: %s", query()));
> -  DBUG_PRINT("info", ("variables.binlog_format: %u",
> -                      variables.binlog_format));
> -  DBUG_PRINT("info", ("lex->get_stmt_unsafe_flags(): 0x%x",
> -                      lex->get_stmt_unsafe_flags()));
> -
> -  /*
> -    We should not decide logging format if the binlog is closed or
> -    binlogging is off, or if the statement is filtered out from the
> -    binlog by filtering rules.
> -  */
> -  if (mysql_bin_log.is_open() && (variables.option_bits &
> OPTION_BIN_LOG) &&
> -      !(variables.binlog_format == BINLOG_FORMAT_STMT &&
> -        !binlog_filter->db_ok(db)))
> -  {
> -    /*
> -      Compute one bit field with the union of all the engine
> -      capabilities, and one with the intersection of all the engine
> -      capabilities.
> -    */
> -    handler::Table_flags flags_write_some_set= 0;
> -    handler::Table_flags flags_some_set= 0;
> -    handler::Table_flags flags_write_all_set=
> -      HA_BINLOG_ROW_CAPABLE | HA_BINLOG_STMT_CAPABLE;
> -
> -    /* 
> -       If different types of engines are about to be updated.
> -       For example: Innodb and Falcon; Innodb and MyIsam.
> -    */
> -    my_bool multi_write_engine= FALSE;
> -    /*
> -       If different types of engines are about to be accessed 
> -       and any of them is about to be updated. For example:
> -       Innodb and Falcon; Innodb and MyIsam.
> -    */
> -    my_bool multi_access_engine= FALSE;
> -    /*
> -       If non-transactional and transactional engines are about
> -       to be accessed and any of them is about to be updated.
> -       For example: Innodb and MyIsam.
> -    */
> -    my_bool trans_non_trans_access_engines= FALSE;
> -    /*
> -       If all engines that are about to be updated are
> -       transactional.
> -    */
> -    my_bool all_trans_write_engines= TRUE;
> -    TABLE* prev_write_table= NULL;
> -    TABLE* prev_access_table= NULL;
> -
> -#ifndef DBUG_OFF
> -    {
> -      static const char *prelocked_mode_name[] = {
> -        "NON_PRELOCKED",
> -        "PRELOCKED",
> -        "PRELOCKED_UNDER_LOCK_TABLES",
> -      };
> -      DBUG_PRINT("debug", ("prelocked_mode: %s",
> -                           prelocked_mode_name[locked_tables_mode]));
> -    }
> -#endif
> -
> -    /*
> -      Get the capabilities vector for all involved storage engines and
> -      mask out the flags for the binary log.
> -    */
> -    for (TABLE_LIST *table= tables; table; table= table->next_global)
> -    {
> -      if (table->placeholder())
> -        continue;
> -      if (table->table->s->table_category == TABLE_CATEGORY_PERFORMANCE)
> -        lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_SYSTEM_TABLE);
> -      handler::Table_flags const flags=
> table->table->file->ha_table_flags();
> -      DBUG_PRINT("info", ("table: %s; ha_table_flags: 0x%llx",
> -                          table->table_name, flags));
> -      if (table->lock_type >= TL_WRITE_ALLOW_WRITE)
> -      {
> -        if (prev_write_table && prev_write_table->file->ht !=
> -            table->table->file->ht)
> -          multi_write_engine= TRUE;
> -        /*
> -          Every temporary table must be always written to the binary
> -          log in transaction boundaries and as such we artificially
> -          classify them as transactional.
> -
> -          Indirectly, this avoids classifying a temporary table created
> -          on a non-transactional engine as unsafe when it is modified
> -          after any transactional table:
> -
> -          BEGIN;
> -            INSERT INTO innodb_t VALUES (1);
> -            INSERT INTO myisam_t_temp VALUES (1);
> -          COMMIT;
> -
> -          BINARY LOG:
> -
> -          BEGIN;
> -            INSERT INTO innodb_t VALUES (1);
> -            INSERT INTO myisam_t_temp VALUES (1);
> -          COMMIT;
> -        */
> -        all_trans_write_engines= all_trans_write_engines &&
> -                                 (table->table->file->has_transactions()
> ||
> -                                  table->table->s->tmp_table);
> -        prev_write_table= table->table;
> -        flags_write_all_set &= flags;
> -        flags_write_some_set |= flags;
> -      }
> -      flags_some_set |= flags;
> -      /*
> -        The mixture of non-transactional and transactional tables must
> -        identified and classified as unsafe. However, a temporary table
> -        must be always handled as a transactional table. Based on that,
> -        we have the following statements classified as mixed and by
> -        consequence as unsafe:
> -
> -        1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -        2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> -
> -        3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> -
> -        4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> -
> -        5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> -
> -        The following statements are not considered mixed and as such
> -        are safe:
> -
> -        1: INSERT INTO innodb_t SELECT * FROM myisam_t_temp;
> -
> -        2: INSERT INTO myisam_t_temp SELECT * FROM innodb_t_temp;
> -      */
> -      if (!trans_non_trans_access_engines && prev_access_table &&
> -          (lex->sql_command != SQLCOM_CREATE_TABLE ||
> -          (lex->sql_command == SQLCOM_CREATE_TABLE &&
> -          (lex->create_info.options & HA_LEX_CREATE_TMP_TABLE))))
> -      {
> -        my_bool prev_trans;
> -        my_bool act_trans;
> -        if (prev_access_table->s->tmp_table ||
> table->table->s->tmp_table)
> -        {
> -          prev_trans= prev_access_table->s->tmp_table ? TRUE :
> -                     prev_access_table->file->has_transactions();
> -          act_trans= table->table->s->tmp_table ? TRUE :
> -                    table->table->file->has_transactions();
> -        }
> -        else
> -        {
> -          prev_trans= prev_access_table->file->has_transactions();
> -          act_trans= table->table->file->has_transactions();
> -        }
> -        trans_non_trans_access_engines= (prev_trans != act_trans);
> -        multi_access_engine= TRUE;
> -      }
> -      thread_temporary_used |= table->table->s->tmp_table;
> -      prev_access_table= table->table;
> -    }
> -
> -    DBUG_PRINT("info", ("flags_write_all_set: 0x%llx", flags_write_all_set));
> -    DBUG_PRINT("info", ("flags_write_some_set: 0x%llx", flags_write_some_set));
> -    DBUG_PRINT("info", ("flags_some_set: 0x%llx", flags_some_set));
> -    DBUG_PRINT("info", ("multi_write_engine: %d", multi_write_engine));
> -    DBUG_PRINT("info", ("multi_access_engine: %d", multi_access_engine));
> -    DBUG_PRINT("info", ("trans_non_trans_access_engines: %d",
> -                        trans_non_trans_access_engines));
> -
> -    int error= 0;
> -    int unsafe_flags;
> -
> -    /*
> -      Set the statement as unsafe if:
> -
> -      . it is a mixed statement, i.e. access transactional and non-transactional
> -      tables, and update any of them;
> -
> -      or:
> -
> -      . an early statement updated a transactional table;
> -      . and, the current statement updates a non-transactional table.
> -
> -      Any mixed statement is classified as unsafe to ensure that mixed mode is
> -      completely safe. Consider the following example to understand why we
> -      decided to do this:
> -
> -      Note that mixed statements such as
> -
> -      1: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -      2: INSERT INTO innodb_t SELECT * FROM myisam_t;
> -
> -      3: INSERT INTO myisam_t SELECT * FROM myisam_t_temp;
> -
> -      4: INSERT INTO myisam_t_temp SELECT * FROM myisam_t;
> -
> -      5: CREATE TEMPORARY TABLE myisam_t_temp SELECT * FROM mysiam_t;
> -
> -      are classified as unsafe to ensure that in mixed mode the execution is
> -      completely safe and equivalent to the row mode. Consider the following
> -      statements and sessions (connections) to understand the reason:
> -
> -      con1: INSERT INTO innodb_t VALUES (1);
> -      con1: INSERT INTO innodb_t VALUES (100);
> -
> -      con1: BEGIN
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -
> -      The point is that the concurrent statements may be written into the binary
> log
> -      in a way different from the execution. For example,
> -
> -      BINARY LOG:
> -
> -      con2: BEGIN;
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con2: COMMIT;
> -      con1: BEGIN
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -
> -      ....
> -
> -      or
> -
> -      BINARY LOG:
> -
> -      con1: BEGIN
> -      con1: INSERT INTO innodb_t VALUES (200);
> -      con1: COMMIT;
> -      con2: BEGIN;
> -      con2: INSERT INTO myisam_t SELECT * FROM innodb_t;
> -      con2: COMMIT;
> -
> -      Clearly, this may become a problem in STMT mode and setting the statement
> -      as unsafe will make rows to be written into the binary log in MIXED mode
> -      and as such the problem will not stand.
> -
> -      In STMT mode, although such statement is classified as unsafe, i.e.
> -
> -      INSERT INTO myisam_t SELECT * FROM innodb_t;
> -
> -      there is no enough information to avoid writing it outside the boundaries
> -      of a transaction. This is not a problem if we are considering snapshot
> -      isolation level but if we have pure repeatable read or serializable the
> -      lock history on the slave will be different from the master.
> -    */
> -    if (trans_non_trans_access_engines)
> -      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MIXED_STATEMENT);
> -    else if (trans_has_updated_trans_table(this) &&
> !all_trans_write_engines)
> -      lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_NONTRANS_AFTER_TRANS);
> -
> -    /*
> -      If more than one engine is involved in the statement and at
> -      least one is doing it's own logging (is *self-logging*), the
> -      statement cannot be logged atomically, so we generate an error
> -      rather than allowing the binlog to become corrupt.
> -    */
> -    if (multi_write_engine &&
> -        (flags_write_some_set & HA_HAS_OWN_BINLOGGING))
> -      my_error((error= ER_BINLOG_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE),
> -               MYF(0));
> -    else if (multi_access_engine && flags_some_set &
> HA_HAS_OWN_BINLOGGING)
> -     
> lex->set_stmt_unsafe(LEX::BINLOG_STMT_UNSAFE_MULTIPLE_ENGINES_AND_SELF_LOGGING_ENGINE);
> -
> -    /* both statement-only and row-only engines involved */
> -    if ((flags_write_all_set & (HA_BINLOG_STMT_CAPABLE | HA_BINLOG_ROW_CAPABLE))
> == 0)
> -    {
> -      /*
> -        1. Error: Binary logging impossible since both row-incapable
> -           engines and statement-incapable engines are involved
> -      */
> -      my_error((error= ER_BINLOG_ROW_ENGINE_AND_STMT_ENGINE), MYF(0));
> -    }
> -    /* statement-only engines involved */
> -    else if ((flags_write_all_set & HA_BINLOG_ROW_CAPABLE) == 0)
> -    {
> -      if (lex->is_stmt_row_injection())
> -      {
> -        /*
> -          4. Error: Cannot execute row injection since table uses
> -             storage engine limited to statement-logging
> -        */
> -        my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_ENGINE), MYF(0));
> -      }
> -      else if (variables.binlog_format == BINLOG_FORMAT_ROW)
> -      {
> -        /*
> -          2. Error: Cannot modify table that uses a storage engine
> -             limited to statement-logging when BINLOG_FORMAT = ROW
> -        */
> -        my_error((error= ER_BINLOG_ROW_MODE_AND_STMT_ENGINE), MYF(0));
> -      }
> -      else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> -      {
> -        /*
> -          3. Error: Cannot execute statement: binlogging of unsafe
> -             statement is impossible when storage engine is limited to
> -             statement-logging and BINLOG_FORMAT = MIXED.
> -        */
> -        for (int unsafe_type= 0;
> -             unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> -             unsafe_type++)
> -          if (unsafe_flags & (1 << unsafe_type))
> -            my_error((error= ER_BINLOG_UNSAFE_AND_STMT_ENGINE), MYF(0),
> -                     ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -      }
> -      /* log in statement format! */
> -    }
> -    /* no statement-only engines */
> -    else
> -    {
> -      /* binlog_format = STATEMENT */
> -      if (variables.binlog_format == BINLOG_FORMAT_STMT)
> -      {
> -        if (lex->is_stmt_row_injection())
> -        {
> -          /*
> -            6. Error: Cannot execute row injection since
> -               BINLOG_FORMAT = STATEMENT
> -          */
> -          my_error((error= ER_BINLOG_ROW_INJECTION_AND_STMT_MODE), MYF(0));
> -        }
> -        else if ((flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> -        {
> -          /*
> -            5. Error: Cannot modify table that uses a storage engine
> -               limited to row-logging when binlog_format = STATEMENT
> -          */
> -          my_error((error= ER_BINLOG_STMT_MODE_AND_ROW_ENGINE), MYF(0), "");
> -        }
> -        else if ((unsafe_flags= lex->get_stmt_unsafe_flags()) != 0)
> -        {
> -          /*
> -            7. Warning: Unsafe statement logged as statement due to
> -               binlog_format = STATEMENT
> -          */
> -          binlog_unsafe_warning_flags|= unsafe_flags;
> -          DBUG_PRINT("info", ("Scheduling warning to be issued by "
> -                              "binlog_query: '%s'",
> -                              ER(ER_BINLOG_UNSAFE_STATEMENT)));
> -          DBUG_PRINT("info", ("binlog_unsafe_warning_flags: 0x%x",
> -                              binlog_unsafe_warning_flags));
> -        }
> -        /* log in statement format! */
> -      }
> -      /* No statement-only engines and binlog_format != STATEMENT.
> -         I.e., nothing prevents us from row logging if needed. */
> -      else
> -      {
> -        if (lex->is_stmt_unsafe() || lex->is_stmt_row_injection()
> -            || (flags_write_all_set & HA_BINLOG_STMT_CAPABLE) == 0)
> -        {
> -          /* log in row format! */
> -          set_current_stmt_binlog_format_row_if_mixed();
> -        }
> -      }
> -    }
> -
> -    if (error) {
> -      DBUG_PRINT("info", ("decision: no logging since an error was generated"));
> -      DBUG_RETURN(-1);
> -    }
> -    DBUG_PRINT("info", ("decision: logging in %s format",
> -                        is_current_stmt_binlog_format_row() ?
> -                        "ROW" : "STATEMENT"));
> -  }
> -#ifndef DBUG_OFF
> -  else
> -    DBUG_PRINT("info", ("decision: no logging since "
> -                        "mysql_bin_log.is_open() = %d "
> -                        "and (options & OPTION_BIN_LOG) = 0x%llx "
> -                        "and binlog_format = %u "
> -                        "and binlog_filter->db_ok(db) = %d",
> -                        mysql_bin_log.is_open(),
> -                        (variables.option_bits & OPTION_BIN_LOG),
> -                        variables.binlog_format,
> -                        binlog_filter->db_ok(db)));
> -#endif
> -
> -  DBUG_RETURN(0);
> -}
> -
> -
> -/*
> -  Implementation of interface to write rows to the binary log through the
> -  thread.  The thread is responsible for writing the rows it has
> -  inserted/updated/deleted.
> -*/
> -
> -#ifndef MYSQL_CLIENT
> -
> -/*
> -  Template member function for ensuring that there is an rows log
> -  event of the apropriate type before proceeding.
> -
> -  PRE CONDITION:
> -    - Events of type 'RowEventT' have the type code 'type_code'.
> -    
> -  POST CONDITION:
> -    If a non-NULL pointer is returned, the pending event for thread 'thd' will
> -    be an event of type 'RowEventT' (which have the type code 'type_code')
> -    will either empty or have enough space to hold 'needed' bytes.  In
> -    addition, the columns bitmap will be correct for the row, meaning that
> -    the pending event will be flushed if the columns in the event differ from
> -    the columns suppled to the function.
> -
> -  RETURNS
> -    If no error, a non-NULL pending event (either one which already existed or
> -    the newly created one).
> -    If error, NULL.
> - */
> -
> -template <class RowsEventT> Rows_log_event* 
> -THD::binlog_prepare_pending_rows_event(TABLE* table, uint32 serv_id,
> -                                       MY_BITMAP const* cols,
> -                                       size_t colcnt,
> -                                       size_t needed,
> -                                       bool is_transactional,
> -				       RowsEventT *hint __attribute__((unused)))
> -{
> -  DBUG_ENTER("binlog_prepare_pending_rows_event");
> -  /* Pre-conditions */
> -  DBUG_ASSERT(table->s->table_map_id != ~0UL);
> -
> -  /* Fetch the type code for the RowsEventT template parameter */
> -  int const type_code= RowsEventT::TYPE_CODE;
> -
> -  /*
> -    There is no good place to set up the transactional data, so we
> -    have to do it here.
> -  */
> -  if (binlog_setup_trx_data())
> -    DBUG_RETURN(NULL);
> -
> -  Rows_log_event* pending= binlog_get_pending_rows_event(is_transactional);
> -
> -  if (unlikely(pending && !pending->is_valid()))
> -    DBUG_RETURN(NULL);
> -
> -  /*
> -    Check if the current event is non-NULL and a write-rows
> -    event. Also check if the table provided is mapped: if it is not,
> -    then we have switched to writing to a new table.
> -    If there is no pending event, we need to create one. If there is a pending
> -    event, but it's not about the same table id, or not of the same type
> -    (between Write, Update and Delete), or not the same affected columns, or
> -    going to be too big, flush this event to disk and create a new pending
> -    event.
> -  */
> -  if (!pending ||
> -      pending->server_id != serv_id || 
> -      pending->get_table_id() != table->s->table_map_id ||
> -      pending->get_type_code() != type_code || 
> -      pending->get_data_size() + needed > opt_binlog_rows_event_max_size || 
> -      pending->get_width() != colcnt ||
> -      !bitmap_cmp(pending->get_cols(), cols)) 
> -  {
> -    /* Create a new RowsEventT... */
> -    Rows_log_event* const
> -	ev= new RowsEventT(this, table, table->s->table_map_id, cols,
> -                           is_transactional);
> -    if (unlikely(!ev))
> -      DBUG_RETURN(NULL);
> -    ev->server_id= serv_id; // I don't like this, it's too easy to forget.
> -    /*
> -      flush the pending event and replace it with the newly created
> -      event...
> -    */
> -    if (unlikely(
> -        mysql_bin_log.flush_and_set_pending_rows_event(this, ev,
> -                                                       is_transactional)))
> -    {
> -      delete ev;
> -      DBUG_RETURN(NULL);
> -    }
> -
> -    DBUG_RETURN(ev);               /* This is the new pending event */
> -  }
> -  DBUG_RETURN(pending);        /* This is the current pending event */
> -}
> -
> -#ifdef HAVE_EXPLICIT_TEMPLATE_INSTANTIATION
> -/*
> -  Instantiate the versions we need, we have -fno-implicit-template as
> -  compiling option.
> -*/
> -template Rows_log_event*
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t, size_t, bool,
> -				       Write_rows_log_event*);
> -
> -template Rows_log_event*
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t colcnt, size_t, bool,
> -				       Delete_rows_log_event *);
> -
> -template Rows_log_event* 
> -THD::binlog_prepare_pending_rows_event(TABLE*, uint32, MY_BITMAP const*,
> -				       size_t colcnt, size_t, bool,
> -				       Update_rows_log_event *);
> -#endif
> -
>  #ifdef NOT_USED
>  static char const* 
>  field_type_name(enum_field_types type) 
> @@ -4147,505 +3543,3 @@ field_type_name(enum_field_types type) 
>    return "Unknown";
>  }
>  #endif
> -
> -
> -namespace {
> -  /**
> -     Class to handle temporary allocation of memory for row data.
> -
> -     The responsibilities of the class is to provide memory for
> -     packing one or two rows of packed data (depending on what
> -     constructor is called).
> -
> -     In order to make the allocation more efficient for "simple" rows,
> -     i.e., rows that do not contain any blobs, a pointer to the
> -     allocated memory is of memory is stored in the table structure
> -     for simple rows.  If memory for a table containing a blob field
> -     is requested, only memory for that is allocated, and subsequently
> -     released when the object is destroyed.
> -
> -   */
> -  class Row_data_memory {
> -  public:
> -    /**
> -      Build an object to keep track of a block-local piece of memory
> -      for storing a row of data.
> -
> -      @param table
> -      Table where the pre-allocated memory is stored.
> -
> -      @param length
> -      Length of data that is needed, if the record contain blobs.
> -     */
> -    Row_data_memory(TABLE *table, size_t const len1)
> -      : m_memory(0)
> -    {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= FALSE;
> -#endif
> -      allocate_memory(table, len1);
> -      m_ptr[0]= has_memory() ? m_memory : 0;
> -      m_ptr[1]= 0;
> -    }
> -
> -    Row_data_memory(TABLE *table, size_t const len1, size_t const len2)
> -      : m_memory(0)
> -    {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= FALSE;
> -#endif
> -      allocate_memory(table, len1 + len2);
> -      m_ptr[0]= has_memory() ? m_memory        : 0;
> -      m_ptr[1]= has_memory() ? m_memory + len1 : 0;
> -    }
> -
> -    ~Row_data_memory()
> -    {
> -      if (m_memory != 0 && m_release_memory_on_destruction)
> -        my_free((uchar*) m_memory, MYF(MY_WME));
> -    }
> -
> -    /**
> -       Is there memory allocated?
> -
> -       @retval true There is memory allocated
> -       @retval false Memory allocation failed
> -     */
> -    bool has_memory() const {
> -#ifndef DBUG_OFF
> -      m_alloc_checked= TRUE;
> -#endif
> -      return m_memory != 0;
> -    }
> -
> -    uchar *slot(uint s)
> -    {
> -      DBUG_ASSERT(s < sizeof(m_ptr)/sizeof(*m_ptr));
> -      DBUG_ASSERT(m_ptr[s] != 0);
> -      DBUG_ASSERT(m_alloc_checked == TRUE);
> -      return m_ptr[s];
> -    }
> -
> -  private:
> -    void allocate_memory(TABLE *const table, size_t const total_length)
> -    {
> -      if (table->s->blob_fields == 0)
> -      {
> -        /*
> -          The maximum length of a packed record is less than this
> -          length. We use this value instead of the supplied length
> -          when allocating memory for records, since we don't know how
> -          the memory will be used in future allocations.
> -
> -          Since table->s->reclength is for unpacked records, we have
> -          to add two bytes for each field, which can potentially be
> -          added to hold the length of a packed field.
> -        */
> -        size_t const maxlen= table->s->reclength + 2 *
> table->s->fields;
> -
> -        /*
> -          Allocate memory for two records if memory hasn't been
> -          allocated. We allocate memory for two records so that it can
> -          be used when processing update rows as well.
> -        */
> -        if (table->write_row_record == 0)
> -          table->write_row_record=
> -            (uchar *) alloc_root(&table->mem_root, 2 * maxlen);
> -        m_memory= table->write_row_record;
> -        m_release_memory_on_destruction= FALSE;
> -      }
> -      else
> -      {
> -        m_memory= (uchar *) my_malloc(total_length, MYF(MY_WME));
> -        m_release_memory_on_destruction= TRUE;
> -      }
> -    }
> -
> -#ifndef DBUG_OFF
> -    mutable bool m_alloc_checked;
> -#endif
> -    bool m_release_memory_on_destruction;
> -    uchar *m_memory;
> -    uchar *m_ptr[2];
> -  };
> -}
> -
> -
> -int THD::binlog_write_row(TABLE* table, bool is_trans, 
> -                          MY_BITMAP const* cols, size_t colcnt, 
> -                          uchar const *record) 
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  /*
> -    Pack records into format for transfer. We are allocating more
> -    memory than needed, but that doesn't matter.
> -  */
> -  Row_data_memory memory(table, max_row_length(table, record));
> -  if (!memory.has_memory())
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *row_data= memory.slot(0);
> -
> -  size_t const len= pack_row(table, cols, row_data, record);
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -                                      len, is_trans,
> -                                      static_cast<Write_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return ev->add_row_data(row_data, len);
> -}
> -
> -int THD::binlog_update_row(TABLE* table, bool is_trans,
> -                           MY_BITMAP const* cols, size_t colcnt,
> -                           const uchar *before_record,
> -                           const uchar *after_record)
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  size_t const before_maxlen = max_row_length(table, before_record);
> -  size_t const after_maxlen  = max_row_length(table, after_record);
> -
> -  Row_data_memory row_data(table, before_maxlen, after_maxlen);
> -  if (!row_data.has_memory())
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *before_row= row_data.slot(0);
> -  uchar *after_row= row_data.slot(1);
> -
> -  size_t const before_size= pack_row(table, cols, before_row,
> -                                        before_record);
> -  size_t const after_size= pack_row(table, cols, after_row,
> -                                       after_record);
> -
> -  /*
> -    Don't print debug messages when running valgrind since they can
> -    trigger false warnings.
> -   */
> -#ifndef HAVE_purify
> -  DBUG_DUMP("before_record", before_record, table->s->reclength);
> -  DBUG_DUMP("after_record",  after_record, table->s->reclength);
> -  DBUG_DUMP("before_row",    before_row, before_size);
> -  DBUG_DUMP("after_row",     after_row, after_size);
> -#endif
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -				      before_size + after_size, is_trans,
> -				      static_cast<Update_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return
> -    ev->add_row_data(before_row, before_size) ||
> -    ev->add_row_data(after_row, after_size);
> -}
> -
> -int THD::binlog_delete_row(TABLE* table, bool is_trans, 
> -                           MY_BITMAP const* cols, size_t colcnt,
> -                           uchar const *record)
> -{ 
> -  DBUG_ASSERT(is_current_stmt_binlog_format_row() &&
> mysql_bin_log.is_open());
> -
> -  /* 
> -     Pack records into format for transfer. We are allocating more
> -     memory than needed, but that doesn't matter.
> -  */
> -  Row_data_memory memory(table, max_row_length(table, record));
> -  if (unlikely(!memory.has_memory()))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  uchar *row_data= memory.slot(0);
> -
> -  size_t const len= pack_row(table, cols, row_data, record);
> -
> -  Rows_log_event* const ev=
> -    binlog_prepare_pending_rows_event(table, server_id, cols, colcnt,
> -				      len, is_trans,
> -				      static_cast<Delete_rows_log_event*>(0));
> -
> -  if (unlikely(ev == 0))
> -    return HA_ERR_OUT_OF_MEM;
> -
> -  return ev->add_row_data(row_data, len);
> -}
> -
> -
> -int THD::binlog_remove_pending_rows_event(bool clear_maps,
> -                                          bool is_transactional)
> -{
> -  DBUG_ENTER("THD::binlog_remove_pending_rows_event");
> -
> -  if (!mysql_bin_log.is_open())
> -    DBUG_RETURN(0);
> -
> -  mysql_bin_log.remove_pending_rows_event(this, is_transactional);
> -
> -  if (clear_maps)
> -    binlog_table_maps= 0;
> -
> -  DBUG_RETURN(0);
> -}
> -
> -int THD::binlog_flush_pending_rows_event(bool stmt_end, bool is_transactional)
> -{
> -  DBUG_ENTER("THD::binlog_flush_pending_rows_event");
> -  /*
> -    We shall flush the pending event even if we are not in row-based
> -    mode: it might be the case that we left row-based mode before
> -    flushing anything (e.g., if we have explicitly locked tables).
> -   */
> -  if (!mysql_bin_log.is_open())
> -    DBUG_RETURN(0);
> -
> -  /*
> -    Mark the event as the last event of a statement if the stmt_end
> -    flag is set.
> -  */
> -  int error= 0;
> -  if (Rows_log_event *pending= binlog_get_pending_rows_event(is_transactional))
> -  {
> -    if (stmt_end)
> -    {
> -      pending->set_flags(Rows_log_event::STMT_END_F);
> -      pending->flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> -      binlog_table_maps= 0;
> -    }
> -
> -    error= mysql_bin_log.flush_and_set_pending_rows_event(this, 0,
> -                                                          is_transactional);
> -  }
> -
> -  DBUG_RETURN(error);
> -}
> -
> -
> -#if !defined(DBUG_OFF) && !defined(_lint)
> -static const char *
> -show_query_type(THD::enum_binlog_query_type qtype)
> -{
> -  switch (qtype) {
> -  case THD::ROW_QUERY_TYPE:
> -    return "ROW";
> -  case THD::STMT_QUERY_TYPE:
> -    return "STMT";
> -  case THD::QUERY_TYPE_COUNT:
> -  default:
> -    DBUG_ASSERT(0 <= qtype && qtype < THD::QUERY_TYPE_COUNT);
> -  }
> -  static char buf[64];
> -  sprintf(buf, "UNKNOWN#%d", qtype);
> -  return buf;
> -}
> -#endif
> -
> -
> -/**
> -  Auxiliary method used by @c binlog_query() to raise warnings.
> -
> -  The type of warning and the type of unsafeness is stored in
> -  THD::binlog_unsafe_warning_flags.
> -*/
> -void THD::issue_unsafe_warnings()
> -{
> -  DBUG_ENTER("issue_unsafe_warnings");
> -  /*
> -    Ensure that binlog_unsafe_warning_flags is big enough to hold all
> -    bits.  This is actually a constant expression.
> -  */
> -  DBUG_ASSERT(2 * LEX::BINLOG_STMT_UNSAFE_COUNT <=
> -              sizeof(binlog_unsafe_warning_flags) * CHAR_BIT);
> -
> -  uint32 unsafe_type_flags= binlog_unsafe_warning_flags;
> -
> -  /*
> -    Clear: (1) bits above BINLOG_STMT_UNSAFE_COUNT; (2) bits for
> -    warnings that have been printed already.
> -  */
> -  unsafe_type_flags &= (LEX::BINLOG_STMT_UNSAFE_ALL_FLAGS ^
> -                        (unsafe_type_flags >>
> LEX::BINLOG_STMT_UNSAFE_COUNT));
> -  /* If all warnings have been printed already, return. */
> -  if (unsafe_type_flags == 0)
> -    DBUG_VOID_RETURN;
> -
> -  DBUG_PRINT("info", ("unsafe_type_flags: 0x%x", unsafe_type_flags));
> -
> -  /*
> -    For each unsafe_type, check if the statement is unsafe in this way
> -    and issue a warning.
> -  */
> -  for (int unsafe_type=0;
> -       unsafe_type < LEX::BINLOG_STMT_UNSAFE_COUNT;
> -       unsafe_type++)
> -  {
> -    if ((unsafe_type_flags & (1 << unsafe_type)) != 0)
> -    {
> -      push_warning_printf(this, MYSQL_ERROR::WARN_LEVEL_NOTE,
> -                          ER_BINLOG_UNSAFE_STATEMENT,
> -                          ER(ER_BINLOG_UNSAFE_STATEMENT),
> -                          ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -      if (global_system_variables.log_warnings)
> -      {
> -        char buf[MYSQL_ERRMSG_SIZE * 2];
> -        sprintf(buf, ER(ER_BINLOG_UNSAFE_STATEMENT),
> -                ER(LEX::binlog_stmt_unsafe_errcode[unsafe_type]));
> -        sql_print_warning(ER(ER_MESSAGE_AND_STATEMENT), buf, query());
> -      }
> -    }
> -  }
> -  /*
> -    Mark these unsafe types as already printed, to avoid printing
> -    warnings for them again.
> -  */
> -  binlog_unsafe_warning_flags|=
> -    unsafe_type_flags << LEX::BINLOG_STMT_UNSAFE_COUNT;
> -  DBUG_VOID_RETURN;
> -}
> -
> -
> -/**
> -  Log the current query.
> -
> -  The query will be logged in either row format or statement format
> -  depending on the value of @c current_stmt_binlog_format_row field and
> -  the value of the @c qtype parameter.
> -
> -  This function must be called:
> -
> -  - After the all calls to ha_*_row() functions have been issued.
> -
> -  - After any writes to system tables. Rationale: if system tables
> -    were written after a call to this function, and the master crashes
> -    after the call to this function and before writing the system
> -    tables, then the master and slave get out of sync.
> -
> -  - Before tables are unlocked and closed.
> -
> -  @see decide_logging_format
> -
> -  @retval 0 Success
> -
> -  @retval nonzero If there is a failure when writing the query (e.g.,
> -  write failure), then the error code is returned.
> -*/
> -int THD::binlog_query(THD::enum_binlog_query_type qtype, char const *query_arg,
> -                      ulong query_len, bool is_trans, bool direct, 
> -                      bool suppress_use, int errcode)
> -{
> -  DBUG_ENTER("THD::binlog_query");
> -  DBUG_PRINT("enter", ("qtype: %s  query: '%s'",
> -                       show_query_type(qtype), query_arg));
> -  DBUG_ASSERT(query_arg && mysql_bin_log.is_open());
> -
> -  /*
> -    If we are not in prelocked mode, mysql_unlock_tables() will be
> -    called after this binlog_query(), so we have to flush the pending
> -    rows event with the STMT_END_F set to unlock all tables at the
> -    slave side as well.
> -
> -    If we are in prelocked mode, the flushing will be done inside the
> -    top-most close_thread_tables().
> -  */
> -  if (this->locked_tables_mode <= LTM_LOCK_TABLES)
> -    if (int error= binlog_flush_pending_rows_event(TRUE, is_trans))
> -      DBUG_RETURN(error);
> -
> -  /*
> -    Warnings for unsafe statements logged in statement format are
> -    printed here instead of in decide_logging_format().  This is
> -    because the warnings should be printed only if the statement is
> -    actually logged. When executing decide_logging_format(), we cannot
> -    know for sure if the statement will be logged.
> -  */
> -  if (sql_log_bin_toplevel)
> -    issue_unsafe_warnings();
> -
> -  switch (qtype) {
> -    /*
> -      ROW_QUERY_TYPE means that the statement may be logged either in
> -      row format or in statement format.  If
> -      current_stmt_binlog_format is row, it means that the
> -      statement has already been logged in row format and hence shall
> -      not be logged again.
> -    */
> -  case THD::ROW_QUERY_TYPE:
> -    DBUG_PRINT("debug",
> -               ("is_current_stmt_binlog_format_row: %d",
> -                is_current_stmt_binlog_format_row()));
> -    if (is_current_stmt_binlog_format_row())
> -      DBUG_RETURN(0);
> -    /* Fall through */
> -
> -    /*
> -      STMT_QUERY_TYPE means that the query must be logged in statement
> -      format; it cannot be logged in row format.  This is typically
> -      used by DDL statements.  It is an error to use this query type
> -      if current_stmt_binlog_format_row is row.
> -
> -      @todo Currently there are places that call this method with
> -      STMT_QUERY_TYPE and current_stmt_binlog_format is row.  Fix those
> -      places and add assert to ensure correct behavior. /Sven
> -    */
> -  case THD::STMT_QUERY_TYPE:
> -    /*
> -      The MYSQL_LOG::write() function will set the STMT_END_F flag and
> -      flush the pending rows event if necessary.
> -    */
> -    {
> -      Query_log_event qinfo(this, query_arg, query_len, is_trans, direct,
> -                            suppress_use, errcode);
> -      qinfo.flags|= LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F;
> -      /*
> -        Binlog table maps will be irrelevant after a Query_log_event
> -        (they are just removed on the slave side) so after the query
> -        log event is written to the binary log, we pretend that no
> -        table maps were written.
> -       */
> -      int error= mysql_bin_log.write(&qinfo);
> -      binlog_table_maps= 0;
> -      DBUG_RETURN(error);
> -    }
> -    break;
> -
> -  case THD::QUERY_TYPE_COUNT:
> -  default:
> -    DBUG_ASSERT(0 <= qtype && qtype < QUERY_TYPE_COUNT);
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -bool Discrete_intervals_list::append(ulonglong start, ulonglong val,
> -                                 ulonglong incr)
> -{
> -  DBUG_ENTER("Discrete_intervals_list::append");
> -  /* first, see if this can be merged with previous */
> -  if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
> -  {
> -    /* it cannot, so need to add a new interval */
> -    Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
> -    DBUG_RETURN(append(new_interval));
> -  }
> -  DBUG_RETURN(0);
> -}
> -
> -bool Discrete_intervals_list::append(Discrete_interval *new_interval)
> -{
> -  DBUG_ENTER("Discrete_intervals_list::append");
> -  if (unlikely(new_interval == NULL))
> -    DBUG_RETURN(1);
> -  DBUG_PRINT("info",("adding new auto_increment interval"));
> -  if (head == NULL)
> -    head= current= new_interval;
> -  else
> -    tail->next= new_interval;
> -  tail= new_interval;
> -  elements++;
> -  DBUG_RETURN(0);
> -}
> -
> -#endif /* !defined(MYSQL_CLIENT) */
> 
> === modified file 'sql/sql_load.cc'
> --- a/sql/sql_load.cc	2010-05-05 10:34:20 +0000
> +++ b/sql/sql_load.cc	2010-05-13 05:54:26 +0000
> @@ -34,7 +34,7 @@
>                          // LOG_EVENT_UPDATE_TABLE_MAP_VERSION_F
>  #include <m_ctype.h>
>  #include "rpl_mi.h"
> -#include "sql_repl.h"
> +#include "slave.h"
>  #include "sp_head.h"
>  #include "sql_trigger.h"
>  
> 
> === modified file 'sql/sql_parse.cc'
> --- a/sql/sql_parse.cc	2010-04-26 09:02:29 +0000
> +++ b/sql/sql_parse.cc	2010-05-13 05:54:26 +0000
> @@ -76,7 +76,8 @@
>  #include "sql_help.h"         // mysqld_help
>  #include "rpl_constants.h"    // Incident, INCIDENT_LOST_EVENTS
>  #include "log_event.h"
> -#include "sql_repl.h"
> +#include "slave.h"
> +#include "master.h"
>  #include "rpl_filter.h"
>  #include "repl_failsafe.h"
>  #include <m_ctype.h>
> @@ -2374,7 +2375,13 @@ case SQLCOM_PREPARE:
>      res = show_slave_hosts(thd);
>      break;
>    }
> -  case SQLCOM_SHOW_RELAYLOG_EVENTS: /* fall through */
> +  case SQLCOM_SHOW_RELAYLOG_EVENTS:
> +  {
> +    if (check_global_access(thd, REPL_SLAVE_ACL))
> +      goto error;
> +    res = mysql_show_relaylog_events(thd);
> +    break;
> +  }
>    case SQLCOM_SHOW_BINLOG_EVENTS:
>    {
>      if (check_global_access(thd, REPL_SLAVE_ACL))
> 
> === removed file 'sql/sql_repl.h'
> --- a/sql/sql_repl.h	2010-03-31 14:05:33 +0000
> +++ b/sql/sql_repl.h	1970-01-01 00:00:00 +0000
> @@ -1,72 +0,0 @@
> -/* Copyright (C) 2000-2006 MySQL AB & Sasha
> -
> -   This program is free software; you can redistribute it and/or modify
> -   it under the terms of the GNU General Public License as published by
> -   the Free Software Foundation; version 2 of the License.
> -
> -   This program is distributed in the hope that it will be useful,
> -   but WITHOUT ANY WARRANTY; without even the implied warranty of
> -   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> -   GNU General Public License for more details.
> -
> -   You should have received a copy of the GNU General Public License
> -   along with this program; if not, write to the Free Software
> -   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */
> -
> -#ifndef SQL_REPL_INCLUDED
> -#define SQL_REPL_INCLUDED
> -
> -#include "rpl_filter.h"
> -
> -#ifdef HAVE_REPLICATION
> -#include "slave.h"
> -
> -typedef struct st_slave_info
> -{
> -  uint32 server_id;
> -  uint32 rpl_recovery_rank, master_id;
> -  char host[HOSTNAME_LENGTH+1];
> -  char user[USERNAME_LENGTH+1];
> -  char password[MAX_PASSWORD_LENGTH+1];
> -  uint16 port;
> -  THD* thd;
> -} SLAVE_INFO;
> -
> -extern my_bool opt_show_slave_auth_info;
> -extern char *master_host, *master_info_file;
> -extern bool server_id_supplied;
> -
> -extern int max_binlog_dump_events;
> -extern my_bool opt_sporadic_binlog_dump_fail;
> -
> -int start_slave(THD* thd, Master_info* mi, bool net_report);
> -int stop_slave(THD* thd, Master_info* mi, bool net_report);
> -bool change_master(THD* thd, Master_info* mi);
> -bool mysql_show_binlog_events(THD* thd);
> -int cmp_master_pos(const char* log_file_name1, ulonglong log_pos1,
> -		   const char* log_file_name2, ulonglong log_pos2);
> -int reset_slave(THD *thd, Master_info* mi);
> -int reset_master(THD* thd);
> -bool purge_master_logs(THD* thd, const char* to_log);
> -bool purge_master_logs_before_date(THD* thd, time_t purge_time);
> -bool log_in_use(const char* log_name);
> -void adjust_linfo_offsets(my_off_t purge_offset);
> -bool show_binlogs(THD* thd);
> -extern int init_master_info(Master_info* mi);
> -void kill_zombie_dump_threads(uint32 slave_server_id);
> -int check_binlog_magic(IO_CACHE* log, const char** errmsg);
> -
> -typedef struct st_load_file_info
> -{
> -  THD* thd;
> -  my_off_t last_pos_in_file;
> -  bool wrote_create_file, log_delayed;
> -} LOAD_FILE_INFO;
> -
> -int log_loaded_block(IO_CACHE* file);
> -int init_replication_sys_vars();
> -void mysql_binlog_send(THD* thd, char* log_ident, my_off_t pos, ushort flags);
> -
> -#endif /* HAVE_REPLICATION */
> -
> -#endif /* SQL_REPL_INCLUDED */
> 
> === modified file 'sql/structs.h'
> --- a/sql/structs.h	2010-03-31 14:05:33 +0000
> +++ b/sql/structs.h	2010-05-13 05:54:26 +0000
> @@ -358,8 +358,30 @@ public:
>      return tmp;
>    }
>    ~Discrete_intervals_list() { empty(); };
> -  bool append(ulonglong start, ulonglong val, ulonglong incr);
> -  bool append(Discrete_interval *interval);
> +  bool append(ulonglong start, ulonglong val, ulonglong incr)
> +  {
> +    /* first, see if this can be merged with previous */
> +    if ((head == NULL) || tail->merge_if_contiguous(start, val, incr))
> +    {
> +      /* it cannot, so need to add a new interval */
> +      Discrete_interval *new_interval= new Discrete_interval(start, val, incr);
> +      return append(new_interval);
> +    }
> +    return 0;
> +  }
> +  
> +  bool append(Discrete_interval *new_interval)
> +  {
> +    if (unlikely(new_interval == NULL))
> +      return 1;
> +    if (head == NULL)
> +      head= current= new_interval;
> +    else
> +      tail->next= new_interval;
> +    tail= new_interval;
> +    elements++;
> +    return 0;
> +  }
>    ulonglong minimum()     const { return (head ? head->minimum() : 0); };
>    ulonglong maximum()     const { return (head ? tail->maximum() : 0); };
>    uint      nb_elements() const { return elements; }
> 
> text/bzr-bundle type attachment
> (bzr/zhenxing.he@stripped)
> # Bazaar merge directive format 2 (Bazaar 0.90)
> # revision_id: zhenxing.he@stripped
> # target_branch: file:///media/sdb2/hezx/work/mysql/bzrwork/w3662\
> #   /trunk-bugfixing/
> # testament_sha1: ad8bd39e334e1b8f5de5bbbb5cad371aa702c02c
> # timestamp: 2010-05-13 13:54:34 +0800
> # base_revision_id: zhenxing.he@stripped\
> #   j8kzr62xlqln5c6f
> # 
> # Begin bundle
> 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
> 
> 


Thread
bzr commit into mysql-trunk-bugfixing branch (zhenxing.he:3037) WL#5385He Zhenxing13 May
  • Re: bzr commit into mysql-trunk-bugfixing branch (zhenxing.he:3037)WL#5385Luís Soares13 May