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 | |