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 */
22
#include "network-mysqld.h"
23
#include "network-mysqld-proto.h"
24
#include "sys-pedantic.h"
31
* signal handlers have to be volatile
34
volatile int agent_shutdown = 0;
36
volatile sig_atomic_t agent_shutdown = 0;
39
static void signal_handler(int sig) {
41
case SIGINT: agent_shutdown = 1; break;
42
case SIGTERM: agent_shutdown = 1; break;
46
static void log_func(const gchar *UNUSED_PARAM(log_domain), GLogLevelFlags UNUSED_PARAM(log_level), const gchar *message, gpointer UNUSED_PARAM(user_data)) {
47
write(STDERR_FILENO, message, strlen(message));
48
write(STDERR_FILENO, "\n", 1);
51
void index_usage_rows(gpointer _key, gpointer _value, gpointer _rows) {
52
GPtrArray *rows = _rows;
55
network_mysqld_index_status *stats = _value;
57
row = g_ptr_array_new();
58
g_ptr_array_add(row, g_strdup(key));
59
g_ptr_array_add(row, g_strdup_printf(F_U64, stats->used));
60
g_ptr_array_add(row, g_strdup_printf("%u", stats->max_used_key_len));
61
g_ptr_array_add(row, g_strdup_printf("%.4f", stats->avg_used_key_len));
62
g_ptr_array_add(rows, row);
65
int index_usage_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
67
network_mysqld *srv = user_data;
69
field = network_mysqld_proto_field_init();
70
field->name = g_strdup("name");
71
field->org_name = g_strdup("name");
72
field->type = FIELD_TYPE_STRING;
73
field->flags = PRI_KEY_FLAG;
76
g_ptr_array_add(fields, field);
78
field = network_mysqld_proto_field_init();
79
field->name = g_strdup("used");
80
field->org_name = g_strdup("used");
81
field->type = FIELD_TYPE_LONGLONG;
82
field->flags = NUM_FLAG | UNSIGNED_FLAG;
84
g_ptr_array_add(fields, field);
86
field = network_mysqld_proto_field_init();
87
field->name = g_strdup("max_used_key_len");
88
field->org_name = g_strdup("max_used_key_len");
89
field->type = FIELD_TYPE_LONGLONG;
90
field->flags = NUM_FLAG | UNSIGNED_FLAG;
92
g_ptr_array_add(fields, field);
94
field = network_mysqld_proto_field_init();
95
field->name = g_strdup("avg_used_key_len");
96
field->org_name = g_strdup("avg_used_key_len");
97
field->type = FIELD_TYPE_DOUBLE;
98
field->flags = NUM_FLAG;
100
g_ptr_array_add(fields, field);
102
g_hash_table_foreach(srv->index_usage, index_usage_rows, rows);
107
int config_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
109
* show the current configuration
111
network_mysqld *srv = user_data;
116
field = network_mysqld_proto_field_init();
117
field->name = g_strdup("option");
118
field->org_name = g_strdup("option");
119
field->type = FIELD_TYPE_STRING;
120
field->flags = PRI_KEY_FLAG;
123
g_ptr_array_add(fields, field);
125
field = network_mysqld_proto_field_init();
126
field->name = g_strdup("value");
127
field->org_name = g_strdup("value");
128
field->type = FIELD_TYPE_STRING;
131
g_ptr_array_add(fields, field);
133
#define RESULTSET_ADD(x) \
134
row = g_ptr_array_new(); \
135
g_ptr_array_add(row, g_strdup(#x)); \
136
g_ptr_array_add(row, g_strdup_printf("%d", srv->config.x)); \
137
g_ptr_array_add(rows, row);
139
#define RESULTSET_ADD_STR(x) \
140
row = g_ptr_array_new(); \
141
g_ptr_array_add(row, g_strdup(#x)); \
142
g_ptr_array_add(row, g_strdup(srv->config.x)); \
143
g_ptr_array_add(rows, row);
145
#define RESULTSET_ADD_STR_ARRAY(x) \
146
for (i = 0; srv->config.x[i]; i++) { \
147
row = g_ptr_array_new(); \
148
g_ptr_array_add(row, g_strdup_printf("%s["F_SIZE_T"]", #x, i)); \
149
g_ptr_array_add(row, g_strdup(srv->config.x[i])); \
150
g_ptr_array_add(rows, row); \
153
RESULTSET_ADD_STR(admin.address);
154
RESULTSET_ADD_STR(proxy.address);
155
RESULTSET_ADD_STR(proxy.lua_script);
156
RESULTSET_ADD_STR_ARRAY(proxy.backend_addresses);
157
RESULTSET_ADD(proxy.fix_bug_25371);
158
RESULTSET_ADD(proxy.profiling);
163
int connections_select(GPtrArray *fields, GPtrArray *rows, gpointer user_data) {
164
network_mysqld *srv = user_data;
166
* show the current configuration
168
* TODO: move to the proxy-module
173
field = network_mysqld_proto_field_init();
174
field->name = g_strdup("id");
175
field->type = FIELD_TYPE_LONG;
176
field->flags = PRI_KEY_FLAG;
178
g_ptr_array_add(fields, field);
180
field = network_mysqld_proto_field_init();
181
field->name = g_strdup("type");
182
field->type = FIELD_TYPE_STRING;
184
g_ptr_array_add(fields, field);
186
field = network_mysqld_proto_field_init();
187
field->name = g_strdup("state");
188
field->type = FIELD_TYPE_STRING;
190
g_ptr_array_add(fields, field);
192
field = network_mysqld_proto_field_init();
193
field->name = g_strdup("db");
194
field->type = FIELD_TYPE_STRING;
196
g_ptr_array_add(fields, field);
198
for (i = 0; i < srv->cons->len; i++) {
200
network_mysqld_con *rcon = srv->cons->pdata[i];
203
if (rcon->is_listen_socket) continue;
205
row = g_ptr_array_new();
207
g_ptr_array_add(row, g_strdup_printf(F_SIZE_T, i));
208
switch (rcon->config.network_type) {
209
case NETWORK_TYPE_SERVER:
210
g_ptr_array_add(row, g_strdup("server"));
212
case NETWORK_TYPE_PROXY:
213
g_ptr_array_add(row, g_strdup("proxy"));
217
g_ptr_array_add(row, g_strdup_printf("%d", rcon->state));
218
g_ptr_array_add(row, g_strdup(rcon->default_db->len ? rcon->default_db->str : ""));
220
g_ptr_array_add(rows, row);
227
#define GETTEXT_PACKAGE "mysql-proxy"
229
int main(int argc, char **argv) {
231
network_mysqld_table *table;
233
/* read the command-line options */
234
GOptionContext *option_ctx;
235
GOptionGroup *option_grp;
239
int print_version = 0;
241
GOptionEntry admin_entries[] =
243
{ "admin-address", 0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of pseudo mysql-server (default: :4041)", "<ip:port>" },
245
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
248
GOptionEntry proxy_entries[] =
250
{ "proxy-address", 0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of the proxy-server (default: :4040)", "<ip:port>" },
251
{ "proxy-read-only-address", 0, 0, G_OPTION_ARG_STRING, NULL, "listening address:port of the proxy-server for read-only connection (default: :4042)", "<ip:port>" },
252
{ "proxy-backend-addresses", 0, 0, G_OPTION_ARG_STRING_ARRAY, NULL, "address:port of the remote backend-servers (default: not set)", "<ip:port>" },
254
{ "proxy-skip-profiling", 0, G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE, NULL, "disables profiling of queries (default: enabled)", NULL },
256
{ "proxy-fix-bug-25371", 0, 0, G_OPTION_ARG_NONE, NULL, "fix bug #25371 (mysqld > 5.1.12) for older libmysql versions", NULL },
257
{ "proxy-lua-script", 0, 0, G_OPTION_ARG_STRING, NULL, "filename of the lua script (default: not set)", "<file>" },
259
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
262
GOptionEntry main_entries[] =
264
{ "version", 0, 0, G_OPTION_ARG_NONE, NULL, "Show version", NULL },
266
{ NULL, 0, 0, G_OPTION_ARG_NONE, NULL, NULL, NULL }
270
srv = network_mysqld_init();
271
srv->config.network_type = NETWORK_TYPE_PROXY; /* doesn't matter anymore */
272
srv->config.proxy.fix_bug_25371 = 0; /** double ERR packet on AUTH failures */
273
srv->config.proxy.profiling = 1;
276
admin_entries[i++].arg_data = &(srv->config.admin.address);
279
proxy_entries[i++].arg_data = &(srv->config.proxy.address);
280
proxy_entries[i++].arg_data = &(srv->config.proxy.read_only_address);
281
proxy_entries[i++].arg_data = &(srv->config.proxy.backend_addresses);
283
proxy_entries[i++].arg_data = &(srv->config.proxy.profiling);
285
proxy_entries[i++].arg_data = &(srv->config.proxy.fix_bug_25371);
286
proxy_entries[i++].arg_data = &(srv->config.proxy.lua_script);
288
main_entries[0].arg_data = &(print_version);
290
signal(SIGINT, signal_handler);
291
signal(SIGTERM, signal_handler);
292
signal(SIGPIPE, SIG_IGN);
294
g_log_set_default_handler(log_func, NULL);
296
option_ctx = g_option_context_new("- MySQL Proxy");
297
g_option_context_add_main_entries(option_ctx, main_entries, GETTEXT_PACKAGE);
299
option_grp = g_option_group_new("admin", "admin module", "Show options for the admin-module", NULL, NULL);
300
g_option_group_add_entries(option_grp, admin_entries);
301
g_option_context_add_group(option_ctx, option_grp);
303
option_grp = g_option_group_new("proxy", "proxy-module", "Show options for the proxy-module", NULL, NULL);
304
g_option_group_add_entries(option_grp, proxy_entries);
305
g_option_context_add_group(option_ctx, option_grp);
307
if (FALSE == g_option_context_parse(option_ctx, &argc, &argv, &gerr)) {
308
g_critical("%s", gerr->message);
315
g_option_context_free(option_ctx);
318
printf("%s\n", PACKAGE_STRING);
322
if (!srv->config.proxy.address) srv->config.proxy.address = g_strdup(":4040");
323
if (!srv->config.proxy.backend_addresses) {
324
srv->config.proxy.backend_addresses = g_new0(char *, 2);
325
srv->config.proxy.backend_addresses[0] = g_strdup("127.0.0.1:3306");
328
if (!srv->config.admin.address) srv->config.admin.address = g_strdup(":4041");
330
table = network_mysqld_table_init();
331
table->select = connections_select;
332
table->user_data = srv;
333
g_hash_table_insert(srv->tables, g_strdup("proxy_connections"), table);
335
table = network_mysqld_table_init();
336
table->select = config_select;
337
table->user_data = srv;
338
g_hash_table_insert(srv->tables, g_strdup("proxy_config"), table);
340
table = network_mysqld_table_init();
341
table->select = index_usage_select;
342
table->user_data = srv;
343
g_hash_table_insert(srv->tables, g_strdup("index_usage"), table);
345
if (network_mysqld_thread(srv)) {
346
/* looks like we failed */
351
network_mysqld_free(srv);