Commit f7a7c0c2 authored by Vladislav Vaintroub's avatar Vladislav Vaintroub

MDEV-10297 Add priorization to threadpool

Also MDEV-10385 Threadpool refactoring
parent f32a5115
--- mysqld--help.result
+++ mysqld--help,win.reject
@@ -321,7 +321,6 @@
--- mysqld--help.result 2016-09-21 13:50:58.682767100 +0000
+++ mysqld--help,win.reject 2016-09-21 13:57:57.494626000 +0000
@@ -318,7 +318,6 @@
The number of segments in a key cache
-L, --language=name Client error messages in given language. May be given as
a full path. Deprecated. Use --lc-messages-dir instead.
......@@ -8,7 +8,7 @@
--lc-messages=name Set the language used for the error messages.
-L, --lc-messages-dir=name
Directory where error messages are
@@ -520,6 +519,7 @@
@@ -517,6 +516,7 @@
Use MySQL-5.6 (instead of MariaDB-5.3) format for TIME,
DATETIME, TIMESTAMP columns.
(Defaults to on; use --skip-mysql56-temporal-format to disable.)
......@@ -16,7 +16,7 @@
--net-buffer-length=#
Buffer length for TCP/IP and socket communication
--net-read-timeout=#
@@ -927,6 +927,9 @@
@@ -924,6 +924,9 @@
characteristics (isolation level, read only/read
write,snapshot - but not any work done / data modified
within the transaction).
......@@ -26,7 +26,7 @@
--show-slave-auth-info
Show user and password in SHOW SLAVE HOSTS on this
master.
@@ -1039,6 +1042,10 @@
@@ -1036,6 +1039,10 @@
Log slow queries to given log file. Defaults logging to
'hostname'-slow.log. Must be enabled to activate other
slow log options
......@@ -37,7 +37,7 @@
--socket=name Socket file to use for connection
--sort-buffer-size=#
Each thread that needs to do a sort allocates a buffer of
@@ -1057,6 +1064,7 @@
@@ -1054,6 +1061,7 @@
NO_ENGINE_SUBSTITUTION, PAD_CHAR_TO_FULL_LENGTH
--stack-trace Print a symbolic stack trace on failure
(Defaults to on; use --skip-stack-trace to disable.)
......@@ -45,35 +45,19 @@
--standards-compliant-cte
Allow only standards compiant CTE
(Defaults to on; use --skip-standards-compliant-cte to disable.)
@@ -1099,25 +1107,11 @@
--thread-cache-size=#
How many threads we should keep in a cache for reuse.
These are freed after 5 minutes of idle time
- --thread-pool-idle-timeout=#
- Timeout in seconds for an idle thread in the thread
- pool.Worker thread will be shut down after timeout
@@ -1102,6 +1110,11 @@
--thread-pool-max-threads=#
Maximum allowed number of worker threads in the thread
pool
- --thread-pool-oversubscribe=#
- How many additional active worker threads in a group are
- allowed.
- --thread-pool-size=#
- Number of thread groups in the pool. This parameter is
- roughly equivalent to maximum number of concurrently
- executing threads (threads in a waiting state do not
- count as executing).
- --thread-pool-stall-limit=#
- Maximum query execution time in milliseconds,before an
- executing non-yielding thread is considered stalled.If a
- worker thread is stalled, additional worker thread may be
- created to handle remaining clients.
+ --thread-pool-min-threads=#
+ Minimum number of threads in the thread pool.
--thread-stack=# The stack size for each thread
--time-format=name The TIME format (ignored)
--timed-mutexes Specify whether to time mutexes. Deprecated, has no
@@ -1126,8 +1120,8 @@
+ --thread-pool-mode=name
+ Chose implementation of the threadpool. One of: windows,
+ generic
--thread-pool-oversubscribe=#
How many additional active worker threads in a group are
allowed.
@@ -1132,8 +1145,8 @@
size, MySQL will automatically convert it to an on-disk
MyISAM or Aria table
-t, --tmpdir=name Path for temporary files. Several paths may be specified,
......@@ -84,7 +68,7 @@
--transaction-alloc-block-size=#
Allocation block size for transactions to be stored in
binary log
@@ -1252,7 +1246,6 @@
@@ -1257,7 +1270,6 @@
key-cache-division-limit 100
key-cache-file-hash-size 512
key-cache-segments 0
......@@ -92,7 +76,7 @@
lc-messages en_US
lc-messages-dir MYSQL_SHAREDIR/
lc-time-names en_US
@@ -1319,6 +1312,7 @@
@@ -1324,6 +1336,7 @@
myisam-stats-method NULLS_UNEQUAL
myisam-use-mmap FALSE
mysql56-temporal-format TRUE
......@@ -100,7 +84,7 @@
net-buffer-length 16384
net-read-timeout 30
net-retry-count 10
@@ -1419,6 +1413,8 @@
@@ -1424,6 +1437,8 @@
session-track-state-change FALSE
session-track-system-variables
session-track-transaction-info OFF
......@@ -109,7 +93,7 @@
show-slave-auth-info FALSE
silent-startup FALSE
skip-grant-tables TRUE
@@ -1443,6 +1439,7 @@
@@ -1448,6 +1463,7 @@
slave-type-conversions
slow-launch-time 2
slow-query-log FALSE
......@@ -117,7 +101,7 @@
sort-buffer-size 2097152
sql-mode NO_AUTO_CREATE_USER,NO_ENGINE_SUBSTITUTION
stack-trace TRUE
@@ -1456,16 +1453,14 @@
@@ -1461,14 +1477,16 @@
sync-relay-log 10000
sync-relay-log-info 10000
sysdate-is-now FALSE
......@@ -129,11 +113,10 @@
table-open-cache-instances 8
tc-heuristic-recover OFF
thread-cache-size 151
-thread-pool-idle-timeout 60
thread-pool-idle-timeout 60
thread-pool-max-threads 1000
-thread-pool-oversubscribe 3
-thread-pool-stall-limit 500
+thread-pool-min-threads 1
thread-stack 297984
time-format %H:%i:%s
timed-mutexes FALSE
+thread-pool-mode windows
thread-pool-oversubscribe 3
thread-pool-prio-kickup-timer 1000
thread-pool-priority auto
......@@ -1105,6 +1105,15 @@ The following options may be given as the first argument:
--thread-pool-oversubscribe=#
How many additional active worker threads in a group are
allowed.
--thread-pool-prio-kickup-timer=#
The number of milliseconds before a dequeued low-priority
statement is moved to the high-priority queue
--thread-pool-priority=name
Threadpool priority. High priority connections usually
start executing earlier than low priority.If priority set
to 'auto', the the actual priority(low or high) is
determined based on whether or not connection is inside
transaction.
--thread-pool-size=#
Number of thread groups in the pool. This parameter is
roughly equivalent to maximum number of concurrently
......@@ -1461,6 +1470,8 @@ thread-cache-size 151
thread-pool-idle-timeout 60
thread-pool-max-threads 1000
thread-pool-oversubscribe 3
thread-pool-prio-kickup-timer 1000
thread-pool-priority auto
thread-pool-stall-limit 500
thread-stack 297984
time-format %H:%i:%s
......
......@@ -4755,6 +4755,34 @@ NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME THREAD_POOL_PRIORITY
SESSION_VALUE auto
GLOBAL_VALUE auto
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE auto
VARIABLE_SCOPE SESSION
VARIABLE_TYPE ENUM
VARIABLE_COMMENT Threadpool priority. High priority connections usually start executing earlier than low priority.If priority set to 'auto', the the actual priority(low or high) is determined based on whether or not connection is inside transaction.
NUMERIC_MIN_VALUE NULL
NUMERIC_MAX_VALUE NULL
NUMERIC_BLOCK_SIZE NULL
ENUM_VALUE_LIST high,low,auto
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME THREAD_POOL_PRIO_KICKUP_TIMER
SESSION_VALUE NULL
GLOBAL_VALUE 1000
GLOBAL_VALUE_ORIGIN COMPILE-TIME
DEFAULT_VALUE 1000
VARIABLE_SCOPE GLOBAL
VARIABLE_TYPE INT UNSIGNED
VARIABLE_COMMENT The number of milliseconds before a dequeued low-priority statement is moved to the high-priority queue
NUMERIC_MIN_VALUE 0
NUMERIC_MAX_VALUE 4294967295
NUMERIC_BLOCK_SIZE 1
ENUM_VALUE_LIST NULL
READ_ONLY NO
COMMAND_LINE_ARGUMENT REQUIRED
VARIABLE_NAME THREAD_POOL_SIZE
SESSION_VALUE NULL
GLOBAL_VALUE 4
......
......@@ -157,9 +157,9 @@ IF (CMAKE_SYSTEM_NAME MATCHES "Linux" OR
ADD_DEFINITIONS(-DHAVE_POOL_OF_THREADS)
IF(WIN32)
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_win.cc)
ELSE()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_unix.cc)
ENDIF()
SET(SQL_SOURCE ${SQL_SOURCE} threadpool_generic.cc)
ENDIF()
MYSQL_ADD_PLUGIN(partition ha_partition.cc STORAGE_ENGINE DEFAULT STATIC_ONLY
......
......@@ -4425,7 +4425,7 @@ static int init_common_variables()
#endif /* HAVE_SOLARIS_LARGE_PAGES */
#if defined(HAVE_POOL_OF_THREADS) && !defined(_WIN32)
#if defined(HAVE_POOL_OF_THREADS)
if (IS_SYSVAR_AUTOSIZE(&threadpool_size))
SYSVAR_AUTOSIZE(threadpool_size, my_getncpus());
#endif
......
......@@ -697,6 +697,7 @@ typedef struct system_variables
my_bool session_track_schema;
my_bool session_track_state_change;
ulong threadpool_priority;
} SV;
/**
......
......@@ -3241,23 +3241,17 @@ static Sys_var_ulong Sys_thread_cache_size(
#ifdef HAVE_POOL_OF_THREADS
static bool fix_tp_max_threads(sys_var *, THD *, enum_var_type)
{
#ifdef _WIN32
tp_set_max_threads(threadpool_max_threads);
#endif
return false;
}
#ifdef _WIN32
static bool fix_tp_min_threads(sys_var *, THD *, enum_var_type)
{
tp_set_min_threads(threadpool_min_threads);
return false;
}
#endif
#ifndef _WIN32
static bool check_threadpool_size(sys_var *self, THD *thd, set_var *var)
{
ulonglong v= var->save_result.ulonglong_value;
......@@ -3282,7 +3276,6 @@ static bool fix_threadpool_stall_limit(sys_var*, THD*, enum_var_type)
tp_set_threadpool_stall_limit(threadpool_stall_limit);
return false;
}
#endif
#ifdef _WIN32
static Sys_var_uint Sys_threadpool_min_threads(
......@@ -3293,7 +3286,24 @@ static Sys_var_uint Sys_threadpool_min_threads(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_tp_min_threads)
);
#else
static const char *threadpool_mode_names[]={ "windows", "generic", 0 };
static Sys_var_enum Sys_threadpool_mode(
"thread_pool_mode",
"Chose implementation of the threadpool",
READ_ONLY GLOBAL_VAR(threadpool_mode), CMD_LINE(REQUIRED_ARG),
threadpool_mode_names, DEFAULT(TP_MODE_WINDOWS)
);
#endif
static const char *threadpool_priority_names[]={ "high", "low", "auto", 0 };
static Sys_var_enum Sys_thread_pool_priority(
"thread_pool_priority",
"Threadpool priority. High priority connections usually start executing earlier than low priority."
"If priority set to 'auto', the the actual priority(low or high) is determined based on whether or not connection is inside transaction.",
SESSION_VAR(threadpool_priority), CMD_LINE(REQUIRED_ARG),
threadpool_priority_names, DEFAULT(TP_PRIORITY_AUTO));
static Sys_var_uint Sys_threadpool_idle_thread_timeout(
"thread_pool_idle_timeout",
"Timeout in seconds for an idle thread in the thread pool."
......@@ -3328,7 +3338,7 @@ static Sys_var_uint Sys_threadpool_stall_limit(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_threadpool_stall_limit)
);
#endif /* !WIN32 */
static Sys_var_uint Sys_threadpool_max_threads(
"thread_pool_max_threads",
"Maximum allowed number of worker threads in the thread pool",
......@@ -3337,6 +3347,13 @@ static Sys_var_uint Sys_threadpool_max_threads(
NO_MUTEX_GUARD, NOT_IN_BINLOG, ON_CHECK(0),
ON_UPDATE(fix_tp_max_threads)
);
static Sys_var_uint Sys_threadpool_threadpool_prio_kickup_timer(
"thread_pool_prio_kickup_timer",
"The number of milliseconds before a dequeued low-priority statement is moved to the high-priority queue",
GLOBAL_VAR(threadpool_prio_kickup_timer), CMD_LINE(REQUIRED_ARG),
VALID_RANGE(0, UINT_MAX), DEFAULT(1000), BLOCK_SIZE(1)
);
#endif /* HAVE_POOL_OF_THREADS */
/**
......
......@@ -23,28 +23,19 @@ extern uint threadpool_max_size;
extern uint threadpool_stall_limit; /* time interval in 10 ms units for stall checks*/
extern uint threadpool_max_threads; /* Maximum threads in pool */
extern uint threadpool_oversubscribe; /* Maximum active threads in group */
extern uint threadpool_prio_kickup_timer; /* Time before low prio item gets prio boost */
#ifdef _WIN32
extern uint threadpool_mode; /* Thread pool implementation , windows or generic */
#define TP_MODE_WINDOWS 0
#define TP_MODE_GENERIC 1
#endif
struct TP_connection;
extern void tp_callback(TP_connection *c);
extern void tp_timeout_handler(TP_connection *c);
/* Common thread pool routines, suitable for different implementations */
extern void threadpool_remove_connection(THD *thd);
extern int threadpool_process_request(THD *thd);
extern THD* threadpool_add_connection(CONNECT *connect, void *scheduled_data);
/*
Functions used by scheduler.
OS-specific implementations are in
threadpool_unix.cc or threadpool_win.cc
*/
extern bool tp_init();
extern void tp_add_connection(CONNECT *);
extern void tp_wait_begin(THD *, int);
extern void tp_wait_end(THD*);
extern void tp_post_kill_notification(THD *thd);
extern void tp_end(void);
/* Used in SHOW for threadpool_idle_thread_count */
extern int tp_get_idle_thread_count();
/*
Threadpool statistics
......@@ -63,9 +54,103 @@ extern void tp_set_min_threads(uint val);
extern void tp_set_max_threads(uint val);
extern void tp_set_threadpool_size(uint val);
extern void tp_set_threadpool_stall_limit(uint val);
extern int tp_get_idle_thread_count();
extern int tp_get_thread_count();
/* Activate threadpool scheduler */
extern void tp_scheduler(void);
extern int show_threadpool_idle_threads(THD *thd, SHOW_VAR *var, char *buff,
enum enum_var_type scope);
enum TP_PRIORITY {
TP_PRIORITY_HIGH,
TP_PRIORITY_LOW,
TP_PRIORITY_AUTO
};
enum TP_STATE
{
TP_STATE_IDLE,
TP_STATE_RUNNING,
};
/*
Connection structure, encapsulates THD + structures for asynchronous
IO and pool.
Platform specific parts are specified in subclasses called connection_t,
inside threadpool_win.cc and threadpool_unix.cc
*/
struct TP_connection
{
THD* thd;
CONNECT* connect;
TP_STATE state;
TP_PRIORITY priority;
TP_connection(CONNECT *c) :
thd(0),
connect(c),
state(TP_STATE_IDLE),
priority(TP_PRIORITY_HIGH)
{}
virtual ~TP_connection()
{};
/* Initialize io structures windows threadpool, epoll etc */
virtual int init() = 0;
virtual void set_io_timeout(int sec) = 0;
/* Read for the next client command (async) with specified timeout */
virtual int start_io() = 0;
virtual void wait_begin(int type)= 0;
virtual void wait_end() = 0;
};
struct TP_pool
{
virtual ~TP_pool(){};
virtual int init()= 0;
virtual TP_connection *new_connection(CONNECT *)= 0;
virtual void add(TP_connection *c)= 0;
virtual int set_max_threads(uint){ return 0; }
virtual int set_min_threads(uint){ return 0; }
virtual int set_pool_size(uint){ return 0; }
virtual int set_idle_timeout(uint){ return 0; }
virtual int set_oversubscribe(uint){ return 0; }
virtual int set_stall_limit(uint){ return 0; }
virtual int get_thread_count() { return tp_stats.num_worker_threads; }
virtual int get_idle_thread_count(){ return 0; }
};
#ifdef _WIN32
struct TP_pool_win:TP_pool
{
TP_pool_win();
virtual int init();
virtual ~TP_pool_win();
virtual TP_connection *new_connection(CONNECT *c);
virtual void add(TP_connection *);
virtual int set_max_threads(uint);
virtual int set_min_threads(uint);
};
#endif
struct TP_pool_generic :TP_pool
{
TP_pool_generic();
~TP_pool_generic();
virtual int init();
virtual TP_connection *new_connection(CONNECT *c);
virtual void add(TP_connection *);
virtual int set_pool_size(uint);
virtual int set_stall_limit(uint);
virtual int get_idle_thread_count();
};
......@@ -34,14 +34,25 @@ uint threadpool_max_size;
uint threadpool_stall_limit;
uint threadpool_max_threads;
uint threadpool_oversubscribe;
uint threadpool_mode;
uint threadpool_prio_kickup_timer;
/* Stats */
TP_STATISTICS tp_stats;
static void threadpool_remove_connection(THD *thd);
static int threadpool_process_request(THD *thd);
static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data);
extern "C" pthread_key(struct st_my_thread_var*, THR_KEY_mysys);
extern bool do_command(THD*);
static inline TP_connection *get_TP_connection(THD *thd)
{
return (TP_connection *)thd->event_scheduler.data;
}
/*
Worker threads contexts, and THD contexts.
=========================================
......@@ -105,15 +116,81 @@ static void thread_attach(THD* thd)
#endif
}
/*
Determine connection priority , using current
transaction state and 'threadpool_priority' variable value.
*/
static TP_PRIORITY get_priority(TP_connection *c)
{
DBUG_ASSERT(c->thd == current_thd);
TP_PRIORITY prio= (TP_PRIORITY)c->thd->variables.threadpool_priority;
if (prio == TP_PRIORITY_AUTO)
{
return c->thd->transaction.is_active() ? TP_PRIORITY_HIGH : TP_PRIORITY_LOW;
}
return prio;
}
THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
void tp_callback(TP_connection *c)
{
THD *thd= NULL;
int error=1;
DBUG_ASSERT(c);
Worker_thread_context worker_context;
worker_context.save();
THD *thd= c->thd;
c->state = TP_STATE_RUNNING;
if (!thd)
{
/* No THD, need to login first. */
DBUG_ASSERT(c->connect);
thd= c->thd= threadpool_add_connection(c->connect, c);
if (!thd)
{
/* Bail out on connect error.*/
goto error;
}
c->connect= 0;
}
else if (threadpool_process_request(thd))
{
/* QUIT or an error occured. */
goto error;
}
/* Set priority */
c->priority= get_priority(c);
/* Read next command from client. */
c->set_io_timeout(thd->variables.net_wait_timeout);
c->state= TP_STATE_IDLE;
if (c->start_io())
goto error;
worker_context.restore();
return;
error:
c->thd= 0;
delete c;
if (thd)
{
threadpool_remove_connection(thd);
}
worker_context.restore();
}
static THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
{
THD *thd= NULL;
int error=1;
/*
Create a new connection context: mysys_thread_var and PSI thread
Store them in THD.
......@@ -137,7 +214,6 @@ THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
#endif
my_thread_end();
}
worker_context.restore();
return NULL;
}
delete connect;
......@@ -184,17 +260,14 @@ THD* threadpool_add_connection(CONNECT *connect, void *scheduler_data)
threadpool_remove_connection(thd);
thd= NULL;
}
worker_context.restore();
return thd;
}
void threadpool_remove_connection(THD *thd)
static void threadpool_remove_connection(THD *thd)
{
Worker_thread_context worker_context;
worker_context.save();
thread_attach(thd);
thd->event_scheduler.data= 0;
thd->net.reading_or_writing = 0;
end_connection(thd);
close_connection(thd, 0);
......@@ -206,19 +279,14 @@ void threadpool_remove_connection(THD *thd)
mysys thread_var and PSI thread.
*/
my_thread_end();
worker_context.restore();
}
/**
Process a single client request or a single batch.
*/
int threadpool_process_request(THD *thd)
static int threadpool_process_request(THD *thd)
{
int retval= 0;
Worker_thread_context worker_context;
worker_context.save();
thread_attach(thd);
if (thd->killed >= KILL_CONNECTION)
......@@ -268,7 +336,6 @@ int threadpool_process_request(THD *thd)
}
end:
worker_context.restore();
return retval;
}
......@@ -286,6 +353,119 @@ static bool tp_end_thread(THD *, bool)
return 0;
}
static TP_pool *pool;
static bool tp_init()
{
#ifdef _WIN32
if (threadpool_mode == TP_MODE_WINDOWS)
pool= new (std::nothrow) TP_pool_win;
else
pool= new (std::nothrow) TP_pool_generic;
#else
pool= new (std::nothrow) TP_pool_generic;
#endif
if (!pool)
return true;
if (pool->init())
{
delete pool;
pool= 0;
return true;
}
return false;
}
static void tp_add_connection(CONNECT *connect)
{
TP_connection *c= pool->new_connection(connect);
DBUG_EXECUTE_IF("simulate_failed_connection_1", delete c ; c= 0;);
if (c)
pool->add(c);
else
connect->close_and_delete();
}
int tp_get_idle_thread_count()
{
return pool? pool->get_idle_thread_count(): 0;
}
int tp_get_thread_count()
{
return pool ? pool->get_thread_count() : 0;
}
void tp_set_min_threads(uint val)
{
if (pool)
pool->set_min_threads(val);
}
void tp_set_max_threads(uint val)
{
if (pool)
pool->set_max_threads(val);
}
void tp_set_threadpool_size(uint val)
{
if (pool)
pool->set_pool_size(val);
}
void tp_set_threadpool_stall_limit(uint val)
{
if (pool)
pool->set_stall_limit(val);
}
void tp_timeout_handler(TP_connection *c)
{
if (c->state != TP_STATE_IDLE)
return;
THD *thd=c->thd;
mysql_mutex_lock(&thd->LOCK_thd_data);
thd->killed= KILL_CONNECTION;
c->priority= TP_PRIORITY_HIGH;
post_kill_notification(thd);
mysql_mutex_unlock(&thd->LOCK_thd_data);
}
static void tp_wait_begin(THD *thd, int type)
{
TP_connection *c = get_TP_connection(thd);
if (c)
c->wait_begin(type);
}
static void tp_wait_end(THD *thd)
{
TP_connection *c = get_TP_connection(thd);
if (c)
c->wait_end();
}
static void tp_end()
{
delete pool;
}
static void tp_post_kill_notification(THD *thd)
{
TP_connection *c= get_TP_connection(thd);
if (c)
c->priority= TP_PRIORITY_HIGH;
post_kill_notification(thd);
}
static scheduler_functions tp_scheduler_functions=
{
0, // max_threads
......@@ -296,7 +476,7 @@ static scheduler_functions tp_scheduler_functions=
tp_add_connection, // add_connection
tp_wait_begin, // thd_wait_begin
tp_wait_end, // thd_wait_end
post_kill_notification, // post_kill_notification
tp_post_kill_notification, // post kill notification
tp_end_thread, // Dummy function
tp_end // end
};
......
This diff is collapsed.
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