~jan-kneschke/mysql-proxy/packet-tracking-assertions

« back to all changes in this revision

Viewing changes to tags/mysql-proxy-0.6.0/src/network-conn-pool.c

  • Committer: Kay Roepke
  • Author(s): Jan Kneschke
  • Date: 2008-01-23 22:00:28 UTC
  • Revision ID: kay@mysql.com-20080123220028-hq2xqb69apa75fnx
first round on mysql-shell based on the proxy code

this is mostly a verification if the proxy-code is flexible enough to handle 
all three scenarios of: client, server and forwarding (proxy)

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* Copyright (C) 2007 MySQL AB
 
2
 
 
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.
 
6
 
 
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.
 
11
 
 
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 */ 
 
15
 
 
16
#include <glib.h>
 
17
 
 
18
#include "network-conn-pool.h"
 
19
#include "glib-ext.h"
 
20
#include "sys-pedantic.h"
 
21
 
 
22
/**
 
23
 * connection pools
 
24
 *
 
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
 
29
 * - ...  
 
30
 */
 
31
 
 
32
/**
 
33
 * create a empty connection pool entry
 
34
 *
 
35
 * @return a connection pool entry
 
36
 */
 
37
network_connection_pool_entry *network_connection_pool_entry_init(void) {
 
38
        network_connection_pool_entry *e;
 
39
 
 
40
        e = g_new0(network_connection_pool_entry, 1);
 
41
 
 
42
        return e;
 
43
}
 
44
 
 
45
/**
 
46
 * free a conn pool entry
 
47
 *
 
48
 * @param e the pool entry to free
 
49
 * @param free_sock if true, the attached server-socket will be freed too
 
50
 */
 
51
void network_connection_pool_entry_free(network_connection_pool_entry *e, gboolean free_sock) {
 
52
        if (!e) return;
 
53
 
 
54
        if (e->sock && free_sock) {
 
55
                network_socket *sock = e->sock;
 
56
                        
 
57
                event_del(&(sock->event));
 
58
                network_socket_free(sock);
 
59
        }
 
60
 
 
61
        g_free(e);
 
62
}
 
63
 
 
64
/**
 
65
 * free all pool entries of the queue
 
66
 *
 
67
 * used as GDestroyFunc in the user-hash of the pool
 
68
 *
 
69
 * @see network_connection_pool_init
 
70
 */
 
71
static void g_queue_free_all(gpointer q) {
 
72
        GQueue *queue = q;
 
73
        network_connection_pool_entry *entry;
 
74
 
 
75
        while ((entry = g_queue_pop_head(queue))) network_connection_pool_entry_free(entry, TRUE);
 
76
 
 
77
        g_queue_free(queue);
 
78
}
 
79
 
 
80
/**
 
81
 * init a connection pool
 
82
 */
 
83
network_connection_pool *network_connection_pool_init(void) {
 
84
        network_connection_pool *pool;
 
85
 
 
86
        pool = g_new0(network_connection_pool, 1);
 
87
 
 
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);
 
89
 
 
90
        return pool;
 
91
}
 
92
 
 
93
/**
 
94
 * free all entries of the pool
 
95
 *
 
96
 */
 
97
void network_connection_pool_free(network_connection_pool *pool) {
 
98
        if (!pool) return;
 
99
 
 
100
        g_hash_table_foreach_remove(pool->users, g_hash_table_true, NULL);
 
101
 
 
102
        g_hash_table_destroy(pool->users);
 
103
 
 
104
        g_free(pool);
 
105
}
 
106
 
 
107
/**
 
108
 * find the entry which has more than max_idle connections idling
 
109
 * 
 
110
 * @return TRUE for the first entry having more than _user_data idling connections
 
111
 * @see network_connection_pool_get_conns 
 
112
 */
 
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;
 
116
 
 
117
        return (conns->length > min_idle_conns);
 
118
}
 
119
 
 
120
GQueue *network_connection_pool_get_conns(network_connection_pool *pool, GString *username, GString *UNUSED_PARAM(default_db)) {
 
121
        GQueue *conns = NULL;
 
122
 
 
123
 
 
124
        if (username && username->len > 0) {
 
125
                conns = g_hash_table_lookup(pool->users, username);
 
126
                /**
 
127
                 * if we know this use, return a authed connection 
 
128
                 */
 
129
#ifdef DEBUG_CONN_POOL
 
130
                g_debug("%s: (get_conns) get user-specific idling connection for '%s' -> %p", G_STRLOC, username->str, conns);
 
131
#endif
 
132
                if (conns) return conns;
 
133
        }
 
134
 
 
135
        /**
 
136
         * we don't have a entry yet, check the others if we have more than 
 
137
         * min_idle waiting
 
138
         */
 
139
 
 
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);
 
143
#endif
 
144
 
 
145
        return conns;
 
146
}
 
147
 
 
148
/**
 
149
 * get a connection from the pool
 
150
 *
 
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
 
153
 *
 
154
 * @param username (optional) name of the auth connection
 
155
 */
 
156
network_socket *network_connection_pool_get(network_connection_pool *pool,
 
157
                GString *username,
 
158
                GString *UNUSED_PARAM(default_db)) {
 
159
 
 
160
        network_connection_pool_entry *entry = NULL;
 
161
        network_socket *sock = NULL;
 
162
 
 
163
        GQueue *conns = network_connection_pool_get_conns(pool, username, NULL);
 
164
 
 
165
        /**
 
166
         * if we know this use, return a authed connection 
 
167
         */
 
168
        if (conns) {
 
169
                entry = g_queue_pop_head(conns);
 
170
 
 
171
                if (conns->length == 0) {
 
172
                        /**
 
173
                         * all connections are gone, remove it from the hash
 
174
                         */
 
175
                        g_hash_table_remove(pool->users, username);
 
176
                }
 
177
        }
 
178
 
 
179
        if (!entry) {
 
180
#ifdef DEBUG_CONN_POOL
 
181
                g_debug("%s: (get) no entry for user '%s' -> %p", G_STRLOC, username ? username->str : "", conns);
 
182
#endif
 
183
                return NULL;
 
184
        }
 
185
 
 
186
        sock = entry->sock;
 
187
 
 
188
        network_connection_pool_entry_free(entry, FALSE);
 
189
 
 
190
        /* remove the idle handler from the socket */   
 
191
        event_del(&(sock->event));
 
192
                
 
193
#ifdef DEBUG_CONN_POOL
 
194
        g_debug("%s: (get) got socket for user '%s' -> %p", G_STRLOC, username ? username->str : "", sock);
 
195
#endif
 
196
 
 
197
        return sock;
 
198
}
 
199
 
 
200
/**
 
201
 * add a connection to the connection pool
 
202
 *
 
203
 */
 
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;
 
207
 
 
208
        entry = network_connection_pool_entry_init();
 
209
        entry->sock = sock;
 
210
        entry->pool = pool;
 
211
 
 
212
        g_get_current_time(&(entry->added_ts));
 
213
        
 
214
#ifdef DEBUG_CONN_POOL
 
215
        g_debug("%s: (add) adding socket to pool for user '%s' -> %p", G_STRLOC, sock->username->str, sock);
 
216
#endif
 
217
 
 
218
        if (NULL == (conns = g_hash_table_lookup(pool->users, sock->username))) {
 
219
                conns = g_queue_new();
 
220
 
 
221
                g_hash_table_insert(pool->users, g_string_dup(sock->username), conns);
 
222
        }
 
223
 
 
224
        g_queue_push_tail(conns, entry);
 
225
 
 
226
        return entry;
 
227
}
 
228
 
 
229
/**
 
230
 * remove the connection referenced by entry from the pool 
 
231
 */
 
232
void network_connection_pool_remove(network_connection_pool *pool, network_connection_pool_entry *entry) {
 
233
        network_socket *sock = entry->sock;
 
234
        GQueue *conns;
 
235
 
 
236
        if (NULL == (conns = g_hash_table_lookup(pool->users, sock->username))) {
 
237
                return;
 
238
        }
 
239
 
 
240
        network_connection_pool_entry_free(entry, TRUE);
 
241
 
 
242
        g_queue_remove(conns, entry);
 
243
}
 
244
 
 
245