| 1 | /* -*- c-basic-offset: 2 -*- */ |
| 2 | /* |
| 3 | Copyright(C) 2013-2017 Brazil |
| 4 | |
| 5 | This library is free software; you can redistribute it and/or |
| 6 | modify it under the terms of the GNU Lesser General Public |
| 7 | License version 2.1 as published by the Free Software Foundation. |
| 8 | |
| 9 | This library is distributed in the hope that it will be useful, |
| 10 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
| 11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
| 12 | Lesser General Public License for more details. |
| 13 | |
| 14 | You should have received a copy of the GNU Lesser General Public |
| 15 | License along with this library; if not, write to the Free Software |
| 16 | Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA |
| 17 | */ |
| 18 | |
| 19 | #include "grn_ctx_impl.h" |
| 20 | |
| 21 | #include <string.h> |
| 22 | |
| 23 | #ifdef GRN_WITH_MRUBY |
| 24 | # include "grn_ctx_impl_mrb.h" |
| 25 | |
| 26 | # include "grn_mrb.h" |
| 27 | # include "mrb/mrb_converter.h" |
| 28 | # include "mrb/mrb_error.h" |
| 29 | # include "mrb/mrb_id.h" |
| 30 | # include "mrb/mrb_operator.h" |
| 31 | # include "mrb/mrb_command_version.h" |
| 32 | # include "mrb/mrb_ctx.h" |
| 33 | # include "mrb/mrb_logger.h" |
| 34 | # include "mrb/mrb_query_logger.h" |
| 35 | # include "mrb/mrb_void.h" |
| 36 | # include "mrb/mrb_bulk.h" |
| 37 | # include "mrb/mrb_pointer.h" |
| 38 | # include "mrb/mrb_cache.h" |
| 39 | # include "mrb/mrb_object.h" |
| 40 | # include "mrb/mrb_object_flags.h" |
| 41 | # include "mrb/mrb_database.h" |
| 42 | # include "mrb/mrb_indexable.h" |
| 43 | # include "mrb/mrb_table.h" |
| 44 | # include "mrb/mrb_array.h" |
| 45 | # include "mrb/mrb_hash_table.h" |
| 46 | # include "mrb/mrb_patricia_trie.h" |
| 47 | # include "mrb/mrb_double_array_trie.h" |
| 48 | # include "mrb/mrb_table_group_flags.h" |
| 49 | # include "mrb/mrb_table_group_result.h" |
| 50 | # include "mrb/mrb_table_sort_flags.h" |
| 51 | # include "mrb/mrb_table_sort_key.h" |
| 52 | # include "mrb/mrb_record.h" |
| 53 | # include "mrb/mrb_column.h" |
| 54 | # include "mrb/mrb_fixed_size_column.h" |
| 55 | # include "mrb/mrb_variable_size_column.h" |
| 56 | # include "mrb/mrb_index_column.h" |
| 57 | # include "mrb/mrb_index_cursor.h" |
| 58 | # include "mrb/mrb_type.h" |
| 59 | # include "mrb/mrb_expr.h" |
| 60 | # include "mrb/mrb_accessor.h" |
| 61 | # include "mrb/mrb_procedure.h" |
| 62 | # include "mrb/mrb_command.h" |
| 63 | # include "mrb/mrb_command_input.h" |
| 64 | # include "mrb/mrb_table_cursor.h" |
| 65 | # include "mrb/mrb_table_cursor_flags.h" |
| 66 | # include "mrb/mrb_content_type.h" |
| 67 | # include "mrb/mrb_writer.h" |
| 68 | # include "mrb/mrb_config.h" |
| 69 | # include "mrb/mrb_eval_context.h" |
| 70 | # include "mrb/mrb_thread.h" |
| 71 | # include "mrb/mrb_window_definition.h" |
| 72 | |
| 73 | # include <mruby/array.h> |
| 74 | # include <mruby/string.h> |
| 75 | # include <mruby/variable.h> |
| 76 | #endif /* GRN_WITH_MRUBY */ |
| 77 | |
| 78 | static grn_bool grn_ctx_impl_mrb_mruby_enabled = GRN_TRUE; |
| 79 | |
| 80 | void |
| 81 | grn_ctx_impl_mrb_init_from_env(void) |
| 82 | { |
| 83 | { |
| 84 | char grn_mruby_enabled_env[GRN_ENV_BUFFER_SIZE]; |
| 85 | grn_getenv("GRN_MRUBY_ENABLED" , |
| 86 | grn_mruby_enabled_env, |
| 87 | GRN_ENV_BUFFER_SIZE); |
| 88 | if (grn_mruby_enabled_env[0] && |
| 89 | strcmp(grn_mruby_enabled_env, "no" ) == 0) { |
| 90 | grn_ctx_impl_mrb_mruby_enabled = GRN_FALSE; |
| 91 | } |
| 92 | } |
| 93 | } |
| 94 | |
| 95 | #ifdef GRN_WITH_MRUBY |
| 96 | static mrb_value |
| 97 | mrb_kernel_load(mrb_state *mrb, mrb_value self) |
| 98 | { |
| 99 | grn_ctx *ctx = (grn_ctx *)mrb->ud; |
| 100 | char *path; |
| 101 | |
| 102 | mrb_get_args(mrb, "z" , &path); |
| 103 | |
| 104 | grn_mrb_load(ctx, path); |
| 105 | if (mrb->exc) { |
| 106 | mrb_exc_raise(mrb, mrb_obj_value(mrb->exc)); |
| 107 | } |
| 108 | |
| 109 | grn_mrb_ctx_check(mrb); |
| 110 | |
| 111 | return mrb_true_value(); |
| 112 | } |
| 113 | |
| 114 | static mrb_value |
| 115 | mrb_groonga_init(mrb_state *mrb, mrb_value self) |
| 116 | { |
| 117 | grn_ctx *ctx = mrb->ud; |
| 118 | |
| 119 | mrb_undef_class_method(mrb, ctx->impl->mrb.module, "init" ); |
| 120 | |
| 121 | mrb_define_class(mrb, "LoadError" , mrb_class_get(mrb, "ScriptError" )); |
| 122 | mrb_define_method(mrb, mrb->kernel_module, |
| 123 | "load" , mrb_kernel_load, MRB_ARGS_REQ(1)); |
| 124 | |
| 125 | { |
| 126 | mrb_value load_path; |
| 127 | const char *plugins_dir; |
| 128 | const char *system_ruby_scripts_dir; |
| 129 | |
| 130 | load_path = mrb_ary_new(mrb); |
| 131 | plugins_dir = grn_plugin_get_system_plugins_dir(); |
| 132 | mrb_ary_push(mrb, load_path, |
| 133 | mrb_str_new_cstr(mrb, plugins_dir)); |
| 134 | system_ruby_scripts_dir = grn_mrb_get_system_ruby_scripts_dir(ctx); |
| 135 | mrb_ary_push(mrb, load_path, |
| 136 | mrb_str_new_cstr(mrb, system_ruby_scripts_dir)); |
| 137 | mrb_gv_set(mrb, mrb_intern_cstr(mrb, "$LOAD_PATH" ), load_path); |
| 138 | } |
| 139 | |
| 140 | grn_mrb_load(ctx, "require.rb" ); |
| 141 | grn_mrb_load(ctx, "initialize/pre.rb" ); |
| 142 | |
| 143 | grn_mrb_converter_init(ctx); |
| 144 | grn_mrb_error_init(ctx); |
| 145 | grn_mrb_id_init(ctx); |
| 146 | grn_mrb_operator_init(ctx); |
| 147 | grn_mrb_command_version_init(ctx); |
| 148 | grn_mrb_ctx_init(ctx); |
| 149 | grn_mrb_logger_init(ctx); |
| 150 | grn_mrb_query_logger_init(ctx); |
| 151 | grn_mrb_void_init(ctx); |
| 152 | grn_mrb_bulk_init(ctx); |
| 153 | grn_mrb_pointer_init(ctx); |
| 154 | grn_mrb_cache_init(ctx); |
| 155 | grn_mrb_object_init(ctx); |
| 156 | grn_mrb_object_flags_init(ctx); |
| 157 | grn_mrb_database_init(ctx); |
| 158 | grn_mrb_indexable_init(ctx); |
| 159 | grn_mrb_table_init(ctx); |
| 160 | grn_mrb_array_init(ctx); |
| 161 | grn_mrb_hash_table_init(ctx); |
| 162 | grn_mrb_patricia_trie_init(ctx); |
| 163 | grn_mrb_double_array_trie_init(ctx); |
| 164 | grn_mrb_table_group_flags_init(ctx); |
| 165 | grn_mrb_table_group_result_init(ctx); |
| 166 | grn_mrb_table_sort_flags_init(ctx); |
| 167 | grn_mrb_table_sort_key_init(ctx); |
| 168 | grn_mrb_record_init(ctx); |
| 169 | grn_mrb_column_init(ctx); |
| 170 | grn_mrb_fixed_size_column_init(ctx); |
| 171 | grn_mrb_variable_size_column_init(ctx); |
| 172 | grn_mrb_index_column_init(ctx); |
| 173 | grn_mrb_index_cursor_init(ctx); |
| 174 | grn_mrb_type_init(ctx); |
| 175 | grn_mrb_expr_init(ctx); |
| 176 | grn_mrb_accessor_init(ctx); |
| 177 | grn_mrb_procedure_init(ctx); |
| 178 | grn_mrb_command_init(ctx); |
| 179 | grn_mrb_command_input_init(ctx); |
| 180 | grn_mrb_table_cursor_init(ctx); |
| 181 | grn_mrb_table_cursor_flags_init(ctx); |
| 182 | grn_mrb_content_type_init(ctx); |
| 183 | grn_mrb_writer_init(ctx); |
| 184 | grn_mrb_config_init(ctx); |
| 185 | grn_mrb_eval_context_init(ctx); |
| 186 | grn_mrb_thread_init(ctx); |
| 187 | grn_mrb_window_definition_init(ctx); |
| 188 | |
| 189 | grn_mrb_load(ctx, "initialize/post.rb" ); |
| 190 | |
| 191 | return mrb_nil_value(); |
| 192 | } |
| 193 | |
| 194 | static void |
| 195 | grn_ctx_impl_mrb_init_bindings(grn_ctx *ctx) |
| 196 | { |
| 197 | mrb_state *mrb = ctx->impl->mrb.state; |
| 198 | |
| 199 | mrb->ud = ctx; |
| 200 | ctx->impl->mrb.module = mrb_define_module(mrb, "Groonga" ); |
| 201 | mrb_define_const(mrb, |
| 202 | ctx->impl->mrb.module, |
| 203 | "ORDER_BY_ESTIMATED_SIZE" , |
| 204 | grn_mrb_is_order_by_estimated_size_enabled() ? |
| 205 | mrb_true_value() : |
| 206 | mrb_false_value()); |
| 207 | mrb_define_class_method(mrb, ctx->impl->mrb.module, |
| 208 | "init" , mrb_groonga_init, MRB_ARGS_NONE()); |
| 209 | mrb_funcall(mrb, mrb_obj_value(ctx->impl->mrb.module), "init" , 0); |
| 210 | } |
| 211 | |
| 212 | #ifndef USE_MEMORY_DEBUG |
| 213 | static void * |
| 214 | grn_ctx_impl_mrb_allocf(mrb_state *mrb, void *ptr, size_t size, void *ud) |
| 215 | { |
| 216 | grn_ctx *ctx = ud; |
| 217 | |
| 218 | if (size == 0) { |
| 219 | if (ptr) { |
| 220 | grn_free(ctx, ptr, __FILE__, __LINE__, __FUNCTION__); |
| 221 | } |
| 222 | return NULL; |
| 223 | } else { |
| 224 | if (ptr) { |
| 225 | return grn_realloc(ctx, ptr, size, __FILE__, __LINE__, __FUNCTION__); |
| 226 | } else { |
| 227 | return grn_malloc(ctx, size, __FILE__, __LINE__, __FUNCTION__); |
| 228 | } |
| 229 | } |
| 230 | } |
| 231 | #endif /* USE_MEMORY_DEBUG */ |
| 232 | |
| 233 | static void |
| 234 | grn_ctx_impl_mrb_init_lazy(grn_ctx *ctx) |
| 235 | { |
| 236 | if (!grn_ctx_impl_mrb_mruby_enabled) { |
| 237 | ctx->impl->mrb.state = NULL; |
| 238 | ctx->impl->mrb.base_directory[0] = '\0'; |
| 239 | ctx->impl->mrb.module = NULL; |
| 240 | ctx->impl->mrb.object_class = NULL; |
| 241 | ctx->impl->mrb.checked_procs = NULL; |
| 242 | ctx->impl->mrb.registered_plugins = NULL; |
| 243 | ctx->impl->mrb.builtin.time_class = NULL; |
| 244 | ctx->impl->mrb.groonga.operator_class = NULL; |
| 245 | } else { |
| 246 | mrb_state *mrb; |
| 247 | #ifdef USE_MEMORY_DEBUG |
| 248 | mrb = mrb_open(); |
| 249 | #else /* USE_MEMORY_DEBUG */ |
| 250 | mrb = mrb_open_allocf(grn_ctx_impl_mrb_allocf, ctx); |
| 251 | #endif /* USE_MEMORY_DEBUG */ |
| 252 | ctx->impl->mrb.state = mrb; |
| 253 | ctx->impl->mrb.base_directory[0] = '\0'; |
| 254 | grn_ctx_impl_mrb_init_bindings(ctx); |
| 255 | if (ctx->impl->mrb.state->exc) { |
| 256 | mrb_value reason; |
| 257 | reason = mrb_funcall(mrb, mrb_obj_value(mrb->exc), "inspect" , 0); |
| 258 | ERR(GRN_UNKNOWN_ERROR, |
| 259 | "failed to initialize mruby: %.*s" , |
| 260 | (int)RSTRING_LEN(reason), |
| 261 | RSTRING_PTR(reason)); |
| 262 | mrb_close(ctx->impl->mrb.state); |
| 263 | ctx->impl->mrb.state = NULL; |
| 264 | } else { |
| 265 | ctx->impl->mrb.checked_procs = |
| 266 | grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY); |
| 267 | ctx->impl->mrb.registered_plugins = |
| 268 | grn_hash_create(ctx, NULL, sizeof(grn_id), 0, GRN_HASH_TINY); |
| 269 | GRN_VOID_INIT(&(ctx->impl->mrb.buffer.from)); |
| 270 | GRN_VOID_INIT(&(ctx->impl->mrb.buffer.to)); |
| 271 | ctx->impl->mrb.builtin.time_class = mrb_class_get(mrb, "Time" ); |
| 272 | } |
| 273 | } |
| 274 | } |
| 275 | |
| 276 | static void |
| 277 | grn_ctx_impl_mrb_fin_real(grn_ctx *ctx) |
| 278 | { |
| 279 | if (ctx->impl->mrb.state) { |
| 280 | mrb_close(ctx->impl->mrb.state); |
| 281 | ctx->impl->mrb.state = NULL; |
| 282 | grn_hash_close(ctx, ctx->impl->mrb.checked_procs); |
| 283 | grn_hash_close(ctx, ctx->impl->mrb.registered_plugins); |
| 284 | GRN_OBJ_FIN(ctx, &(ctx->impl->mrb.buffer.from)); |
| 285 | GRN_OBJ_FIN(ctx, &(ctx->impl->mrb.buffer.to)); |
| 286 | } |
| 287 | } |
| 288 | #else /* GRN_WITH_MRUBY */ |
| 289 | static void |
| 290 | grn_ctx_impl_mrb_init_lazy(grn_ctx *ctx) |
| 291 | { |
| 292 | } |
| 293 | |
| 294 | static void |
| 295 | grn_ctx_impl_mrb_fin_real(grn_ctx *ctx) |
| 296 | { |
| 297 | } |
| 298 | #endif /* GRN_WITH_MRUBY */ |
| 299 | |
| 300 | void |
| 301 | grn_ctx_impl_mrb_init(grn_ctx *ctx) |
| 302 | { |
| 303 | ctx->impl->mrb.initialized = GRN_FALSE; |
| 304 | } |
| 305 | |
| 306 | void |
| 307 | grn_ctx_impl_mrb_fin(grn_ctx *ctx) |
| 308 | { |
| 309 | if (!ctx->impl->mrb.initialized) { |
| 310 | return; |
| 311 | } |
| 312 | |
| 313 | ctx->impl->mrb.initialized = GRN_FALSE; |
| 314 | grn_ctx_impl_mrb_fin_real(ctx); |
| 315 | } |
| 316 | |
| 317 | void |
| 318 | grn_ctx_impl_mrb_ensure_init(grn_ctx *ctx) |
| 319 | { |
| 320 | if (!ctx->impl->mrb.initialized) { |
| 321 | ctx->impl->mrb.initialized = GRN_TRUE; |
| 322 | grn_ctx_impl_mrb_init_lazy(ctx); |
| 323 | } |
| 324 | } |
| 325 | |