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
78static grn_bool grn_ctx_impl_mrb_mruby_enabled = GRN_TRUE;
79
80void
81grn_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
96static mrb_value
97mrb_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
114static mrb_value
115mrb_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
194static void
195grn_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
213static void *
214grn_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
233static void
234grn_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
276static void
277grn_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 */
289static void
290grn_ctx_impl_mrb_init_lazy(grn_ctx *ctx)
291{
292}
293
294static void
295grn_ctx_impl_mrb_fin_real(grn_ctx *ctx)
296{
297}
298#endif /* GRN_WITH_MRUBY */
299
300void
301grn_ctx_impl_mrb_init(grn_ctx *ctx)
302{
303 ctx->impl->mrb.initialized = GRN_FALSE;
304}
305
306void
307grn_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
317void
318grn_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