mysql5/mysql-5.7.27/plugin/replication_observers_example/replication_observers_example.cc

1178 lines
37 KiB
C++

/* Copyright (c) 2014, 2017, 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
/*
This plugin serves as an example for all those who which to use the new
Hooks installed by Replication in order to capture:
- Transaction progress
- Server state
*/
#include <mysql/group_replication_priv.h>
#include <mysql/plugin.h>
#include <mysql/service_my_plugin_log.h>
#include <mysql/service_rpl_transaction_ctx.h>
static MYSQL_PLUGIN plugin_info_ptr;
int validate_plugin_server_requirements(Trans_param *param);
int test_channel_service_interface_initialization();
int test_channel_service_interface();
int test_channel_service_interface_io_thread();
bool test_channel_service_interface_is_io_stopping();
bool test_channel_service_interface_is_sql_stopping();
bool test_channel_service_interface_relay_log_renamed();
/*
Will register the number of calls to each method of Server state
*/
static int before_handle_connection_call= 0;
static int before_recovery_call= 0;
static int after_engine_recovery_call= 0;
static int after_recovery_call= 0;
static int before_server_shutdown_call= 0;
static int after_server_shutdown_call= 0;
static bool thread_aborted= false;
static void dump_server_state_calls()
{
if(before_handle_connection_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:before_handle_connection");
}
if(before_recovery_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:before_recovery");
}
if(after_engine_recovery_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:after_engine_recovery");
}
if(after_recovery_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:after_recovery");
}
if(before_server_shutdown_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:before_server_shutdown");
}
if(after_server_shutdown_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:after_server_shutdown");
}
}
/*
DBMS lifecycle events observers.
*/
int before_handle_connection(Server_state_param *param)
{
before_handle_connection_call++;
return 0;
}
int before_recovery(Server_state_param *param)
{
before_recovery_call++;
return 0;
}
int after_engine_recovery(Server_state_param *param)
{
after_engine_recovery_call++;
return 0;
}
int after_recovery(Server_state_param *param)
{
after_recovery_call++;
return 0;
}
int before_server_shutdown(Server_state_param *param)
{
before_server_shutdown_call++;
return 0;
}
int after_server_shutdown(Server_state_param *param)
{
after_server_shutdown_call++;
return 0;
}
Server_state_observer server_state_observer = {
sizeof(Server_state_observer),
before_handle_connection, //before the client connect the node
before_recovery, //before_recovery
after_engine_recovery, //after engine recovery
after_recovery, //after_recovery
before_server_shutdown, //before shutdown
after_server_shutdown, //after shutdown
};
static int trans_before_dml_call= 0;
static int trans_before_commit_call= 0;
static int trans_before_rollback_call= 0;
static int trans_after_commit_call= 0;
static int trans_after_rollback_call= 0;
static void dump_transaction_calls()
{
if(trans_before_dml_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:trans_before_dml");
}
if(trans_before_commit_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:trans_before_commit");
}
if(trans_before_rollback_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:trans_before_rollback");
}
if(trans_after_commit_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:trans_after_commit");
}
if(trans_after_rollback_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:trans_after_rollback");
}
}
/*
Transaction lifecycle events observers.
*/
int trans_before_dml(Trans_param *param, int& out_val)
{
trans_before_dml_call++;
DBUG_EXECUTE_IF("cause_failure_in_before_dml_hook",
out_val= 1;);
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_channels",
test_channel_service_interface(););
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_channel_io_thread",
test_channel_service_interface_io_thread(););
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_channels_init",
test_channel_service_interface_initialization(););
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_is_io_stopping",
test_channel_service_interface_is_io_stopping(););
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_is_sql_stopping",
test_channel_service_interface_is_sql_stopping(););
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_relay_log_renamed",
test_channel_service_interface_relay_log_renamed(););
return 0;
}
typedef enum enum_before_commit_test_cases {
NEGATIVE_CERTIFICATION,
POSITIVE_CERTIFICATION_WITH_GTID,
POSITIVE_CERTIFICATION_WITHOUT_GTID,
INVALID_CERTIFICATION_OUTCOME
} before_commit_test_cases;
int before_commit_tests(Trans_param *param,
before_commit_test_cases test_case)
{
rpl_sid fake_sid;
rpl_sidno fake_sidno;
rpl_gno fake_gno;
Transaction_termination_ctx transaction_termination_ctx;
memset(&transaction_termination_ctx, 0, sizeof(transaction_termination_ctx));
transaction_termination_ctx.m_thread_id= param->thread_id;
switch(test_case)
{
case NEGATIVE_CERTIFICATION:
transaction_termination_ctx.m_rollback_transaction= TRUE;
transaction_termination_ctx.m_generated_gtid= FALSE;
transaction_termination_ctx.m_sidno= -1;
transaction_termination_ctx.m_gno= -1;
break;
case POSITIVE_CERTIFICATION_WITH_GTID:
fake_sid.parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
fake_sidno= get_sidno_from_global_sid_map(fake_sid);
fake_gno= get_last_executed_gno(fake_sidno);
fake_gno++;
transaction_termination_ctx.m_rollback_transaction= FALSE;
transaction_termination_ctx.m_generated_gtid= TRUE;
transaction_termination_ctx.m_sidno= fake_sidno;
transaction_termination_ctx.m_gno= fake_gno;
break;
case POSITIVE_CERTIFICATION_WITHOUT_GTID:
transaction_termination_ctx.m_rollback_transaction= FALSE;
transaction_termination_ctx.m_generated_gtid= FALSE;
transaction_termination_ctx.m_sidno= 0;
transaction_termination_ctx.m_gno= 0;
break;
case INVALID_CERTIFICATION_OUTCOME:
transaction_termination_ctx.m_rollback_transaction= TRUE;
transaction_termination_ctx.m_generated_gtid= TRUE;
transaction_termination_ctx.m_sidno= -1;
transaction_termination_ctx.m_gno= -1;
default:
break;
}
if (set_transaction_ctx(transaction_termination_ctx))
{
my_plugin_log_message(&plugin_info_ptr,
MY_ERROR_LEVEL,
"Unable to update transaction context service on server, thread_id: %lu",
param->thread_id);
return 1;
}
return 0;
}
int trans_before_commit(Trans_param *param)
{
trans_before_commit_call++;
DBUG_EXECUTE_IF("force_error_on_before_commit_listener",
return 1;);
DBUG_EXECUTE_IF("force_negative_certification_outcome",
return before_commit_tests(param, NEGATIVE_CERTIFICATION););
DBUG_EXECUTE_IF("force_positive_certification_outcome_without_gtid",
return before_commit_tests(param, POSITIVE_CERTIFICATION_WITHOUT_GTID););
DBUG_EXECUTE_IF("force_positive_certification_outcome_with_gtid",
return before_commit_tests(param, POSITIVE_CERTIFICATION_WITH_GTID););
DBUG_EXECUTE_IF("force_invalid_certification_outcome",
return before_commit_tests(param, INVALID_CERTIFICATION_OUTCOME););
return 0;
}
int trans_before_rollback(Trans_param *param)
{
trans_before_rollback_call++;
return 0;
}
int trans_after_commit(Trans_param *param)
{
trans_after_commit_call++;
return 0;
}
int trans_after_rollback(Trans_param *param)
{
trans_after_rollback_call++;
DBUG_EXECUTE_IF("validate_replication_observers_plugin_server_requirements",
return validate_plugin_server_requirements(param););
return 0;
}
Trans_observer trans_observer = {
sizeof(Trans_observer),
trans_before_dml,
trans_before_commit,
trans_before_rollback,
trans_after_commit,
trans_after_rollback,
};
/*
Binlog relay IO events observers.
*/
static int binlog_relay_thread_start_call= 0;
static int binlog_relay_thread_stop_call= 0;
static int binlog_relay_applier_start_call= 0;
static int binlog_relay_applier_stop_call= 0;
static int binlog_relay_before_request_transmit_call= 0;
static int binlog_relay_after_read_event_call= 0;
static int binlog_relay_after_queue_event_call= 0;
static int binlog_relay_after_reset_slave_call= 0;
static void dump_binlog_relay_calls()
{
if (binlog_relay_thread_start_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_thread_start");
}
if (binlog_relay_thread_stop_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_thread_stop");
}
if (binlog_relay_applier_start_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_applier_start");
}
if (binlog_relay_applier_stop_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_applier_stop");
}
if (binlog_relay_before_request_transmit_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_before_request_transmit");
}
if (binlog_relay_after_read_event_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_after_read_event");
}
if (binlog_relay_after_queue_event_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_after_queue_event");
}
if (binlog_relay_after_reset_slave_call)
{
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:binlog_relay_after_reset_slave");
}
}
int binlog_relay_thread_start(Binlog_relay_IO_param *param)
{
binlog_relay_thread_start_call++;
return 0;
}
int binlog_relay_thread_stop(Binlog_relay_IO_param *param)
{
binlog_relay_thread_stop_call++;
return 0;
}
int binlog_relay_applier_start(Binlog_relay_IO_param *param)
{
binlog_relay_applier_start_call++;
return 0;
}
int binlog_relay_applier_stop(Binlog_relay_IO_param *param,
bool aborted)
{
binlog_relay_applier_stop_call++;
thread_aborted = aborted;
return 0;
}
int binlog_relay_before_request_transmit(Binlog_relay_IO_param *param,
uint32 flags)
{
binlog_relay_before_request_transmit_call++;
return 0;
}
int binlog_relay_after_read_event(Binlog_relay_IO_param *param,
const char *packet, unsigned long len,
const char **event_buf, unsigned long *event_len)
{
binlog_relay_after_read_event_call++;
return 0;
}
int binlog_relay_after_queue_event(Binlog_relay_IO_param *param,
const char *event_buf,
unsigned long event_len,
uint32 flags)
{
binlog_relay_after_queue_event_call++;
return 0;
}
int binlog_relay_after_reset_slave(Binlog_relay_IO_param *param)
{
binlog_relay_after_reset_slave_call++;
return 0;
}
Binlog_relay_IO_observer relay_io_observer = {
sizeof(Binlog_relay_IO_observer),
binlog_relay_thread_start,
binlog_relay_thread_stop,
binlog_relay_applier_start,
binlog_relay_applier_stop,
binlog_relay_before_request_transmit,
binlog_relay_after_read_event,
binlog_relay_after_queue_event,
binlog_relay_after_reset_slave,
};
/*
Validate plugin requirements on server code.
This function is mainly to ensure that any change on server code
will not break Group Replication requirements.
*/
int validate_plugin_server_requirements(Trans_param *param)
{
int success= 0;
/*
Instantiate a Gtid_log_event without a THD parameter.
*/
rpl_sid fake_sid;
fake_sid.parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
rpl_sidno fake_sidno= get_sidno_from_global_sid_map(fake_sid);
rpl_gno fake_gno= get_last_executed_gno(fake_sidno)+1;
Gtid gtid= { fake_sidno, fake_gno };
Gtid_specification gtid_spec= { GTID_GROUP, gtid };
Gtid_log_event *gle=
new Gtid_log_event(param->server_id, true, 0, 1, true, gtid_spec);
if (gle->is_valid())
success++;
else
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"replication_observers_example_plugin:validate_plugin_server_requirements:"
" failed to instantiate a Gtid_log_event");
delete gle;
/*
Instantiate a anonymous Gtid_log_event without a THD parameter.
*/
Gtid_specification anonymous_gtid_spec= { ANONYMOUS_GROUP, gtid };
gle=
new Gtid_log_event(param->server_id, true, 0, 1, true, anonymous_gtid_spec);
if (gle->is_valid())
success++;
else
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"replication_observers_example_plugin:validate_plugin_server_requirements:"
" failed to instantiate a anonymous Gtid_log_event");
delete gle;
/*
Instantiate a Transaction_context_log_event.
*/
Transaction_context_log_event *tcle= new Transaction_context_log_event(param->server_uuid,
true,
param->thread_id,
false);
if (tcle->is_valid())
{
Gtid_set *snapshot_version= tcle->get_snapshot_version();
size_t snapshot_version_len= snapshot_version->get_encoded_length();
uchar* snapshot_version_buf= (uchar *)my_malloc(PSI_NOT_INSTRUMENTED,
snapshot_version_len, MYF(0));
snapshot_version->encode(snapshot_version_buf);
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"snapshot version is '%s'",
snapshot_version_buf);
my_free(snapshot_version_buf);
success++;
}
else
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"replication_observers_example_plugin:validate_plugin_server_requirements:"
" failed to instantiate a Transaction_context_log_event");
delete tcle;
/*
Instantiate a View_Change_log_event.
*/
View_change_log_event *vcle= new View_change_log_event(const_cast<char*>("1421867646:1"));
if (vcle->is_valid())
{
success++;
}
else
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"replication_observers_example_plugin:validate_plugin_server_requirements:"
" failed to instantiate a View_change_log_event");
delete vcle;
/*
include/mysql/group_replication_priv.h exported functions.
*/
my_thread_attr_t *thread_attr= get_connection_attrib();
char *hostname, *uuid;
uint port;
unsigned int server_version;
st_server_ssl_variables server_ssl_variables=
{false,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};
get_server_parameters(&hostname, &port, &uuid, &server_version,
&server_ssl_variables);
Trans_context_info startup_pre_reqs;
get_server_startup_prerequirements(startup_pre_reqs, false);
//check the server is initialized by checking if the default channel exists
bool server_engine_ready= channel_is_active("", CHANNEL_NO_THD);
uchar *encoded_gtid_executed= NULL;
size_t length;
get_server_encoded_gtid_executed(&encoded_gtid_executed, &length);
#if !defined(DBUG_OFF)
char *encoded_gtid_executed_string=
encoded_gtid_set_to_string(encoded_gtid_executed, length);
#endif
if (thread_attr != NULL &&
hostname != NULL &&
uuid != NULL &&
port > 0 &&
startup_pre_reqs.gtid_mode == 3 &&
server_engine_ready &&
encoded_gtid_executed != NULL
#if !defined(DBUG_OFF)
&& encoded_gtid_executed_string != NULL
#endif
)
success++;
else
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"replication_observers_example_plugin:validate_plugin_server_requirements:"
" failed to invoke group_replication_priv.h exported functions");
#if !defined(DBUG_OFF)
my_free(encoded_gtid_executed_string);
#endif
my_free(encoded_gtid_executed);
/*
Log number of successful validations.
*/
my_plugin_log_message(&plugin_info_ptr,
MY_INFORMATION_LEVEL,
"\nreplication_observers_example_plugin:validate_plugin_server_requirements=%d",
success);
return 0;
}
int test_channel_service_interface_initialization()
{
int error= initialize_channel_service_interface();
DBUG_ASSERT(error);
return error;
}
int test_channel_service_interface()
{
//The initialization method should return OK
int error= initialize_channel_service_interface();
DBUG_ASSERT(!error);
//Test channel creation
char interface_channel[]= "example_channel";
Channel_creation_info info;
initialize_channel_creation_info(&info);
error= channel_create(interface_channel, &info);
DBUG_ASSERT(!error);
//Assert the channel exists
bool exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
//Check that a non existing channel is declared as such
char dummy_channel[]= "dummy_channel";
exists= channel_is_active(dummy_channel, CHANNEL_NO_THD);
DBUG_ASSERT(!exists);
//Test that we cannot create a empty named channel (the default channel)
char empty_interface_channel[]= "";
initialize_channel_creation_info(&info);
error= channel_create(empty_interface_channel, &info);
DBUG_ASSERT(error == RPL_CHANNEL_SERVICE_DEFAULT_CHANNEL_CREATION_ERROR);
//Start the applier thread (since it does not need an external server)
Channel_connection_info connection_info;
initialize_channel_connection_info(&connection_info);
error= channel_start(interface_channel,
&connection_info,
CHANNEL_APPLIER_THREAD,
true);
DBUG_ASSERT(!error);
//Assert that the applier thread is running
bool running= channel_is_active(interface_channel, CHANNEL_APPLIER_THREAD);
DBUG_ASSERT(running);
//Wait for execution of events (none in this case so it should return OK)
error= channel_wait_until_apply_queue_applied(interface_channel, 100000);
DBUG_ASSERT(!error);
//Get the last delivered gno (should be 0)
rpl_sid fake_sid;
fake_sid.parse("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa");
rpl_sidno fake_sidno= get_sidno_from_global_sid_map(fake_sid);
rpl_gno gno= channel_get_last_delivered_gno(interface_channel, fake_sidno);
DBUG_ASSERT(gno == 0);
//Check that for non existing channels it returns the corresponding error
gno= channel_get_last_delivered_gno(dummy_channel, fake_sidno);
DBUG_ASSERT(gno == RPL_CHANNEL_SERVICE_CHANNEL_DOES_NOT_EXISTS_ERROR);
//Extract the applier id
long unsigned int * applier_id= NULL;
channel_get_thread_id(interface_channel,
CHANNEL_APPLIER_THREAD,
&applier_id);
DBUG_ASSERT(*applier_id > 0);
my_free(applier_id);
DBUG_ASSERT(binlog_relay_applier_stop_call==0);
//Stop the channel applier
error= channel_stop(interface_channel,
3,
10000);
DBUG_ASSERT(!error);
//Repeat the stop to check it goes ok
error= channel_stop(interface_channel,
3,
10000);
DBUG_ASSERT(!error);
DBUG_ASSERT(binlog_relay_applier_stop_call>0);
DBUG_ASSERT(!thread_aborted);
//Assert that the applier thread is not running
running= channel_is_active(interface_channel, CHANNEL_APPLIER_THREAD);
DBUG_ASSERT(!running);
//Purge the channel and assert all is OK
error= channel_purge_queue(interface_channel, true);
DBUG_ASSERT(!error);
//Assert the channel is not there.
exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(!exists);
//Check that a queue in an empty channel will fail.
char empty_event[]= "";
error= channel_queue_packet(dummy_channel, empty_event, 0);
DBUG_ASSERT(error);
//Test a multi thread channel
info.channel_mts_parallel_type= CHANNEL_MTS_PARALLEL_TYPE_LOGICAL_CLOCK;
info.channel_mts_parallel_workers= 3;
error= channel_create(interface_channel, &info);
DBUG_ASSERT(!error);
//Assert the channel exists
exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
error= channel_start(interface_channel,
&connection_info,
CHANNEL_APPLIER_THREAD,
true);
DBUG_ASSERT(!error);
//Extract the applier ids
applier_id= NULL;
int num_appliers= channel_get_thread_id(interface_channel,
CHANNEL_APPLIER_THREAD,
&applier_id);
DBUG_ASSERT(num_appliers == 4);
unsigned long thread_id= 0;
for (int i = 0; i < num_appliers; i++)
{
thread_id= applier_id[i];
DBUG_ASSERT(thread_id > 0);
}
my_free(applier_id);
//Stop the channel applier
error= channel_stop(interface_channel,
3,
10000);
DBUG_ASSERT(!error);
//Purge the channel and assert all is OK
error= channel_purge_queue(interface_channel, true);
DBUG_ASSERT(!error);
//Assert the channel is not there.
exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(!exists);
return (error && exists && running && gno && num_appliers && thread_id);
}
int test_channel_service_interface_io_thread()
{
//The initialization method should return OK
int error= initialize_channel_service_interface();
DBUG_ASSERT(!error);
char interface_channel[]= "example_channel";
//Assert the channel exists
bool exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
//Assert that the receiver is running
bool running= channel_is_active(interface_channel, CHANNEL_RECEIVER_THREAD);
DBUG_ASSERT(running);
//Extract the receiver id
long unsigned int * thread_id= NULL;
int num_threads= channel_get_thread_id(interface_channel,
CHANNEL_RECEIVER_THREAD,
&thread_id);
DBUG_ASSERT(num_threads == 1);
DBUG_ASSERT(*thread_id > 0);
my_free(thread_id);
//Get the I/O thread retrieved GTID set
char *retrieved_gtid_set;
error= channel_get_retrieved_gtid_set(interface_channel,
&retrieved_gtid_set);
DBUG_ASSERT(!error);
DBUG_ASSERT(strlen(retrieved_gtid_set) > 0);
my_free(retrieved_gtid_set);
//Check that the applier thread is waiting for events to be queued.
int is_waiting= channel_is_applier_waiting(interface_channel);
DBUG_ASSERT(is_waiting == 1);
//Stop the channel
error= channel_stop(interface_channel,
3,
10000);
DBUG_ASSERT(!error);
//Assert that the receiver thread is not running
running= channel_is_active(interface_channel, CHANNEL_RECEIVER_THREAD);
DBUG_ASSERT(!running);
return (error && exists && running && num_threads && is_waiting);
}
bool test_channel_service_interface_is_io_stopping()
{
//The initialization method should return OK
int error= initialize_channel_service_interface();
DBUG_ASSERT(!error);
//Initialize the channel to be used with the channel service interface
char interface_channel[]= "example_channel";
Channel_creation_info info;
initialize_channel_creation_info(&info);
error= channel_create(interface_channel, &info);
DBUG_ASSERT(!error);
//Reset the I/O stop counter
binlog_relay_thread_stop_call= 0;
//Unregister the thread stop hook
error= unregister_binlog_relay_io_observer(&relay_io_observer,
(void *)plugin_info_ptr);
DBUG_ASSERT(!error);
//Start the I/O thread
Channel_connection_info connection_info;
initialize_channel_connection_info(&connection_info);
error= channel_start(interface_channel,
&connection_info,
CHANNEL_RECEIVER_THREAD,
true);
DBUG_ASSERT(!error);
//Assert the channel exists
bool exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
//Wait until I/O thread reached the error and is going to stop
DBUG_EXECUTE_IF("pause_after_io_thread_stop_hook",
{
const char act[]= "now "
"WAIT_FOR reached_stopping_io_thread";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
//Register the thread stop hook again
error= register_binlog_relay_io_observer(&relay_io_observer,
(void *)plugin_info_ptr);
DBUG_ASSERT(!error);
//Assert that the receiver is stopping
bool io_stopping= channel_is_stopping(interface_channel, CHANNEL_RECEIVER_THREAD);
DBUG_ASSERT(io_stopping);
//Assert that the receiver is running
bool io_running= channel_is_active(interface_channel, CHANNEL_RECEIVER_THREAD);
DBUG_ASSERT(io_running);
//Signal to make the MTR test case to start monitoring the I/O thread
DBUG_EXECUTE_IF("pause_after_io_thread_stop_hook",
{
const char act[]= "now "
"SIGNAL reached_io_thread_started";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
DBUG_EXECUTE_IF("pause_after_io_thread_stop_hook",
{
const char act[]= "now SIGNAL continue_to_stop_io_thread";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
// The plug-in has missed the stop
DBUG_ASSERT(binlog_relay_thread_stop_call==0);
return (error | exists | io_stopping | io_running);
}
bool test_channel_service_interface_is_sql_stopping()
{
//The initialization method should return OK
int error= initialize_channel_service_interface();
DBUG_ASSERT(!error);
//Initialize the channel to be used with the channel service interface
char interface_channel[]= "example_channel";
Channel_creation_info info;
initialize_channel_creation_info(&info);
error= channel_create(interface_channel, &info);
DBUG_ASSERT(!error);
//Assert the channel exists
bool exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
//Unregister the thread stop hook
error= unregister_binlog_relay_io_observer(&relay_io_observer,
(void *)plugin_info_ptr);
DBUG_ASSERT(!error);
//Start the I/O thread
Channel_connection_info connection_info;
initialize_channel_connection_info(&connection_info);
error= channel_start(interface_channel,
&connection_info,
CHANNEL_RECEIVER_THREAD,
true);
DBUG_ASSERT(!error);
//Start the SQL thread
error= channel_start(interface_channel,
&connection_info,
CHANNEL_APPLIER_THREAD,
true);
DBUG_ASSERT(!error);
//Wait until SQL thread reached the error and is going to stop
DBUG_EXECUTE_IF("pause_after_sql_thread_stop_hook",
{
const char act[]= "now "
"WAIT_FOR reached_stopping_sql_thread";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
//Register the thread stop hook again
error= register_binlog_relay_io_observer(&relay_io_observer,
(void *)plugin_info_ptr);
DBUG_ASSERT(!error);
//Assert that the applier is stopping
bool sql_stopping= channel_is_stopping(interface_channel, CHANNEL_APPLIER_THREAD);
DBUG_ASSERT(sql_stopping);
//Assert that the applier is running
bool sql_running= channel_is_active(interface_channel, CHANNEL_APPLIER_THREAD);
DBUG_ASSERT(sql_running);
//Signal to make the MTR test case to start monitoring the SQL thread
DBUG_EXECUTE_IF("pause_after_sql_thread_stop_hook",
{
const char act[]= "now "
"SIGNAL reached_sql_thread_started";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
DBUG_EXECUTE_IF("pause_after_sql_thread_stop_hook",
{
const char act[]= "now SIGNAL continue_to_stop_sql_thread";
DBUG_ASSERT(!debug_sync_set_action(current_thd,
STRING_WITH_LEN(act)));
};);
//The plug-in has missed the stop
DBUG_ASSERT(binlog_relay_applier_stop_call==0);
return (error | exists | sql_stopping | sql_running);
}
bool test_channel_service_interface_relay_log_renamed()
{
//The initialization method should return OK
int error= initialize_channel_service_interface();
DBUG_ASSERT(!error);
//Initialize the channel to be used with the channel service interface
char interface_channel[]= "example_channel";
char channel_hostname[]= "127.0.0.1";
char channel_user[]= "root";
Channel_creation_info info;
initialize_channel_creation_info(&info);
info.preserve_relay_logs= true;
info.hostname= channel_hostname;
info.user= channel_user;
error= channel_create(interface_channel, &info);
DBUG_ASSERT(!error);
//Assert the channel exists
bool exists= channel_is_active(interface_channel, CHANNEL_NO_THD);
DBUG_ASSERT(exists);
//Start the SQL thread
Channel_connection_info connection_info;
initialize_channel_connection_info(&connection_info);
error= channel_start(interface_channel,
&connection_info,
CHANNEL_APPLIER_THREAD,
true);
if (error)
{
THD *thd= current_thd;
thd->clear_error();
#if !defined(DBUG_OFF)
const char act[]= "now SIGNAL reached_sql_thread_startup_failed";
DBUG_ASSERT(!debug_sync_set_action(thd, STRING_WITH_LEN(act)));
#endif
}
else
{
#if !defined(DBUG_OFF)
const char act[]= "now SIGNAL reached_sql_thread_started";
DBUG_ASSERT(!debug_sync_set_action(current_thd, STRING_WITH_LEN(act)));
#endif
}
return (error | exists);
}
/*
Initialize the Replication Observer example at server start or plugin
installation.
SYNOPSIS
replication_observers_example_plugin_init()
DESCRIPTION
Registers Server state observer and Transaction Observer
RETURN VALUE
0 success
1 failure (cannot happen)
*/
static int replication_observers_example_plugin_init(MYSQL_PLUGIN plugin_info)
{
plugin_info_ptr= plugin_info;
DBUG_ENTER("replication_observers_example_plugin_init");
if(register_server_state_observer(&server_state_observer, (void *)plugin_info_ptr))
{
my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL, "Failure in registering the server state observers");
DBUG_RETURN(1);
}
if (register_trans_observer(&trans_observer, (void *)plugin_info_ptr))
{
my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL,"Failure in registering the transactions state observers");
DBUG_RETURN(1);
}
if (register_binlog_relay_io_observer(&relay_io_observer, (void *)plugin_info_ptr))
{
my_plugin_log_message(&plugin_info_ptr, MY_ERROR_LEVEL,"Failure in registering the relay io observer");
DBUG_RETURN(1);
}
my_plugin_log_message(&plugin_info_ptr, MY_INFORMATION_LEVEL,"replication_observers_example_plugin: init finished");
DBUG_RETURN(0);
}
/*
Terminate the Replication Observer example at server shutdown or
plugin deinstallation.
SYNOPSIS
replication_observers_example_plugin_deinit()
DESCRIPTION
Unregisters Server state observer and Transaction Observer
RETURN VALUE
0 success
1 failure (cannot happen)
*/
static int replication_observers_example_plugin_deinit(void *p)
{
DBUG_ENTER("replication_observers_example_plugin_deinit");
dump_server_state_calls();
dump_transaction_calls();
dump_binlog_relay_calls();
if (unregister_server_state_observer(&server_state_observer, p))
{
my_plugin_log_message(&p, MY_ERROR_LEVEL,"Failure in unregistering the server state observers");
DBUG_RETURN(1);
}
if (unregister_trans_observer(&trans_observer, p))
{
my_plugin_log_message(&p, MY_ERROR_LEVEL,"Failure in unregistering the transactions state observers");
DBUG_RETURN(1);
}
if (unregister_binlog_relay_io_observer(&relay_io_observer, p))
{
my_plugin_log_message(&p, MY_ERROR_LEVEL,"Failure in unregistering the relay io observer");
DBUG_RETURN(1);
}
my_plugin_log_message(&p, MY_INFORMATION_LEVEL,"replication_observers_example_plugin: deinit finished");
DBUG_RETURN(0);
}
/*
Plugin library descriptor
*/
struct Mysql_replication replication_observers_example_plugin=
{ MYSQL_REPLICATION_INTERFACE_VERSION };
mysql_declare_plugin(replication_observers_example)
{
MYSQL_REPLICATION_PLUGIN,
&replication_observers_example_plugin,
"replication_observers_example",
"ORACLE",
"Replication observer infrastructure example.",
PLUGIN_LICENSE_GPL,
replication_observers_example_plugin_init, /* Plugin Init */
replication_observers_example_plugin_deinit, /* Plugin Deinit */
0x0100 /* 1.0 */,
NULL, /* status variables */
NULL, /* system variables */
NULL, /* config options */
0, /* flags */
}
mysql_declare_plugin_end;