/** * get a connection from the pool * * make sure we have at lease <min-conns> for each user * if we have more, reuse a connect to reauth it to another user * * @param pool connection pool to get the connection from * @param username (optional) name of the auth connection * @param default_db (unused) unused name of the default-db */ network_socket *network_connection_pool_get(network_connection_pool *pool, GString *username, GString *UNUSED_PARAM(default_db)) { network_connection_pool_entry *entry = NULL; network_socket *sock = NULL; GQueue *conns = network_connection_pool_get_conns(pool, username, NULL); /** * if we know this use, return a authed connection */ if (conns) { entry = g_queue_pop_head(conns); if (conns->length == 0) { /** * all connections are gone, remove it from the hash */ g_hash_table_remove(pool->users, username); } } if (!entry) { #ifdef DEBUG_CONN_POOL g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns); #endif return NULL; } sock = entry->sock; network_connection_pool_entry_free(entry, FALSE); /* remove the idle handler from the socket */ event_del(&(sock->event)); #ifdef DEBUG_CONN_POOL g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock); #endif return sock; }
network_socket *network_connection_pool_get_new(chassis *chas, network_backend_t *backend, proxy_rw type, network_connection_pool *pool, const GString *username, user_pool_config *user_pool_conf, connection_scaler_pool_statistics *pool_stats) { guint pool_conn_current_using_sum = 0; GQueue *conns = NULL; network_connection_pool_entry *entry = NULL; GTimeVal now_tv; guint removed = 0; network_socket *sock = NULL; g_assert(chas); g_assert(backend); g_assert(type == PROXY_TYPE_WRITE || type == PROXY_TYPE_READ); g_assert(pool); g_assert(username); g_assert(user_pool_conf); g_assert(pool_stats); g_assert(backend->pool[type] == pool); /** * 取用户连接池 */ g_mutex_lock(&(pool->connection_pool_mutex)); conns = network_connection_pool_get_conns(pool, username, NULL ); if (conns == NULL ) { pool_stats->conn_nopool++; goto NETWORK_CONNECTION_POOL_GET_NEW_EXIT; } pool_stats->conn_length = g_queue_get_length(conns); /** * 删除空的用户连接池 * 比如最小连接数等于零 */ if (pool_stats->conn_length == 0) { pool_stats->conn_zerosize++; g_hash_table_remove(pool->users, username); goto NETWORK_CONNECTION_POOL_GET_NEW_EXIT; } /** * 取用户连接池当前连接数,包括未决的和已用的,不包括空闲的(空闲数量应该约等于连接池长度) */ pool_conn_current_using_sum = get_conn_using_pending_count(pool, username->str); /** * 是否[连接池当前连接]大于[最大连接数] */ if (pool_conn_current_using_sum > user_pool_conf->max_connections) { pool_stats->conn_toomany++; goto NETWORK_CONNECTION_POOL_GET_NEW_EXIT; } g_get_current_time(&now_tv); /**取出一个连接*/ for (entry = g_queue_pop_head(conns); conns != NULL && entry != NULL ; entry = g_queue_pop_head(conns)) { pool_stats->conn_checked++; /**proxy_get_server_connection_list()这里idle--*/ //update_conn_pool_status_in_state(pool, username->str, POOL_STATUS_STATE_REMOVE_FROM_POOL); /** * 检查时间间隔未到,不需要检查,退出(此用户连接池)循环 */ if (check_pool_entry_connectivity_timeout(entry, &now_tv) == FALSE) { pool_stats->conn_again++; break; } /** * 是否断开 */ if (check_pool_entry_connectivity(entry) == FALSE) { update_conn_pool_status_in_state(pool, username->str, POOL_STATUS_STATE_REMOVE_FROM_POOL); garbage_connection_pool_add_entry(pool->garbage_connection_pool, entry); pool_stats->conn_disconnected++; entry = NULL; pool_conn_current_using_sum = get_conn_using_pending_count(pool, username->str); continue; } /** * 正常的连接 */ if (entry != NULL) { pool_stats->conn_good++; break; } } NETWORK_CONNECTION_POOL_GET_NEW_EXIT: g_mutex_unlock( &(pool->connection_pool_mutex)); removed += pool_stats->conn_disconnected; if (entry == NULL ) { #ifdef DEBUG_CONN_POOL g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns); #endif return NULL ; } else { sock = entry->sock; network_connection_pool_entry_free(entry, FALSE); #ifdef DEBUG_CONN_POOL g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock); #endif } return sock; }
/** * get a connection from the pool * * make sure we have at lease <min-conns> for each user * if we have more, reuse a connect to reauth it to another user * * @param pool connection pool to get the connection from * @param username (optional) name of the auth connection * @param default_db (unused) unused name of the default-db */ network_socket *network_connection_pool_get(network_connection_pool *pool, GString *username, GString *UNUSED_PARAM(default_db), conn_ctl_info *info) { guint32 cur; guint len, i; network_socket *sock = NULL; network_connection_pool_entry *entry, *found_entry = NULL; GQueue *conns = network_connection_pool_get_conns(pool, username, NULL); /** * if we know this use, return a authed connection */ if (conns) { cur = time(0); len = g_queue_get_length(conns); for (i = 0; i < len; i++) { entry = g_queue_peek_nth(conns, i); if (entry->key == info->key) { if (!entry->shared) { found_entry = entry; g_queue_pop_nth (conns, i); break; } } } if (!found_entry && len > 0) { entry = g_queue_peek_nth(conns, 0); found_entry = entry; g_queue_pop_nth (conns, 0); g_debug("%s: (get) entry for user '%s' -> %p, cur:%u", G_STRLOC, username ? username->str : "", entry, cur); } if (conns->length == 0) { /** * all connections are gone, remove it from the hash */ g_hash_table_remove(pool->users, username); } } if (!found_entry) { g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns); return NULL; } sock = found_entry->sock; g_debug("%s: recv queue length:%d, sock:%p", G_STRLOC, sock->recv_queue->chunks->length, sock); network_connection_pool_entry_free(found_entry, FALSE); /* remove the idle handler from the socket */ event_del(&(sock->event)); g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock); return sock; }
/** * get a connection from the pool * 从连接池头部取出一个连接 * * make sure we have at lease <min-conns> for each user * if we have more, reuse a connect to reauth it to another user * * @param pool connection pool to get the connection from * @param username (optional) name of the auth connection * @param default_db (unused) unused name of the default-db */ network_socket *network_connection_pool_get(network_connection_pool *pool, GString *username, GString *UNUSED_PARAM(default_db)) { GQueue *conns = NULL; network_connection_pool_entry *entry = NULL; network_socket *sock = NULL; g_mutex_lock(&(pool->connection_pool_mutex)); conns = network_connection_pool_get_conns(pool, username, NULL); /** * if we know this use, return a authed connection */ #ifndef CONNECTION_POOL_REGISTER_EVENTS_ENABLED if (conns) { entry = g_queue_pop_head(conns); /** * 取出一个状态正常的连接,将状态异常的连接放入垃圾回收池 * @todo 这里可以不用检查了?因为已有单独scaler线程定期(若干秒)检查连接状态 */ while (entry != NULL ) { if (check_pool_entry_status(entry) == TRUE) { break; } else { garbage_connection_pool_add_entry(pool->garbage_connection_pool, entry); } entry = g_queue_pop_head(conns); } if (conns->length == 0) { /** * all connections are gone, remove it from the hash */ g_hash_table_remove(pool->users, username); } } #else if (conns) { entry = g_queue_pop_head(conns); if (conns->length == 0) { /** * all connections are gone, remove it from the hash */ g_hash_table_remove(pool->users, username); } } #endif if (!entry) { #ifdef DEBUG_CONN_POOL g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns); #endif g_mutex_unlock(&(pool->connection_pool_mutex)); return NULL; } sock = entry->sock; network_connection_pool_entry_free(entry, FALSE); /**连接加入连接池时没有注册事件,所以取出时也不需要删除事件*/ // struct event *ev = &(sock->event); // /* remove the idle handler from the socket */ // if(sock->event.ev_base) { // g_debug("[%s]: fd: %d, events: %x, callback: %p network_mysqld_pool_con_idle_handle: %p, network_mysqld_cache_con_idle_handle: %p", // G_STRLOC, event_get_fd(ev), event_get_events(ev), // event_get_callback(ev), // network_mysqld_pool_con_idle_handle, // network_mysqld_cache_con_idle_handle); // event_del(&(sock->event)); // } // g_debug("[%s]: fd: %d, events: %x, callback: %p network_mysqld_pool_con_idle_handle: %p, network_mysqld_cache_con_idle_handle: %p", // G_STRLOC, event_get_fd(ev), event_get_events(ev), // event_get_callback(ev), // network_mysqld_pool_con_idle_handle, // network_mysqld_cache_con_idle_handle); #ifdef DEBUG_CONN_POOL g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock); #endif g_mutex_unlock(&(pool->connection_pool_mutex)); return sock; }