mirror of
https://github.com/MariaDB/server.git
synced 2025-07-29 05:21:33 +03:00
debug_sync is now a service, available to dynamically loaded plugins.
new make target - abi_update libservices/HOWTO: remove references to Makefile.am small tweaks
This commit is contained in:
@ -55,6 +55,17 @@ IF(CMAKE_COMPILER_IS_GNUCC AND RUN_ABI_CHECK)
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
ADD_CUSTOM_TARGET(abi_update
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCOMPILER=${COMPILER}
|
||||
-DABI_UPDATE=1
|
||||
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-DBINARY_DIR=${CMAKE_BINARY_DIR}
|
||||
"-DABI_HEADERS=${API_PREPROCESSOR_HEADER}"
|
||||
-P ${CMAKE_SOURCE_DIR}/cmake/do_abi_check.cmake
|
||||
VERBATIM
|
||||
)
|
||||
|
||||
ADD_CUSTOM_TARGET(abi_check_all
|
||||
COMMAND ${CMAKE_COMMAND}
|
||||
-DCOMPILER=${COMPILER}
|
||||
|
@ -75,8 +75,12 @@ FOREACH(file ${ABI_HEADERS})
|
||||
EXECUTE_PROCESS(
|
||||
COMMAND diff -w ${file}.pp ${abi_check_out} RESULT_VARIABLE result)
|
||||
IF(NOT ${result} EQUAL 0)
|
||||
MESSAGE(FATAL_ERROR
|
||||
"ABI check found difference between ${file}.pp and ${abi_check_out}")
|
||||
IF(ABI_UPDATE)
|
||||
EXECUTE_PROCESS(COMMAND mv -v ${abi_check_out} ${file}.pp)
|
||||
ELSE(ABI_UPDATE)
|
||||
MESSAGE(FATAL_ERROR
|
||||
"ABI check found difference between ${file}.pp and ${abi_check_out}")
|
||||
ENDIF(ABI_UPDATE)
|
||||
ENDIF()
|
||||
FILE(REMOVE ${abi_check_out})
|
||||
ENDFOREACH()
|
||||
|
@ -157,16 +157,6 @@ extern char *my_strndup(const char *from, size_t length, myf MyFlags);
|
||||
|
||||
extern int sf_leaking_memory; /* set to 1 to disable memleak detection */
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
extern void (*debug_sync_C_callback_ptr)(const char *, size_t);
|
||||
#define DEBUG_SYNC_C(_sync_point_name_) do { \
|
||||
if (debug_sync_C_callback_ptr != NULL) \
|
||||
(*debug_sync_C_callback_ptr)(STRING_WITH_LEN(_sync_point_name_)); } \
|
||||
while(0)
|
||||
#else
|
||||
#define DEBUG_SYNC_C(_sync_point_name_)
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
#ifdef HAVE_LARGE_PAGES
|
||||
extern uint my_get_large_page_size(void);
|
||||
extern uchar * my_large_malloc(size_t size, myf my_flags);
|
||||
|
@ -72,7 +72,7 @@ typedef struct st_mysql_xid MYSQL_XID;
|
||||
#define MYSQL_PLUGIN_INTERFACE_VERSION 0x0103
|
||||
|
||||
/* MariaDB plugin interface version */
|
||||
#define MARIA_PLUGIN_INTERFACE_VERSION 0x0102
|
||||
#define MARIA_PLUGIN_INTERFACE_VERSION 0x0103
|
||||
|
||||
/*
|
||||
The allowable types of plugins
|
||||
|
@ -80,6 +80,8 @@ void thd_progress_next_stage(void* thd);
|
||||
void thd_progress_end(void* thd);
|
||||
const char *set_thd_proc_info(void*, const char * info, const char *func,
|
||||
const char *file, unsigned int line);
|
||||
#include <mysql/service_debug_sync.h>
|
||||
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
|
||||
struct st_mysql_xid {
|
||||
long formatID;
|
||||
long gtrid_length;
|
||||
|
@ -80,6 +80,8 @@ void thd_progress_next_stage(void* thd);
|
||||
void thd_progress_end(void* thd);
|
||||
const char *set_thd_proc_info(void*, const char * info, const char *func,
|
||||
const char *file, unsigned int line);
|
||||
#include <mysql/service_debug_sync.h>
|
||||
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
|
||||
struct st_mysql_xid {
|
||||
long formatID;
|
||||
long gtrid_length;
|
||||
|
@ -80,6 +80,8 @@ void thd_progress_next_stage(void* thd);
|
||||
void thd_progress_end(void* thd);
|
||||
const char *set_thd_proc_info(void*, const char * info, const char *func,
|
||||
const char *file, unsigned int line);
|
||||
#include <mysql/service_debug_sync.h>
|
||||
extern void (*debug_sync_C_callback_ptr)(void*, const char *, size_t);
|
||||
struct st_mysql_xid {
|
||||
long formatID;
|
||||
long gtrid_length;
|
||||
|
354
include/mysql/service_debug_sync.h
Normal file
354
include/mysql/service_debug_sync.h
Normal file
@ -0,0 +1,354 @@
|
||||
#ifndef MYSQL_SERVICE_DEBUG_SYNC_INCLUDED
|
||||
/* Copyright (c) 2009, 2010, Oracle and/or its affiliates.
|
||||
Copyright (c) 2012, Monty Program Ab
|
||||
|
||||
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 */
|
||||
|
||||
/**
|
||||
@file
|
||||
== Debug Sync Facility ==
|
||||
|
||||
The Debug Sync Facility allows placement of synchronization points in
|
||||
the server code by using the DEBUG_SYNC macro:
|
||||
|
||||
open_tables(...)
|
||||
|
||||
DEBUG_SYNC(thd, "after_open_tables");
|
||||
|
||||
lock_tables(...)
|
||||
|
||||
When activated, a sync point can
|
||||
|
||||
- Emit a signal and/or
|
||||
- Wait for a signal
|
||||
|
||||
Nomenclature:
|
||||
|
||||
- signal: A value of a global variable that persists
|
||||
until overwritten by a new signal. The global
|
||||
variable can also be seen as a "signal post"
|
||||
or "flag mast". Then the signal is what is
|
||||
attached to the "signal post" or "flag mast".
|
||||
|
||||
- emit a signal: Assign the value (the signal) to the global
|
||||
variable ("set a flag") and broadcast a
|
||||
global condition to wake those waiting for
|
||||
a signal.
|
||||
|
||||
- wait for a signal: Loop over waiting for the global condition until
|
||||
the global value matches the wait-for signal.
|
||||
|
||||
By default, all sync points are inactive. They do nothing (except to
|
||||
burn a couple of CPU cycles for checking if they are active).
|
||||
|
||||
A sync point becomes active when an action is requested for it.
|
||||
To do so, put a line like this in the test case file:
|
||||
|
||||
SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
|
||||
|
||||
This activates the sync point 'after_open_tables'. It requests it to
|
||||
emit the signal 'opened' and wait for another thread to emit the signal
|
||||
'flushed' when the thread's execution runs through the sync point.
|
||||
|
||||
For every sync point there can be one action per thread only. Every
|
||||
thread can request multiple actions, but only one per sync point. In
|
||||
other words, a thread can activate multiple sync points.
|
||||
|
||||
Here is an example how to activate and use the sync points:
|
||||
|
||||
--connection conn1
|
||||
SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
|
||||
send INSERT INTO t1 VALUES(1);
|
||||
--connection conn2
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||
SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed';
|
||||
FLUSH TABLE t1;
|
||||
|
||||
When conn1 runs through the INSERT statement, it hits the sync point
|
||||
'after_open_tables'. It notices that it is active and executes its
|
||||
action. It emits the signal 'opened' and waits for another thread to
|
||||
emit the signal 'flushed'.
|
||||
|
||||
conn2 waits immediately at the special sync point 'now' for another
|
||||
thread to emit the 'opened' signal.
|
||||
|
||||
A signal remains in effect until it is overwritten. If conn1 signals
|
||||
'opened' before conn2 reaches 'now', conn2 will still find the 'opened'
|
||||
signal. It does not wait in this case.
|
||||
|
||||
When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets
|
||||
conn1 awake.
|
||||
|
||||
Normally the activation of a sync point is cleared when it has been
|
||||
executed. Sometimes it is necessary to keep the sync point active for
|
||||
another execution. You can add an execute count to the action:
|
||||
|
||||
SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3';
|
||||
|
||||
This sets the signal point's activation counter to 3. Each execution
|
||||
decrements the counter. After the third execution the sync point
|
||||
becomes inactive.
|
||||
|
||||
One of the primary goals of this facility is to eliminate sleeps from
|
||||
the test suite. In most cases it should be possible to rewrite test
|
||||
cases so that they do not need to sleep. (But this facility cannot
|
||||
synchronize multiple processes.) However, to support test development,
|
||||
and as a last resort, sync point waiting times out. There is a default
|
||||
timeout, but it can be overridden:
|
||||
|
||||
SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2';
|
||||
|
||||
TIMEOUT 0 is special: If the signal is not present, the wait times out
|
||||
immediately.
|
||||
|
||||
When a wait timed out (even on TIMEOUT 0), a warning is generated so
|
||||
that it shows up in the test result.
|
||||
|
||||
You can throw an error message and kill the query when a synchronization
|
||||
point is hit a certain number of times:
|
||||
|
||||
SET DEBUG_SYNC= 'name HIT_LIMIT 3';
|
||||
|
||||
Or combine it with signal and/or wait:
|
||||
|
||||
SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3';
|
||||
|
||||
Here the first two hits emit the signal, the third hit returns the error
|
||||
message and kills the query.
|
||||
|
||||
For cases where you are not sure that an action is taken and thus
|
||||
cleared in any case, you can force to clear (deactivate) a sync point:
|
||||
|
||||
SET DEBUG_SYNC= 'name CLEAR';
|
||||
|
||||
If you want to clear all actions and clear the global signal, use:
|
||||
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
|
||||
This is the only way to reset the global signal to an empty string.
|
||||
|
||||
For testing of the facility itself you can execute a sync point just
|
||||
as if it had been hit:
|
||||
|
||||
SET DEBUG_SYNC= 'name TEST';
|
||||
|
||||
|
||||
=== Formal Syntax ===
|
||||
|
||||
The string to "assign" to the DEBUG_SYNC variable can contain:
|
||||
|
||||
{RESET |
|
||||
<sync point name> TEST |
|
||||
<sync point name> CLEAR |
|
||||
<sync point name> {{SIGNAL <signal name> |
|
||||
WAIT_FOR <signal name> [TIMEOUT <seconds>]}
|
||||
[EXECUTE <count>] &| HIT_LIMIT <count>}
|
||||
|
||||
Here '&|' means 'and/or'. This means that one of the sections
|
||||
separated by '&|' must be present or both of them.
|
||||
|
||||
|
||||
=== Activation/Deactivation ===
|
||||
|
||||
The facility is an optional part of the MySQL server.
|
||||
It is enabled in a debug server by default.
|
||||
|
||||
./configure --enable-debug-sync
|
||||
|
||||
The Debug Sync Facility, when compiled in, is disabled by default. It
|
||||
can be enabled by a mysqld command line option:
|
||||
|
||||
--debug-sync-timeout[=default_wait_timeout_value_in_seconds]
|
||||
|
||||
'default_wait_timeout_value_in_seconds' is the default timeout for the
|
||||
WAIT_FOR action. If set to zero, the facility stays disabled.
|
||||
|
||||
The facility is enabled by default in the test suite, but can be
|
||||
disabled with:
|
||||
|
||||
mysql-test-run.pl ... --debug-sync-timeout=0 ...
|
||||
|
||||
Likewise the default wait timeout can be set:
|
||||
|
||||
mysql-test-run.pl ... --debug-sync-timeout=10 ...
|
||||
|
||||
The command line option influences the readable value of the system
|
||||
variable 'debug_sync'.
|
||||
|
||||
* If the facility is not compiled in, the system variable does not exist.
|
||||
|
||||
* If --debug-sync-timeout=0 the value of the variable reads as "OFF".
|
||||
|
||||
* Otherwise the value reads as "ON - current signal: " followed by the
|
||||
current signal string, which can be empty.
|
||||
|
||||
The readable variable value is the same, regardless if read as global
|
||||
or session value.
|
||||
|
||||
Setting the 'debug-sync' system variable requires 'SUPER' privilege.
|
||||
You can never read back the string that you assigned to the variable,
|
||||
unless you assign the value that the variable does already have. But
|
||||
that would give a parse error. A syntactically correct string is
|
||||
parsed into a debug sync action and stored apart from the variable value.
|
||||
|
||||
|
||||
=== Implementation ===
|
||||
|
||||
Pseudo code for a sync point:
|
||||
|
||||
#define DEBUG_SYNC(thd, sync_point_name)
|
||||
if (unlikely(opt_debug_sync_timeout))
|
||||
debug_sync(thd, STRING_WITH_LEN(sync_point_name))
|
||||
|
||||
The sync point performs a binary search in a sorted array of actions
|
||||
for this thread.
|
||||
|
||||
The SET DEBUG_SYNC statement adds a requested action to the array or
|
||||
overwrites an existing action for the same sync point. When it adds a
|
||||
new action, the array is sorted again.
|
||||
|
||||
|
||||
=== A typical synchronization pattern ===
|
||||
|
||||
There are quite a few places in MySQL, where we use a synchronization
|
||||
pattern like this:
|
||||
|
||||
mysql_mutex_lock(&mutex);
|
||||
thd->enter_cond(&condition_variable, &mutex, new_message);
|
||||
#if defined(ENABLE_DEBUG_SYNC)
|
||||
if (!thd->killed && !end_of_wait_condition)
|
||||
DEBUG_SYNC(thd, "sync_point_name");
|
||||
#endif
|
||||
while (!thd->killed && !end_of_wait_condition)
|
||||
mysql_cond_wait(&condition_variable, &mutex);
|
||||
thd->exit_cond(old_message);
|
||||
|
||||
Here some explanations:
|
||||
|
||||
thd->enter_cond() is used to register the condition variable and the
|
||||
mutex in thd->mysys_var. This is done to allow the thread to be
|
||||
interrupted (killed) from its sleep. Another thread can find the
|
||||
condition variable to signal and mutex to use for synchronization in
|
||||
this thread's THD::mysys_var.
|
||||
|
||||
thd->enter_cond() requires the mutex to be acquired in advance.
|
||||
|
||||
thd->exit_cond() unregisters the condition variable and mutex and
|
||||
releases the mutex.
|
||||
|
||||
If you want to have a Debug Sync point with the wait, please place it
|
||||
behind enter_cond(). Only then you can safely decide, if the wait will
|
||||
be taken. Also you will have THD::proc_info correct when the sync
|
||||
point emits a signal. DEBUG_SYNC sets its own proc_info, but restores
|
||||
the previous one before releasing its internal mutex. As soon as
|
||||
another thread sees the signal, it does also see the proc_info from
|
||||
before entering the sync point. In this case it will be "new_message",
|
||||
which is associated with the wait that is to be synchronized.
|
||||
|
||||
In the example above, the wait condition is repeated before the sync
|
||||
point. This is done to skip the sync point, if no wait takes place.
|
||||
The sync point is before the loop (not inside the loop) to have it hit
|
||||
once only. It is possible that the condition variable is signaled
|
||||
multiple times without the wait condition to be true.
|
||||
|
||||
A bit off-topic: At some places, the loop is taken around the whole
|
||||
synchronization pattern:
|
||||
|
||||
while (!thd->killed && !end_of_wait_condition)
|
||||
{
|
||||
mysql_mutex_lock(&mutex);
|
||||
thd->enter_cond(&condition_variable, &mutex, new_message);
|
||||
if (!thd->killed [&& !end_of_wait_condition])
|
||||
{
|
||||
[DEBUG_SYNC(thd, "sync_point_name");]
|
||||
mysql_cond_wait(&condition_variable, &mutex);
|
||||
}
|
||||
thd->exit_cond(old_message);
|
||||
}
|
||||
|
||||
Note that it is important to repeat the test for thd->killed after
|
||||
enter_cond(). Otherwise the killing thread may kill this thread after
|
||||
it tested thd->killed in the loop condition and before it registered
|
||||
the condition variable and mutex in enter_cond(). In this case, the
|
||||
killing thread does not know that this thread is going to wait on a
|
||||
condition variable. It would just set THD::killed. But if we would not
|
||||
test it again, we would go asleep though we are killed. If the killing
|
||||
thread would kill us when we are after the second test, but still
|
||||
before sleeping, we hold the mutex, which is registered in mysys_var.
|
||||
The killing thread would try to acquire the mutex before signaling
|
||||
the condition variable. Since the mutex is only released implicitly in
|
||||
mysql_cond_wait(), the signaling happens at the right place. We
|
||||
have a safe synchronization.
|
||||
|
||||
=== Co-work with the DBUG facility ===
|
||||
|
||||
When running the MySQL test suite with the --debug-dbug command line
|
||||
option, the Debug Sync Facility writes trace messages to the DBUG
|
||||
trace. The following shell commands proved very useful in extracting
|
||||
relevant information:
|
||||
|
||||
egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace
|
||||
|
||||
It shows all executed SQL statements and all actions executed by
|
||||
synchronization points.
|
||||
|
||||
Sometimes it is also useful to see, which synchronization points have
|
||||
been run through (hit) with or without executing actions. Then add
|
||||
"|debug_sync_point:" to the egrep pattern.
|
||||
|
||||
=== Further reading ===
|
||||
|
||||
For a discussion of other methods to synchronize threads see
|
||||
http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization
|
||||
|
||||
For complete syntax tests, functional tests, and examples see the test
|
||||
case debug_sync.test.
|
||||
|
||||
See also http://forge.mysql.com/worklog/task.php?id=4259
|
||||
*/
|
||||
|
||||
#ifndef MYSQL_ABI_CHECK
|
||||
#include <stdlib.h>
|
||||
#endif
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||
extern void (*debug_sync_service)(MYSQL_THD, const char *, size_t);
|
||||
#else
|
||||
#define debug_sync_service debug_sync_C_callback_ptr
|
||||
extern void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t);
|
||||
#endif
|
||||
|
||||
#ifdef ENABLED_DEBUG_SYNC
|
||||
#define DEBUG_SYNC(thd, name) \
|
||||
do { \
|
||||
if (debug_sync_service) \
|
||||
debug_sync_service(thd, name, sizeof(name)-1); \
|
||||
} while(0)
|
||||
#else
|
||||
#define DEBUG_SYNC(thd,name) do { } while(0)
|
||||
#endif
|
||||
|
||||
/* compatibility macro */
|
||||
#define DEBUG_SYNC_C(name) DEBUG_SYNC(NULL, name)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#define MYSQL_SERVICE_DEBUG_SYNC_INCLUDED
|
||||
#endif
|
@ -23,7 +23,7 @@ extern "C" {
|
||||
#include <mysql/service_thd_wait.h>
|
||||
#include <mysql/service_thread_scheduler.h>
|
||||
#include <mysql/service_progress_report.h>
|
||||
|
||||
#include <mysql/service_debug_sync.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
@ -24,3 +24,4 @@
|
||||
#define VERSION_thd_wait 0x0100
|
||||
#define VERSION_my_thread_scheduler 0x0100
|
||||
#define VERSION_progress_report 0x0100
|
||||
#define VERSION_debug_sync 0x1000
|
||||
|
@ -20,7 +20,8 @@ SET(MYSQLSERVICES_SOURCES
|
||||
thd_alloc_service.c
|
||||
thd_wait_service.c
|
||||
my_thread_scheduler_service.c
|
||||
progress_report_service.c)
|
||||
progress_report_service.c
|
||||
debug_sync_service.c)
|
||||
|
||||
ADD_CONVENIENCE_LIBRARY(mysqlservices ${MYSQLSERVICES_SOURCES})
|
||||
INSTALL(TARGETS mysqlservices DESTINATION ${INSTALL_LIBDIR} COMPONENT Development)
|
||||
|
@ -34,19 +34,19 @@ into a service "foo" you need to
|
||||
#endif
|
||||
|
||||
extern struct foo_service_st {
|
||||
int (*foo_func1_type)(...); /* fix the prototype as appropriate */
|
||||
void (*foo_func2_type)(...); /* fix the prototype as appropriate */
|
||||
int (*foo_func1_ptr)(...); /* fix the prototype as appropriate */
|
||||
void (*foo_func2_ptr)(...); /* fix the prototype as appropriate */
|
||||
} *foo_service;
|
||||
|
||||
#ifdef MYSQL_DYNAMIC_PLUGIN
|
||||
|
||||
#define foo_func1(...) foo_service->foo_func1_type(...)
|
||||
#define foo_func2(...) foo_service->foo_func2_type(...)
|
||||
#define foo_func1(...) foo_service->foo_func1_ptr(...)
|
||||
#define foo_func2(...) foo_service->foo_func2_ptr(...)
|
||||
|
||||
#else
|
||||
|
||||
int foo_func1_type(...); /* fix the prototype as appropriate */
|
||||
void foo_func2_type(...); /* fix the prototype as appropriate */
|
||||
int foo_func1(...); /* fix the prototype as appropriate */
|
||||
void foo_func2(...); /* fix the prototype as appropriate */
|
||||
|
||||
#endif
|
||||
|
||||
@ -64,27 +64,26 @@ include them in it, e.g. if you use size_t - #include <stdlib.h>
|
||||
it should also declare all the accompanying data structures, as necessary
|
||||
(e.g. thd_alloc_service declares MYSQL_LEX_STRING).
|
||||
|
||||
3. add the new file to include/Makefile.am (pkginclude_HEADERS)
|
||||
4. add the new file to include/mysql/services.h
|
||||
5. increase the minor plugin ABI version in include/mysql/plugin.h
|
||||
(MYSQL_PLUGIN_INTERFACE_VERSION = MYSQL_PLUGIN_INTERFACE_VERSION+1)
|
||||
6. add the version of your service to include/service_versions.h:
|
||||
3. add the new file to include/mysql/services.h
|
||||
4. increase the minor plugin ABI version in include/mysql/plugin.h
|
||||
(MARIA_PLUGIN_INTERFACE_VERSION = MARIA_PLUGIN_INTERFACE_VERSION+1)
|
||||
5. add the version of your service to include/service_versions.h:
|
||||
==================================================================
|
||||
#define VERSION_foo 0x0100
|
||||
==================================================================
|
||||
|
||||
7. create a new file libservices/foo_service.h using the following template:
|
||||
6. create a new file libservices/foo_service.h using the following template:
|
||||
==================================================================
|
||||
/* GPL header */
|
||||
#include <service_versions.h>
|
||||
SERVICE_VERSION *foo_service= (void*)VERSION_foo;
|
||||
==================================================================
|
||||
|
||||
8. add the new file to libservices/CMakeLists.txt (MYSQLSERVICES_SOURCES)
|
||||
9. add the new file to libservices/Makefile.am (libmysqlservices_a_SOURCES)
|
||||
10. and finally, register your service for dynamic linking in
|
||||
sql/sql_plugin_services.h
|
||||
10.1 fill in the service structure:
|
||||
7. add the new file to libservices/CMakeLists.txt (MYSQLSERVICES_SOURCES)
|
||||
8. Add all new files to repository (bzr add)
|
||||
9. and finally, register your service for dynamic linking in
|
||||
sql/sql_plugin_services.h as follows:
|
||||
9.1 fill in the service structure:
|
||||
==================================================================
|
||||
static struct foo_service_st foo_handler = {
|
||||
foo_func1,
|
||||
@ -92,7 +91,7 @@ it should also declare all the accompanying data structures, as necessary
|
||||
}
|
||||
==================================================================
|
||||
|
||||
10.2 and add it to the list of services
|
||||
9.2 and add it to the list of services
|
||||
|
||||
==================================================================
|
||||
{ "foo_service", VERSION_foo, &foo_handler }
|
||||
|
18
libservices/debug_sync_service.c
Normal file
18
libservices/debug_sync_service.c
Normal file
@ -0,0 +1,18 @@
|
||||
/* Copyright (c) 2012, Monty Program Ab
|
||||
|
||||
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
|
||||
*/
|
||||
|
||||
#include <service_versions.h>
|
||||
SERVICE_VERSION *debug_sync_service= (void*)VERSION_debug_sync;
|
@ -15,7 +15,7 @@ PLUGIN_STATUS ACTIVE
|
||||
PLUGIN_TYPE STORAGE ENGINE
|
||||
PLUGIN_TYPE_VERSION #
|
||||
PLUGIN_LIBRARY ha_example.so
|
||||
PLUGIN_LIBRARY_VERSION 1.2
|
||||
PLUGIN_LIBRARY_VERSION 1.3
|
||||
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
||||
PLUGIN_DESCRIPTION Example storage engine
|
||||
PLUGIN_LICENSE GPL
|
||||
@ -28,7 +28,7 @@ PLUGIN_STATUS ACTIVE
|
||||
PLUGIN_TYPE DAEMON
|
||||
PLUGIN_TYPE_VERSION #
|
||||
PLUGIN_LIBRARY ha_example.so
|
||||
PLUGIN_LIBRARY_VERSION 1.2
|
||||
PLUGIN_LIBRARY_VERSION 1.3
|
||||
PLUGIN_AUTHOR Sergei Golubchik
|
||||
PLUGIN_DESCRIPTION Unusable Daemon
|
||||
PLUGIN_LICENSE GPL
|
||||
@ -57,7 +57,7 @@ PLUGIN_STATUS DELETED
|
||||
PLUGIN_TYPE STORAGE ENGINE
|
||||
PLUGIN_TYPE_VERSION #
|
||||
PLUGIN_LIBRARY ha_example.so
|
||||
PLUGIN_LIBRARY_VERSION 1.2
|
||||
PLUGIN_LIBRARY_VERSION 1.3
|
||||
PLUGIN_AUTHOR Brian Aker, MySQL AB
|
||||
PLUGIN_DESCRIPTION Example storage engine
|
||||
PLUGIN_LICENSE GPL
|
||||
|
@ -90,13 +90,7 @@ static const char *proc_info_dummy(void *a __attribute__((unused)),
|
||||
/* this is to be able to call set_thd_proc_info from the C code */
|
||||
const char *(*proc_info_hook)(void *, const char *, const char *, const char *,
|
||||
const unsigned int)= proc_info_dummy;
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
/**
|
||||
Global pointer to be set if callback function is defined
|
||||
(e.g. in mysqld). See sql/debug_sync.cc.
|
||||
*/
|
||||
void (*debug_sync_C_callback_ptr)(const char *, size_t);
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
void (*debug_sync_C_callback_ptr)(MYSQL_THD, const char *, size_t)= 0;
|
||||
|
||||
/* How to disable options */
|
||||
my_bool my_disable_locking=0;
|
||||
|
@ -13,307 +13,7 @@
|
||||
along with this program; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */
|
||||
|
||||
/**
|
||||
== Debug Sync Facility ==
|
||||
|
||||
The Debug Sync Facility allows placement of synchronization points in
|
||||
the server code by using the DEBUG_SYNC macro:
|
||||
|
||||
open_tables(...)
|
||||
|
||||
DEBUG_SYNC(thd, "after_open_tables");
|
||||
|
||||
lock_tables(...)
|
||||
|
||||
When activated, a sync point can
|
||||
|
||||
- Emit a signal and/or
|
||||
- Wait for a signal
|
||||
|
||||
Nomenclature:
|
||||
|
||||
- signal: A value of a global variable that persists
|
||||
until overwritten by a new signal. The global
|
||||
variable can also be seen as a "signal post"
|
||||
or "flag mast". Then the signal is what is
|
||||
attached to the "signal post" or "flag mast".
|
||||
|
||||
- emit a signal: Assign the value (the signal) to the global
|
||||
variable ("set a flag") and broadcast a
|
||||
global condition to wake those waiting for
|
||||
a signal.
|
||||
|
||||
- wait for a signal: Loop over waiting for the global condition until
|
||||
the global value matches the wait-for signal.
|
||||
|
||||
By default, all sync points are inactive. They do nothing (except to
|
||||
burn a couple of CPU cycles for checking if they are active).
|
||||
|
||||
A sync point becomes active when an action is requested for it.
|
||||
To do so, put a line like this in the test case file:
|
||||
|
||||
SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
|
||||
|
||||
This activates the sync point 'after_open_tables'. It requests it to
|
||||
emit the signal 'opened' and wait for another thread to emit the signal
|
||||
'flushed' when the thread's execution runs through the sync point.
|
||||
|
||||
For every sync point there can be one action per thread only. Every
|
||||
thread can request multiple actions, but only one per sync point. In
|
||||
other words, a thread can activate multiple sync points.
|
||||
|
||||
Here is an example how to activate and use the sync points:
|
||||
|
||||
--connection conn1
|
||||
SET DEBUG_SYNC= 'after_open_tables SIGNAL opened WAIT_FOR flushed';
|
||||
send INSERT INTO t1 VALUES(1);
|
||||
--connection conn2
|
||||
SET DEBUG_SYNC= 'now WAIT_FOR opened';
|
||||
SET DEBUG_SYNC= 'after_abort_locks SIGNAL flushed';
|
||||
FLUSH TABLE t1;
|
||||
|
||||
When conn1 runs through the INSERT statement, it hits the sync point
|
||||
'after_open_tables'. It notices that it is active and executes its
|
||||
action. It emits the signal 'opened' and waits for another thread to
|
||||
emit the signal 'flushed'.
|
||||
|
||||
conn2 waits immediately at the special sync point 'now' for another
|
||||
thread to emit the 'opened' signal.
|
||||
|
||||
A signal remains in effect until it is overwritten. If conn1 signals
|
||||
'opened' before conn2 reaches 'now', conn2 will still find the 'opened'
|
||||
signal. It does not wait in this case.
|
||||
|
||||
When conn2 reaches 'after_abort_locks', it signals 'flushed', which lets
|
||||
conn1 awake.
|
||||
|
||||
Normally the activation of a sync point is cleared when it has been
|
||||
executed. Sometimes it is necessary to keep the sync point active for
|
||||
another execution. You can add an execute count to the action:
|
||||
|
||||
SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 3';
|
||||
|
||||
This sets the signal point's activation counter to 3. Each execution
|
||||
decrements the counter. After the third execution the sync point
|
||||
becomes inactive.
|
||||
|
||||
One of the primary goals of this facility is to eliminate sleeps from
|
||||
the test suite. In most cases it should be possible to rewrite test
|
||||
cases so that they do not need to sleep. (But this facility cannot
|
||||
synchronize multiple processes.) However, to support test development,
|
||||
and as a last resort, sync point waiting times out. There is a default
|
||||
timeout, but it can be overridden:
|
||||
|
||||
SET DEBUG_SYNC= 'name WAIT_FOR sig TIMEOUT 10 EXECUTE 2';
|
||||
|
||||
TIMEOUT 0 is special: If the signal is not present, the wait times out
|
||||
immediately.
|
||||
|
||||
When a wait timed out (even on TIMEOUT 0), a warning is generated so
|
||||
that it shows up in the test result.
|
||||
|
||||
You can throw an error message and kill the query when a synchronization
|
||||
point is hit a certain number of times:
|
||||
|
||||
SET DEBUG_SYNC= 'name HIT_LIMIT 3';
|
||||
|
||||
Or combine it with signal and/or wait:
|
||||
|
||||
SET DEBUG_SYNC= 'name SIGNAL sig EXECUTE 2 HIT_LIMIT 3';
|
||||
|
||||
Here the first two hits emit the signal, the third hit returns the error
|
||||
message and kills the query.
|
||||
|
||||
For cases where you are not sure that an action is taken and thus
|
||||
cleared in any case, you can force to clear (deactivate) a sync point:
|
||||
|
||||
SET DEBUG_SYNC= 'name CLEAR';
|
||||
|
||||
If you want to clear all actions and clear the global signal, use:
|
||||
|
||||
SET DEBUG_SYNC= 'RESET';
|
||||
|
||||
This is the only way to reset the global signal to an empty string.
|
||||
|
||||
For testing of the facility itself you can execute a sync point just
|
||||
as if it had been hit:
|
||||
|
||||
SET DEBUG_SYNC= 'name TEST';
|
||||
|
||||
|
||||
=== Formal Syntax ===
|
||||
|
||||
The string to "assign" to the DEBUG_SYNC variable can contain:
|
||||
|
||||
{RESET |
|
||||
<sync point name> TEST |
|
||||
<sync point name> CLEAR |
|
||||
<sync point name> {{SIGNAL <signal name> |
|
||||
WAIT_FOR <signal name> [TIMEOUT <seconds>]}
|
||||
[EXECUTE <count>] &| HIT_LIMIT <count>}
|
||||
|
||||
Here '&|' means 'and/or'. This means that one of the sections
|
||||
separated by '&|' must be present or both of them.
|
||||
|
||||
|
||||
=== Activation/Deactivation ===
|
||||
|
||||
The facility is an optional part of the MySQL server.
|
||||
It is enabled in a debug server by default.
|
||||
|
||||
./configure --enable-debug-sync
|
||||
|
||||
The Debug Sync Facility, when compiled in, is disabled by default. It
|
||||
can be enabled by a mysqld command line option:
|
||||
|
||||
--debug-sync-timeout[=default_wait_timeout_value_in_seconds]
|
||||
|
||||
'default_wait_timeout_value_in_seconds' is the default timeout for the
|
||||
WAIT_FOR action. If set to zero, the facility stays disabled.
|
||||
|
||||
The facility is enabled by default in the test suite, but can be
|
||||
disabled with:
|
||||
|
||||
mysql-test-run.pl ... --debug-sync-timeout=0 ...
|
||||
|
||||
Likewise the default wait timeout can be set:
|
||||
|
||||
mysql-test-run.pl ... --debug-sync-timeout=10 ...
|
||||
|
||||
The command line option influences the readable value of the system
|
||||
variable 'debug_sync'.
|
||||
|
||||
* If the facility is not compiled in, the system variable does not exist.
|
||||
|
||||
* If --debug-sync-timeout=0 the value of the variable reads as "OFF".
|
||||
|
||||
* Otherwise the value reads as "ON - current signal: " followed by the
|
||||
current signal string, which can be empty.
|
||||
|
||||
The readable variable value is the same, regardless if read as global
|
||||
or session value.
|
||||
|
||||
Setting the 'debug-sync' system variable requires 'SUPER' privilege.
|
||||
You can never read back the string that you assigned to the variable,
|
||||
unless you assign the value that the variable does already have. But
|
||||
that would give a parse error. A syntactically correct string is
|
||||
parsed into a debug sync action and stored apart from the variable value.
|
||||
|
||||
|
||||
=== Implementation ===
|
||||
|
||||
Pseudo code for a sync point:
|
||||
|
||||
#define DEBUG_SYNC(thd, sync_point_name)
|
||||
if (unlikely(opt_debug_sync_timeout))
|
||||
debug_sync(thd, STRING_WITH_LEN(sync_point_name))
|
||||
|
||||
The sync point performs a binary search in a sorted array of actions
|
||||
for this thread.
|
||||
|
||||
The SET DEBUG_SYNC statement adds a requested action to the array or
|
||||
overwrites an existing action for the same sync point. When it adds a
|
||||
new action, the array is sorted again.
|
||||
|
||||
|
||||
=== A typical synchronization pattern ===
|
||||
|
||||
There are quite a few places in MySQL, where we use a synchronization
|
||||
pattern like this:
|
||||
|
||||
mysql_mutex_lock(&mutex);
|
||||
thd->enter_cond(&condition_variable, &mutex, new_message);
|
||||
#if defined(ENABLE_DEBUG_SYNC)
|
||||
if (!thd->killed && !end_of_wait_condition)
|
||||
DEBUG_SYNC(thd, "sync_point_name");
|
||||
#endif
|
||||
while (!thd->killed && !end_of_wait_condition)
|
||||
mysql_cond_wait(&condition_variable, &mutex);
|
||||
thd->exit_cond(old_message);
|
||||
|
||||
Here some explanations:
|
||||
|
||||
thd->enter_cond() is used to register the condition variable and the
|
||||
mutex in thd->mysys_var. This is done to allow the thread to be
|
||||
interrupted (killed) from its sleep. Another thread can find the
|
||||
condition variable to signal and mutex to use for synchronization in
|
||||
this thread's THD::mysys_var.
|
||||
|
||||
thd->enter_cond() requires the mutex to be acquired in advance.
|
||||
|
||||
thd->exit_cond() unregisters the condition variable and mutex and
|
||||
releases the mutex.
|
||||
|
||||
If you want to have a Debug Sync point with the wait, please place it
|
||||
behind enter_cond(). Only then you can safely decide, if the wait will
|
||||
be taken. Also you will have THD::proc_info correct when the sync
|
||||
point emits a signal. DEBUG_SYNC sets its own proc_info, but restores
|
||||
the previous one before releasing its internal mutex. As soon as
|
||||
another thread sees the signal, it does also see the proc_info from
|
||||
before entering the sync point. In this case it will be "new_message",
|
||||
which is associated with the wait that is to be synchronized.
|
||||
|
||||
In the example above, the wait condition is repeated before the sync
|
||||
point. This is done to skip the sync point, if no wait takes place.
|
||||
The sync point is before the loop (not inside the loop) to have it hit
|
||||
once only. It is possible that the condition variable is signaled
|
||||
multiple times without the wait condition to be true.
|
||||
|
||||
A bit off-topic: At some places, the loop is taken around the whole
|
||||
synchronization pattern:
|
||||
|
||||
while (!thd->killed && !end_of_wait_condition)
|
||||
{
|
||||
mysql_mutex_lock(&mutex);
|
||||
thd->enter_cond(&condition_variable, &mutex, new_message);
|
||||
if (!thd->killed [&& !end_of_wait_condition])
|
||||
{
|
||||
[DEBUG_SYNC(thd, "sync_point_name");]
|
||||
mysql_cond_wait(&condition_variable, &mutex);
|
||||
}
|
||||
thd->exit_cond(old_message);
|
||||
}
|
||||
|
||||
Note that it is important to repeat the test for thd->killed after
|
||||
enter_cond(). Otherwise the killing thread may kill this thread after
|
||||
it tested thd->killed in the loop condition and before it registered
|
||||
the condition variable and mutex in enter_cond(). In this case, the
|
||||
killing thread does not know that this thread is going to wait on a
|
||||
condition variable. It would just set THD::killed. But if we would not
|
||||
test it again, we would go asleep though we are killed. If the killing
|
||||
thread would kill us when we are after the second test, but still
|
||||
before sleeping, we hold the mutex, which is registered in mysys_var.
|
||||
The killing thread would try to acquire the mutex before signaling
|
||||
the condition variable. Since the mutex is only released implicitly in
|
||||
mysql_cond_wait(), the signaling happens at the right place. We
|
||||
have a safe synchronization.
|
||||
|
||||
=== Co-work with the DBUG facility ===
|
||||
|
||||
When running the MySQL test suite with the --debug-dbug command line
|
||||
option, the Debug Sync Facility writes trace messages to the DBUG
|
||||
trace. The following shell commands proved very useful in extracting
|
||||
relevant information:
|
||||
|
||||
egrep 'query:|debug_sync_exec:' mysql-test/var/log/mysqld.1.trace
|
||||
|
||||
It shows all executed SQL statements and all actions executed by
|
||||
synchronization points.
|
||||
|
||||
Sometimes it is also useful to see, which synchronization points have
|
||||
been run through (hit) with or without executing actions. Then add
|
||||
"|debug_sync_point:" to the egrep pattern.
|
||||
|
||||
=== Further reading ===
|
||||
|
||||
For a discussion of other methods to synchronize threads see
|
||||
http://forge.mysql.com/wiki/MySQL_Internals_Test_Synchronization
|
||||
|
||||
For complete syntax tests, functional tests, and examples see the test
|
||||
case debug_sync.test.
|
||||
|
||||
See also worklog entry WL#4259 - Test Synchronization Facility
|
||||
*/
|
||||
/* see include/mysql/service_debug_sync.h for debug sync documentation */
|
||||
|
||||
#include "debug_sync.h"
|
||||
|
||||
@ -382,57 +82,16 @@ struct st_debug_sync_globals
|
||||
};
|
||||
static st_debug_sync_globals debug_sync_global; /* All globals in one object */
|
||||
|
||||
/**
|
||||
Callback pointer for C files.
|
||||
*/
|
||||
extern "C" void (*debug_sync_C_callback_ptr)(const char *, size_t);
|
||||
extern uint opt_debug_sync_timeout;
|
||||
|
||||
/**
|
||||
Callbacks from C files.
|
||||
*/
|
||||
C_MODE_START
|
||||
static void debug_sync_C_callback(const char *, size_t);
|
||||
static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len);
|
||||
static int debug_sync_qsort_cmp(const void *, const void *);
|
||||
C_MODE_END
|
||||
|
||||
/**
|
||||
Callback for debug sync, to be used by C files. See thr_lock.c for example.
|
||||
|
||||
@description
|
||||
|
||||
We cannot place a sync point directly in C files (like those in mysys or
|
||||
certain storage engines written mostly in C like MyISAM or Maria). Because
|
||||
they are C code and do not include sql_priv.h. So they do not know the
|
||||
macro DEBUG_SYNC(thd, sync_point_name). The macro needs a 'thd' argument.
|
||||
Hence it cannot be used in files outside of the sql/ directory.
|
||||
|
||||
The workaround is to call back simple functions like this one from
|
||||
non-sql/ files.
|
||||
|
||||
We want to allow modules like thr_lock to be used without sql/ and
|
||||
especially without Debug Sync. So we cannot just do a simple call
|
||||
of the callback function. Instead we provide a global pointer in
|
||||
the other file, which is to be set to the callback by Debug Sync.
|
||||
If the pointer is not set, no call back will be done. If Debug
|
||||
Sync sets the pointer to a callback function like this one, it will
|
||||
be called. That way thr_lock.c does not have an undefined reference
|
||||
to Debug Sync and can be used without it. Debug Sync, in contrast,
|
||||
has an undefined reference to that pointer and thus requires
|
||||
thr_lock to be linked too. But this is not a problem as it is part
|
||||
of the MySQL server anyway.
|
||||
|
||||
@note
|
||||
The callback pointer in C files is set only if debug sync is
|
||||
initialized. And this is done only if opt_debug_sync_timeout is set.
|
||||
*/
|
||||
|
||||
static void debug_sync_C_callback(const char *sync_point_name,
|
||||
size_t name_len)
|
||||
{
|
||||
if (unlikely(opt_debug_sync_timeout))
|
||||
debug_sync(current_thd, sync_point_name, name_len);
|
||||
}
|
||||
|
||||
#ifdef HAVE_PSI_INTERFACE
|
||||
static PSI_mutex_key key_debug_sync_globals_ds_mutex;
|
||||
|
||||
@ -495,7 +154,7 @@ int debug_sync_init(void)
|
||||
DBUG_RETURN(rc); /* purecov: inspected */
|
||||
|
||||
/* Set the call back pointer in C files. */
|
||||
debug_sync_C_callback_ptr= debug_sync_C_callback;
|
||||
debug_sync_C_callback_ptr= debug_sync;
|
||||
}
|
||||
|
||||
DBUG_RETURN(0);
|
||||
@ -1857,12 +1516,14 @@ static void debug_sync_execute(THD *thd, st_debug_sync_action *action)
|
||||
@param[in] name_len length of sync point name
|
||||
*/
|
||||
|
||||
void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
|
||||
static void debug_sync(THD *thd, const char *sync_point_name, size_t name_len)
|
||||
{
|
||||
if (!thd)
|
||||
thd= current_thd;
|
||||
|
||||
st_debug_sync_control *ds_control= thd->debug_sync_control;
|
||||
st_debug_sync_action *action;
|
||||
DBUG_ENTER("debug_sync");
|
||||
DBUG_ASSERT(thd);
|
||||
DBUG_ASSERT(sync_point_name);
|
||||
DBUG_ASSERT(name_len);
|
||||
DBUG_ASSERT(ds_control);
|
||||
|
@ -32,15 +32,6 @@ class THD;
|
||||
|
||||
#if defined(ENABLED_DEBUG_SYNC)
|
||||
|
||||
/* Macro to be put in the code at synchronization points. */
|
||||
#define DEBUG_SYNC(_thd_, _sync_point_name_) \
|
||||
do { if (unlikely(opt_debug_sync_timeout)) \
|
||||
debug_sync(_thd_, STRING_WITH_LEN(_sync_point_name_)); \
|
||||
} while (0)
|
||||
|
||||
/* Command line option --debug-sync-timeout. See mysqld.cc. */
|
||||
extern MYSQL_PLUGIN_IMPORT uint opt_debug_sync_timeout;
|
||||
|
||||
/* Default WAIT_FOR timeout if command line option is given without argument. */
|
||||
#define DEBUG_SYNC_DEFAULT_WAIT_TIMEOUT 300
|
||||
|
||||
@ -49,13 +40,8 @@ extern int debug_sync_init(void);
|
||||
extern void debug_sync_end(void);
|
||||
extern void debug_sync_init_thread(THD *thd);
|
||||
extern void debug_sync_end_thread(THD *thd);
|
||||
extern void debug_sync(THD *thd, const char *sync_point_name, size_t name_len);
|
||||
extern bool debug_sync_set_action(THD *thd, const char *action_str, size_t len);
|
||||
|
||||
#else /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
#define DEBUG_SYNC(_thd_, _sync_point_name_) /* disabled DEBUG_SYNC */
|
||||
|
||||
#endif /* defined(ENABLED_DEBUG_SYNC) */
|
||||
|
||||
#endif /* DEBUG_SYNC_INCLUDED */
|
||||
|
@ -1339,7 +1339,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
|
||||
const char act[]=
|
||||
"now "
|
||||
"wait_for signal.get_unix_timestamp";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(debug_sync_service);
|
||||
DBUG_ASSERT(!debug_sync_set_action(current_thd,
|
||||
STRING_WITH_LEN(act)));
|
||||
};);
|
||||
@ -1389,7 +1389,7 @@ static int get_master_version_and_clock(MYSQL* mysql, Master_info* mi)
|
||||
const char act[]=
|
||||
"now "
|
||||
"wait_for signal.get_server_id";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(debug_sync_service);
|
||||
DBUG_ASSERT(!debug_sync_set_action(current_thd,
|
||||
STRING_WITH_LEN(act)));
|
||||
};);
|
||||
@ -3034,7 +3034,7 @@ connected:
|
||||
const char act[]=
|
||||
"now "
|
||||
"wait_for signal.io_thread_let_running";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(debug_sync_service);
|
||||
DBUG_ASSERT(!debug_sync_set_action(thd,
|
||||
STRING_WITH_LEN(act)));
|
||||
};);
|
||||
|
@ -2934,7 +2934,7 @@ end_with_restore_list:
|
||||
const char act2[]=
|
||||
"now "
|
||||
"signal signal.continued";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(debug_sync_service);
|
||||
DBUG_ASSERT(!debug_sync_set_action(thd,
|
||||
STRING_WITH_LEN(act1)));
|
||||
DBUG_ASSERT(!debug_sync_set_action(thd,
|
||||
|
@ -1520,6 +1520,10 @@ int plugin_init(int *argc, char **argv, int flags)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* prepare debug_sync service */
|
||||
DBUG_ASSERT(strcmp(list_of_services[5].name, "debug_sync_service") == 0);
|
||||
list_of_services[5].service= *(void**)&debug_sync_C_callback_ptr;
|
||||
|
||||
mysql_mutex_lock(&LOCK_plugin);
|
||||
|
||||
initialized= 1;
|
||||
|
@ -61,5 +61,6 @@ static struct st_service_ref list_of_services[]=
|
||||
{ "thd_wait_service", VERSION_thd_wait, &thd_wait_handler },
|
||||
{ "my_thread_scheduler_service", VERSION_my_thread_scheduler, &my_thread_scheduler_handler },
|
||||
{ "progress_report_service", VERSION_progress_report, &progress_report_handler },
|
||||
{ "debug_sync_service", VERSION_debug_sync, 0 } // updated in plugin_init()
|
||||
};
|
||||
|
||||
|
@ -904,7 +904,7 @@ impossible position";
|
||||
const char act[]=
|
||||
"now "
|
||||
"wait_for signal.continue";
|
||||
DBUG_ASSERT(opt_debug_sync_timeout > 0);
|
||||
DBUG_ASSERT(debug_sync_service);
|
||||
DBUG_ASSERT(!debug_sync_set_action(thd,
|
||||
STRING_WITH_LEN(act)));
|
||||
const char act2[]=
|
||||
|
Reference in New Issue
Block a user