main主函数
int main(int argc, char **argv) {
return main_cmdline(argc, argv);
}
main_cmdline函数
int main_cmdline(int argc, char **argv) {
//设置底盘的选项
opts = chassis_options_new();
chassis_frontend_set_chassis_options(frontend, opts);
main_entries = chassis_options_to_g_option_entries(opts);
//src\chassis-keyfile.c
chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)
//src\mysql-proxy-cli.c
//得到用户输入的/usr/local/wm/mysql-proxy/bin/mysql-proxy --defaults-file=/usr/local/wm/mysql-proxy/conf/source_wtf.cnf
//中的defaults-file
if (chassis_frontend_init_base_options(option_ctx, &argc, &argv, &(frontend->print_version), &(frontend->default_file), &gerr)) {
}
if (frontend->default_file) {
if (!(frontend->keyfile = chassis_frontend_open_config_file(frontend->default_file, &gerr))) {
g_log_dbproxy(g_critical, "loading config from ‘%s‘ failed: %s", frontend->default_file, gerr->message);
exit;
}
}
//得到defaults-file中的参数
if (frontend->keyfile) {
if (chassis_keyfile_to_options(frontend->keyfile, "mysql-proxy", main_entries)) {
GOTO_EXIT(EXIT_FAILURE);
}
}
//加载插件
if (chassis_frontend_load_plugins(srv->modules, frontend->plugin_dir, frontend->plugin_names)) {
}
//初始化插件选项
chassis_frontend_init_plugins(srv->modules, option_ctx, &argc, &argv, frontend->keyfile, "mysql-proxy", srv->base_dir, &gerr)) {
}
//启动多个线程, 并设置回调函数chassis_event_handle, 使用libevent
if (chassis_mainloop(srv)) {
/* looks like we failed */
g_log_dbproxy(g_critical, "Failure from chassis_mainloop. Shutting down");
exit;
}
}
chassis_options_new
位置:src\chassis-options.c
/** * create a command-line option */ chassis_options_t *chassis_options_new() { chassis_options_t *opt; opt = g_slice_new0(chassis_options_t); return opt; }
chassis_frontend_set_chassis_options
位置:src\mysql-proxy-cli.c
/** * setup the options of the chassis */ int chassis_frontend_set_chassis_options(chassis_frontend_t *frontend, chassis_options_t *opts) { chassis_options_add(opts, "verbose-shutdown", 0, 0, G_OPTION_ARG_NONE, &(frontend->verbose_shutdown), "Always log the exit code when shutting down", NULL, NULL, NULL, 0); }
chassis_options_add
位置:src\chassis-options.c
int chassis_options_add(chassis_options_t *opts, const char *long_name, gchar short_name, gint flags, GOptionArg arg, gpointer arg_data, const char *description, const char *arg_description, chas_opt_assign_hook assign_hook, chas_opt_show_hook show_hook, gint opt_property) { chassis_option_t *opt; opt = chassis_option_new(); if (0 != chassis_option_set(opt, long_name, short_name, flags, arg, arg_data, description, arg_description, assign_hook, show_hook, opt_property) || 0 != chassis_options_add_option(opts, opt)) { chassis_option_free(opt); return -1; } else { return 0; } }
chassis_option_set
位置:src\chassis-options.c
/** * add a option * * GOptionEntry */ int chassis_option_set(chassis_option_t *opt, const char *long_name, gchar short_name, gint flags, GOptionArg arg, gpointer arg_data, const char *description, const char *arg_description, chas_opt_assign_hook assign_hook, chas_opt_show_hook show_hook, gint opt_property) { opt->long_name = g_strdup(long_name); opt->short_name = short_name; opt->flags = flags; opt->arg = arg; opt->arg_data = arg_data; opt->description = g_strdup(description); opt->arg_description = g_strdup(arg_description); opt->assign_opts_hook = assign_hook; opt->show_hook = show_hook; opt->opt_property = opt_property; return 0; }
chassis_options_add_option
位置:src\chassis-options.c
/** * add a option * * GOptionEntry */ int chassis_options_add_option(chassis_options_t *opts, chassis_option_t *opt) { opts->options = g_list_append(opts->options, opt); return 0; }
chassis_options_to_g_option_entries
位置:src\chassis-options.c
/** * convert the chassis_options into a GOptionEntry * * @see chassis_options_free_g_option_entries */ GOptionEntry *chassis_options_to_g_option_entries(chassis_options_t *opts) { GOptionEntry *entries; int count; GList *node; /* build the GOptionEntry block */ for (node = opts->options, count = 0; node; node = node->next) { count++; } entries = g_new0(GOptionEntry, count + 1); for (node = opts->options, count = 0; node; node = node->next) { chassis_option_t *opt = node->data; entries[count].long_name = g_strdup(opt->long_name); entries[count].short_name = opt->short_name; entries[count].flags = opt->flags; entries[count].arg = opt->arg; entries[count].arg_data = opt->arg_data; entries[count].description = g_strdup(opt->description); entries[count].arg_description = g_strdup(opt->arg_description); count++; } entries[count].long_name = NULL; entries[count].short_name = 0; entries[count].flags = 0; entries[count].arg = 0; entries[count].arg_data = NULL; entries[count].description = NULL; entries[count].arg_description = NULL; return entries; }
chassis_keyfile_to_options
位置:src\chassis-keyfile.c
int chassis_keyfile_to_options(GKeyFile* keyfile, const gchar *ini_group_name, GOptionEntry *config_entries) { GError *gerr = NULL; int ret = 0; int i, j; /* all the options are in the group for "mysql-proxy" */ if (!keyfile) return -1; if (!g_key_file_has_group(keyfile, ini_group_name)) return 0; /* set the defaults */ for (i = 0; config_entries[i].long_name; i++) { GOptionEntry *entry = &(config_entries[i]); gchar *arg_string; gchar **arg_string_array; gboolean arg_bool = 0; gint arg_int = 0; gdouble arg_double = 0; gsize len = 0; switch (entry->arg) { case G_OPTION_ARG_FILENAME: case G_OPTION_ARG_STRING: /* is this option set already */ if (NULL == entry->arg_data || NULL != *(gchar **)(entry->arg_data)) break; arg_string = g_key_file_get_string(keyfile, ini_group_name, entry->long_name, &gerr); if (!gerr) { /* strip trailing spaces */ *(gchar **)(entry->arg_data) = g_strchomp(arg_string); } break; case G_OPTION_ARG_FILENAME_ARRAY: case G_OPTION_ARG_STRING_ARRAY: /* is this option set already */ if (NULL == entry->arg_data || NULL != *(gchar ***)(entry->arg_data)) break; arg_string_array = g_key_file_get_string_list(keyfile, ini_group_name, entry->long_name, &len, &gerr); if (!gerr) { for (j = 0; arg_string_array[j]; j++) { arg_string_array[j] = g_strstrip(arg_string_array[j]); } *(gchar ***)(entry->arg_data) = arg_string_array; } break; case G_OPTION_ARG_NONE: arg_bool = g_key_file_get_boolean(keyfile, ini_group_name, entry->long_name, &gerr); if (!gerr) { *(int *)(entry->arg_data) = arg_bool; } break; case G_OPTION_ARG_INT: arg_int = g_key_file_get_integer(keyfile, ini_group_name, entry->long_name, &gerr); if (!gerr) { *(gint *)(entry->arg_data) = arg_int; } break; #if GLIB_MAJOR_VERSION >= 2 && GLIB_MINOR_VERSION >= 12 case G_OPTION_ARG_DOUBLE: arg_double = g_key_file_get_double(keyfile, ini_group_name, entry->long_name, &gerr); if (!gerr) { *(gdouble *)(entry->arg_data) = arg_double; } break; #endif default: g_log_dbproxy(g_error, "(keyfile) the option %d can‘t be handled", entry->arg); break; } if (gerr) { if (gerr->code != G_KEY_FILE_ERROR_KEY_NOT_FOUND) { g_log_dbproxy(g_critical, "%s", gerr->message); ret = -1; } g_error_free(gerr); gerr = NULL; } } return ret; }
chassis_frontend_init_base_options
位置:src\chassis-frontend.c
int chassis_frontend_init_base_options(GOptionContext *option_ctx, int *argc_p, char ***argv_p, int *print_version, char **config_file, GError **gerr) { chassis_options_t *opts; GOptionEntry *base_main_entries; int ret = 0; opts = chassis_options_new(); chassis_options_set_cmdline_only_options(opts, print_version, config_file); base_main_entries = chassis_options_to_g_option_entries(opts); g_option_context_add_main_entries(option_ctx, base_main_entries, NULL); g_option_context_set_help_enabled(option_ctx, FALSE); g_option_context_set_ignore_unknown_options(option_ctx, TRUE); if (FALSE == g_option_context_parse(option_ctx, argc_p, argv_p, gerr)) { ret = -1; } /* do not use chassis_options_free_g_options... here, we need to hang on to the data until the end of the program! */ chassis_frontend_options_free(base_main_entries); chassis_options_free(opts); return ret; }
chassis_options_set_cmdline_only_options
位置: src\chassis-frontend.c
/** * setup the options that can only appear on the command-line */ int chassis_options_set_cmdline_only_options(chassis_options_t *opts, int *print_version, char **config_file) { chassis_options_add(opts, "version", ‘V‘, 0, G_OPTION_ARG_NONE, print_version, "Show version", NULL, NULL, NULL, 0); chassis_options_add(opts, "defaults-file", 0, 0, G_OPTION_ARG_STRING, config_file, "configuration file", "<file>", NULL, NULL, 0); return 0; }
chassis_frontend_init_plugins
位置:src\chassis-frontend.c
int chassis_frontend_init_plugins(GPtrArray *plugins, GOptionContext *option_ctx, int *argc_p, char ***argv_p, GKeyFile *keyfile, const char* keyfile_section_name, const char *base_dir, GError **gerr) { guint i; for (i = 0; i < plugins->len; i++) { GOptionEntry *config_entries = NULL; chassis_plugin *p = plugins->pdata[i]; chassis_options_t *plugin_opts = NULL; if (NULL != (plugin_opts = chassis_plugin_get_options(p))) { gchar *group_desc = g_strdup_printf("%s-module", p->option_grp_name); gchar *help_msg = g_strdup_printf("Show options for the %s-module", p->option_grp_name); const gchar *group_name = p->option_grp_name; config_entries = chassis_options_to_g_option_entries(plugin_opts); GOptionGroup *option_grp = g_option_group_new(group_name, group_desc, help_msg, NULL, NULL); g_option_group_add_entries(option_grp, config_entries); g_option_context_add_group(option_ctx, option_grp); g_free(help_msg); g_free(group_desc); /* parse the new options */ if (FALSE == g_option_context_parse(option_ctx, argc_p, argv_p, gerr)) { return -1; } if (keyfile) { if (chassis_keyfile_to_options(keyfile, keyfile_section_name, config_entries)) { return -1; } } /* resolve the path names for these config entries */ chassis_keyfile_resolve_path(base_dir, config_entries); } if (config_entries != NULL) { chassis_frontend_options_free(config_entries); } } return 0; }
chassis_plugin_get_options
位置:src\chassis-plugin.c
chassis_options_t* chassis_plugin_get_options(chassis_plugin *p) { chassis_options_t * options; if (!p->get_options) return NULL; if (NULL == (options = p->get_options(p->config))) { g_log_dbproxy(g_critical, "adding config options for module ‘%s‘ failed", p->name); } return options; }
chassis_frontend_load_plugins
位置src\chassis-frontend.c
int chassis_frontend_load_plugins(GPtrArray *plugins, const gchar *plugin_dir, gchar **plugin_names) { int i; /* load the plugins */ for (i = 0; plugin_names && plugin_names[i]; i++) { chassis_plugin *p; char *plugin_filename; /* skip trying to load a plugin when the parameter was --plugins= that will never work... */ if (!g_strcmp0("", plugin_names[i])) { continue; } plugin_filename = g_strdup_printf("%s%c%s%s.%s", plugin_dir, G_DIR_SEPARATOR, G_MODULE_PREFIX, plugin_names[i], SHARED_LIBRARY_SUFFIX); p = chassis_plugin_load(plugin_filename); g_free(plugin_filename); if (NULL == p) { g_log_dbproxy(g_critical, "setting --plugin-dir=<dir> might help"); return -1; } p->option_grp_name = g_strdup(plugin_names[i]); g_ptr_array_add(plugins, p); } return 0; }
chassis_plugin_load
位置:src\chassis-plugin.c
chassis_plugin* chassis_plugin_load(const gchar *name) { int (*plugin_init)(chassis_plugin *p); chassis_plugin *p = chassis_plugin_new(); p->module = g_module_open(name, G_MODULE_BIND_LOCAL); if (!p->module) { g_log_dbproxy(g_critical, "loading module ‘%s‘ failed: %s", name, g_module_error()); chassis_plugin_free(p); return NULL; } /* each module has to have a plugin_init function */ if (!g_module_symbol(p->module, "plugin_init", (gpointer) &plugin_init)) { g_log_dbproxy(g_critical, "module ‘%s‘ doesn‘t have a init-function: %s", name, g_module_error()); chassis_plugin_free(p); return NULL; } if (0 != plugin_init(p)) { g_log_dbproxy(g_critical, "init-function for module ‘%s‘ failed", name); chassis_plugin_free(p); return NULL; } if (p->magic != CHASSIS_PLUGIN_MAGIC) { g_log_dbproxy(g_critical, "plugin ‘%s‘ doesn‘t match the current plugin interface (plugin is %lx, chassis is %lx)", name, p->magic, CHASSIS_PLUGIN_MAGIC); chassis_plugin_free(p); return NULL; } if (p->init) { p->config = p->init(); } /* if the plugins haven‘t set p->name provide our own name */ if (!p->name) p->name = g_strdup(name); /* set dummy version number if the plugin doesn‘t provide a real one */ if (!p->version) { g_log_dbproxy(g_critical, "plugin ‘%s‘ doesn‘t set a version number, refusing to load this plugin", name); chassis_plugin_free(p); return NULL; } if (p->new_stats) { p->stats = p->new_stats(); } return p; }
plugin_init
位置:plugins\proxy\proxy-plugin.c
G_MODULE_EXPORT int plugin_init(chassis_plugin *p) { p->magic = CHASSIS_PLUGIN_MAGIC; p->name = g_strdup("proxy"); p->version = g_strdup(PACKAGE_VERSION); p->init = network_mysqld_proxy_plugin_new; p->get_options = network_mysqld_proxy_plugin_get_options; p->apply_config = network_mysqld_proxy_plugin_apply_config; p->destroy = network_mysqld_proxy_plugin_free; return 0; }
network_mysqld_proxy_plugin_new
位置:plugins\proxy\proxy-plugin.c
//全局变量 chassis_plugin_config *config = NULL; chassis_plugin_config * network_mysqld_proxy_plugin_new(void) { config = g_new0(chassis_plugin_config, 1); config->fix_bug_25371 = 0; /** double ERR packet on AUTH failures */ config->profiling = 1; config->start_proxy = 1; config->pool_change_user = 1; /* issue a COM_CHANGE_USER to cleanup the connection when we get back the connection from the pool */ config->dt_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)dt_table_free); config->select_where_limit_str = NULL; config->select_where_limit = SEL_OFF; config->charset = NULL; config->opts = NULL; config->percentile_value = 64; config->check_state_conn_timeout = 3; config->check_state_interval = PROXY_CHECK_STATE_WAIT_TIMEOUT; config->check_state_retry_times = RETRY_TIMES; config->check_state_sleep_delay = SLEEP_DELAY; g_rw_lock_init(&config->config_lock); config->sql_log_mgr = sql_log_t_new(); config->percentile_controller = pt_percentile_new(6.0, 29.0, 2); config->plugin_threads = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, (GDestroyNotify)plugin_thread_t_free); config->table_prefix = NULL; config->table_suffix = NULL; config->tnw = tbl_name_wrap_new(); return config; }
network_mysqld_proxy_plugin_get_options
位置:plugins\proxy\proxy-plugin.c
设置插件的选项 我们更改的id-generate 就在这里 需要在 1)config增加新的属性id-generate ./plugins/proxy/proxy-plugin.h struct chassis_plugin_config { ... gchar* id_generate; }; 2)初始化 ./plugins/proxy/proxy-plugin.c chassis_plugin_config * network_mysqld_proxy_plugin_new(void) { ... config->id_generate = NULL; return config; }
static chassis_options_t * network_mysqld_proxy_plugin_get_options(chassis_plugin_config *oldconfig) { if (config->opts == NULL) { chassis_options_t *opts = chassis_options_new(); chassis_options_add(opts, "proxy-address", ‘P‘, 0, G_OPTION_ARG_STRING, &(config->address), "listening address:port of the proxy-server (default: :4040)", "<host:port>", NULL, show_proxy_address, SHOW_OPTS_PROPERTY); chassis_options_add(opts, "id-generate", 0, 0, G_OPTION_ARG_STRING, &(config->id_generate), "Run mysql-proxy as user", NULL, NULL, NULL, 0); config->opts = opts; } return config->opts; }
chassis_mainloop
位置:src\chassis-mainloop.c
int chassis_mainloop(void *_chas) { chassis *chas = _chas; guint i; struct event ev_sigterm, ev_sigint; #ifdef SIGHUP struct event ev_sighup; #endif chassis_event_thread_t *mainloop_thread; /* redirect logging from libevent to glib */ event_set_log_callback(event_log_use_glib); /* add a event-handler for the "main" events */ mainloop_thread = chassis_event_thread_new(0); chassis_event_threads_init_thread(mainloop_thread, chas); g_ptr_array_add(chas->threads, mainloop_thread); chas->event_base = mainloop_thread->event_base; /* all global events go to the 1st thread */ g_assert(chas->event_base); /* setup all plugins all plugins */ for (i = 0; i < chas->modules->len; i++) { chassis_plugin *p = chas->modules->pdata[i]; g_assert(p->apply_config); if (0 != p->apply_config(chas, p->config)) { g_log_dbproxy(g_critical, "applying config of plugin %s failed", p->name); return -1; } } signal_set(&ev_sigterm, SIGTERM, sigterm_handler, NULL); event_base_set(chas->event_base, &ev_sigterm); signal_add(&ev_sigterm, NULL); signal_set(&ev_sigint, SIGINT, sigint_handler, NULL); event_base_set(chas->event_base, &ev_sigint); signal_add(&ev_sigint, NULL); #ifdef SIGHUP signal_set(&ev_sighup, SIGHUP, sighup_handler, chas); event_base_set(chas->event_base, &ev_sighup); if (signal_add(&ev_sighup, NULL)) { g_log_dbproxy(g_critical, "signal_add(SIGHUP) failed"); } #endif if (chas->event_thread_count < 1) chas->event_thread_count = 1; /* create the event-threads * * - dup the async-queue-ping-fds * - setup the events notification * */ for (i = 1; i <= (guint)chas->event_thread_count; i++) { /* we already have 1 event-thread running, the main-thread */ chassis_event_thread_t *thread = chassis_event_thread_new(i); chassis_event_threads_init_thread(thread, chas); g_ptr_array_add(chas->threads, thread); } /* start the event threads */ chassis_event_threads_start(chas->threads); /** * handle signals and all basic events into the main-thread * * block until we are asked to shutdown */ chassis_mainloop_thread_loop(mainloop_thread); signal_del(&ev_sigterm); signal_del(&ev_sigint); #ifdef SIGHUP signal_del(&ev_sighup); #endif return 0; }
chassis_event_thread_new
位置:src\chassis-event-thread.c
/** * create the data structure for a new event-thread */ chassis_event_thread_t* chassis_event_thread_new(guint index) { chassis_event_thread_t *thread = g_new0(chassis_event_thread_t, 1); thread->index = index; thread->event_queue = g_async_queue_new(); g_rw_lock_init(&thread->connection_lock); thread->connection_list = NULL; thread->exit_phase = EVENT_THREAD_NORMAL; return thread; }
chassis_event_threads_init_thread
位置:src\chassis-event-thread.c
/** * setup the notification-fd of a event-thread * * all event-threads listen on the same notification pipe * * @see chassis_event_handle() */ int chassis_event_threads_init_thread(chassis_event_thread_t *thread, chassis *chas) { thread->event_base = event_base_new(); thread->chas = chas; int fds[2]; if (pipe(fds)) { int err; err = errno; g_log_dbproxy(g_error, "evutil_socketpair() failed: %s (%d)", g_strerror(err), err); } thread->notify_receive_fd = fds[0]; thread->notify_send_fd = fds[1]; event_set(&(thread->notify_fd_event), thread->notify_receive_fd, EV_READ | EV_PERSIST, chassis_event_handle, thread); event_base_set(thread->event_base, &(thread->notify_fd_event)); event_add(&(thread->notify_fd_event), NULL); return 0; }
chassis_event_threads_start
位置:src\chassis-event-thread.c
/** * start all the event-threads * * starts all the event-threads that got added by chassis_event_threads_add() * * @see chassis_event_threads_add */ void chassis_event_threads_start(GPtrArray *threads) { guint i; g_log_dbproxy(g_message, "starting %d threads", threads->len - 1); for (i = 1; i < threads->len; i++) { /* the 1st is the main-thread and already set up */ chassis_event_thread_t *thread = threads->pdata[i]; GError *gerr = NULL; thread->thr = g_thread_try_new("event thread", (GThreadFunc)chassis_event_thread_loop, thread, &gerr); if (gerr) { g_log_dbproxy(g_critical, "%s", gerr->message); g_error_free(gerr); gerr = NULL; } } }
chassis_mainloop_thread_loop
位置:src\chassis-event-thread.c
/** * event-handler thread * */ void* chassis_mainloop_thread_loop(chassis_event_thread_t *thread) { cur_thid = thread->index; gboolean is_all_work_thread_exit = FALSE; g_assert(thread->index == 0); /** * check once a second if we shall shutdown the proxy */ while (!chassis_is_shutdown() || !is_all_work_thread_exit) { struct timeval timeout; int r; timeout.tv_sec = 1; timeout.tv_usec = 0; g_assert(event_base_loopexit(thread->event_base, &timeout) == 0); r = event_base_dispatch(thread->event_base); if (r == -1) { if (errno == EINTR) continue; g_log_dbproxy(g_critical, "leaving chassis_event_thread_loop early, errno != EINTR was: %s (%d)", g_strerror(errno), errno); break; } if (chassis_is_shutdown()) { gint i = 1; for (; i < thread->chas->threads->len; i++) { chassis_event_thread_t *event_thread = g_ptr_array_index(thread->chas->threads, i); if (g_atomic_int_get(&event_thread->exit_phase) != EVENT_THREAD_EXITED) break; } if (i == thread->chas->threads->len) { is_all_work_thread_exit = TRUE; } } } g_log_dbproxy(g_message, "main loop thread will exit"); return NULL; }