summaryrefslogtreecommitdiff
path: root/storage/mroonga/vendor/groonga/lib/plugin.c
diff options
context:
space:
mode:
Diffstat (limited to 'storage/mroonga/vendor/groonga/lib/plugin.c')
-rw-r--r--storage/mroonga/vendor/groonga/lib/plugin.c395
1 files changed, 319 insertions, 76 deletions
diff --git a/storage/mroonga/vendor/groonga/lib/plugin.c b/storage/mroonga/vendor/groonga/lib/plugin.c
index 3483cc9a5b0..7fd0fbd1971 100644
--- a/storage/mroonga/vendor/groonga/lib/plugin.c
+++ b/storage/mroonga/vendor/groonga/lib/plugin.c
@@ -1,6 +1,6 @@
/* -*- c-basic-offset: 2 -*- */
/*
- Copyright(C) 2012-2013 Brazil
+ Copyright(C) 2012-2015 Brazil
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
@@ -15,22 +15,39 @@
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
-#include "groonga_in.h"
-#include "groonga/plugin.h"
+#include "grn.h"
+#include <groonga/plugin.h>
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
-#include "db.h"
-#include "plugin_in.h"
-#include "ctx_impl.h"
-#include "util.h"
+#include <sys/stat.h>
+#ifdef HAVE_DIRENT_H
+# include <dirent.h>
+#endif /* HAVE_DIRENT_H */
+
+#ifndef S_ISREG
+# ifdef _S_IFREG
+# define S_ISREG(mode) (mode & _S_IFREG)
+# endif /* _S_IFREG */
+#endif /* !S_ISREG */
+
+#include "grn_db.h"
+#include "grn_plugin.h"
+#include "grn_ctx_impl.h"
+#include "grn_util.h"
+
+#ifdef GRN_WITH_MRUBY
+# include <mruby.h>
+#endif /* GRN_WITH_MRUBY */
static grn_hash *grn_plugins = NULL;
static grn_critical_section grn_plugins_lock;
-#define PATHLEN(filename) (strlen(filename) + 1)
+#ifdef GRN_WITH_MRUBY
+static const char *grn_plugin_mrb_suffix = ".rb";
+#endif /* GRN_WITH_MRUBY */
#ifdef HAVE_DLFCN_H
# include <dlfcn.h>
@@ -71,7 +88,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++;
@@ -89,6 +106,10 @@ grn_plugin_path(grn_ctx *ctx, grn_id id)
const char *system_plugins_dir;
size_t system_plugins_dir_size;
+ if (id == GRN_ID_NIL) {
+ return NULL;
+ }
+
CRITICAL_SECTION_ENTER(grn_plugins_lock);
path = _grn_hash_key(&grn_gctx, grn_plugins, id, &key_size);
CRITICAL_SECTION_LEAVE(grn_plugins_lock);
@@ -114,7 +135,7 @@ grn_plugin_path(grn_ctx *ctx, grn_id id)
#define GRN_PLUGIN_FUNC_PREFIX "grn_plugin_impl_"
static grn_rc
-grn_plugin_call_init (grn_ctx *ctx, grn_id id)
+grn_plugin_call_init(grn_ctx *ctx, grn_id id)
{
grn_plugin *plugin;
if (!grn_hash_get_value(&grn_gctx, grn_plugins, id, &plugin)) {
@@ -126,6 +147,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)
{
@@ -133,6 +182,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);
}
@@ -193,22 +247,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) {
@@ -270,11 +365,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);
@@ -369,8 +466,8 @@ grn_plugin_register_by_path(grn_ctx *ctx, const char *path)
#ifdef WIN32
static char *win32_plugins_dir = NULL;
static char win32_plugins_dir_buffer[PATH_MAX];
-const char *
-grn_plugin_get_system_plugins_dir(void)
+static const char *
+grn_plugin_get_default_system_plugins_dir(void)
{
if (!win32_plugins_dir) {
const char *base_dir;
@@ -388,13 +485,126 @@ grn_plugin_get_system_plugins_dir(void)
}
#else /* WIN32 */
-const char *
-grn_plugin_get_system_plugins_dir(void)
+static const char *
+grn_plugin_get_default_system_plugins_dir(void)
{
return GRN_PLUGINS_DIR;
}
#endif /* WIN32 */
+const char *
+grn_plugin_get_system_plugins_dir(void)
+{
+ const char *plugins_dir;
+
+ plugins_dir = getenv("GRN_PLUGINS_DIR");
+ if (!plugins_dir) {
+ plugins_dir = grn_plugin_get_default_system_plugins_dir();
+ }
+
+ return plugins_dir;
+}
+
+static char *
+grn_plugin_find_path_raw(grn_ctx *ctx, const char *path)
+{
+ struct stat path_stat;
+
+ if (stat(path, &path_stat) != 0) {
+ return NULL;
+ }
+
+ if (!S_ISREG(path_stat.st_mode)) {
+ return NULL;
+ }
+
+ 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)
{
@@ -402,8 +612,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;
@@ -411,10 +619,7 @@ grn_plugin_find_path(grn_ctx *ctx, const char *name)
if (name[0] == '/') {
path[0] = '\0';
} else {
- plugins_dir = getenv("GRN_PLUGINS_DIR");
- if (!plugins_dir) {
- plugins_dir = grn_plugin_get_system_plugins_dir();
- }
+ plugins_dir = grn_plugin_get_system_plugins_dir();
strcpy(path, plugins_dir);
dir_last_char = plugins_dir[strlen(path) - 1];
@@ -434,50 +639,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 :
@@ -503,10 +692,7 @@ grn_plugin_register(grn_ctx *ctx, const char *name)
prefix_separator = "";
suffix = "";
} else {
- prefix = getenv("GRN_PLUGINS_DIR");
- if (!prefix) {
- prefix = grn_plugin_get_system_plugins_dir();
- }
+ prefix = grn_plugin_get_system_plugins_dir();
if (prefix[strlen(prefix) - 1] != '/') {
prefix_separator = "/";
} else {
@@ -523,6 +709,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)
@@ -647,6 +884,12 @@ grn_plugin_proc_alloc(grn_ctx *ctx, grn_user_data *user_data,
}
grn_obj *
+grn_plugin_proc_get_vars(grn_ctx *ctx, grn_user_data *user_data)
+{
+ return grn_proc_get_vars(ctx, user_data);
+}
+
+grn_obj *
grn_plugin_proc_get_var(grn_ctx *ctx, grn_user_data *user_data,
const char *name, int name_size)
{