2852 Alfranio Correia 2009-05-15
vWL#4828 Augment DBUG_ENTER/DBUG_EXIT to crash MySQL in different functions
The assessment of the replication code in the presence of faults is extremely
import to increase reliability. In particular, one needs to know if servers
will either correctly recovery or print out appropriate error messages thus
avoiding unexpected problems in a production environment.
In order to accomplish this, the current patch changes the debug macros
already provided in the source code and introduces three new macros that
allows fault-injection, specifically crashes, while entering or exiting
a function or method. For instance, to crash a server while returning
from the init_slave function (see module sql/slave.cc), one needs to do
what follows:
1 - Modify the source replacing DBUG_RETURN by DBUG_CRASH_RETURN;
DBUG_CRASH_RETURN(0);
2 - Use the debug variable to activate dbug instructions:
SET SESSION debug="+d,init_slave_crash_return";
The new macros are briefly described below:
DBUG_CRASH_ENTER (function) is equivalent to DBUG_ENTER which registers the
beginning of a function but in addition to it allows for crashing the server
while entering the function if the appropriate dbug instruction is activate.
In this case, the dbug instruction should be "+d,function_crash_enter".
DBUG_CRASH_RETURN (value) is equivalent to DBUG_RETURN which notifies the
end of a function but in addition to it allows for crashing the server
while returning from the function if the appropriate dbug instruction is
activate. In this case, the dbug instruction should be
"+d,function_crash_return". Note that "function" should be the same string
used by either the DBUG_ENTER or DBUG_CRASH_ENTER.
DBUG_CRASH_VOID_RETURN (value) is equivalent to DBUG_VOID_RETURN which
notifies the end of a function but in addition to it allows for crashing
the server while returning from the function if the appropriate dbug
instruction is activate. In this case, the dbug instruction should be
"+d,function_crash_return". Note that "function" should be the same string
used by either the DBUG_ENTER or DBUG_CRASH_ENTER.
To inject other faults, for instance, wrong return values, one should rely
on the macros already available. The current patch also removes a set of
macros that were either not being used or were redundant as other macros
could be used to provide the same feature. In the future, we also consider
dynamic instrumentation of the code.
@ dbug/dbug.c
1 - _db_keywords_ that concatenates two strings and checks if the result
string is activated by the dbug instructions. The first string is the name
of the function and the second string is either "crash_enter" or "crash_return".
This is used by the new macros: DBUG_CRASH_ENTER, DBUG_CRASH_VOID_RETURN and
DBUG_CRASH_RETURN.
2 - _db_get_func_ returns the name of the current function. This is used by
the DBUG_CRASH_VOID_RETURN and DBUG_CRASH_RETURN to automatically figure out
which is the function they are referencing to.
@ include/my_dbug.h
Defines the new macros.
@ sql/mysql_priv.h
Removes a set of unused macros.
@ sql/sql_class.cc
Removes a set of unused macros.
@ sql/sql_class.h
Removes a set of unused macros.
@ sql/sql_partition.cc
Localy redefines a macro that was removed to avoid changing the module
in several places.
modified:
dbug/dbug.c
include/my_dbug.h
sql/mysql_priv.h
sql/sql_class.cc
sql/sql_class.h
sql/sql_partition.cc
2851 Luis Soares 2009-05-14 [merge]
merge: 6.0-rpl bug branch --> 6.0-rpl up-to-date.
added:
mysql-test/extra/rpl_tests/rpl_show_relaylog_events.inc
mysql-test/include/show_relaylog_events.inc
mysql-test/suite/rpl/r/rpl_row_show_relaylog_events.result
mysql-test/suite/rpl/r/rpl_stm_mix_show_relaylog_events.result
mysql-test/suite/rpl/t/rpl_row_show_relaylog_events.test
mysql-test/suite/rpl/t/rpl_stm_mix_show_relaylog_events.test
modified:
mysql-test/include/show_binlog_events.inc
sql/lex.h
sql/mysqld.cc
sql/sp_head.cc
sql/sql_lex.h
sql/sql_parse.cc
sql/sql_repl.cc
sql/sql_yacc.yy
=== modified file 'dbug/dbug.c'
--- a/dbug/dbug.c 2009-03-25 16:51:28 +0000
+++ b/dbug/dbug.c 2009-05-15 10:06:26 +0000
@@ -1836,6 +1836,27 @@ BOOLEAN _db_keyword_(CODE_STATE *cs, con
/*
* FUNCTION
*
+ * _db_keywords_ test keyword formed by a set of strings for member
+ * of keyword list
+ *
+ * DESCRIPTION
+ *
+ * This function is similar to _db_keyword but receives a set of strings to
+ * be concatenated in order to make the keyword to be compared.
+ */
+
+BOOLEAN _db_keywords_(CODE_STATE *cs, int strict, char *function, char *type)
+{
+ char dest[_DBUG_MAX_FUNC_NAME_ + 1];
+
+ strxnmov(dest, _DBUG_MAX_FUNC_NAME_, function, type, NULL);
+
+ return _db_keyword_(cs, dest, strict);
+}
+
+/*
+ * FUNCTION
+ *
* Indent indent a line to the given indentation level
*
* SYNOPSIS
@@ -2460,6 +2481,13 @@ void _db_unlock_file_()
pthread_mutex_unlock(&THR_LOCK_dbug);
}
+const char* _db_get_func_(void)
+{
+ CODE_STATE *cs;
+ get_code_state_or_return NULL;
+ return cs->func;
+}
+
/*
* Here we need the definitions of the clock routine. Add your
* own for whatever system that you have.
=== modified file 'include/my_dbug.h'
--- a/include/my_dbug.h 2008-12-10 17:04:38 +0000
+++ b/include/my_dbug.h 2009-05-15 10:06:26 +0000
@@ -31,6 +31,7 @@ struct _db_stack_frame_ {
struct _db_code_state_;
extern my_bool _dbug_on_;
extern my_bool _db_keyword_(struct _db_code_state_ *, const char *, int);
+extern my_bool _db_keywords_(struct _db_code_state_ *, int, char *, char *);
extern int _db_explain_(struct _db_code_state_ *cs, char *buf, size_t len);
extern int _db_explain_init_(char *buf, size_t len);
extern int _db_is_pushed_(void);
@@ -54,6 +55,7 @@ extern void _db_lock_file_(void);
extern void _db_unlock_file_(void);
extern FILE *_db_fp_(void);
extern void _db_flush_();
+extern const char* _db_get_func_(void);
#define DBUG_ENTER(a) struct _db_stack_frame_ _db_stack_frame_; \
_db_enter_ (a,__FILE__,__LINE__,&_db_stack_frame_)
@@ -101,6 +103,20 @@ extern void _db_flush_();
(void)_CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR),\
_exit(3))
#endif
+#define _DBUG_MAX_FUNC_NAME_ 255
+#define DBUG_CHECK_CRASH(func, op) \
+ do { \
+ if (_db_keywords_(0, 0, (func), (op))) \
+ { (_db_flush_(), abort()); } \
+ } while (0)
+#define DBUG_CRASH_ENTER(func) \
+ DBUG_ENTER(func); DBUG_CHECK_CRASH(func, "_crash_enter")
+#define DBUG_CRASH_RETURN(val) \
+ do {DBUG_CHECK_CRASH(_db_get_func_(), "_crash_return"); \
+ DBUG_RETURN(val);} while(0)
+#define DBUG_CRASH_VOID_RETURN \
+ do {DBUG_CHECK_CRASH (_db_get_func_(), "_crash_return"); \
+ DBUG_VOID_RETURN;} while(0)
#else /* No debugger */
@@ -132,6 +148,9 @@ extern void _db_flush_();
#define DEBUGGER_ON do { } while(0)
#define IF_DBUG(A)
#define DBUG_ABORT() abort()
+#define DBUG_CRASH_ENTER(func)
+#define DBUG_CRASH_RETURN(val) do { return(val); } while(0)
+#define DBUG_CRASH_VOID_RETURN do { return; } while(0)
#endif
#ifdef __cplusplus
=== modified file 'sql/mysql_priv.h'
--- a/sql/mysql_priv.h 2009-05-07 20:48:24 +0000
+++ b/sql/mysql_priv.h 2009-05-15 10:06:26 +0000
@@ -977,100 +977,6 @@ struct Query_cache_query_flags
#define query_cache_is_cacheable_query(L) 0
#endif /*HAVE_QUERY_CACHE*/
-/*
- Error injector Macros to enable easy testing of recovery after failures
- in various error cases.
-*/
-#ifndef ERROR_INJECT_SUPPORT
-
-#define ERROR_INJECT(x) 0
-#define ERROR_INJECT_ACTION(x,action) 0
-#define ERROR_INJECT_CRASH(x) 0
-#define ERROR_INJECT_VALUE(x) 0
-#define ERROR_INJECT_VALUE_ACTION(x,action) 0
-#define ERROR_INJECT_VALUE_CRASH(x) 0
-#define SET_ERROR_INJECT_VALUE(x)
-
-#else
-
-inline bool check_and_unset_keyword(const char *dbug_str)
-{
- const char *extra_str= "-d,";
- char total_str[200];
- if (_db_keyword_ (0, dbug_str, 1))
- {
- strxmov(total_str, extra_str, dbug_str, NullS);
- DBUG_SET(total_str);
- return 1;
- }
- return 0;
-}
-
-
-inline bool
-check_and_unset_inject_value(int value)
-{
- THD *thd= current_thd;
- if (thd->error_inject_value == (uint)value)
- {
- thd->error_inject_value= 0;
- return 1;
- }
- return 0;
-}
-
-/*
- ERROR INJECT MODULE:
- --------------------
- These macros are used to insert macros from the application code.
- The event that activates those error injections can be activated
- from SQL by using:
- SET SESSION dbug=+d,code;
-
- After the error has been injected, the macros will automatically
- remove the debug code, thus similar to using:
- SET SESSION dbug=-d,code
- from SQL.
-
- ERROR_INJECT_CRASH will inject a crash of the MySQL Server if code
- is set when macro is called. ERROR_INJECT_CRASH can be used in
- if-statements, it will always return FALSE unless of course it
- crashes in which case it doesn't return at all.
-
- ERROR_INJECT_ACTION will inject the action specified in the action
- parameter of the macro, before performing the action the code will
- be removed such that no more events occur. ERROR_INJECT_ACTION
- can also be used in if-statements and always returns FALSE.
- ERROR_INJECT can be used in a normal if-statement, where the action
- part is performed in the if-block. The macro returns TRUE if the
- error was activated and otherwise returns FALSE. If activated the
- code is removed.
-
- Sometimes it is necessary to perform error inject actions as a serie
- of events. In this case one can use one variable on the THD object.
- Thus one sets this value by using e.g. SET_ERROR_INJECT_VALUE(100).
- Then one can later test for it by using ERROR_INJECT_CRASH_VALUE,
- ERROR_INJECT_ACTION_VALUE and ERROR_INJECT_VALUE. This have the same
- behaviour as the above described macros except that they use the
- error inject value instead of a code used by DBUG macros.
-*/
-#define SET_ERROR_INJECT_VALUE(x) \
- current_thd->error_inject_value= (x)
-#define ERROR_INJECT_CRASH(code) \
- DBUG_EVALUATE_IF(code, (DBUG_ABORT(), 0), 0)
-#define ERROR_INJECT_ACTION(code, action) \
- (check_and_unset_keyword(code) ? ((action), 0) : 0)
-#define ERROR_INJECT(code) \
- check_and_unset_keyword(code)
-#define ERROR_INJECT_VALUE(value) \
- check_and_unset_inject_value(value)
-#define ERROR_INJECT_VALUE_ACTION(value,action) \
- (check_and_unset_inject_value(value) ? (action) : 0)
-#define ERROR_INJECT_VALUE_CRASH(value) \
- ERROR_INJECT_VALUE_ACTION(value, (DBUG_ABORT(), 0))
-
-#endif
-
void write_bin_log(THD *thd, bool clear_error,
char const *query, ulong query_length);
=== modified file 'sql/sql_class.cc'
--- a/sql/sql_class.cc 2009-05-12 08:58:44 +0000
+++ b/sql/sql_class.cc 2009-05-15 10:06:26 +0000
@@ -493,9 +493,6 @@ THD::THD()
limit_found_rows= 0;
row_count_func= -1;
statement_id_counter= 0UL;
-#ifdef ERROR_INJECT_SUPPORT
- error_inject_value= 0UL;
-#endif
// Must be reset to handle error with THD's created for init of mysqld
lex->current_select= 0;
start_time=(time_t) 0;
=== modified file 'sql/sql_class.h'
--- a/sql/sql_class.h 2009-05-12 08:58:44 +0000
+++ b/sql/sql_class.h 2009-05-15 10:06:26 +0000
@@ -1696,9 +1696,6 @@ public:
query_id_t query_id;
ulong col_access;
-#ifdef ERROR_INJECT_SUPPORT
- ulong error_inject_value;
-#endif
/* Statement id is thread-wide. This counter is used to generate ids */
ulong statement_id_counter;
ulong rand_saved_seed1, rand_saved_seed2;
=== modified file 'sql/sql_partition.cc'
--- a/sql/sql_partition.cc 2009-04-01 09:15:50 +0000
+++ b/sql/sql_partition.cc 2009-05-15 10:06:26 +0000
@@ -41,6 +41,10 @@
#ifdef WITH_PARTITION_STORAGE_ENGINE
#include "ha_partition.h"
+
+#define ERROR_INJECT_CRASH(code) \
+ DBUG_EVALUATE_IF(code, (DBUG_ABORT(), 0), 0)
+
/*
Partition related functions declarations and some static constants;
*/
Attachment: [text/bzr-bundle]
| Thread |
|---|
| • bzr push into mysql-6.0-rpl branch (alfranio.correia:2851 to 2852) | Alfranio Correia | 15 May |