[Groonga-commit] groonga/groonga at 568d8e0 [master] plugin mrb: support plugin written by mruby

Back to archive index

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����������������������������...
Download 



More information about the Groonga-commit mailing list
Back to archive index