WL#5600: Add hooks for START SLAVE and STOP SLAVE

Affects: Benchmarks-3.0   —   Status: Un-Assigned   —   Priority: Medium

Add hooks in replication code that will be invoked when the slave SQL thread
starts and stops, respectively.

See also WL#4411, WL#3305, WL#3663.
Extend the existing replication plugin interface. There exist hooks where
plugins can register to get notified at various points in the master transaction
execution code, the master binlog writer code, the master dump code, and the
slave IO thread code.

There are currently no hooks in the slave SQL thread code. The hooks for start
and stop thread exist already for the IO thread, so we just need to mimic that
in the SQL thread. Below is a sketch of what we need to do.



==== BEGIN REPLICATION CODE ====

---- replication.h/.cc ----

typedef struct Replication_slave_SQL_thread_param {
  // similar to Binlog_relay_IO_param
}

typedef struct Replication_slave_SQL_thread_observer {
  // similar to Binlog_relay_IO_observer
}

int register_replication_slave_sql_thread_observer(
  Replication_slave_SQL_thread_observer *observer, void *p)
{
  // similar to register_binlog_relay_io_observer.
}

int unregister_replication_slave_sql_thread_observer(
  Replication_slave_SQL_thread_observer *observer, void *p);
{
  // similar to unregister_binlog_relay_io_observer.
}

---- rpl_handler.h/.cc ----

class Replication_slave_SQL_thread_delegate {
  // similar to Binlog_relay_IO_delegate
};

extern Replication_slave_SQL_thread_delegate
  *replication_slave_sql_thread_delegate;

int delegates_init()
void delegates_destroy()
  // extend these functions so that they initialize/deinitialize
  // replication_slave_sql_thread_delegate in similar ways as
  // is currently done with binlog_relay_io_delegate

---- slave.cc ----

  // in the beginning of handle_slave_sql:
  if (RUN_HOOK(replication_slave_sql_thread, thread_start, (thd, rli)))
  {
    mi->report(ERROR_LEVEL, ER_SLAVE_FATAL_ERROR,
               ER(ER_SLAVE_FATAL_ERROR),
               "Failed to run 'thread_start' hook");
    goto err;
  }

  // at the end of handle_slave_sql:
  RUN_HOOK(replication_slave_sql_thread, thread_stop, (thd, rli));

==== END REPLICATION CODE ====


The above interface can be used in the following manner by a plugin:


==== BEGIN PLUGIN CODE ====

#include "replication.h"

// Hook that will get invoked by replication code when slave starts
int my_plugin_rpl_slave_sql_start(Replication_SQL_thread_param *param)
{
  do something useful.
  'param' contains copies of some fields from of Relay_log_info,
  such as the relay log read position.
}

// Hook that will get invoked by replication code when slave stops
int my_plugin_rpl_slave_sql_stop(Replication_SQL_thread_param *param)
{
  do something useful
}

// Declare observers.
static Replication_slave_SQL_thread_observer
  my_plugin_rpl_sql_thread_observer =
{
  my_plugin_rpl_slave_sql_start,         // hook executed when slave starts
  my_plugin_rpl_slave_sql_stop,          // hook executed when slave stops
};

// Register observers.
static int my_plugin_rpl_slave_plugin_init(void *p)
{
  if (register_replication_slave_sql_thread_observer(
      &my_plugin_rpl_sql_thread_observer))
    return 1;
  return 0;
}

// Unregister observers.
static int my_plugin_rpl_slave_plugin_deinit(void *p)
{
  if (unregister_replication_slave_sql_thread_observer(
    &relay_io_observer, p))
    return 1;
  return 0;
}

// Declare replication specific plugin information.
struct Mysql_replication my_plugin_rpl_slave_plugin= {
  MYSQL_REPLICATION_INTERFACE_VERSION
};

// Declare plugin.
mysql_declare_plugin(my_plugin_rpl_slave)
{
  MYSQL_REPLICATION_PLUGIN,
  &my_plugin_rpl_slave_plugin, /* struct declared above */
  "my_plugin_slave", /* Plugin name */
  "J. Hacker", /* Plugin author */
  "My_Plugin replication slave", /* Description */
  PLUGIN_LICENSE_GPL, /* Licence */
  my_plugin_rpl_slave_plugin_init, /* Plugin Init */
  my_plugin_rpl_slave_plugin_deinit, /* Plugin Deinit */
  0x0100 /* 1.0 */,
  NULL,    /* status variables */
  NULL,    /* system variables */
  NULL /* config options */
}
mysql_declare_plugin_end;

==== END PLUGIN CODE ====