|
|
|
|
@ -11,8 +11,8 @@
|
|
|
|
|
// Explicitly instantiate the required template class and member functions
|
|
|
|
|
template MySQL_Session* Base_Thread::create_new_session_and_client_data_stream<MySQL_Thread, MySQL_Session*>(int);
|
|
|
|
|
template PgSQL_Session* Base_Thread::create_new_session_and_client_data_stream<PgSQL_Thread, PgSQL_Session*>(int);
|
|
|
|
|
template void Base_Thread::ProcessAllSessions_SortingSessions<MySQL_Session>();
|
|
|
|
|
template void Base_Thread::ProcessAllSessions_SortingSessions<PgSQL_Session>();
|
|
|
|
|
template void Base_Thread::ProcessAllSessions_Partition<MySQL_Session>();
|
|
|
|
|
template void Base_Thread::ProcessAllSessions_Partition<PgSQL_Session>();
|
|
|
|
|
template void Base_Thread::ProcessAllMyDS_AfterPoll<MySQL_Thread>();
|
|
|
|
|
template void Base_Thread::ProcessAllMyDS_AfterPoll<PgSQL_Thread>();
|
|
|
|
|
template void Base_Thread::ProcessAllMyDS_BeforePoll<MySQL_Thread>();
|
|
|
|
|
@ -34,6 +34,29 @@ Base_Thread::Base_Thread() :
|
|
|
|
|
Base_Thread::~Base_Thread() {
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
bool Base_Thread::update_partition_gate() {
|
|
|
|
|
// 64-bit so the multiplications below cannot overflow unsigned int.
|
|
|
|
|
const uint64_t attempts = partition_pool_attempts;
|
|
|
|
|
const uint64_t nulls = partition_pool_nulls;
|
|
|
|
|
partition_pool_attempts = 0;
|
|
|
|
|
partition_pool_nulls = 0;
|
|
|
|
|
|
|
|
|
|
// Low-volume ticks carry no signal; leave gate and streak unchanged.
|
|
|
|
|
if (attempts < PARTITION_GATE_MIN_ATTEMPTS) {
|
|
|
|
|
return partition_active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const bool stressed = (nulls * PARTITION_GATE_NULL_RATIO_DEN
|
|
|
|
|
>= attempts * PARTITION_GATE_NULL_RATIO_NUM);
|
|
|
|
|
if (stressed == partition_active) {
|
|
|
|
|
partition_streak = 0;
|
|
|
|
|
} else if (++partition_streak >= PARTITION_GATE_STREAK) {
|
|
|
|
|
partition_active = stressed;
|
|
|
|
|
partition_streak = 0;
|
|
|
|
|
}
|
|
|
|
|
return partition_active;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
template<typename T, typename S>
|
|
|
|
|
void Base_Thread::register_session(T thr, S _sess, bool up_start) {
|
|
|
|
|
if (mysql_sessions==NULL) {
|
|
|
|
|
@ -230,34 +253,64 @@ void Base_Thread::check_for_invalid_fd(unsigned int n) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// this function was inline in MySQL_Thread::process_all_sessions()
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* @brief Sort all sessions based on maximum connection time.
|
|
|
|
|
*
|
|
|
|
|
* This function iterates through all MySQL sessions and sorts them based on their maximum connection time.
|
|
|
|
|
* Sessions with a valid maximum connection time are compared, and if one session has a greater maximum connection
|
|
|
|
|
* time than another, their positions in the session list are swapped. The sorting is performed in-place.
|
|
|
|
|
*
|
|
|
|
|
* @note This function assumes that MySQL sessions and their associated data structures have been initialized
|
|
|
|
|
* and are accessible within the MySQL Thread.
|
|
|
|
|
* @brief Partition all sessions into three blocks by backend state.
|
|
|
|
|
*
|
|
|
|
|
* Block layout produced in mysql_sessions->pdata:
|
|
|
|
|
* [0, running_end) block A - running a query against the backend
|
|
|
|
|
* (myconn != NULL, mct == 0, status != WAITING_CLIENT_DATA)
|
|
|
|
|
* [running_end, idle_begin) block B - acquiring/awaiting a backend
|
|
|
|
|
* (mct != 0)
|
|
|
|
|
* [idle_begin, len) block C - idle, or holds-conn-but-WAITING_CLIENT_DATA
|
|
|
|
|
*
|
|
|
|
|
* Block A drives the backend and may release its conn at end-of-query, giving
|
|
|
|
|
* block B sessions a fairness chance to acquire it. Sessions parked in
|
|
|
|
|
* WAITING_CLIENT_DATA (idle in a transaction after BEGIN) hold the conn but
|
|
|
|
|
* cannot release it until the client sends the next packet, so they live in C.
|
|
|
|
|
*
|
|
|
|
|
* Classification tests max_connect_time first: it must win over A even when
|
|
|
|
|
* myconn != NULL, to catch CHANGING_USER_SERVER on pooled connections and the
|
|
|
|
|
* post-error retry path where the old conn hasn't been destroyed yet.
|
|
|
|
|
*
|
|
|
|
|
* Single O(n) pass, in place. idx walks up, idle_begin walks down, they meet
|
|
|
|
|
* and terminate. A previous Lomuto-style sort of the B band by max_connect_time
|
|
|
|
|
* was removed: measurement showed it hurt throughput by ~12% at 500 clients /
|
|
|
|
|
* 50-conn pool under SSL, without a corresponding tail-latency benefit. If
|
|
|
|
|
* reintroduced, it should be gated on an explicit starvation-age signal rather
|
|
|
|
|
* than run unconditionally on every iteration.
|
|
|
|
|
*/
|
|
|
|
|
template<typename S>
|
|
|
|
|
void Base_Thread::ProcessAllSessions_SortingSessions() {
|
|
|
|
|
unsigned int a=0;
|
|
|
|
|
for (unsigned int n=0; n<mysql_sessions->len; n++) {
|
|
|
|
|
S *sess=(S *)mysql_sessions->index(n);
|
|
|
|
|
if (sess->mybe && sess->mybe->server_myds) {
|
|
|
|
|
if (sess->mybe->server_myds->max_connect_time) {
|
|
|
|
|
S *sess2=(S *)mysql_sessions->index(a);
|
|
|
|
|
if (sess2->mybe && sess2->mybe->server_myds && sess2->mybe->server_myds->max_connect_time && sess2->mybe->server_myds->max_connect_time <= sess->mybe->server_myds->max_connect_time) {
|
|
|
|
|
// do nothing
|
|
|
|
|
} else {
|
|
|
|
|
void *p=mysql_sessions->pdata[a];
|
|
|
|
|
mysql_sessions->pdata[a]=mysql_sessions->pdata[n];
|
|
|
|
|
mysql_sessions->pdata[n]=p;
|
|
|
|
|
a++;
|
|
|
|
|
}
|
|
|
|
|
void Base_Thread::ProcessAllSessions_Partition() {
|
|
|
|
|
size_t running_end = 0;
|
|
|
|
|
size_t idle_begin = mysql_sessions->len;
|
|
|
|
|
size_t idx = 0;
|
|
|
|
|
|
|
|
|
|
while (idx < idle_begin) {
|
|
|
|
|
S* s = static_cast<S*>(mysql_sessions->index(idx));
|
|
|
|
|
|
|
|
|
|
const bool has_be = (s->mybe && s->mybe->server_myds);
|
|
|
|
|
const bool is_B = has_be && (s->mybe->server_myds->max_connect_time != 0);
|
|
|
|
|
const bool is_A = !is_B && has_be && (s->mybe->server_myds->myconn != nullptr) && (s->status != WAITING_CLIENT_DATA);
|
|
|
|
|
|
|
|
|
|
if (is_A) {
|
|
|
|
|
if (idx != running_end) {
|
|
|
|
|
void* p = mysql_sessions->pdata[idx];
|
|
|
|
|
mysql_sessions->pdata[idx] = mysql_sessions->pdata[running_end];
|
|
|
|
|
mysql_sessions->pdata[running_end] = p;
|
|
|
|
|
}
|
|
|
|
|
++running_end;
|
|
|
|
|
++idx;
|
|
|
|
|
} else if (is_B) {
|
|
|
|
|
++idx;
|
|
|
|
|
} else {
|
|
|
|
|
--idle_begin;
|
|
|
|
|
if (idx != idle_begin) {
|
|
|
|
|
void* p = mysql_sessions->pdata[idx];
|
|
|
|
|
mysql_sessions->pdata[idx] = mysql_sessions->pdata[idle_begin];
|
|
|
|
|
mysql_sessions->pdata[idle_begin] = p;
|
|
|
|
|
}
|
|
|
|
|
// do NOT advance idx - re-examine the swapped-in element test
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|