MDEV-33161 Function pointer signature mismatch in LF_HASH
In cmake -DWITH_UBSAN=ON builds with clang but not with GCC, -fsanitize=undefined will flag several runtime errors on function pointer mismatch related to the lock-free hash table LF_HASH. Let us use matching function signatures and remove function pointer casts in order to avoid potential bugs due to undefined behaviour. These errors could be caught at compilation time by -Wcast-function-type-strict, which is available starting with clang-16, but not available in any version of GCC as of now. The old GCC flag -Wcast-function-type is enabled as part of -Wextra, but it specifically does not catch these errors. Reviewed by: Vladislav Vaintroub
This commit is contained in:
parent
246c0b3a35
commit
a2bd936c52
@ -242,8 +242,10 @@ void lf_pinbox_put_pins(LF_PINS *pins)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int ptr_cmp(void **a, void **b)
|
static int ptr_cmp(const void *pa, const void *pb)
|
||||||
{
|
{
|
||||||
|
const void *const*a= pa;
|
||||||
|
const void *const*b= pb;
|
||||||
return *a < *b ? -1 : *a == *b ? 0 : 1;
|
return *a < *b ? -1 : *a == *b ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -283,8 +285,10 @@ struct st_harvester {
|
|||||||
callback forlf_dynarray_iterate:
|
callback forlf_dynarray_iterate:
|
||||||
scan all pins of all threads and accumulate all pins
|
scan all pins of all threads and accumulate all pins
|
||||||
*/
|
*/
|
||||||
static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
|
static int harvest_pins(void *e, void *h)
|
||||||
{
|
{
|
||||||
|
LF_PINS *el= e;
|
||||||
|
struct st_harvester *hv= h;
|
||||||
int i;
|
int i;
|
||||||
LF_PINS *el_end= el+MY_MIN(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
|
LF_PINS *el_end= el+MY_MIN(hv->npins, LF_DYNARRAY_LEVEL_LENGTH);
|
||||||
for (; el < el_end; el++)
|
for (; el < el_end; el++)
|
||||||
@ -310,8 +314,9 @@ static int harvest_pins(LF_PINS *el, struct st_harvester *hv)
|
|||||||
callback forlf_dynarray_iterate:
|
callback forlf_dynarray_iterate:
|
||||||
scan all pins of all threads and see if addr is present there
|
scan all pins of all threads and see if addr is present there
|
||||||
*/
|
*/
|
||||||
static int match_pins(LF_PINS *el, void *addr)
|
static int match_pins(void *e, void *addr)
|
||||||
{
|
{
|
||||||
|
LF_PINS *el= e;
|
||||||
int i;
|
int i;
|
||||||
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
|
LF_PINS *el_end= el+LF_DYNARRAY_LEVEL_LENGTH;
|
||||||
for (; el < el_end; el++)
|
for (; el < el_end; el++)
|
||||||
@ -352,13 +357,12 @@ static void lf_pinbox_real_free(LF_PINS *pins)
|
|||||||
hv.granary= addr;
|
hv.granary= addr;
|
||||||
hv.npins= npins;
|
hv.npins= npins;
|
||||||
/* scan the dynarray and accumulate all pinned addresses */
|
/* scan the dynarray and accumulate all pinned addresses */
|
||||||
lf_dynarray_iterate(&pinbox->pinarray,
|
lf_dynarray_iterate(&pinbox->pinarray, harvest_pins, &hv);
|
||||||
(lf_dynarray_func)harvest_pins, &hv);
|
|
||||||
|
|
||||||
npins= (int)(hv.granary-addr);
|
npins= (int)(hv.granary-addr);
|
||||||
/* and sort them */
|
/* and sort them */
|
||||||
if (npins)
|
if (npins)
|
||||||
qsort(addr, npins, sizeof(void *), (qsort_cmp)ptr_cmp);
|
qsort(addr, npins, sizeof(void *), ptr_cmp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
@ -387,8 +391,7 @@ static void lf_pinbox_real_free(LF_PINS *pins)
|
|||||||
}
|
}
|
||||||
else /* no alloca - no cookie. linear search here */
|
else /* no alloca - no cookie. linear search here */
|
||||||
{
|
{
|
||||||
if (lf_dynarray_iterate(&pinbox->pinarray,
|
if (lf_dynarray_iterate(&pinbox->pinarray, match_pins, cur))
|
||||||
(lf_dynarray_func)match_pins, cur))
|
|
||||||
goto found;
|
goto found;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -416,10 +419,11 @@ found:
|
|||||||
'first' and 'last' are the ends of the linked list of nodes:
|
'first' and 'last' are the ends of the linked list of nodes:
|
||||||
first->el->el->....->el->last. Use first==last to free only one element.
|
first->el->el->....->el->last. Use first==last to free only one element.
|
||||||
*/
|
*/
|
||||||
static void alloc_free(uchar *first,
|
static void alloc_free(void *f, void *l, void *alloc)
|
||||||
uchar volatile *last,
|
|
||||||
LF_ALLOCATOR *allocator)
|
|
||||||
{
|
{
|
||||||
|
uchar *first= f;
|
||||||
|
uchar volatile *last= l;
|
||||||
|
LF_ALLOCATOR *allocator= alloc;
|
||||||
/*
|
/*
|
||||||
we need a union here to access type-punned pointer reliably.
|
we need a union here to access type-punned pointer reliably.
|
||||||
otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
|
otherwise gcc -fstrict-aliasing will not see 'tmp' changed in the loop
|
||||||
@ -448,8 +452,7 @@ static void alloc_free(uchar *first,
|
|||||||
*/
|
*/
|
||||||
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
|
void lf_alloc_init(LF_ALLOCATOR *allocator, uint size, uint free_ptr_offset)
|
||||||
{
|
{
|
||||||
lf_pinbox_init(&allocator->pinbox, free_ptr_offset,
|
lf_pinbox_init(&allocator->pinbox, free_ptr_offset, alloc_free, allocator);
|
||||||
(lf_pinbox_free_func *)alloc_free, allocator);
|
|
||||||
allocator->top= 0;
|
allocator->top= 0;
|
||||||
allocator->mallocs= 0;
|
allocator->mallocs= 0;
|
||||||
allocator->element_size= size;
|
allocator->element_size= size;
|
||||||
|
@ -62,14 +62,10 @@ my_bool safe_mutex_deadlock_detector= 1; /* On by default */
|
|||||||
static struct st_safe_mutex_create_info_t *safe_mutex_create_root= NULL;
|
static struct st_safe_mutex_create_info_t *safe_mutex_create_root= NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
|
static my_bool add_used_to_locked_mutex(void *used, void *locked);
|
||||||
safe_mutex_deadlock_t *locked_mutex);
|
static my_bool add_to_locked_mutex(void *locked, void *current);
|
||||||
static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
|
static my_bool remove_from_locked_mutex(void *m, void* remove);
|
||||||
safe_mutex_t *current_mutex);
|
static my_bool remove_from_used_mutex(void *locked, void *m);
|
||||||
static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
|
|
||||||
safe_mutex_t *delete_mutex);
|
|
||||||
static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
|
|
||||||
safe_mutex_t *mutex);
|
|
||||||
static void print_deadlock_warning(safe_mutex_t *new_mutex,
|
static void print_deadlock_warning(safe_mutex_t *new_mutex,
|
||||||
safe_mutex_t *conflicting_mutex);
|
safe_mutex_t *conflicting_mutex);
|
||||||
#endif
|
#endif
|
||||||
@ -373,8 +369,7 @@ int safe_mutex_lock(safe_mutex_t *mp, myf my_flags, const char *file,
|
|||||||
are now locking (C) in B->C, then we would add C into
|
are now locking (C) in B->C, then we would add C into
|
||||||
B->locked_mutex and A->locked_mutex
|
B->locked_mutex and A->locked_mutex
|
||||||
*/
|
*/
|
||||||
my_hash_iterate(mutex_root->used_mutex,
|
my_hash_iterate(mutex_root->used_mutex, add_used_to_locked_mutex,
|
||||||
(my_hash_walk_action) add_used_to_locked_mutex,
|
|
||||||
deadlock);
|
deadlock);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -654,12 +649,8 @@ void safe_mutex_free_deadlock_data(safe_mutex_t *mp)
|
|||||||
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION) && mp->used_mutex != NULL)
|
if (!(mp->create_flags & MYF_NO_DEADLOCK_DETECTION) && mp->used_mutex != NULL)
|
||||||
{
|
{
|
||||||
pthread_mutex_lock(&THR_LOCK_mutex);
|
pthread_mutex_lock(&THR_LOCK_mutex);
|
||||||
my_hash_iterate(mp->used_mutex,
|
my_hash_iterate(mp->used_mutex, remove_from_locked_mutex, mp);
|
||||||
(my_hash_walk_action) remove_from_locked_mutex,
|
my_hash_iterate(mp->locked_mutex, remove_from_used_mutex, mp);
|
||||||
mp);
|
|
||||||
my_hash_iterate(mp->locked_mutex,
|
|
||||||
(my_hash_walk_action) remove_from_used_mutex,
|
|
||||||
mp);
|
|
||||||
pthread_mutex_unlock(&THR_LOCK_mutex);
|
pthread_mutex_unlock(&THR_LOCK_mutex);
|
||||||
|
|
||||||
my_hash_free(mp->used_mutex);
|
my_hash_free(mp->used_mutex);
|
||||||
@ -709,15 +700,15 @@ void safe_mutex_end(FILE *file __attribute__((unused)))
|
|||||||
#endif /* SAFE_MUTEX_DETECT_DESTROY */
|
#endif /* SAFE_MUTEX_DETECT_DESTROY */
|
||||||
}
|
}
|
||||||
|
|
||||||
static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
|
static my_bool add_used_to_locked_mutex(void *used, void *locked)
|
||||||
safe_mutex_deadlock_t *locked_mutex)
|
|
||||||
{
|
{
|
||||||
|
safe_mutex_t *used_mutex= used;
|
||||||
|
safe_mutex_deadlock_t *locked_mutex= locked;
|
||||||
/* Add mutex to all parent of the current mutex */
|
/* Add mutex to all parent of the current mutex */
|
||||||
if (!locked_mutex->warning_only)
|
if (!locked_mutex->warning_only)
|
||||||
{
|
{
|
||||||
(void) my_hash_iterate(locked_mutex->mutex->locked_mutex,
|
(void) my_hash_iterate(locked_mutex->mutex->locked_mutex,
|
||||||
(my_hash_walk_action) add_to_locked_mutex,
|
add_to_locked_mutex, used_mutex);
|
||||||
used_mutex);
|
|
||||||
/* mark that locked_mutex is locked after used_mutex */
|
/* mark that locked_mutex is locked after used_mutex */
|
||||||
(void) add_to_locked_mutex(locked_mutex, used_mutex);
|
(void) add_to_locked_mutex(locked_mutex, used_mutex);
|
||||||
}
|
}
|
||||||
@ -729,12 +720,13 @@ static my_bool add_used_to_locked_mutex(safe_mutex_t *used_mutex,
|
|||||||
register that locked_mutex was locked after current_mutex
|
register that locked_mutex was locked after current_mutex
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
|
static my_bool add_to_locked_mutex(void *locked, void *current)
|
||||||
safe_mutex_t *current_mutex)
|
|
||||||
{
|
{
|
||||||
|
safe_mutex_deadlock_t *locked_mutex= locked;
|
||||||
|
safe_mutex_t *current_mutex= current;
|
||||||
DBUG_ENTER("add_to_locked_mutex");
|
DBUG_ENTER("add_to_locked_mutex");
|
||||||
DBUG_PRINT("info", ("inserting 0x%lx into 0x%lx (id: %lu -> %lu)",
|
DBUG_PRINT("info", ("inserting %p into %p (id: %lu -> %lu)",
|
||||||
(ulong) locked_mutex, (long) current_mutex,
|
locked_mutex, current_mutex,
|
||||||
locked_mutex->id, current_mutex->id));
|
locked_mutex->id, current_mutex->id));
|
||||||
if (my_hash_insert(current_mutex->locked_mutex, (uchar*) locked_mutex))
|
if (my_hash_insert(current_mutex->locked_mutex, (uchar*) locked_mutex))
|
||||||
{
|
{
|
||||||
@ -762,13 +754,14 @@ static my_bool add_to_locked_mutex(safe_mutex_deadlock_t *locked_mutex,
|
|||||||
When counter goes to 0, we delete the safe_mutex_deadlock_t entry.
|
When counter goes to 0, we delete the safe_mutex_deadlock_t entry.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
|
static my_bool remove_from_locked_mutex(void *m, void *remove)
|
||||||
safe_mutex_t *delete_mutex)
|
|
||||||
{
|
{
|
||||||
|
safe_mutex_t *mp= m;
|
||||||
|
safe_mutex_t *delete_mutex= remove;
|
||||||
safe_mutex_deadlock_t *found;
|
safe_mutex_deadlock_t *found;
|
||||||
DBUG_ENTER("remove_from_locked_mutex");
|
DBUG_ENTER("remove_from_locked_mutex");
|
||||||
DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
|
DBUG_PRINT("enter", ("delete_mutex: %p mutex: %p (id: %lu <- %lu)",
|
||||||
(ulong) delete_mutex, (ulong) mp,
|
delete_mutex, mp,
|
||||||
delete_mutex->id, mp->id));
|
delete_mutex->id, mp->id));
|
||||||
|
|
||||||
found= (safe_mutex_deadlock_t *) my_hash_search(mp->locked_mutex,
|
found= (safe_mutex_deadlock_t *) my_hash_search(mp->locked_mutex,
|
||||||
@ -786,12 +779,13 @@ static my_bool remove_from_locked_mutex(safe_mutex_t *mp,
|
|||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static my_bool remove_from_used_mutex(safe_mutex_deadlock_t *locked_mutex,
|
static my_bool remove_from_used_mutex(void *locked, void *m)
|
||||||
safe_mutex_t *mutex)
|
|
||||||
{
|
{
|
||||||
|
safe_mutex_deadlock_t *locked_mutex= locked;
|
||||||
|
safe_mutex_t *mutex= m;
|
||||||
DBUG_ENTER("remove_from_used_mutex");
|
DBUG_ENTER("remove_from_used_mutex");
|
||||||
DBUG_PRINT("enter", ("delete_mutex: 0x%lx mutex: 0x%lx (id: %lu <- %lu)",
|
DBUG_PRINT("enter", ("delete_mutex: %p mutex: %p (id: %lu <- %lu)",
|
||||||
(ulong) mutex, (ulong) locked_mutex,
|
mutex, locked_mutex,
|
||||||
mutex->id, locked_mutex->id));
|
mutex->id, locked_mutex->id));
|
||||||
if (my_hash_delete(locked_mutex->mutex->used_mutex, (uchar*) mutex))
|
if (my_hash_delete(locked_mutex->mutex->used_mutex, (uchar*) mutex))
|
||||||
{
|
{
|
||||||
|
@ -424,8 +424,10 @@ static void wt_resource_destroy(uchar *arg)
|
|||||||
It's called from lf_hash when an element is inserted.
|
It's called from lf_hash when an element is inserted.
|
||||||
*/
|
*/
|
||||||
static void wt_resource_init(LF_HASH *hash __attribute__((unused)),
|
static void wt_resource_init(LF_HASH *hash __attribute__((unused)),
|
||||||
WT_RESOURCE *rc, WT_RESOURCE_ID *id)
|
void *resource, const void *ident)
|
||||||
{
|
{
|
||||||
|
WT_RESOURCE *rc= resource;
|
||||||
|
const WT_RESOURCE_ID *id= ident;
|
||||||
DBUG_ENTER("wt_resource_init");
|
DBUG_ENTER("wt_resource_init");
|
||||||
rc->id= *id;
|
rc->id= *id;
|
||||||
rc->waiter_count= 0;
|
rc->waiter_count= 0;
|
||||||
|
11
sql/mdl.cc
11
sql/mdl.cc
@ -762,8 +762,10 @@ struct mdl_iterate_arg
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool mdl_iterate_lock(MDL_lock *lock, mdl_iterate_arg *arg)
|
static my_bool mdl_iterate_lock(void *lk, void *a)
|
||||||
{
|
{
|
||||||
|
MDL_lock *lock= static_cast<MDL_lock*>(lk);
|
||||||
|
mdl_iterate_arg *arg= static_cast<mdl_iterate_arg*>(a);
|
||||||
/*
|
/*
|
||||||
We can skip check for m_strategy here, becase m_granted
|
We can skip check for m_strategy here, becase m_granted
|
||||||
must be empty for such locks anyway.
|
must be empty for such locks anyway.
|
||||||
@ -786,14 +788,13 @@ int mdl_iterate(mdl_iterator_callback callback, void *arg)
|
|||||||
{
|
{
|
||||||
DBUG_ENTER("mdl_iterate");
|
DBUG_ENTER("mdl_iterate");
|
||||||
mdl_iterate_arg argument= { callback, arg };
|
mdl_iterate_arg argument= { callback, arg };
|
||||||
LF_PINS *pins= mdl_locks.get_pins();
|
|
||||||
int res= 1;
|
int res= 1;
|
||||||
|
|
||||||
if (pins)
|
if (LF_PINS *pins= mdl_locks.get_pins())
|
||||||
{
|
{
|
||||||
res= mdl_iterate_lock(mdl_locks.m_backup_lock, &argument) ||
|
res= mdl_iterate_lock(mdl_locks.m_backup_lock, &argument) ||
|
||||||
lf_hash_iterate(&mdl_locks.m_locks, pins,
|
lf_hash_iterate(&mdl_locks.m_locks, pins, mdl_iterate_lock,
|
||||||
(my_hash_walk_action) mdl_iterate_lock, &argument);
|
&argument);
|
||||||
lf_hash_put_pins(pins);
|
lf_hash_put_pins(pins);
|
||||||
}
|
}
|
||||||
DBUG_RETURN(res);
|
DBUG_RETURN(res);
|
||||||
|
@ -252,9 +252,10 @@ public:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool list_open_tables_callback(TDC_element *element,
|
static my_bool list_open_tables_callback(void *el, void *a)
|
||||||
list_open_tables_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
TDC_element *element= static_cast<TDC_element*>(el);
|
||||||
|
list_open_tables_arg *arg= static_cast<list_open_tables_arg*>(a);
|
||||||
const Lex_ident_db
|
const Lex_ident_db
|
||||||
db= Lex_ident_db(Lex_cstring_strlen((const char*) element->m_key));
|
db= Lex_ident_db(Lex_cstring_strlen((const char*) element->m_key));
|
||||||
const char *table_name= db.str + db.length + 1;
|
const char *table_name= db.str + db.length + 1;
|
||||||
@ -302,8 +303,7 @@ OPEN_TABLE_LIST *list_open_tables(THD *thd,
|
|||||||
DBUG_ENTER("list_open_tables");
|
DBUG_ENTER("list_open_tables");
|
||||||
list_open_tables_arg argument(thd, db, wild);
|
list_open_tables_arg argument(thd, db, wild);
|
||||||
|
|
||||||
if (tdc_iterate(thd, (my_hash_walk_action) list_open_tables_callback,
|
if (tdc_iterate(thd, list_open_tables_callback, &argument, true))
|
||||||
&argument, true))
|
|
||||||
DBUG_RETURN(0);
|
DBUG_RETURN(0);
|
||||||
|
|
||||||
DBUG_RETURN(argument.open_list);
|
DBUG_RETURN(argument.open_list);
|
||||||
@ -462,9 +462,10 @@ struct tc_collect_arg
|
|||||||
flush_tables_type flush_type;
|
flush_tables_type flush_type;
|
||||||
};
|
};
|
||||||
|
|
||||||
static my_bool tc_collect_used_shares(TDC_element *element,
|
static my_bool tc_collect_used_shares(void *el, void *a)
|
||||||
tc_collect_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
TDC_element *element= static_cast<TDC_element*>(el);
|
||||||
|
tc_collect_arg *arg= static_cast<tc_collect_arg*>(a);
|
||||||
my_bool result= FALSE;
|
my_bool result= FALSE;
|
||||||
|
|
||||||
DYNAMIC_ARRAY *shares= &arg->shares;
|
DYNAMIC_ARRAY *shares= &arg->shares;
|
||||||
@ -573,8 +574,7 @@ bool flush_tables(THD *thd, flush_tables_type flag)
|
|||||||
my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares,
|
my_init_dynamic_array(PSI_INSTRUMENT_ME, &collect_arg.shares,
|
||||||
sizeof(TABLE_SHARE*), 100, 100, MYF(0));
|
sizeof(TABLE_SHARE*), 100, 100, MYF(0));
|
||||||
collect_arg.flush_type= flag;
|
collect_arg.flush_type= flag;
|
||||||
if (tdc_iterate(thd, (my_hash_walk_action) tc_collect_used_shares,
|
if (tdc_iterate(thd, tc_collect_used_shares, &collect_arg, true))
|
||||||
&collect_arg, true))
|
|
||||||
{
|
{
|
||||||
/* Release already collected shares */
|
/* Release already collected shares */
|
||||||
for (uint i= 0 ; i < collect_arg.shares.elements ; i++)
|
for (uint i= 0 ; i < collect_arg.shares.elements ; i++)
|
||||||
|
@ -133,9 +133,10 @@ struct close_cached_connection_tables_arg
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool close_cached_connection_tables_callback(
|
static my_bool close_cached_connection_tables_callback(void *el, void *a)
|
||||||
TDC_element *element, close_cached_connection_tables_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
TDC_element *element= static_cast<TDC_element*>(el);
|
||||||
|
auto arg= static_cast<close_cached_connection_tables_arg*>(a);
|
||||||
TABLE_LIST *tmp;
|
TABLE_LIST *tmp;
|
||||||
|
|
||||||
mysql_mutex_lock(&element->LOCK_table_share);
|
mysql_mutex_lock(&element->LOCK_table_share);
|
||||||
@ -188,9 +189,7 @@ static bool close_cached_connection_tables(THD *thd, LEX_CSTRING *connection)
|
|||||||
close_cached_connection_tables_arg argument= { thd, connection, 0 };
|
close_cached_connection_tables_arg argument= { thd, connection, 0 };
|
||||||
DBUG_ENTER("close_cached_connections");
|
DBUG_ENTER("close_cached_connections");
|
||||||
|
|
||||||
if (tdc_iterate(thd,
|
if (tdc_iterate(thd, close_cached_connection_tables_callback, &argument))
|
||||||
(my_hash_walk_action) close_cached_connection_tables_callback,
|
|
||||||
&argument))
|
|
||||||
DBUG_RETURN(true);
|
DBUG_RETURN(true);
|
||||||
|
|
||||||
DBUG_RETURN(argument.tables ?
|
DBUG_RETURN(argument.tables ?
|
||||||
|
@ -116,7 +116,7 @@ static void print_cached_tables(void)
|
|||||||
/* purecov: begin tested */
|
/* purecov: begin tested */
|
||||||
puts("DB Table Version Thread Open Lock");
|
puts("DB Table Version Thread Open Lock");
|
||||||
|
|
||||||
tdc_iterate(0, (my_hash_walk_action) print_cached_tables_callback, NULL, true);
|
tdc_iterate(0, print_cached_tables_callback, NULL, true);
|
||||||
|
|
||||||
fflush(stdout);
|
fflush(stdout);
|
||||||
/* purecov: end */
|
/* purecov: end */
|
||||||
|
@ -309,7 +309,7 @@ void tc_purge()
|
|||||||
{
|
{
|
||||||
Share_free_tables::List purge_tables;
|
Share_free_tables::List purge_tables;
|
||||||
|
|
||||||
tdc_iterate(0, (my_hash_walk_action) tc_purge_callback, &purge_tables);
|
tdc_iterate(0, tc_purge_callback, &purge_tables);
|
||||||
while (auto table= purge_tables.pop_front())
|
while (auto table= purge_tables.pop_front())
|
||||||
intern_close_table(table);
|
intern_close_table(table);
|
||||||
}
|
}
|
||||||
@ -1126,7 +1126,7 @@ struct eliminate_duplicates_arg
|
|||||||
|
|
||||||
|
|
||||||
static uchar *eliminate_duplicates_get_key(const uchar *element, size_t *length,
|
static uchar *eliminate_duplicates_get_key(const uchar *element, size_t *length,
|
||||||
my_bool not_used __attribute__((unused)))
|
my_bool)
|
||||||
{
|
{
|
||||||
LEX_STRING *key= (LEX_STRING *) element;
|
LEX_STRING *key= (LEX_STRING *) element;
|
||||||
*length= key->length;
|
*length= key->length;
|
||||||
@ -1134,9 +1134,10 @@ static uchar *eliminate_duplicates_get_key(const uchar *element, size_t *length,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static my_bool eliminate_duplicates(TDC_element *element,
|
static my_bool eliminate_duplicates(void *el, void *a)
|
||||||
eliminate_duplicates_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
TDC_element *element= static_cast<TDC_element*>(el);
|
||||||
|
eliminate_duplicates_arg *arg= static_cast<eliminate_duplicates_arg*>(a);
|
||||||
LEX_STRING *key= (LEX_STRING *) alloc_root(&arg->root, sizeof(LEX_STRING));
|
LEX_STRING *key= (LEX_STRING *) alloc_root(&arg->root, sizeof(LEX_STRING));
|
||||||
|
|
||||||
if (!key || !(key->str= (char*) memdup_root(&arg->root, element->m_key,
|
if (!key || !(key->str= (char*) memdup_root(&arg->root, element->m_key,
|
||||||
@ -1182,7 +1183,7 @@ int tdc_iterate(THD *thd, my_hash_walk_action action, void *argument,
|
|||||||
hash_flags);
|
hash_flags);
|
||||||
no_dups_argument.action= action;
|
no_dups_argument.action= action;
|
||||||
no_dups_argument.argument= argument;
|
no_dups_argument.argument= argument;
|
||||||
action= (my_hash_walk_action) eliminate_duplicates;
|
action= eliminate_duplicates;
|
||||||
argument= &no_dups_argument;
|
argument= &no_dups_argument;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
42
sql/xa.cc
42
sql/xa.cc
@ -126,10 +126,11 @@ public:
|
|||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
static void lf_hash_initializer(LF_HASH *hash __attribute__((unused)),
|
static void lf_hash_initializer(LF_HASH *, void *el, const void *ie)
|
||||||
XID_cache_element *element,
|
|
||||||
XID_cache_insert_element *new_element)
|
|
||||||
{
|
{
|
||||||
|
XID_cache_element *element= static_cast<XID_cache_element*>(el);
|
||||||
|
XID_cache_insert_element *new_element=
|
||||||
|
static_cast<XID_cache_insert_element*>(const_cast<void*>(ie));
|
||||||
DBUG_ASSERT(!element->is_set(ACQUIRED | RECOVERED));
|
DBUG_ASSERT(!element->is_set(ACQUIRED | RECOVERED));
|
||||||
element->rm_error= 0;
|
element->rm_error= 0;
|
||||||
element->xa_state= new_element->xa_state;
|
element->xa_state= new_element->xa_state;
|
||||||
@ -146,11 +147,11 @@ public:
|
|||||||
DBUG_ASSERT(!reinterpret_cast<XID_cache_element*>(ptr + LF_HASH_OVERHEAD)
|
DBUG_ASSERT(!reinterpret_cast<XID_cache_element*>(ptr + LF_HASH_OVERHEAD)
|
||||||
->is_set(ACQUIRED));
|
->is_set(ACQUIRED));
|
||||||
}
|
}
|
||||||
static uchar *key(const XID_cache_element *element, size_t *length,
|
static uchar *key(const unsigned char *el, size_t *length, my_bool)
|
||||||
my_bool not_used __attribute__((unused)))
|
|
||||||
{
|
{
|
||||||
*length= element->xid.key_length();
|
const XID &xid= reinterpret_cast<const XID_cache_element*>(el)->xid;
|
||||||
return element->xid.key();
|
*length= xid.key_length();
|
||||||
|
return xid.key();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -221,11 +222,10 @@ void xid_cache_init()
|
|||||||
{
|
{
|
||||||
xid_cache_inited= true;
|
xid_cache_inited= true;
|
||||||
lf_hash_init(&xid_cache, sizeof(XID_cache_element), LF_HASH_UNIQUE, 0, 0,
|
lf_hash_init(&xid_cache, sizeof(XID_cache_element), LF_HASH_UNIQUE, 0, 0,
|
||||||
(my_hash_get_key) XID_cache_element::key, &my_charset_bin);
|
XID_cache_element::key, &my_charset_bin);
|
||||||
xid_cache.alloc.constructor= XID_cache_element::lf_alloc_constructor;
|
xid_cache.alloc.constructor= XID_cache_element::lf_alloc_constructor;
|
||||||
xid_cache.alloc.destructor= XID_cache_element::lf_alloc_destructor;
|
xid_cache.alloc.destructor= XID_cache_element::lf_alloc_destructor;
|
||||||
xid_cache.initializer=
|
xid_cache.initializer= XID_cache_element::lf_hash_initializer;
|
||||||
(lf_hash_initializer) XID_cache_element::lf_hash_initializer;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -331,9 +331,10 @@ struct xid_cache_iterate_arg
|
|||||||
void *argument;
|
void *argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
static my_bool xid_cache_iterate_callback(XID_cache_element *element,
|
static my_bool xid_cache_iterate_callback(void *el, void *a)
|
||||||
xid_cache_iterate_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
XID_cache_element *element= static_cast<XID_cache_element*>(el);
|
||||||
|
xid_cache_iterate_arg *arg= static_cast<xid_cache_iterate_arg*>(a);
|
||||||
my_bool res= FALSE;
|
my_bool res= FALSE;
|
||||||
if (element->lock())
|
if (element->lock())
|
||||||
{
|
{
|
||||||
@ -348,8 +349,7 @@ static int xid_cache_iterate(THD *thd, my_hash_walk_action action, void *arg)
|
|||||||
xid_cache_iterate_arg argument= { action, arg };
|
xid_cache_iterate_arg argument= { action, arg };
|
||||||
return thd->fix_xid_hash_pins() ? -1 :
|
return thd->fix_xid_hash_pins() ? -1 :
|
||||||
lf_hash_iterate(&xid_cache, thd->xid_hash_pins,
|
lf_hash_iterate(&xid_cache, thd->xid_hash_pins,
|
||||||
(my_hash_walk_action) xid_cache_iterate_callback,
|
xid_cache_iterate_callback, &argument);
|
||||||
&argument);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -1039,17 +1039,19 @@ static my_bool xa_recover_callback(XID_cache_element *xs, Protocol *protocol,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static my_bool xa_recover_callback_short(XID_cache_element *xs,
|
static my_bool xa_recover_callback_short(void *x, void *p)
|
||||||
Protocol *protocol)
|
|
||||||
{
|
{
|
||||||
|
XID_cache_element *xs= static_cast<XID_cache_element*>(x);
|
||||||
|
Protocol *protocol= static_cast<Protocol*>(p);
|
||||||
return xa_recover_callback(xs, protocol, xs->xid.data,
|
return xa_recover_callback(xs, protocol, xs->xid.data,
|
||||||
xs->xid.gtrid_length + xs->xid.bqual_length, &my_charset_bin);
|
xs->xid.gtrid_length + xs->xid.bqual_length, &my_charset_bin);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static my_bool xa_recover_callback_verbose(XID_cache_element *xs,
|
static my_bool xa_recover_callback_verbose(void *x, void *p)
|
||||||
Protocol *protocol)
|
|
||||||
{
|
{
|
||||||
|
XID_cache_element *xs= static_cast<XID_cache_element*>(x);
|
||||||
|
Protocol *protocol= static_cast<Protocol*>(p);
|
||||||
char buf[SQL_XIDSIZE];
|
char buf[SQL_XIDSIZE];
|
||||||
uint len= get_sql_xid(&xs->xid, buf);
|
uint len= get_sql_xid(&xs->xid, buf);
|
||||||
return xa_recover_callback(xs, protocol, buf, len,
|
return xa_recover_callback(xs, protocol, buf, len,
|
||||||
@ -1082,13 +1084,13 @@ bool mysql_xa_recover(THD *thd)
|
|||||||
{
|
{
|
||||||
len= SQL_XIDSIZE;
|
len= SQL_XIDSIZE;
|
||||||
cs= &my_charset_utf8mb3_general_ci;
|
cs= &my_charset_utf8mb3_general_ci;
|
||||||
action= (my_hash_walk_action) xa_recover_callback_verbose;
|
action= xa_recover_callback_verbose;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
len= XIDDATASIZE;
|
len= XIDDATASIZE;
|
||||||
cs= &my_charset_bin;
|
cs= &my_charset_bin;
|
||||||
action= (my_hash_walk_action) xa_recover_callback_short;
|
action= xa_recover_callback_short;
|
||||||
}
|
}
|
||||||
|
|
||||||
field_list.push_back(new (mem_root)
|
field_list.push_back(new (mem_root)
|
||||||
|
@ -453,10 +453,10 @@ class rw_trx_hash_t
|
|||||||
not accessible by concurrent threads.
|
not accessible by concurrent threads.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static void rw_trx_hash_initializer(LF_HASH *,
|
static void rw_trx_hash_initializer(LF_HASH *, void *el, const void *t)
|
||||||
rw_trx_hash_element_t *element,
|
|
||||||
trx_t *trx)
|
|
||||||
{
|
{
|
||||||
|
rw_trx_hash_element_t *element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
trx_t *trx= static_cast<trx_t*>(const_cast<void*>(t));
|
||||||
ut_ad(element->trx == 0);
|
ut_ad(element->trx == 0);
|
||||||
element->trx= trx;
|
element->trx= trx;
|
||||||
element->id= trx->id;
|
element->id= trx->id;
|
||||||
@ -470,7 +470,7 @@ class rw_trx_hash_t
|
|||||||
|
|
||||||
Pins are used to protect object from being destroyed or reused. They are
|
Pins are used to protect object from being destroyed or reused. They are
|
||||||
normally stored in trx object for quick access. If caller doesn't have trx
|
normally stored in trx object for quick access. If caller doesn't have trx
|
||||||
available, we try to get it using currnet_trx(). If caller doesn't have trx
|
available, we try to get it using current_trx(). If caller doesn't have trx
|
||||||
at all, temporary pins are allocated.
|
at all, temporary pins are allocated.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -496,9 +496,10 @@ class rw_trx_hash_t
|
|||||||
|
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
static my_bool eliminate_duplicates(rw_trx_hash_element_t *element,
|
static my_bool eliminate_duplicates(void *el, void *a)
|
||||||
eliminate_duplicates_arg<T> *arg)
|
|
||||||
{
|
{
|
||||||
|
rw_trx_hash_element_t *element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
auto arg= static_cast<eliminate_duplicates_arg<T>*>(a);
|
||||||
for (trx_ids_t::iterator it= arg->ids.begin(); it != arg->ids.end(); it++)
|
for (trx_ids_t::iterator it= arg->ids.begin(); it != arg->ids.end(); it++)
|
||||||
{
|
{
|
||||||
if (*it == element->id)
|
if (*it == element->id)
|
||||||
@ -524,17 +525,17 @@ class rw_trx_hash_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T> struct debug_iterator_arg
|
struct debug_iterator_arg
|
||||||
{
|
{
|
||||||
walk_action<T> *action;
|
my_hash_walk_action action;
|
||||||
T *argument;
|
void *argument;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
static my_bool debug_iterator(void *el, void *a)
|
||||||
static my_bool debug_iterator(rw_trx_hash_element_t *element,
|
|
||||||
debug_iterator_arg<T> *arg)
|
|
||||||
{
|
{
|
||||||
|
rw_trx_hash_element_t *element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
debug_iterator_arg *arg= static_cast<debug_iterator_arg*>(a);
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (element->trx)
|
if (element->trx)
|
||||||
validate_element(element->trx);
|
validate_element(element->trx);
|
||||||
@ -744,7 +745,7 @@ public:
|
|||||||
|
|
||||||
@param caller_trx used to get/set pins
|
@param caller_trx used to get/set pins
|
||||||
@param action called for every element in hash
|
@param action called for every element in hash
|
||||||
@param argument opque argument passed to action
|
@param argument opaque argument passed to action
|
||||||
|
|
||||||
May return the same element multiple times if hash is under contention.
|
May return the same element multiple times if hash is under contention.
|
||||||
If caller doesn't like to see the same transaction multiple times, it has
|
If caller doesn't like to see the same transaction multiple times, it has
|
||||||
@ -767,28 +768,24 @@ public:
|
|||||||
@retval 1 iteration was interrupted (action returned 1)
|
@retval 1 iteration was interrupted (action returned 1)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
template <typename T>
|
int iterate(trx_t *caller_trx, my_hash_walk_action action,
|
||||||
int iterate(trx_t *caller_trx, walk_action<T> *action, T *argument= nullptr)
|
void *argument= nullptr)
|
||||||
{
|
{
|
||||||
LF_PINS *pins= caller_trx ? get_pins(caller_trx) : lf_hash_get_pins(&hash);
|
LF_PINS *pins= caller_trx ? get_pins(caller_trx) : lf_hash_get_pins(&hash);
|
||||||
ut_a(pins);
|
ut_a(pins);
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
debug_iterator_arg<T> debug_arg= { action, argument };
|
debug_iterator_arg debug_arg= { action, argument };
|
||||||
action= reinterpret_cast<decltype(action)>(debug_iterator<T>);
|
action= debug_iterator;
|
||||||
argument= reinterpret_cast<T*>(&debug_arg);
|
argument= reinterpret_cast<void*>(&debug_arg);
|
||||||
#endif
|
#endif
|
||||||
int res= lf_hash_iterate(&hash, pins,
|
int res= lf_hash_iterate(&hash, pins, action, argument);
|
||||||
reinterpret_cast<my_hash_walk_action>(action),
|
|
||||||
const_cast<void*>(static_cast<const void*>
|
|
||||||
(argument)));
|
|
||||||
if (!caller_trx)
|
if (!caller_trx)
|
||||||
lf_hash_put_pins(pins);
|
lf_hash_put_pins(pins);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
template <typename T>
|
int iterate(my_hash_walk_action action, void *argument= nullptr)
|
||||||
int iterate(walk_action<T> *action, T *argument= nullptr)
|
|
||||||
{
|
{
|
||||||
return iterate(current_trx(), action, argument);
|
return iterate(current_trx(), action, argument);
|
||||||
}
|
}
|
||||||
@ -1176,9 +1173,10 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static my_bool get_min_trx_id_callback(rw_trx_hash_element_t *element,
|
static my_bool get_min_trx_id_callback(void *el, void *i)
|
||||||
trx_id_t *id)
|
|
||||||
{
|
{
|
||||||
|
auto element= static_cast<rw_trx_hash_element_t *>(el);
|
||||||
|
auto id= static_cast<trx_id_t*>(i);
|
||||||
if (element->id < *id)
|
if (element->id < *id)
|
||||||
{
|
{
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
@ -1200,9 +1198,10 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool copy_one_id(rw_trx_hash_element_t *element,
|
static my_bool copy_one_id(void* el, void *a)
|
||||||
snapshot_ids_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
auto element= static_cast<const rw_trx_hash_element_t *>(el);
|
||||||
|
auto arg= static_cast<snapshot_ids_arg*>(a);
|
||||||
if (element->id < arg->m_id)
|
if (element->id < arg->m_id)
|
||||||
{
|
{
|
||||||
trx_id_t no= element->no;
|
trx_id_t no= element->no;
|
||||||
|
@ -5234,8 +5234,9 @@ static void lock_rec_block_validate(const page_id_t page_id)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static my_bool lock_validate_table_locks(rw_trx_hash_element_t *element, void*)
|
static my_bool lock_validate_table_locks(void *el, void*)
|
||||||
{
|
{
|
||||||
|
rw_trx_hash_element_t *element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
ut_ad(lock_mutex_own());
|
ut_ad(lock_mutex_own());
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (element->trx)
|
if (element->trx)
|
||||||
@ -5499,10 +5500,10 @@ struct lock_rec_other_trx_holds_expl_arg
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool lock_rec_other_trx_holds_expl_callback(
|
static my_bool lock_rec_other_trx_holds_expl_callback(void *el, void *a)
|
||||||
rw_trx_hash_element_t *element,
|
|
||||||
lock_rec_other_trx_holds_expl_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
auto element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
auto arg= static_cast<lock_rec_other_trx_holds_expl_arg*>(a);
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (element->trx)
|
if (element->trx)
|
||||||
{
|
{
|
||||||
@ -6325,13 +6326,14 @@ lock_table_get_n_locks(
|
|||||||
/**
|
/**
|
||||||
Do an exhaustive check for any locks (table or rec) against the table.
|
Do an exhaustive check for any locks (table or rec) against the table.
|
||||||
|
|
||||||
@param[in] table check if there are any locks held on records in this table
|
@param t check if there are any locks held on records in this table
|
||||||
or on the table itself
|
or on the table itself
|
||||||
*/
|
*/
|
||||||
|
|
||||||
static my_bool lock_table_locks_lookup(rw_trx_hash_element_t *element,
|
static my_bool lock_table_locks_lookup(void *el, void *t)
|
||||||
const dict_table_t *table)
|
|
||||||
{
|
{
|
||||||
|
auto element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
const dict_table_t *table= static_cast<const dict_table_t*>(t);
|
||||||
ut_ad(lock_mutex_own());
|
ut_ad(lock_mutex_own());
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (element->trx)
|
if (element->trx)
|
||||||
@ -6381,7 +6383,9 @@ lock_table_has_locks(
|
|||||||
|
|
||||||
#ifdef UNIV_DEBUG
|
#ifdef UNIV_DEBUG
|
||||||
if (!has_locks) {
|
if (!has_locks) {
|
||||||
trx_sys.rw_trx_hash.iterate(lock_table_locks_lookup, table);
|
trx_sys.rw_trx_hash.iterate(lock_table_locks_lookup,
|
||||||
|
const_cast<void*>
|
||||||
|
(static_cast<const void*>(table)));
|
||||||
}
|
}
|
||||||
#endif /* UNIV_DEBUG */
|
#endif /* UNIV_DEBUG */
|
||||||
|
|
||||||
|
@ -2053,9 +2053,9 @@ static my_bool trx_recover_for_mysql_callback(rw_trx_hash_element_t *element,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static my_bool trx_recover_reset_callback(rw_trx_hash_element_t *element,
|
static my_bool trx_recover_reset_callback(void *el, void*)
|
||||||
void*)
|
|
||||||
{
|
{
|
||||||
|
rw_trx_hash_element_t *element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (trx_t *trx= element->trx)
|
if (trx_t *trx= element->trx)
|
||||||
{
|
{
|
||||||
@ -2107,9 +2107,10 @@ struct trx_get_trx_by_xid_callback_arg
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static my_bool trx_get_trx_by_xid_callback(rw_trx_hash_element_t *element,
|
static my_bool trx_get_trx_by_xid_callback(void *el, void *a)
|
||||||
trx_get_trx_by_xid_callback_arg *arg)
|
|
||||||
{
|
{
|
||||||
|
auto element= static_cast<rw_trx_hash_element_t*>(el);
|
||||||
|
auto arg= static_cast<trx_get_trx_by_xid_callback_arg*>(a);
|
||||||
my_bool found= 0;
|
my_bool found= 0;
|
||||||
mutex_enter(&element->mutex);
|
mutex_enter(&element->mutex);
|
||||||
if (trx_t *trx= element->trx)
|
if (trx_t *trx= element->trx)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user