Kouhei Sutou
null+****@clear*****
Mon Jan 5 22:54:41 JST 2015
Kouhei Sutou 2015-01-05 22:54:41 +0900 (Mon, 05 Jan 2015) New Revision: 568d8e082b67bded0af537deebda5c5c3b22f6da https://github.com/groonga/groonga/commit/568d8e082b67bded0af537deebda5c5c3b22f6da Message: plugin mrb: support plugin written by mruby It's experimental feature. Added files: lib/mrb/scripts/plugin_loader.rb Modified files: include/groonga/groonga.h lib/ctx_impl_mrb.c lib/db.c lib/grn_ctx_impl.h lib/grn_plugin.h lib/mrb/scripts/context/rc.rb lib/mrb/scripts/initialize/post.rb lib/mrb/scripts/sources.am lib/plugin.c Modified: include/groonga/groonga.h (+1 -0) =================================================================== --- include/groonga/groonga.h 2015-01-05 22:48:29 +0900 (cdab232) +++ include/groonga/groonga.h 2015-01-05 22:54:41 +0900 (d1c9347) @@ -120,6 +120,7 @@ typedef enum { GRN_NORMALIZER_ERROR = -72, GRN_TOKEN_FILTER_ERROR = -73, GRN_COMMAND_ERROR = -74, + GRN_PLUGIN_ERROR = -75, } grn_rc; GRN_API grn_rc grn_init(void); Modified: lib/ctx_impl_mrb.c (+8 -0) =================================================================== --- lib/ctx_impl_mrb.c 2015-01-05 22:48:29 +0900 (1c2cf39) +++ lib/ctx_impl_mrb.c 2015-01-05 22:54:41 +0900 (c6d4eea) @@ -139,6 +139,8 @@ grn_ctx_impl_mrb_init(grn_ctx *ctx) ctx->impl->mrb.base_directory[0] = '\0'; ctx->impl->mrb.module = NULL; ctx->impl->mrb.object_class = NULL; + ctx->impl->mrb.checked_procs = NULL; + ctx->impl->mrb.registered_plugins = NULL; } else { ctx->impl->mrb.state = mrb_open(); ctx->impl->mrb.base_directory[0] = '\0'; @@ -147,6 +149,10 @@ grn_ctx_impl_mrb_init(grn_ctx *ctx) if (ctx->impl->mrb.state->exc) { mrb_print_error(ctx->impl->mrb.state); } + ctx->impl->mrb.checked_procs = + grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY); + ctx->impl->mrb.registered_plugins = + grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY); } } @@ -156,6 +162,8 @@ grn_ctx_impl_mrb_fin(grn_ctx *ctx) if (ctx->impl->mrb.state) { mrb_close(ctx->impl->mrb.state); ctx->impl->mrb.state = NULL; + grn_hash_close(ctx, ctx->impl->mrb.checked_procs); + grn_hash_close(ctx, ctx->impl->mrb.registered_plugins); } } #else Modified: lib/db.c (+3 -0) =================================================================== --- lib/db.c 2015-01-05 22:48:29 +0900 (28b8cbf) +++ lib/db.c 2015-01-05 22:54:41 +0900 (1ebbfd1) @@ -8564,6 +8564,9 @@ grn_ctx_at(grn_ctx *ctx, grn_id id) } } res = vp->ptr; + if (res->header.type == GRN_PROC) { + grn_plugin_ensure_registered(ctx, res); + } } } exit : Modified: lib/grn_ctx_impl.h (+2 -0) =================================================================== --- lib/grn_ctx_impl.h 2015-01-05 22:48:29 +0900 (03fe8fc) +++ lib/grn_ctx_impl.h 2015-01-05 22:54:41 +0900 (1c41fe1) @@ -99,6 +99,8 @@ struct _grn_mrb_data { char base_directory[PATH_MAX]; struct RClass *module; struct RClass *object_class; + grn_hash *checked_procs; + grn_hash *registered_plugins; }; #endif Modified: lib/grn_plugin.h (+1 -0) =================================================================== --- lib/grn_plugin.h 2015-01-05 22:48:29 +0900 (d5636e3) +++ lib/grn_plugin.h 2015-01-05 22:54:41 +0900 (121c314) @@ -52,6 +52,7 @@ grn_rc grn_plugin_close(grn_ctx *ctx, grn_id id); grn_id grn_plugin_reference(grn_ctx *ctx, const char *filename); const char *grn_plugin_path(grn_ctx *ctx, grn_id id); char *grn_plugin_find_path(grn_ctx *ctx, const char *name); +void grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc); #ifdef __cplusplus } Modified: lib/mrb/scripts/context/rc.rb (+1 -0) =================================================================== --- lib/mrb/scripts/context/rc.rb 2015-01-05 22:48:29 +0900 (bd062d4) +++ lib/mrb/scripts/context/rc.rb 2015-01-05 22:54:41 +0900 (30dd312) @@ -96,6 +96,7 @@ module Groonga NORMALIZER_ERROR = new(:normalizer_error, -72) TOKEN_FILTER_ERROR = new(:token_filter, -73) COMMAND_ERROR = new(:command_error, -74) + PLUGIN_ERROR = new(:plugin_error, -75) end end end Modified: lib/mrb/scripts/initialize/post.rb (+2 -0) =================================================================== --- lib/mrb/scripts/initialize/post.rb 2015-01-05 22:48:29 +0900 (bfbee07) +++ lib/mrb/scripts/initialize/post.rb 2015-01-05 22:54:41 +0900 (b9ae0cb) @@ -4,4 +4,6 @@ require "database" require "command" require "table_cursor" +require "plugin_loader" + require "eval_context" Added: lib/mrb/scripts/plugin_loader.rb (+14 -0) 100644 =================================================================== --- /dev/null +++ lib/mrb/scripts/plugin_loader.rb 2015-01-05 22:54:41 +0900 (09b972f) @@ -0,0 +1,14 @@ +module Groonga + class PluginLoader + class << self + def load_file(path) + begin + load(path) + rescue => error + Context.instance.record_error(:plugin_error, error) + nil + end + end + end + end +end Modified: lib/mrb/scripts/sources.am (+1 -0) =================================================================== --- lib/mrb/scripts/sources.am 2015-01-05 22:48:29 +0900 (4a7da87) +++ lib/mrb/scripts/sources.am 2015-01-05 22:54:41 +0900 (79ef475) @@ -14,6 +14,7 @@ RUBY_SCRIPT_FILES = \ initialize/post.rb \ logger.rb \ logger/level.rb \ + plugin_loader.rb \ require.rb \ scan_info.rb \ scan_info_builder.rb \ Modified: lib/plugin.c (+268 -56) =================================================================== --- lib/plugin.c 2015-01-05 22:48:29 +0900 (6ee33cc) +++ lib/plugin.c 2015-01-05 22:54:41 +0900 (a6ba608) @@ -27,10 +27,14 @@ #include "grn_ctx_impl.h" #include "grn_util.h" +#ifdef GRN_WITH_MRUBY +# include <mruby.h> +#endif + static grn_hash *grn_plugins = NULL; static grn_critical_section grn_plugins_lock; -#define PATHLEN(filename) (strlen(filename) + 1) +static const char *grn_plugin_mrb_suffix = ".rb"; #ifdef HAVE_DLFCN_H # include <dlfcn.h> @@ -71,7 +75,7 @@ grn_plugin_reference(grn_ctx *ctx, const char *filename) grn_plugin **plugin = NULL; CRITICAL_SECTION_ENTER(grn_plugins_lock); - id = grn_hash_get(&grn_gctx, grn_plugins, filename, PATHLEN(filename), + id = grn_hash_get(&grn_gctx, grn_plugins, filename, strlen(filename), (void **)&plugin); if (plugin) { (*plugin)->refcount++; @@ -130,6 +134,34 @@ grn_plugin_call_init(grn_ctx *ctx, grn_id id) return GRN_SUCCESS; } +#ifdef GRN_WITH_MRUBY +static grn_rc +grn_plugin_call_register_mrb(grn_ctx *ctx, grn_id id, grn_plugin *plugin) +{ + grn_mrb_data *data = &(ctx->impl->mrb); + mrb_state *mrb = data->state; + struct RClass *module = data->module; + struct RClass *plugin_loader_class; + int arena_index; + + { + int added; + grn_hash_add(ctx, ctx->impl->mrb.registered_plugins, + &id, sizeof(grn_id), NULL, &added); + if (!added) { + return ctx->rc; + } + } + + arena_index = mrb_gc_arena_save(mrb); + plugin_loader_class = mrb_class_get_under(mrb, module, "PluginLoader"); + mrb_funcall(mrb, mrb_obj_value(plugin_loader_class), + "load_file", 1, mrb_str_new_cstr(mrb, ctx->impl->plugin_path)); + mrb_gc_arena_restore(mrb, arena_index); + return ctx->rc; +} +#endif /*GRN_WITH_MRUBY */ + static grn_rc grn_plugin_call_register(grn_ctx *ctx, grn_id id) { @@ -137,6 +169,11 @@ grn_plugin_call_register(grn_ctx *ctx, grn_id id) if (!grn_hash_get_value(&grn_gctx, grn_plugins, id, &plugin)) { return GRN_INVALID_ARGUMENT; } +#ifdef GRN_WITH_MRUBY + if (!plugin->dl) { + return grn_plugin_call_register_mrb(ctx, id, plugin); + } +#endif /* GRN_WITH_MRUBY */ if (plugin->register_func) { return plugin->register_func(ctx); } @@ -197,22 +234,63 @@ grn_plugin_initialize(grn_ctx *ctx, grn_plugin *plugin, return ctx->rc; } +#ifdef GRN_WITH_MRUBY +static grn_id +grn_plugin_open_mrb(grn_ctx *ctx, const char *filename, size_t filename_size) +{ + grn_id id = GRN_ID_NIL; + grn_plugin **plugin = NULL; + + id = grn_hash_add(&grn_gctx, grn_plugins, filename, filename_size, + (void **)&plugin, NULL); + if (!id) { + return id; + } + + *plugin = GRN_GMALLOCN(grn_plugin, 1); + if (!*plugin) { + grn_hash_delete_by_id(&grn_gctx, grn_plugins, id, NULL); + return GRN_ID_NIL; + } + + (*plugin)->dl = NULL; + (*plugin)->init_func = NULL; + (*plugin)->register_func = NULL; + (*plugin)->fin_func = NULL; + (*plugin)->refcount = 1; + + return id; +} +#endif /* GRN_WITH_MRUBY */ + grn_id grn_plugin_open(grn_ctx *ctx, const char *filename) { - grn_id id; + grn_id id = GRN_ID_NIL; grn_dl dl; grn_plugin **plugin = NULL; + size_t filename_size; + + filename_size = strlen(filename); CRITICAL_SECTION_ENTER(grn_plugins_lock); - if ((id = grn_hash_get(&grn_gctx, grn_plugins, filename, PATHLEN(filename), + if ((id = grn_hash_get(&grn_gctx, grn_plugins, filename, filename_size, (void **)&plugin))) { (*plugin)->refcount++; goto exit; } +#ifdef GRN_WITH_MRUBY + if (filename_size > strlen(grn_plugin_mrb_suffix) && + strcmp(filename + (filename_size - strlen(grn_plugin_mrb_suffix)), + grn_plugin_mrb_suffix) == 0) { + id = grn_plugin_open_mrb(ctx, filename, filename_size); + goto exit; + } +#endif /* GRN_WITH_MRUBY */ + if ((dl = grn_dl_open(filename))) { - if ((id = grn_hash_add(&grn_gctx, grn_plugins, filename, PATHLEN(filename), + if ((id = grn_hash_add(&grn_gctx, grn_plugins, filename, filename_size, (void **)&plugin, NULL))) { *plugin = GRN_GMALLOCN(grn_plugin, 1); if (*plugin) { @@ -274,11 +352,13 @@ grn_plugin_close(grn_ctx *ctx, grn_id id) rc = GRN_SUCCESS; goto exit; } - grn_plugin_call_fin(ctx, id); - if (!grn_dl_close(plugin->dl)) { - const char *label; - label = grn_dl_close_error_label(); - SERR(label); + if (plugin->dl) { + grn_plugin_call_fin(ctx, id); + if (!grn_dl_close(plugin->dl)) { + const char *label; + label = grn_dl_close_error_label(); + SERR(label); + } } GRN_GFREE(plugin); rc = grn_hash_delete_by_id(&grn_gctx, grn_plugins, id, NULL); @@ -399,6 +479,105 @@ grn_plugin_get_system_plugins_dir(void) } #endif /* WIN32 */ +static char * +grn_plugin_find_path_raw(grn_ctx *ctx, const char *path) +{ + FILE *plugin_file; + + plugin_file = fopen(path, "r"); + + if (!plugin_file) { + return NULL; + } + + fclose(plugin_file); + return GRN_STRDUP(path); +} + +#if GRN_WITH_MRUBY +static char * +grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) +{ + char mrb_path[PATH_MAX]; + const char *mrb_suffix = grn_plugin_mrb_suffix; + size_t mrb_path_len; + + mrb_path_len = path_len + strlen(mrb_suffix); + if (mrb_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%s%s>", + path, mrb_suffix); + return NULL; + } + + strcpy(mrb_path, path); + strcat(mrb_path, mrb_suffix); + return grn_plugin_find_path_raw(ctx, mrb_path); +} +#else /* GRN_WITH_MRUBY */ +static char * +grn_plugin_find_path_mrb(grn_ctx *ctx, const char *path, size_t path_len) +{ + return NULL; +} +#endif /* GRN_WITH_MRUBY */ + +static char * +grn_plugin_find_path_so(grn_ctx *ctx, const char *path, size_t path_len) +{ + char so_path[PATH_MAX]; + const char *so_suffix; + size_t so_path_len; + + so_suffix = grn_plugin_get_suffix(); + so_path_len = path_len + strlen(so_suffix); + if (so_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%s%s>", + path, so_suffix); + return NULL; + } + + strcpy(so_path, path); + strcat(so_path, so_suffix); + return grn_plugin_find_path_raw(ctx, so_path); +} + +static char * +grn_plugin_find_path_libs_so(grn_ctx *ctx, const char *path, size_t path_len) +{ + char libs_so_path[PATH_MAX]; + const char *base_name; + const char *so_suffix; + const char *libs_path = "/.libs"; + size_t libs_so_path_len; + + base_name = strrchr(path, '/'); + if (!base_name) { + return NULL; + } + + so_suffix = grn_plugin_get_suffix(); + libs_so_path_len = + base_name - path + + strlen(libs_path) + + strlen(base_name) + + strlen(so_suffix); + if (libs_so_path_len >= PATH_MAX) { + ERR(GRN_FILENAME_TOO_LONG, + "too long plugin path: <%.*s/.libs%s%s>", + (int)(base_name - path), path, base_name, so_suffix); + return NULL; + } + + libs_so_path[0] = '\0'; + strncat(libs_so_path, path, base_name - path); + strcat(libs_so_path, libs_path); + strcat(libs_so_path, base_name); + strcat(libs_so_path, so_suffix); + return grn_plugin_find_path_raw(ctx, libs_so_path); +} + char * grn_plugin_find_path(grn_ctx *ctx, const char *name) { @@ -406,8 +585,6 @@ grn_plugin_find_path(grn_ctx *ctx, const char *name) char dir_last_char; char path[PATH_MAX]; int name_length, max_name_length; - FILE *plugin_file; - char complemented_path[PATH_MAX], complemented_libs_path[PATH_MAX]; char *found_path = NULL; size_t path_len; @@ -438,50 +615,34 @@ grn_plugin_find_path(grn_ctx *ctx, const char *name) } strcat(path, name); - plugin_file = fopen(path, "r"); - if (plugin_file) { - fclose(plugin_file); - found_path = GRN_STRDUP(path); - } else { - path_len = strlen(path); - path_len += strlen(grn_plugin_get_suffix()); - if (path_len >= PATH_MAX) { - ERR(GRN_FILENAME_TOO_LONG, - "too long plugin path: <%s%s>", - path, grn_plugin_get_suffix()); - goto exit; - } - strcpy(complemented_path, path); - strcat(complemented_path, grn_plugin_get_suffix()); - plugin_file = fopen(complemented_path, "r"); - if (plugin_file) { - fclose(plugin_file); - found_path = GRN_STRDUP(complemented_path); - } else { - const char *base_name; - - base_name = strrchr(path, '/'); - if (base_name) { - path_len = base_name - path + strlen("/.libs") + strlen(base_name); - path_len += strlen(grn_plugin_get_suffix()); - if (path_len >= PATH_MAX) { - ERR(GRN_FILENAME_TOO_LONG, - "too long plugin path: <%.*s/.libs%s%s>", - (int)(base_name - path), path, base_name, grn_plugin_get_suffix()); - goto exit; - } - complemented_libs_path[0] = '\0'; - strncat(complemented_libs_path, path, base_name - path); - strcat(complemented_libs_path, "/.libs"); - strcat(complemented_libs_path, base_name); - strcat(complemented_libs_path, grn_plugin_get_suffix()); - plugin_file = fopen(complemented_libs_path, "r"); - if (plugin_file) { - fclose(plugin_file); - found_path = GRN_STRDUP(complemented_libs_path); - } - } - } + found_path = grn_plugin_find_path_raw(ctx, path); + if (found_path) { + goto exit; + } + + path_len = strlen(path); + found_path = grn_plugin_find_path_mrb(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; + } + + found_path = grn_plugin_find_path_so(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; + } + + found_path = grn_plugin_find_path_libs_so(ctx, path, path_len); + if (found_path) { + goto exit; + } + if (ctx->rc) { + goto exit; } exit : @@ -527,6 +688,57 @@ grn_plugin_register(grn_ctx *ctx, const char *name) GRN_API_RETURN(rc); } +void +grn_plugin_ensure_registered(grn_ctx *ctx, grn_obj *proc) +{ +#ifdef GRN_WITH_MRUBY + grn_id plugin_id; + const char *plugin_path; + uint32_t key_size; + grn_plugin *plugin; + int value_size; + + if (!ctx->impl->mrb.state) { + return; + } + + if (!(proc->header.flags & GRN_OBJ_CUSTOM_NAME)) { + return; + } + + { + grn_id id; + int added; + id = DB_OBJ(proc)->id; + grn_hash_add(ctx, ctx->impl->mrb.checked_procs, + &id, sizeof(grn_id), NULL, &added); + if (!added) { + return; + } + } + + plugin_id = DB_OBJ(proc)->range; + CRITICAL_SECTION_ENTER(grn_plugins_lock); + plugin_path = _grn_hash_key(&grn_gctx, grn_plugins, plugin_id, &key_size); + if (plugin_path) { + value_size = grn_hash_get_value(&grn_gctx, grn_plugins, plugin_id, &plugin); + } + CRITICAL_SECTION_LEAVE(grn_plugins_lock); + + if (!plugin_path) { + return; + } + + if (plugin->dl) { + return; + } + + ctx->impl->plugin_path = plugin_path; + grn_plugin_call_register_mrb(ctx, plugin_id, plugin); + ctx->impl->plugin_path = NULL; +#endif /* GRN_WITH_MRUBY */ +} + void * grn_plugin_malloc(grn_ctx *ctx, size_t size, const char *file, int line, const char *func) -------------- next part -------------- HTML����������������������������... 下载