Commit c4ce446f authored by Mikael Ronstrom's avatar Mikael Ronstrom

Backported my_atomic from 6.0-codebase and added support for 64-bit atomics to...

Backported my_atomic from 6.0-codebase and added support for 64-bit atomics to enable removal of LOCK_thread_count from every query, removed LOCK_thread_count from use in dispatch_command and close of query which is used in every query, now uses atomic increments/decrements instead
parent 6e4f01fa
...@@ -38,7 +38,7 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \ ...@@ -38,7 +38,7 @@ noinst_HEADERS = config-win.h config-netware.h my_bit.h \
thr_lock.h t_ctype.h violite.h my_md5.h base64.h \ thr_lock.h t_ctype.h violite.h my_md5.h base64.h \
my_handler.h my_time.h \ my_handler.h my_time.h \
my_vle.h my_user.h my_atomic.h atomic/nolock.h \ my_vle.h my_user.h my_atomic.h atomic/nolock.h \
atomic/rwlock.h atomic/x86-gcc.h atomic/x86-msvc.h \ atomic/rwlock.h atomic/x86-gcc.h atomic/generic-msvc.h \
atomic/solaris.h \ atomic/solaris.h \
atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h atomic/gcc_builtins.h my_libwrap.h my_stacktrace.h
......
#ifndef ATOMIC_RWLOCK_INCLUDED
#define ATOMIC_RWLOCK_INCLUDED
/* Copyright (C) 2006 MySQL AB /* Copyright (C) 2006 MySQL AB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
...@@ -13,7 +16,8 @@ ...@@ -13,7 +16,8 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t; typedef struct {pthread_mutex_t rw;} my_atomic_rwlock_t;
#define MY_ATOMIC_MODE_RWLOCKS 1
#ifdef MY_ATOMIC_MODE_DUMMY #ifdef MY_ATOMIC_MODE_DUMMY
/* /*
...@@ -31,18 +35,27 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t; ...@@ -31,18 +35,27 @@ typedef struct {pthread_rwlock_t rw;} my_atomic_rwlock_t;
#define my_atomic_rwlock_wrunlock(name) #define my_atomic_rwlock_wrunlock(name)
#define MY_ATOMIC_MODE "dummy (non-atomic)" #define MY_ATOMIC_MODE "dummy (non-atomic)"
#else #else
#define my_atomic_rwlock_destroy(name) pthread_rwlock_destroy(& (name)->rw) /*
#define my_atomic_rwlock_init(name) pthread_rwlock_init(& (name)->rw, 0) we're using read-write lock macros but map them to mutex locks, and they're
#define my_atomic_rwlock_rdlock(name) pthread_rwlock_rdlock(& (name)->rw) faster. Still, having semantically rich API we can change the
#define my_atomic_rwlock_wrlock(name) pthread_rwlock_wrlock(& (name)->rw) underlying implementation, if necessary.
#define my_atomic_rwlock_rdunlock(name) pthread_rwlock_unlock(& (name)->rw) */
#define my_atomic_rwlock_wrunlock(name) pthread_rwlock_unlock(& (name)->rw) #define my_atomic_rwlock_destroy(name) pthread_mutex_destroy(& (name)->rw)
#define MY_ATOMIC_MODE "rwlocks" #define my_atomic_rwlock_init(name) pthread_mutex_init(& (name)->rw, 0)
#define my_atomic_rwlock_rdlock(name) pthread_mutex_lock(& (name)->rw)
#define my_atomic_rwlock_wrlock(name) pthread_mutex_lock(& (name)->rw)
#define my_atomic_rwlock_rdunlock(name) pthread_mutex_unlock(& (name)->rw)
#define my_atomic_rwlock_wrunlock(name) pthread_mutex_unlock(& (name)->rw)
#define MY_ATOMIC_MODE "mutex"
#ifndef MY_ATOMIC_MODE_RWLOCKS
#define MY_ATOMIC_MODE_RWLOCKS 1
#endif
#endif #endif
#define make_atomic_add_body(S) int ## S sav; sav= *a; *a+= v; v=sav; #define make_atomic_add_body(S) int ## S sav; sav= *a; *a+= v; v=sav;
#define make_atomic_swap_body(S) int ## S sav; sav= *a; *a= v; v=sav; #define make_atomic_fas_body(S) int ## S sav; sav= *a; *a= v; v=sav;
#define make_atomic_cas_body(S) if ((ret= (*a == *cmp))) *a= set; else *cmp=*a; #define make_atomic_cas_body(S) if ((ret= (*a == *cmp))) *a= set; else *cmp=*a;
#define make_atomic_load_body(S) ret= *a; #define make_atomic_load_body(S) ret= *a;
#define make_atomic_store_body(S) *a= v; #define make_atomic_store_body(S) *a= v;
#endif /* ATOMIC_RWLOCK_INCLUDED */
...@@ -42,15 +42,37 @@ ...@@ -42,15 +42,37 @@
#endif #endif
#ifndef MY_ATOMIC_NO_XADD #ifndef MY_ATOMIC_NO_XADD
#define make_atomic_add_body(S) \ #define make_atomic_add_body(S) make_atomic_add_body ## S
asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a)) #define make_atomic_cas_body(S) make_atomic_cas_body ## S
#endif #endif
#define make_atomic_fas_body(S) \
asm volatile ("xchg %0, %1;" : "+q" (v) , "+m" (*a)) #define make_atomic_add_body32 \
#define make_atomic_cas_body(S) \ asm volatile (LOCK_prefix "; xadd %0, %1;" : "+r" (v) , "+m" (*a))
#define make_atomic_cas_body32 \
asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \ asm volatile (LOCK_prefix "; cmpxchg %3, %0; setz %2;" \
: "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set)) : "+m" (*a), "+a" (*cmp), "=q" (ret): "r" (set))
#define make_atomic_cas_bodyptr make_atomic_cas_body32
#ifndef __x86_64__
#define make_atomic_add_body64 make_atomic_add_body32
#define make_atomic_cas_body64 make_atomic_cas_body32
#else
#define make_atomic_add_body64 \
int64 tmp=*a; \
while (!my_atomic_cas64(a, &tmp, tmp+v)); \
v=tmp;
#define make_atomic_cas_body64 \
int32 ebx=(set & 0xFFFFFFFF), ecx=(set >> 32); \
asm volatile (LOCK_prefix "; cmpxchg8b %0; setz %2;" \
: "+m" (*a), "+A" (*cmp), "=q" (ret) \
:"b" (ebx), "c" (ecx))
#endif
#define make_atomic_fas_body(S) \
asm volatile ("xchg %0, %1;" : "+r" (v) , "+m" (*a))
#ifdef MY_ATOMIC_MODE_DUMMY #ifdef MY_ATOMIC_MODE_DUMMY
#define make_atomic_load_body(S) ret=*a #define make_atomic_load_body(S) ret=*a
#define make_atomic_store_body(S) *a=v #define make_atomic_store_body(S) *a=v
......
...@@ -37,7 +37,7 @@ ...@@ -37,7 +37,7 @@
my_atomic_store#(&var, what) my_atomic_store#(&var, what)
store 'what' in *var store 'what' in *var
'#' is substituted by a size suffix - 8, 16, 32, or ptr '#' is substituted by a size suffix - 8, 16, 32, 64, or ptr
(e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr). (e.g. my_atomic_add8, my_atomic_fas32, my_atomic_casptr).
NOTE This operations are not always atomic, so they always must be NOTE This operations are not always atomic, so they always must be
...@@ -129,6 +129,7 @@ ...@@ -129,6 +129,7 @@
make_transparent_unions(8) make_transparent_unions(8)
make_transparent_unions(16) make_transparent_unions(16)
make_transparent_unions(32) make_transparent_unions(32)
make_transparent_unions(64)
make_transparent_unions(ptr) make_transparent_unions(ptr)
#undef uintptr #undef uintptr
#undef make_transparent_unions #undef make_transparent_unions
...@@ -140,10 +141,12 @@ make_transparent_unions(ptr) ...@@ -140,10 +141,12 @@ make_transparent_unions(ptr)
#define U_8 int8 #define U_8 int8
#define U_16 int16 #define U_16 int16
#define U_32 int32 #define U_32 int32
#define U_64 int64
#define U_ptr intptr #define U_ptr intptr
#define Uv_8 int8 #define Uv_8 int8
#define Uv_16 int16 #define Uv_16 int16
#define Uv_32 int32 #define Uv_32 int32
#define Uv_64 int64
#define Uv_ptr intptr #define Uv_ptr intptr
#define U_a volatile *a #define U_a volatile *a
#define U_cmp *cmp #define U_cmp *cmp
...@@ -217,6 +220,7 @@ make_atomic_cas(8) ...@@ -217,6 +220,7 @@ make_atomic_cas(8)
make_atomic_cas(16) make_atomic_cas(16)
#endif #endif
make_atomic_cas(32) make_atomic_cas(32)
make_atomic_cas(64)
make_atomic_cas(ptr) make_atomic_cas(ptr)
#ifdef MY_ATOMIC_HAS_8_16 #ifdef MY_ATOMIC_HAS_8_16
...@@ -224,12 +228,14 @@ make_atomic_add(8) ...@@ -224,12 +228,14 @@ make_atomic_add(8)
make_atomic_add(16) make_atomic_add(16)
#endif #endif
make_atomic_add(32) make_atomic_add(32)
make_atomic_add(64)
#ifdef MY_ATOMIC_HAS_8_16 #ifdef MY_ATOMIC_HAS_8_16
make_atomic_load(8) make_atomic_load(8)
make_atomic_load(16) make_atomic_load(16)
#endif #endif
make_atomic_load(32) make_atomic_load(32)
make_atomic_load(64)
make_atomic_load(ptr) make_atomic_load(ptr)
#ifdef MY_ATOMIC_HAS_8_16 #ifdef MY_ATOMIC_HAS_8_16
...@@ -237,6 +243,7 @@ make_atomic_fas(8) ...@@ -237,6 +243,7 @@ make_atomic_fas(8)
make_atomic_fas(16) make_atomic_fas(16)
#endif #endif
make_atomic_fas(32) make_atomic_fas(32)
make_atomic_fas(64)
make_atomic_fas(ptr) make_atomic_fas(ptr)
#ifdef MY_ATOMIC_HAS_8_16 #ifdef MY_ATOMIC_HAS_8_16
...@@ -244,6 +251,7 @@ make_atomic_store(8) ...@@ -244,6 +251,7 @@ make_atomic_store(8)
make_atomic_store(16) make_atomic_store(16)
#endif #endif
make_atomic_store(32) make_atomic_store(32)
make_atomic_store(64)
make_atomic_store(ptr) make_atomic_store(ptr)
#ifdef _atomic_h_cleanup_ #ifdef _atomic_h_cleanup_
...@@ -254,10 +262,12 @@ make_atomic_store(ptr) ...@@ -254,10 +262,12 @@ make_atomic_store(ptr)
#undef U_8 #undef U_8
#undef U_16 #undef U_16
#undef U_32 #undef U_32
#undef U_64
#undef U_ptr #undef U_ptr
#undef Uv_8 #undef Uv_8
#undef Uv_16 #undef Uv_16
#undef Uv_32 #undef Uv_32
#undef Uv_64
#undef Uv_ptr #undef Uv_ptr
#undef a #undef a
#undef cmp #undef cmp
......
...@@ -832,6 +832,8 @@ typedef SOCKET_SIZE_TYPE size_socket; ...@@ -832,6 +832,8 @@ typedef SOCKET_SIZE_TYPE size_socket;
#endif #endif
#endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/ #endif /* defined (HAVE_LONG_LONG) && !defined(ULONGLONG_MAX)*/
#define INT_MIN64 (~0x7FFFFFFFFFFFFFFFLL)
#define INT_MAX64 0x7FFFFFFFFFFFFFFFLL
#define INT_MIN32 (~0x7FFFFFFFL) #define INT_MIN32 (~0x7FFFFFFFL)
#define INT_MAX32 0x7FFFFFFFL #define INT_MAX32 0x7FFFFFFFL
#define UINT_MAX32 0xFFFFFFFFL #define UINT_MAX32 0xFFFFFFFFL
......
...@@ -132,9 +132,10 @@ post_init_event_thread(THD *thd) ...@@ -132,9 +132,10 @@ post_init_event_thread(THD *thd)
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
threads.append(thd); threads.append(thd);
thread_count++; thread_count++;
thread_running++;
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
my_atomic_rwlock_wrlock(&global_query_id_lock);
inc_thread_running();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
return FALSE; return FALSE;
} }
...@@ -156,10 +157,12 @@ deinit_event_thread(THD *thd) ...@@ -156,10 +157,12 @@ deinit_event_thread(THD *thd)
DBUG_PRINT("exit", ("Event thread finishing")); DBUG_PRINT("exit", ("Event thread finishing"));
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
thread_count--; thread_count--;
thread_running--;
delete thd; delete thd;
pthread_cond_broadcast(&COND_thread_count); pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
my_atomic_rwlock_wrlock(&global_query_id_lock);
dec_thread_running();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
} }
...@@ -417,10 +420,12 @@ Event_scheduler::start() ...@@ -417,10 +420,12 @@ Event_scheduler::start()
net_end(&new_thd->net); net_end(&new_thd->net);
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
thread_count--; thread_count--;
thread_running--;
delete new_thd; delete new_thd;
pthread_cond_broadcast(&COND_thread_count); pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
my_atomic_rwlock_wrlock(&global_query_id_lock);
dec_thread_running();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
} }
end: end:
UNLOCK_DATA(); UNLOCK_DATA();
...@@ -550,10 +555,12 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name) ...@@ -550,10 +555,12 @@ Event_scheduler::execute_top(Event_queue_element_for_exec *event_name)
net_end(&new_thd->net); net_end(&new_thd->net);
pthread_mutex_lock(&LOCK_thread_count); pthread_mutex_lock(&LOCK_thread_count);
thread_count--; thread_count--;
thread_running--;
delete new_thd; delete new_thd;
pthread_cond_broadcast(&COND_thread_count); pthread_cond_broadcast(&COND_thread_count);
pthread_mutex_unlock(&LOCK_thread_count); pthread_mutex_unlock(&LOCK_thread_count);
my_atomic_rwlock_wrlock(&global_query_id_lock);
dec_thread_running();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
} }
delete event_name; delete event_name;
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
......
...@@ -3026,9 +3026,9 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli, ...@@ -3026,9 +3026,9 @@ int Query_log_event::do_apply_event(Relay_log_info const *rli,
{ {
thd->set_time((time_t)when); thd->set_time((time_t)when);
thd->set_query((char*)query_arg, q_len_arg); thd->set_query((char*)query_arg, q_len_arg);
VOID(pthread_mutex_lock(&LOCK_thread_count)); my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id = next_query_id(); thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count)); my_atomic_rwlock_wrunlock(&global_query_id_lock);
thd->variables.pseudo_thread_id= thread_id; // for temp tables thd->variables.pseudo_thread_id= thread_id; // for temp tables
DBUG_PRINT("query",("%s",thd->query)); DBUG_PRINT("query",("%s",thd->query));
...@@ -4504,9 +4504,9 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli, ...@@ -4504,9 +4504,9 @@ int Load_log_event::do_apply_event(NET* net, Relay_log_info const *rli,
if (rpl_filter->db_ok(thd->db)) if (rpl_filter->db_ok(thd->db))
{ {
thd->set_time((time_t)when); thd->set_time((time_t)when);
VOID(pthread_mutex_lock(&LOCK_thread_count)); my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id = next_query_id(); thd->query_id = next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count)); my_atomic_rwlock_wrunlock(&global_query_id_lock);
/* /*
Initing thd->row_count is not necessary in theory as this variable has no Initing thd->row_count is not necessary in theory as this variable has no
influence in the case of the slave SQL thread (it is used to generate a influence in the case of the slave SQL thread (it is used to generate a
...@@ -8025,9 +8025,9 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli) ...@@ -8025,9 +8025,9 @@ int Table_map_log_event::do_apply_event(Relay_log_info const *rli)
DBUG_ASSERT(rli->sql_thd == thd); DBUG_ASSERT(rli->sql_thd == thd);
/* Step the query id to mark what columns that are actually used. */ /* Step the query id to mark what columns that are actually used. */
pthread_mutex_lock(&LOCK_thread_count); my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id= next_query_id(); thd->query_id= next_query_id();
pthread_mutex_unlock(&LOCK_thread_count); my_atomic_rwlock_wrunlock(&global_query_id_lock);
if (!(memory= my_multi_malloc(MYF(MY_WME), if (!(memory= my_multi_malloc(MYF(MY_WME),
&table_list, (uint) sizeof(RPL_TABLE_LIST), &table_list, (uint) sizeof(RPL_TABLE_LIST),
......
...@@ -43,6 +43,7 @@ ...@@ -43,6 +43,7 @@
#include "sql_array.h" #include "sql_array.h"
#include "sql_plugin.h" #include "sql_plugin.h"
#include "scheduler.h" #include "scheduler.h"
#include <my_atomic.h>
class Parser_state; class Parser_state;
...@@ -75,11 +76,49 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */ ...@@ -75,11 +76,49 @@ typedef ulong nesting_map; /* Used for flags of nesting constructs */
typedef ulonglong nested_join_map; typedef ulonglong nested_join_map;
/* query_id */ /* query_id */
typedef ulonglong query_id_t; typedef int64 query_id_t;
extern query_id_t global_query_id; extern query_id_t global_query_id;
extern int32 thread_running;
extern my_atomic_rwlock_t global_query_id_lock;
/* increment query_id and return it. */ /* increment query_id and return it. */
inline query_id_t next_query_id() { return global_query_id++; } inline query_id_t next_query_id()
{
query_id_t id;
id= my_atomic_add64(&global_query_id, 1);
return (id+1);
}
inline query_id_t get_query_id()
{
query_id_t id;
id= my_atomic_load64(&global_query_id);
return id;
}
inline int32
inc_thread_running()
{
int32 num_thread_running;
num_thread_running= my_atomic_add32(&thread_running, 1);
return (num_thread_running+1);
}
inline int32
dec_thread_running()
{
int32 num_thread_running;
num_thread_running= my_atomic_add32(&thread_running, -1);
return (num_thread_running-1);
}
inline int32
get_thread_running()
{
int32 num_thread_running;
num_thread_running= my_atomic_load32(&thread_running);
return num_thread_running;
}
/* useful constants */ /* useful constants */
extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty; extern MYSQL_PLUGIN_IMPORT const key_map key_map_empty;
...@@ -1994,7 +2033,7 @@ extern bool opt_ignore_builtin_innodb; ...@@ -1994,7 +2033,7 @@ extern bool opt_ignore_builtin_innodb;
extern my_bool opt_character_set_client_handshake; extern my_bool opt_character_set_client_handshake;
extern bool volatile abort_loop, shutdown_in_progress; extern bool volatile abort_loop, shutdown_in_progress;
extern bool in_bootstrap; extern bool in_bootstrap;
extern uint volatile thread_count, thread_running, global_read_lock; extern uint volatile thread_count, global_read_lock;
extern uint connection_count; extern uint connection_count;
extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types; extern my_bool opt_sql_bin_update, opt_safe_user_create, opt_no_mix_types;
extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap; extern my_bool opt_safe_show_db, opt_local_infile, opt_myisam_use_mmap;
......
...@@ -523,7 +523,8 @@ uint mysqld_port_timeout; ...@@ -523,7 +523,8 @@ uint mysqld_port_timeout;
uint delay_key_write_options, protocol_version; uint delay_key_write_options, protocol_version;
uint lower_case_table_names; uint lower_case_table_names;
uint tc_heuristic_recover= 0; uint tc_heuristic_recover= 0;
uint volatile thread_count, thread_running; uint volatile thread_count;
int32 thread_running;
ulonglong thd_startup_options; ulonglong thd_startup_options;
ulong back_log, connect_timeout, concurrency, server_id; ulong back_log, connect_timeout, concurrency, server_id;
ulong table_cache_size, table_def_size; ulong table_cache_size, table_def_size;
...@@ -539,6 +540,7 @@ ulonglong max_binlog_cache_size=0; ...@@ -539,6 +540,7 @@ ulonglong max_binlog_cache_size=0;
ulong query_cache_size=0; ulong query_cache_size=0;
ulong refresh_version; /* Increments on each reload */ ulong refresh_version; /* Increments on each reload */
query_id_t global_query_id; query_id_t global_query_id;
my_atomic_rwlock_t global_query_id_lock;
ulong aborted_threads, aborted_connects; ulong aborted_threads, aborted_connects;
ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size; ulong delayed_insert_timeout, delayed_insert_limit, delayed_queue_size;
ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use; ulong delayed_insert_threads, delayed_insert_writes, delayed_rows_in_use;
...@@ -1349,6 +1351,7 @@ void clean_up(bool print_message) ...@@ -1349,6 +1351,7 @@ void clean_up(bool print_message)
DBUG_PRINT("quit", ("Error messages freed")); DBUG_PRINT("quit", ("Error messages freed"));
/* Tell main we are ready */ /* Tell main we are ready */
logger.cleanup_end(); logger.cleanup_end();
my_atomic_rwlock_destroy(&global_query_id_lock);
(void) pthread_mutex_lock(&LOCK_thread_count); (void) pthread_mutex_lock(&LOCK_thread_count);
DBUG_PRINT("quit", ("got thread count lock")); DBUG_PRINT("quit", ("got thread count lock"));
ready_to_exit=1; ready_to_exit=1;
...@@ -7730,6 +7733,7 @@ static int mysql_init_variables(void) ...@@ -7730,6 +7733,7 @@ static int mysql_init_variables(void)
what_to_log= ~ (1L << (uint) COM_TIME); what_to_log= ~ (1L << (uint) COM_TIME);
refresh_version= 1L; /* Increments on each reload */ refresh_version= 1L; /* Increments on each reload */
global_query_id= thread_id= 1L; global_query_id= thread_id= 1L;
my_atomic_rwlock_init(&global_query_id_lock);
strmov(server_version, MYSQL_SERVER_VERSION); strmov(server_version, MYSQL_SERVER_VERSION);
myisam_recover_options_str= sql_mode_str= "OFF"; myisam_recover_options_str= sql_mode_str= "OFF";
myisam_stats_method_str= "nulls_unequal"; myisam_stats_method_str= "nulls_unequal";
......
...@@ -2702,9 +2702,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp, ...@@ -2702,9 +2702,9 @@ sp_lex_keeper::reset_lex_and_exec_core(THD *thd, uint *nextp,
*/ */
thd->lex= m_lex; thd->lex= m_lex;
VOID(pthread_mutex_lock(&LOCK_thread_count)); my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id= next_query_id(); thd->query_id= next_query_id();
VOID(pthread_mutex_unlock(&LOCK_thread_count)); my_atomic_rwlock_wrunlock(&global_query_id_lock);
if (thd->prelocked_mode == NON_PRELOCKED) if (thd->prelocked_mode == NON_PRELOCKED)
{ {
......
...@@ -505,7 +505,9 @@ pthread_handler_t handle_bootstrap(void *arg) ...@@ -505,7 +505,9 @@ pthread_handler_t handle_bootstrap(void *arg)
We don't need to obtain LOCK_thread_count here because in bootstrap We don't need to obtain LOCK_thread_count here because in bootstrap
mode we have only one thread. mode we have only one thread.
*/ */
my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id=next_query_id(); thd->query_id=next_query_id();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
thd->set_time(); thd->set_time();
mysql_parse(thd, thd->query, length, & found_semicolon); mysql_parse(thd, thd->query, length, & found_semicolon);
close_thread_tables(thd); // Free tables close_thread_tables(thd); // Free tables
...@@ -971,29 +973,30 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -971,29 +973,30 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd->enable_slow_log= TRUE; thd->enable_slow_log= TRUE;
thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */ thd->lex->sql_command= SQLCOM_END; /* to avoid confusing VIEW detectors */
thd->set_time(); thd->set_time();
VOID(pthread_mutex_lock(&LOCK_thread_count)); my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id= global_query_id; {
query_id_t query_id;
switch( command ) { switch( command ) {
/* Ignore these statements. */ /* Ignore these statements. */
case COM_STATISTICS: case COM_STATISTICS:
case COM_PING: case COM_PING:
break; query_id= get_query_id();
/* Only increase id on these statements but don't count them. */ break;
case COM_STMT_PREPARE: /* Only increase id on these statements but don't count them. */
case COM_STMT_CLOSE: case COM_STMT_PREPARE:
case COM_STMT_RESET: case COM_STMT_CLOSE:
next_query_id(); case COM_STMT_RESET:
break; query_id= next_query_id() - 1;
/* Increase id and count all other statements. */ break;
default: /* Increase id and count all other statements. */
statistic_increment(thd->status_var.questions, &LOCK_status); default:
next_query_id(); statistic_increment(thd->status_var.questions, &LOCK_status);
query_id= next_query_id() - 1;
}
thd->query_id= query_id;
} }
inc_thread_running();
thread_running++; my_atomic_rwlock_wrunlock(&global_query_id_lock);
/* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
/** /**
Clear the set of flags that are expected to be cleared at the Clear the set of flags that are expected to be cleared at the
...@@ -1259,15 +1262,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1259,15 +1262,15 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
(char *) thd->security_ctx->host_or_ip); (char *) thd->security_ctx->host_or_ip);
thd->set_query(beginning_of_next_stmt, length); thd->set_query(beginning_of_next_stmt, length);
VOID(pthread_mutex_lock(&LOCK_thread_count));
/* /*
Count each statement from the client. Count each statement from the client.
*/ */
statistic_increment(thd->status_var.questions, &LOCK_status); statistic_increment(thd->status_var.questions, &LOCK_status);
my_atomic_rwlock_wrlock(&global_query_id_lock);
thd->query_id= next_query_id(); thd->query_id= next_query_id();
my_atomic_rwlock_wrunlock(&global_query_id_lock);
thd->set_time(); /* Reset the query start time. */ thd->set_time(); /* Reset the query start time. */
/* TODO: set thd->lex->sql_command to SQLCOM_END here */ /* TODO: set thd->lex->sql_command to SQLCOM_END here */
VOID(pthread_mutex_unlock(&LOCK_thread_count));
mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt); mysql_parse(thd, beginning_of_next_stmt, length, &end_of_stmt);
} }
...@@ -1610,9 +1613,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd, ...@@ -1610,9 +1613,9 @@ bool dispatch_command(enum enum_server_command command, THD *thd,
thd_proc_info(thd, "cleaning up"); thd_proc_info(thd, "cleaning up");
thd->set_query(NULL, 0); thd->set_query(NULL, 0);
thd->command=COM_SLEEP; thd->command=COM_SLEEP;
VOID(pthread_mutex_lock(&LOCK_thread_count)); // For process list my_atomic_rwlock_wrlock(&global_query_id_lock);
thread_running--; dec_thread_running();
VOID(pthread_mutex_unlock(&LOCK_thread_count)); my_atomic_rwlock_wrunlock(&global_query_id_lock);
thd_proc_info(thd, 0); thd_proc_info(thd, 0);
thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory thd->packet.shrink(thd->variables.net_buffer_length); // Reclaim some memory
free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC)); free_root(thd->mem_root,MYF(MY_KEEP_PREALLOC));
......
/* Copyright (C) 2006 MySQL AB /* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
This program is free software; you can redistribute it and/or modify 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 it under the terms of the GNU General Public License as published by
...@@ -13,10 +13,7 @@ ...@@ -13,10 +13,7 @@
along with this program; if not, write to the Free Software along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h> #include "thr_template.c"
#include <my_sys.h>
#include <my_atomic.h>
#include <tap.h>
/* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */ /* at least gcc 3.4.5 and 3.4.6 (but not 3.2.3) on RHEL */
#if __GNUC__ == 3 && __GNUC_MINOR__ == 4 #if __GNUC__ == 3 && __GNUC_MINOR__ == 4
...@@ -25,181 +22,162 @@ ...@@ -25,181 +22,162 @@
#define GCC_BUG_WORKAROUND #define GCC_BUG_WORKAROUND
#endif #endif
int32 a32,b32,c32; volatile uint32 b32;
volatile int32 c32;
my_atomic_rwlock_t rwl; my_atomic_rwlock_t rwl;
pthread_attr_t thr_attr;
pthread_mutex_t mutex;
pthread_cond_t cond;
int N;
/* add and sub a random number in a loop. Must get 0 at the end */ /* add and sub a random number in a loop. Must get 0 at the end */
pthread_handler_t test_atomic_add_handler(void *arg) pthread_handler_t test_atomic_add(void *arg)
{ {
int m=*(int *)arg; int m= (*(int *)arg)/2;
GCC_BUG_WORKAROUND int32 x; GCC_BUG_WORKAROUND int32 x;
for (x=((int)((long)(&m))); m ; m--) for (x= ((int)(intptr)(&m)); m ; m--)
{
x= (x*m+0x87654321) & INT_MAX32;
my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&bad, x);
my_atomic_rwlock_wrunlock(&rwl);
my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&bad, -x);
my_atomic_rwlock_wrunlock(&rwl);
}
pthread_mutex_lock(&mutex);
if (!--running_threads) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex);
return 0;
}
volatile int64 a64;
/* add and sub a random number in a loop. Must get 0 at the end */
pthread_handler_t test_atomic_add64(void *arg)
{
int m= (*(int *)arg)/2;
GCC_BUG_WORKAROUND int64 x;
for (x= ((int64)(intptr)(&m)); m ; m--)
{ {
x=x*m+0x87654321; x= (x*m+0xfdecba987654321LL) & INT_MAX64;
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&a32, x); my_atomic_add64(&a64, x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&a32, -x); my_atomic_add64(&a64, -x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
} }
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
N--; if (!--running_threads)
if (!N) pthread_cond_signal(&cond); {
bad= (a64 != 0);
pthread_cond_signal(&cond);
}
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return 0; return 0;
} }
/* /*
1. generate thread number 0..N-1 from b32 1. generate thread number 0..N-1 from b32
2. add it to a32 2. add it to bad
3. swap thread numbers in c32 3. swap thread numbers in c32
4. (optionally) one more swap to avoid 0 as a result 4. (optionally) one more swap to avoid 0 as a result
5. subtract result from a32 5. subtract result from bad
must get 0 in a32 at the end must get 0 in bad at the end
*/ */
pthread_handler_t test_atomic_swap_handler(void *arg) pthread_handler_t test_atomic_fas(void *arg)
{ {
int m=*(int *)arg; int m= *(int *)arg;
int32 x; int32 x;
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
x=my_atomic_add32(&b32, 1); x= my_atomic_add32(&b32, 1);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&a32, x); my_atomic_add32(&bad, x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
for (; m ; m--) for (; m ; m--)
{ {
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
x=my_atomic_swap32(&c32, x); x= my_atomic_fas32(&c32, x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
} }
if (!x) if (!x)
{ {
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
x=my_atomic_swap32(&c32, x); x= my_atomic_fas32(&c32, x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
} }
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
my_atomic_add32(&a32, -x); my_atomic_add32(&bad, -x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
N--; if (!--running_threads) pthread_cond_signal(&cond);
if (!N) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return 0; return 0;
} }
/* /*
same as test_atomic_add_handler, but my_atomic_add32 is emulated with same as test_atomic_add, but my_atomic_add32 is emulated with
(slower) my_atomic_cas32 my_atomic_cas32 - notice that the slowdown is proportional to the
number of CPUs
*/ */
pthread_handler_t test_atomic_cas_handler(void *arg) pthread_handler_t test_atomic_cas(void *arg)
{ {
int m=*(int *)arg, ok; int m= (*(int *)arg)/2, ok= 0;
GCC_BUG_WORKAROUND int32 x,y; GCC_BUG_WORKAROUND int32 x, y;
for (x=((int)((long)(&m))); m ; m--) for (x= ((int)(intptr)(&m)); m ; m--)
{ {
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
y=my_atomic_load32(&a32); y= my_atomic_load32(&bad);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
x= (x*m+0x87654321) & INT_MAX32;
x=x*m+0x87654321;
do { do {
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
ok=my_atomic_cas32(&a32, &y, y+x); ok= my_atomic_cas32(&bad, &y, (uint32)y+x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
} while (!ok); } while (!ok) ;
do { do {
my_atomic_rwlock_wrlock(&rwl); my_atomic_rwlock_wrlock(&rwl);
ok=my_atomic_cas32(&a32, &y, y-x); ok= my_atomic_cas32(&bad, &y, y-x);
my_atomic_rwlock_wrunlock(&rwl); my_atomic_rwlock_wrunlock(&rwl);
} while (!ok); } while (!ok) ;
} }
pthread_mutex_lock(&mutex); pthread_mutex_lock(&mutex);
N--; if (!--running_threads) pthread_cond_signal(&cond);
if (!N) pthread_cond_signal(&cond);
pthread_mutex_unlock(&mutex); pthread_mutex_unlock(&mutex);
return 0; return 0;
} }
void test_atomic(const char *test, pthread_handler handler, int n, int m)
{
pthread_t t;
ulonglong now=my_getsystime();
a32= 0;
b32= 0;
c32= 0;
diag("Testing %s with %d threads, %d iterations... ", test, n, m);
for (N=n ; n ; n--)
{
if (pthread_create(&t, &thr_attr, handler, &m) != 0)
{
diag("Could not create thread");
a32= 1;
goto err;
}
}
pthread_mutex_lock(&mutex);
while (N)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
now=my_getsystime()-now;
err:
ok(a32 == 0, "tested %s in %g secs", test, ((double)now)/1e7);
}
int main() void do_tests()
{ {
int err; plan(6);
MY_INIT("my_atomic-t.c");
diag("N CPUs: %d", my_getncpus());
err= my_atomic_initialize();
plan(4); bad= my_atomic_initialize();
ok(err == 0, "my_atomic_initialize() returned %d", err); ok(!bad, "my_atomic_initialize() returned %d", bad);
pthread_attr_init(&thr_attr);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
pthread_mutex_init(&mutex, 0);
pthread_cond_init(&cond, 0);
my_atomic_rwlock_init(&rwl); my_atomic_rwlock_init(&rwl);
#ifdef HPUX11 b32= c32= 0;
#define CYCLES 1000 test_concurrently("my_atomic_add32", test_atomic_add, THREADS, CYCLES);
#else b32= c32= 0;
#define CYCLES 10000 test_concurrently("my_atomic_fas32", test_atomic_fas, THREADS, CYCLES);
#endif b32= c32= 0;
#define THREADS 100 test_concurrently("my_atomic_cas32", test_atomic_cas, THREADS, CYCLES);
test_atomic("my_atomic_add32", test_atomic_add_handler, THREADS, CYCLES);
test_atomic("my_atomic_swap32", test_atomic_swap_handler, THREADS, CYCLES); {
test_atomic("my_atomic_cas32", test_atomic_cas_handler, THREADS, CYCLES); int64 b=0x1000200030004000LL;
/* a64=0;
workaround until we know why it crashes randomly on some machine my_atomic_add64(&a64, b);
(BUG#22320). ok(a64==b, "add64");
*/ }
sleep(2); a64=0;
test_concurrently("my_atomic_add64", test_atomic_add64, THREADS, CYCLES);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&thr_attr);
my_atomic_rwlock_destroy(&rwl); my_atomic_rwlock_destroy(&rwl);
return exit_status();
} }
/* Copyright (C) 2006-2008 MySQL AB, 2008 Sun Microsystems, Inc.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
#include <my_global.h>
#include <my_sys.h>
#include <my_atomic.h>
#include <tap.h>
volatile uint32 bad;
pthread_attr_t thr_attr;
pthread_mutex_t mutex;
pthread_cond_t cond;
uint running_threads;
void do_tests();
void test_concurrently(const char *test, pthread_handler handler, int n, int m)
{
pthread_t t;
ulonglong now= my_getsystime();
bad= 0;
diag("Testing %s with %d threads, %d iterations... ", test, n, m);
for (running_threads= n ; n ; n--)
{
if (pthread_create(&t, &thr_attr, handler, &m) != 0)
{
diag("Could not create thread");
abort();
}
}
pthread_mutex_lock(&mutex);
while (running_threads)
pthread_cond_wait(&cond, &mutex);
pthread_mutex_unlock(&mutex);
now= my_getsystime()-now;
ok(!bad, "tested %s in %g secs (%d)", test, ((double)now)/1e7, bad);
}
int main(int argc __attribute__((unused)), char **argv)
{
MY_INIT("thd_template");
if (argv[1] && *argv[1])
DBUG_SET_INITIAL(argv[1]);
pthread_mutex_init(&mutex, 0);
pthread_cond_init(&cond, 0);
pthread_attr_init(&thr_attr);
pthread_attr_setdetachstate(&thr_attr,PTHREAD_CREATE_DETACHED);
#ifdef MY_ATOMIC_MODE_RWLOCKS
#if defined(HPUX11) || defined(__POWERPC__) /* showed to be very slow (scheduler-related) */
#define CYCLES 300
#else
#define CYCLES 3000
#endif
#else
#define CYCLES 3000
#endif
#define THREADS 30
diag("N CPUs: %d, atomic ops: %s", my_getncpus(), MY_ATOMIC_MODE);
do_tests();
/*
workaround until we know why it crashes randomly on some machine
(BUG#22320).
*/
sleep(2);
pthread_mutex_destroy(&mutex);
pthread_cond_destroy(&cond);
pthread_attr_destroy(&thr_attr);
my_end(0);
return exit_status();
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment