YoushouldhavereceivedacopyoftheGNUGeneralPublicLicense alongwiththisprogram;ifnot,writetotheFreeSoftwareFoundation,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1335 USA */
/* see include/mysql/service_debug_sync.h for debug sync documentation */
/* Actiontoperformatasynchronizationpoint. NOTE:Thisstructureismovedaroundinmemorybyrealloc(),qsort(), andmemmove().Donotaddobjectswithnon-trivialconstructors ordestructors,whichmightpreventmovingofthisstructure withthesefunctions.
*/ struct st_debug_sync_action
{
ulong activation_count; /* MY_MAX(hit_limit, execute) */
ulong hit_limit; /* hits before kill query */
ulong execute; /* executes before self-clear */
ulong timeout; /* wait_for timeout */
String signal; /* signal to emit */
String wait_for; /* signal to wait for */
String sync_point; /* sync point name */ bool need_sort; /* if new action, array needs sort */ bool clear_event; /* do not clear signal when waited
for if false. */
};
bool set_signal(constchar *signal_name, size_t length)
{ /* Need to check if the signal is already in the hash set, because
Hash_set doesn't differentiate between OOM and key already in. */ if (is_signalled(signal_name, length)) returnFALSE; /* LEX_CSTRING and the string allocated with only one malloc. */
LEX_CSTRING *s= (LEX_CSTRING *) my_malloc(PSI_NOT_INSTRUMENTED, sizeof(LEX_CSTRING) + length + 1,
MYF(0)); char *str= (char *)(s + 1);
memcpy(str, signal_name, length);
str[length]= '\0';
s->length= length;
s->str= str; if (ds_signal_set.insert(s)) returnTRUE; returnFALSE;
}
};
static st_debug_sync_globals *debug_sync_global; /* All globals in one object */
/* End the facility only if it had been initialized. */ if (debug_sync_C_callback_ptr)
{ /* Clear the call back pointer in C files. */
debug_sync_C_callback_ptr= NULL;
/* Destroy the global variables. */
debug_sync_global->clear_set();
mysql_cond_destroy(&debug_sync_global->ds_cond);
mysql_mutex_destroy(&debug_sync_global->ds_mutex);
/* Print statistics. */
{
sql_print_information("Debug sync points hit: %lld",
debug_sync_global->dsp_hits);
sql_print_information("Debug sync points executed: %lld",
debug_sync_global->dsp_executed);
sql_print_information("Debug sync points max active per thread: %lld",
debug_sync_global->dsp_max_active);
}
}
delete debug_sync_global; /* Just to be safe */
debug_sync_global= NULL;
DBUG_PRINT("debug_sync",
("Debug Sync Facility disabled due to lack of memory."));
sql_print_error("Debug Sync Facility disabled due to lack of memory.");
Buffermustbefreedbythecaller.
*/ staticconstchar *get_signal_set_as_string()
{
mysql_mutex_assert_owner(&debug_sync_global->ds_mutex);
size_t req_size= 1; // In case of empty set for the end '\0' char.
for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
req_size+= debug_sync_global->ds_signal_set.at(i)->length + 1;
/* If an execute count is present, signal or wait_for are needed too. */
DBUG_ASSERT(!action->execute ||
action->signal.length() || action->wait_for.length());
/* Remove all actions of this thread. */
ds_control->ds_active= 0;
/* Clear the global signal. */
mysql_mutex_lock(&debug_sync_global->ds_mutex);
debug_sync_global->clear_set();
mysql_mutex_unlock(&debug_sync_global->ds_mutex);
/* There cannot be more active actions than allocated. */
DBUG_ASSERT(ds_control->ds_active <= ds_control->ds_allocated); /* If there are active actions, the action array must be present. */
DBUG_ASSERT(!ds_control->ds_active || ds_control->ds_action);
/* Try to reuse existing action if there is one for this sync point. */ if (ds_control->ds_active &&
(action= debug_sync_find(ds_control->ds_action, ds_control->ds_active,
dsp_name, name_len)))
{ /* Reuse an already active sync point action. */
DBUG_ASSERT((uint)(action - ds_control->ds_action) < ds_control->ds_active);
DBUG_PRINT("debug_sync", ("reuse action idx: %ld",
(long) (action - ds_control->ds_action)));
} else
{ /* Create a new action. */ int dsp_idx= ds_control->ds_active++;
set_if_bigger(ds_control->dsp_max_active, ds_control->ds_active); if (ds_control->ds_active > ds_control->ds_allocated)
{
uint new_alloc= ds_control->ds_active + 3; void *new_action= my_realloc(PSI_NOT_INSTRUMENTED, ds_control->ds_action,
new_alloc * sizeof(st_debug_sync_action),
MYF(MY_WME | MY_ALLOW_ZERO_PTR)); if (!new_action)
{ /* Error is reported by my_malloc(). */ goto err; /* purecov: tested */
}
ds_control->ds_action= (st_debug_sync_action*) new_action;
ds_control->ds_allocated= new_alloc; /* Clear memory as we do not run string constructors here. */
bzero((uchar*) (ds_control->ds_action + dsp_idx),
(new_alloc - dsp_idx) * sizeof(st_debug_sync_action));
}
DBUG_PRINT("debug_sync", ("added action idx: %u", dsp_idx));
action= ds_control->ds_action + dsp_idx; if (action->sync_point.copy(dsp_name, name_len, system_charset_info))
{ /* Error is reported by my_malloc(). */ goto err; /* purecov: tested */
}
action->need_sort= TRUE;
}
DBUG_ASSERT(action >= ds_control->ds_action);
DBUG_ASSERT(action < ds_control->ds_action + ds_control->ds_active);
DBUG_PRINT("debug_sync", ("action: %p array: %p count: %u",
action, ds_control->ds_action,
ds_control->ds_active));
DBUG_RETURN(action);
/* purecov: begin tested */
err:
DBUG_RETURN(NULL); /* purecov: end */
}
class Debug_token: public Lex_ident_ci
{ public: using Lex_ident_ci::Lex_ident_ci;
};
/* Execute the special sync point 'now' if activated above. */ if (is_dsp_now)
{
DEBUG_SYNC(thd, "now"); /* IfHIT_LIMITforsyncpoint"now"was1,theexecutionofthesync pointdecrementeditto0.Inthiscasethefollowinghappened:
/* TryTEST.
*/ if (token.streq("TEST"_LEX_CSTRING))
{ /* It is TEST. Nothing must follow it. */ if (*ptr)
{
errmsg= "Nothing must follow action TEST"; goto err;
}
/* Execute sync point. */
debug_sync(thd, action->sync_point.ptr(), action->sync_point.length()); /* Fix statistics. This was not a real hit of the sync point. */
thd->debug_sync_control->dsp_hits--; goto end;
}
/* TryCLEAR.
*/ if (token.streq("CLEAR"_LEX_CSTRING))
{ /* It is CLEAR. Nothing must follow it. */ if (*ptr)
{
errmsg= "Nothing must follow action CLEAR"; goto err;
}
/* Set (clear/remove) action. */ goto set_action;
}
/* Nowcheckforrealsyncpointactions.
*/
/* TrySIGNAL.
*/ if (token.streq("SIGNAL"_LEX_CSTRING))
{ /* It is SIGNAL. Signal name must follow. */ if (!(ptr= debug_sync_token(&token, ptr, action_end)))
{
errmsg= "Missing signal name after action SIGNAL"; goto err;
} if (action->signal.copy(token.str, token.length, system_charset_info))
{ /* Error is reported by my_malloc(). */ /* purecov: begin tested */
errmsg= NULL; goto err; /* purecov: end */
}
/* Set default for EXECUTE option. */
action->execute= 1;
/* Get next token. If none follows, set action. */ if (!(ptr= debug_sync_token(&token, ptr, action_end))) goto set_action;
}
/* TryWAIT_FOR.
*/ if (token.streq("WAIT_FOR"_LEX_CSTRING))
{ /* It is WAIT_FOR. Wait_for signal name must follow. */ if (!(ptr= debug_sync_token(&token, ptr, action_end)))
{
errmsg= "Missing signal name after action WAIT_FOR"; goto err;
} if (action->wait_for.copy(token.str, token.length, system_charset_info))
{ /* Error is reported by my_malloc(). */ /* purecov: begin tested */
errmsg= NULL; goto err; /* purecov: end */
}
/* Set default for EXECUTE and TIMEOUT options. */
action->execute= 1;
action->timeout= opt_debug_sync_timeout;
action->clear_event= true;
/* Get next token. If none follows, set action. */ if (!(ptr= debug_sync_token(&token, ptr, action_end))) goto set_action;
/* TryTIMEOUT.
*/ if (token.streq("TIMEOUT"_LEX_CSTRING))
{ /* It is TIMEOUT. Number must follow. */ if (!(ptr= debug_sync_number(&action->timeout, ptr, action_end)))
{
errmsg= "Missing valid number after TIMEOUT"; goto err;
}
/* Get next token. If none follows, set action. */ if (!(ptr= debug_sync_token(&token, ptr, action_end))) goto set_action;
}
}
/* TryEXECUTE.
*/ if (token.streq("EXECUTE"_LEX_CSTRING))
{ /* EXECUTErequireseitherSIGNALand/orWAIT_FORtobepresent. Inthiscaseaction->executehasbeenpresetto1.
*/ if (!action->execute)
{
errmsg= "Missing action before EXECUTE"; goto err;
}
/* Number must follow. */ if (!(ptr= debug_sync_number(&action->execute, ptr, action_end)))
{
errmsg= "Missing valid number after EXECUTE"; goto err;
}
/* Get next token. If none follows, set action. */ if (!(ptr= debug_sync_token(&token, ptr, action_end))) goto set_action;
}
/* TryNO_CLEAR_EVENT.
*/ if (token.streq("NO_CLEAR_EVENT"_LEX_CSTRING))
{
action->clear_event= false; /* Get next token. If none follows, set action. */ if (!(ptr = debug_sync_token(&token, ptr, action_end))) goto set_action;
}
/* TryHIT_LIMIT.
*/ if (token.streq("HIT_LIMIT"_LEX_CSTRING))
{ /* Number must follow. */ if (!(ptr= debug_sync_number(&action->hit_limit, ptr, action_end)))
{
errmsg= "Missing valid number after HIT_LIMIT"; goto err;
}
/* Get next token. If none follows, set action. */ if (!(ptr= debug_sync_token(&token, ptr, action_end))) goto set_action;
}
if (opt_debug_sync_timeout)
{ staticconstchar on[]= "ON - current signals: '";
// Ensure exclusive access to debug_sync_global.ds_signal
mysql_mutex_lock(&debug_sync_global->ds_mutex);
size_t lgt= sizeof(on) + 1; /* +1 as we'll have to append ' at the end. */
for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
{ /* Assume each signal is separated by a comma, hence +1. */
lgt+= debug_sync_global->ds_signal_set.at(i)->length + 1;
}
char *vend; char *vptr;
if ((value= (char*) alloc_root(thd->mem_root, lgt)))
{
vend= value + lgt - 1; /* reserve space for '\0'. */
vptr= debug_sync_bmove_len(value, vend, STRING_WITH_LEN(on)); for (size_t i= 0; i < debug_sync_global->ds_signal_set.size(); i++)
{ const LEX_CSTRING *s= debug_sync_global->ds_signal_set.at(i);
vptr= debug_sync_bmove_len(vptr, vend, s->str, s->length); if (i != debug_sync_global->ds_signal_set.size() - 1)
*(vptr++)= ',';
}
DBUG_ASSERT(vptr < vend);
*(vptr++)= '\'';
*vptr= '\0'; /* We have one byte reserved for the worst case. */
}
mysql_mutex_unlock(&debug_sync_global->ds_mutex);
} else
{ /* purecov: begin tested */
value= const_cast<char*>("OFF"); /* purecov: end */
}
if (action->signal.length())
{ int offset= 0, pos; bool error= false;
/* This loop covers all signals in the list except for the last one. Splitthesignalstringbycommasandsetasignalintheglobal
variable for each one. */ while (!error && (pos= action->signal.strstr(",", 1, offset)) > 0)
{
error= debug_sync_global->set_signal(action->signal.ptr() + offset,
pos - offset);
offset= pos + 1;
}
if (error || /* The last signal in the list. */
debug_sync_global->set_signal(action->signal.ptr() + offset,
action->signal.length() - offset))
{ /* Errorisreportedbymy_malloc(). Wemustdisablethefacility.Wehavenowaytoreturnanerror.
*/
debug_sync_emergency_disable(); /* purecov: tested */
} /* Wake threads waiting in a sync point. */
mysql_cond_broadcast(&debug_sync_global->ds_cond);
DBUG_PRINT("debug_sync_exec", ("signal '%s' at: '%s'",
sig_emit, dsp_name));
} /* end if (action->signal.length()) */
if (action->wait_for.length())
{
mysql_mutex_t *old_mutex= NULL;
mysql_cond_t *old_cond= NULL; bool restore_current_mutex; int error= 0; struct timespec abstime;
set_timespec(abstime, action->timeout);
DBUG_EXECUTE("debug_sync_exec", { constchar *signal_set= get_signal_set_as_string(); if (!signal_set)
{
DBUG_PRINT("debug_sync_exec",
("Out of memory when fetching signal set"));
} else
{ /* Functions as DBUG_PRINT args can change keyword and line nr. */
DBUG_PRINT("debug_sync_exec",
("wait for '%s' at: '%s', curr: '%s'",
sig_wait, dsp_name, signal_set));
my_free((void *)signal_set);
}});
/* Waituntilthesignalsetcontainsthewait_forstring. Interruptwhenthreadorqueryiskilledorfacilityisdisabled. Thefacilitycanbecomedisabledwhensomethreadcannotget therequireddynamicmemoryallocated.
*/ while (!debug_sync_global->is_signalled(action->wait_for.ptr(),
action->wait_for.length()) &&
!(thd->killed & KILL_HARD_BIT) &&
opt_debug_sync_timeout)
{
error= mysql_cond_timedwait(&debug_sync_global->ds_cond,
&debug_sync_global->ds_mutex,
&abstime); // TODO turn this into a for loop printing.
DBUG_EXECUTE("debug_sync", { /* Functions as DBUG_PRINT args can change keyword and line nr. */
DBUG_PRINT("debug_sync",
("awoke from %s error: %d",
sig_wait, error));}); if (unlikely(error == ETIMEDOUT || error == ETIME))
{ // We should not make the statement fail, even if in strict mode.
Abort_on_warning_instant_set aws(thd, false);
push_warning(thd, Sql_condition::WARN_LEVEL_WARN,
ER_DEBUG_SYNC_TIMEOUT,
ER_THD(thd, ER_DEBUG_SYNC_TIMEOUT));
DBUG_EXECUTE_IF("debug_sync_abort_on_timeout", DBUG_ASSERT(0);); break;
}
error= 0;
}
if (action->clear_event)
debug_sync_global->clear_signal(action->wait_for);
DBUG_EXECUTE("debug_sync_exec", if (thd->killed)
DBUG_PRINT("debug_sync_exec",
("killed %d from '%s' at: '%s'",
thd->killed, sig_wait, dsp_name)); else
DBUG_PRINT("debug_sync_exec",
("%s from '%s' at: '%s'",
error ? "timeout" : "resume",
sig_wait, dsp_name)););
/* Wedon'tuseenter_cond()/exit_cond().Theydonotsaveold mutexandcond.ThiswouldprohibittheuseofDEBUG_SYNC betweenotherplacesofenter_cond()andexit_cond().The protectedmutexmustalwaysunlocked_before_mysys_var->mutex islocked.(SeecommentinTHD::exit_cond().)
*/
mysql_mutex_unlock(&debug_sync_global->ds_mutex); if (restore_current_mutex)
{
mysql_mutex_lock(&thd->mysys_var->mutex);
thd->mysys_var->current_mutex= old_mutex;
thd->mysys_var->current_cond= old_cond;
debug_sync_thd_proc_info(thd, old_proc_info);
mysql_mutex_unlock(&thd->mysys_var->mutex);
} else
debug_sync_thd_proc_info(thd, old_proc_info);
} else
{ /* In case we don't wait, we just release the mutex. */
mysql_mutex_unlock(&debug_sync_global->ds_mutex);
} /* end if (action->wait_for.length()) */
} /* end if (action->execute) */
/* hit_limit is zero for infinite. Don't decrement unconditionally. */ if (action->hit_limit)
{ if (!--action->hit_limit)
{
thd->set_killed(KILL_QUERY);
my_error(ER_DEBUG_SYNC_HIT_LIMIT, MYF(0));
}
DBUG_PRINT("debug_sync_exec", ("hit_limit: %lu at: '%s'",
action->hit_limit, dsp_name));
}
#else/* defined(ENABLED_DEBUG_SYNC) */ /* prevent linker/lib warning about file without public symbols */ int debug_sync_dummy; #endif/* defined(ENABLED_DEBUG_SYNC) */
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.66Bemerkung:
(vorverarbeitet am 2026-10-08)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.