1
/* Copyright (C) 2007 MySQL AB
3
This program is free software; you can redistribute it and/or modify
4
it under the terms of the GNU General Public License as published by
5
the Free Software Foundation; version 2 of the License.
7
This program is distributed in the hope that it will be useful,
8
but WITHOUT ANY WARRANTY; without even the implied warranty of
9
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10
GNU General Public License for more details.
12
You should have received a copy of the GNU General Public License
13
along with this program; if not, write to the Free Software
14
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA */
18
#include "network-conn-pool.h"
20
#include "sys-pedantic.h"
25
* in the pool we manage idle connections
26
* - keep them up as long as possible
27
* - make sure we don't run out of seconds
28
* - if the client is authed, we have to pick connection with the same user
33
* create a empty connection pool entry
35
* @return a connection pool entry
37
network_connection_pool_entry *network_connection_pool_entry_init(void) {
38
network_connection_pool_entry *e;
40
e = g_new0(network_connection_pool_entry, 1);
46
* free a conn pool entry
48
* @param e the pool entry to free
49
* @param free_sock if true, the attached server-socket will be freed too
51
void network_connection_pool_entry_free(network_connection_pool_entry *e, gboolean free_sock) {
54
if (e->sock && free_sock) {
55
network_socket *sock = e->sock;
57
event_del(&(sock->event));
58
network_socket_free(sock);
65
* free all pool entries of the queue
67
* used as GDestroyFunc in the user-hash of the pool
69
* @see network_connection_pool_init
71
static void g_queue_free_all(gpointer q) {
73
network_connection_pool_entry *entry;
75
while ((entry = g_queue_pop_head(queue))) network_connection_pool_entry_free(entry, TRUE);
81
* init a connection pool
83
network_connection_pool *network_connection_pool_init(void) {
84
network_connection_pool *pool;
86
pool = g_new0(network_connection_pool, 1);
88
pool->users = g_hash_table_new_full(g_hash_table_string_hash, g_hash_table_string_equal, g_hash_table_string_free, g_queue_free_all);
94
* free all entries of the pool
97
void network_connection_pool_free(network_connection_pool *pool) {
100
g_hash_table_foreach_remove(pool->users, g_hash_table_true, NULL);
102
g_hash_table_destroy(pool->users);
108
* find the entry which has more than max_idle connections idling
110
* @return TRUE for the first entry having more than _user_data idling connections
111
* @see network_connection_pool_get_conns
113
static gboolean find_idle_conns(gpointer UNUSED_PARAM(_key), gpointer _val, gpointer _user_data) {
114
guint min_idle_conns = *(gint *)_user_data;
115
GQueue *conns = _val;
117
return (conns->length > min_idle_conns);
120
GQueue *network_connection_pool_get_conns(network_connection_pool *pool, GString *username, GString *UNUSED_PARAM(default_db)) {
121
GQueue *conns = NULL;
124
if (username && username->len > 0) {
125
conns = g_hash_table_lookup(pool->users, username);
127
* if we know this use, return a authed connection
129
#ifdef DEBUG_CONN_POOL
130
g_debug("%s: (get_conns) get user-specific idling connection for '%s' -> %p", G_STRLOC, username->str, conns);
132
if (conns) return conns;
136
* we don't have a entry yet, check the others if we have more than
140
conns = g_hash_table_find(pool->users, find_idle_conns, &(pool->min_idle_connections));
141
#ifdef DEBUG_CONN_POOL
142
g_debug("%s: (get_conns) try to find max-idling conns for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns);
149
* get a connection from the pool
151
* make sure we have at lease <min-conns> for each user
152
* if we have more, reuse a connect to reauth it to another user
154
* @param username (optional) name of the auth connection
156
network_socket *network_connection_pool_get(network_connection_pool *pool,
158
GString *UNUSED_PARAM(default_db)) {
160
network_connection_pool_entry *entry = NULL;
161
network_socket *sock = NULL;
163
GQueue *conns = network_connection_pool_get_conns(pool, username, NULL);
166
* if we know this use, return a authed connection
169
entry = g_queue_pop_head(conns);
171
if (conns->length == 0) {
173
* all connections are gone, remove it from the hash
175
g_hash_table_remove(pool->users, username);
180
#ifdef DEBUG_CONN_POOL
181
g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns);
188
network_connection_pool_entry_free(entry, FALSE);
190
/* remove the idle handler from the socket */
191
event_del(&(sock->event));
193
#ifdef DEBUG_CONN_POOL
194
g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock);
201
* add a connection to the connection pool
204
network_connection_pool_entry *network_connection_pool_add(network_connection_pool *pool, network_socket *sock) {
205
network_connection_pool_entry *entry;
206
GQueue *conns = NULL;
208
entry = network_connection_pool_entry_init();
212
g_get_current_time(&(entry->added_ts));
214
#ifdef DEBUG_CONN_POOL
215
g_debug("%s: (add) adding socket to pool for user '%s' -> %p", G_STRLOC, sock->username->str, sock);
218
if (NULL == (conns = g_hash_table_lookup(pool->users, sock->username))) {
219
conns = g_queue_new();
221
g_hash_table_insert(pool->users, g_string_dup(sock->username), conns);
224
g_queue_push_tail(conns, entry);
230
* remove the connection referenced by entry from the pool
232
void network_connection_pool_remove(network_connection_pool *pool, network_connection_pool_entry *entry) {
233
network_socket *sock = entry->sock;
236
if (NULL == (conns = g_hash_table_lookup(pool->users, sock->username))) {
240
network_connection_pool_entry_free(entry, TRUE);
242
g_queue_remove(conns, entry);