/* 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 #include #include #include 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("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;