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

538 by Kay Roepke
merge copyright changes
1
/* $%BEGINLICENSE%$
1037 by Kay Roepke
update copyright notices to oracle, update modification years
2
 Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
538 by Kay Roepke
merge copyright changes
3
1037 by Kay Roepke
update copyright notices to oracle, update modification years
4
 This program is free software; you can redistribute it and/or
5
 modify it under the terms of the GNU General Public License as
6
 published by the Free Software Foundation; version 2 of the
7
 License.
538 by Kay Roepke
merge copyright changes
8
9
 This program is distributed in the hope that it will be useful,
10
 but WITHOUT ANY WARRANTY; without even the implied warranty of
1037 by Kay Roepke
update copyright notices to oracle, update modification years
11
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
538 by Kay Roepke
merge copyright changes
12
 GNU General Public License for more details.
13
14
 You should have received a copy of the GNU General Public License
15
 along with this program; if not, write to the Free Software
1037 by Kay Roepke
update copyright notices to oracle, update modification years
16
 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
17
 02110-1301  USA
538 by Kay Roepke
merge copyright changes
18
19
 $%ENDLICENSE%$ */
431 by Kay Roepke
merge
20
#ifdef HAVE_CONFIG_H
21
#include "config.h"
22
#endif
23
24
#ifdef HAVE_SYS_FILIO_H
25
/**
26
 * required for FIONREAD on solaris
27
 */
28
#include <sys/filio.h>
29
#endif
30
31
#ifndef _WIN32
32
#include <sys/ioctl.h>
33
34
#include <sys/socket.h>
35
#include <netinet/in.h>
36
#include <arpa/inet.h>
37
#define ioctlsocket ioctl
38
#endif
39
40
#include <errno.h>
41
#include <lua.h>
42
43
#include "lua-env.h"
44
#include "glib-ext.h"
45
46
#include "network-mysqld.h"
468 by Kay Roepke
merge with jan's changes
47
#include "network-mysqld-packet.h"
566.1.4 by jan at mysql
replaced the direct calls to event_add() by the chassis-event-thread.c calls
48
#include "chassis-event-thread.h"
431 by Kay Roepke
merge
49
#include "network-mysqld-lua.h"
50
51
#include "network-conn-pool.h"
52
#include "network-conn-pool-lua.h"
53
54
/**
55
 * lua wrappers around the connection pool
56
 */
57
58
#define C(x) x, sizeof(x) - 1
59
60
/**
61
 * get the info connection pool 
62
 *
63
 * @return nil or requested information
64
 */
65
static int proxy_pool_queue_get(lua_State *L) {
66
	GQueue *queue = *(GQueue **)luaL_checkself(L); 
67
	gsize keysize = 0;
68
	const char *key = luaL_checklstring(L, 2, &keysize);
69
70
	if (strleq(key, keysize, C("cur_idle_connections"))) {
71
		lua_pushinteger(L, queue ? queue->length : 0);
72
	} else {
73
		lua_pushnil(L);
74
	}
75
76
	return 1;
77
}
78
79
int network_connection_pool_queue_getmetatable(lua_State *L) {
80
	static const struct luaL_reg methods[] = { 
81
		{ "__index", proxy_pool_queue_get },
82
83
		{ NULL, NULL },
84
	};
85
86
	return proxy_getmetatable(L, methods);
87
}
88
89
/**
90
 * get the info connection pool 
91
 *
92
 * @return nil or requested information
93
 */
94
static int proxy_pool_users_get(lua_State *L) {
95
	network_connection_pool *pool = *(network_connection_pool **)luaL_checkself(L); 
96
	const char *key = luaL_checkstring(L, 2); /** the username */
97
	GString *s = g_string_new(key);
98
	GQueue **q_p = NULL;
99
100
	q_p = lua_newuserdata(L, sizeof(*q_p)); 
101
	*q_p = network_connection_pool_get_conns(pool, s, NULL);
102
	g_string_free(s, TRUE);
103
104
	network_connection_pool_queue_getmetatable(L);
105
	lua_setmetatable(L, -2);
106
107
	return 1;
108
}
109
110
int network_connection_pool_users_getmetatable(lua_State *L) {
111
	static const struct luaL_reg methods[] = {
112
		{ "__index", proxy_pool_users_get },
113
		{ NULL, NULL },
114
	};
115
	
116
	return proxy_getmetatable(L, methods);
117
}
118
119
static int proxy_pool_get(lua_State *L) {
120
	network_connection_pool *pool = *(network_connection_pool **)luaL_checkself(L); 
121
	gsize keysize = 0;
122
	const char *key = luaL_checklstring(L, 2, &keysize);
123
124
	if (strleq(key, keysize, C("max_idle_connections"))) {
125
		lua_pushinteger(L, pool->max_idle_connections);
126
	} else if (strleq(key, keysize, C("min_idle_connections"))) {
127
		lua_pushinteger(L, pool->min_idle_connections);
128
	} else if (strleq(key, keysize, C("users"))) {
129
		network_connection_pool **pool_p;
130
131
		pool_p = lua_newuserdata(L, sizeof(*pool_p)); 
132
		*pool_p = pool;
133
134
		network_connection_pool_users_getmetatable(L);
135
		lua_setmetatable(L, -2);
136
	} else {
137
		lua_pushnil(L);
138
	}
139
140
	return 1;
141
}
142
143
144
static int proxy_pool_set(lua_State *L) {
145
	network_connection_pool *pool = *(network_connection_pool **)luaL_checkself(L);
146
	gsize keysize = 0;
147
	const char *key = luaL_checklstring(L, 2, &keysize);
148
149
	if (strleq(key, keysize, C("max_idle_connections"))) {
150
		pool->max_idle_connections = lua_tointeger(L, -1);
151
	} else if (strleq(key, keysize, C("min_idle_connections"))) {
152
		pool->min_idle_connections = lua_tointeger(L, -1);
153
	} else {
154
		return luaL_error(L, "proxy.backend[...].%s is not writable", key);
155
	}
156
157
	return 0;
158
}
159
160
int network_connection_pool_getmetatable(lua_State *L) {
161
	static const struct luaL_reg methods[] = {
162
		{ "__index", proxy_pool_get },
163
		{ "__newindex", proxy_pool_set },
164
		{ NULL, NULL },
165
	};
166
167
	return proxy_getmetatable(L, methods);
168
}
169
170
/**
171
 * handle the events of a idling server connection in the pool 
172
 *
173
 * make sure we know about connection close from the server side
174
 * - wait_timeout
175
 */
176
static void network_mysqld_con_idle_handle(int event_fd, short events, void *user_data) {
177
	network_connection_pool_entry *pool_entry = user_data;
178
	network_connection_pool *pool             = pool_entry->pool;
179
180
	if (events == EV_READ) {
181
		int b = -1;
182
183
		/**
184
		 * @todo we have to handle the case that the server really sent use something
185
		 *        up to now we just ignore it
186
		 */
187
		if (ioctlsocket(event_fd, FIONREAD, &b)) {
444 by jan at mysql
use g_strerror() instead of strerror() to satisfy win32
188
			g_critical("ioctl(%d, FIONREAD, ...) failed: %s", event_fd, g_strerror(errno));
431 by Kay Roepke
merge
189
		} else if (b != 0) {
190
			g_critical("ioctl(%d, FIONREAD, ...) said there is something to read, oops: %d", event_fd, b);
191
		} else {
192
			/* the server decided the close the connection (wait_timeout, crash, ... )
193
			 *
194
			 * remove us from the connection pool and close the connection */
195
		
196
			network_connection_pool_remove(pool, pool_entry);
197
		}
198
	}
199
}
200
201
202
/**
203
 * move the con->server into connection pool and disconnect the 
204
 * proxy from its backend 
205
 */
206
int network_connection_pool_lua_add_connection(network_mysqld_con *con) {
207
	network_connection_pool_entry *pool_entry = NULL;
208
	network_mysqld_con_lua_t *st = con->plugin_con_state;
209
210
	/* con-server is already disconnected, got out */
211
	if (!con->server) return 0;
212
213
	/* the server connection is still authed */
214
	con->server->is_authed = 1;
215
216
	/* insert the server socket into the connection pool */
217
	pool_entry = network_connection_pool_add(st->backend->pool, con->server);
218
219
	event_set(&(con->server->event), con->server->fd, EV_READ, network_mysqld_con_idle_handle, pool_entry);
566.1.4 by jan at mysql
replaced the direct calls to event_add() by the chassis-event-thread.c calls
220
	chassis_event_add_local(con->srv, &(con->server->event)); /* add a event, but stay in the same thread */
431 by Kay Roepke
merge
221
	
222
	st->backend->connected_clients--;
223
	st->backend = NULL;
224
	st->backend_ndx = -1;
225
	
226
	con->server = NULL;
227
228
	return 0;
229
}
230
231
/**
232
 * swap the server connection with a connection from
233
 * the connection pool
234
 *
235
 * we can only switch backends if we have a authed connection in the pool.
236
 *
237
 * @return NULL if swapping failed
238
 *         the new backend on success
239
 */
240
network_socket *network_connection_pool_lua_swap(network_mysqld_con *con, int backend_ndx) {
620 by jan at mysql
deprecated "backend_t", backend_init() and backend_free() in favour of network_backend_*
241
	network_backend_t *backend = NULL;
431 by Kay Roepke
merge
242
	network_socket *send_sock;
243
	network_mysqld_con_lua_t *st = con->plugin_con_state;
244
	chassis_private *g = con->srv->priv;
790 by jan at mysql
fixed compiler crash on hpux
245
	GString empty_username = { "", 0, 0 };
431 by Kay Roepke
merge
246
247
	/*
248
	 * we can only change to another backend if the backend is already
249
	 * in the connection pool and connected
250
	 */
251
252
	backend = network_backends_get(g->backends, backend_ndx);
253
	if (!backend) return NULL;
254
255
256
	/**
257
	 * get a connection from the pool which matches our basic requirements
258
	 * - username has to match
259
	 * - default_db should match
260
	 */
261
		
262
#ifdef DEBUG_CONN_POOL
263
	g_debug("%s: (swap) check if we have a connection for this user in the pool '%s'", G_STRLOC, con->client->username->str);
264
#endif
265
	if (NULL == (send_sock = network_connection_pool_get(backend->pool, 
461 by jan at mysql
fixed crash if connection pooling is used (regression of the cleanup in client->response)
266
					con->client->response ? con->client->response->username : &empty_username,
431 by Kay Roepke
merge
267
					con->client->default_db))) {
268
		/**
269
		 * no connections in the pool
270
		 */
271
		st->backend_ndx = -1;
272
		return NULL;
273
	}
274
275
	/* the backend is up and cool, take and move the current backend into the pool */
276
#ifdef DEBUG_CONN_POOL
277
	g_debug("%s: (swap) added the previous connection to the pool", G_STRLOC);
278
#endif
279
	network_connection_pool_lua_add_connection(con);
280
281
	/* connect to the new backend */
282
	st->backend = backend;
283
	st->backend->connected_clients++;
284
	st->backend_ndx = backend_ndx;
285
286
	return send_sock;
287
}
288
289
290