1/* -*- c-basic-offset: 2 -*- */
2/*
3 Copyright(C) 2016-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_pat.h"
20#include "../grn_dat.h"
21#include "../grn_ii.h"
22
23#include "../grn_proc.h"
24
25#include <groonga/plugin.h>
26
27static void command_object_inspect_dispatch(grn_ctx *ctx, grn_obj *obj);
28
29static void
30command_object_inspect_obj_name(grn_ctx *ctx, grn_obj *obj)
31{
32 char name[GRN_TABLE_MAX_KEY_SIZE];
33 int name_size;
34
35 name_size = grn_obj_name(ctx, obj, name, GRN_TABLE_MAX_KEY_SIZE);
36 grn_ctx_output_str(ctx, name, name_size);
37}
38
39static void
40command_object_inspect_obj_type(grn_ctx *ctx, uint8_t type)
41{
42 grn_ctx_output_map_open(ctx, "type", 2);
43 {
44 grn_ctx_output_cstr(ctx, "id");
45 grn_ctx_output_uint64(ctx, type);
46 grn_ctx_output_cstr(ctx, "name");
47 grn_ctx_output_cstr(ctx, grn_obj_type_to_string(type));
48 }
49 grn_ctx_output_map_close(ctx);
50}
51
52static void
53command_object_inspect_type(grn_ctx *ctx, grn_obj *type)
54{
55 if (!type) {
56 grn_ctx_output_null(ctx);
57 return;
58 }
59
60 grn_ctx_output_map_open(ctx, "type", 4);
61 {
62 grn_ctx_output_cstr(ctx, "id");
63 grn_ctx_output_uint64(ctx, grn_obj_id(ctx, type));
64 grn_ctx_output_cstr(ctx, "name");
65 command_object_inspect_obj_name(ctx, type);
66 grn_ctx_output_cstr(ctx, "type");
67 command_object_inspect_obj_type(ctx, type->header.type);
68 grn_ctx_output_cstr(ctx, "size");
69 if (type->header.type == GRN_TYPE) {
70 grn_ctx_output_uint64(ctx, grn_type_size(ctx, type));
71 } else {
72 grn_ctx_output_uint64(ctx, sizeof(grn_id));
73 }
74 }
75 grn_ctx_output_map_close(ctx);
76}
77
78static void
79command_object_inspect_disk_usage(grn_ctx *ctx, grn_obj *obj)
80{
81 grn_ctx_output_uint64(ctx, grn_obj_get_disk_usage(ctx, obj));
82}
83
84static void
85command_object_inspect_table_hash_key_key(grn_ctx *ctx, grn_hash *hash)
86{
87 grn_ctx_output_map_open(ctx, "key", 3);
88 {
89 grn_ctx_output_cstr(ctx, "type");
90 command_object_inspect_type(ctx, grn_ctx_at(ctx, hash->obj.header.domain));
91 grn_ctx_output_cstr(ctx, "total_size");
92 grn_ctx_output_uint64(ctx, grn_hash_total_key_size(ctx, hash));
93 grn_ctx_output_cstr(ctx, "max_total_size");
94 grn_ctx_output_uint64(ctx, grn_hash_max_total_key_size(ctx, hash));
95 }
96 grn_ctx_output_map_close(ctx);
97}
98
99static void
100command_object_inspect_table_pat_key_key(grn_ctx *ctx, grn_pat *pat)
101{
102 grn_ctx_output_map_open(ctx, "key", 3);
103 {
104 grn_ctx_output_cstr(ctx, "type");
105 command_object_inspect_type(ctx, grn_ctx_at(ctx, pat->obj.header.domain));
106 grn_ctx_output_cstr(ctx, "total_size");
107 grn_ctx_output_uint64(ctx, grn_pat_total_key_size(ctx, pat));
108 grn_ctx_output_cstr(ctx, "max_total_size");
109 grn_ctx_output_uint64(ctx, GRN_PAT_MAX_TOTAL_KEY_SIZE);
110 }
111 grn_ctx_output_map_close(ctx);
112}
113
114static void
115command_object_inspect_table_dat_key_key(grn_ctx *ctx, grn_dat *dat)
116{
117 grn_ctx_output_map_open(ctx, "key", 1);
118 {
119 grn_ctx_output_cstr(ctx, "type");
120 command_object_inspect_type(ctx, grn_ctx_at(ctx, dat->obj.header.domain));
121 }
122 grn_ctx_output_map_close(ctx);
123}
124
125static void
126command_object_inspect_table_key(grn_ctx *ctx, grn_obj *table)
127{
128 switch (table->header.type) {
129 case GRN_TABLE_HASH_KEY :
130 command_object_inspect_table_hash_key_key(ctx, (grn_hash *)table);
131 break;
132 case GRN_TABLE_PAT_KEY :
133 command_object_inspect_table_pat_key_key(ctx, (grn_pat *)table);
134 break;
135 case GRN_TABLE_DAT_KEY :
136 command_object_inspect_table_dat_key_key(ctx, (grn_dat *)table);
137 break;
138 case GRN_TABLE_NO_KEY :
139 grn_ctx_output_null(ctx);
140 break;
141 default :
142 break;
143 }
144}
145
146static void
147command_object_inspect_table_value(grn_ctx *ctx, grn_obj *table)
148{
149 if (table->header.type == GRN_TABLE_DAT_KEY) {
150 grn_ctx_output_null(ctx);
151 } else {
152 grn_ctx_output_map_open(ctx, "value", 1);
153 {
154 grn_id range_id = grn_obj_get_range(ctx, table);
155 grn_ctx_output_cstr(ctx, "type");
156 command_object_inspect_type(ctx, grn_ctx_at(ctx, range_id));
157 }
158 grn_ctx_output_map_close(ctx);
159 }
160}
161
162static void
163command_object_inspect_table(grn_ctx *ctx, grn_obj *obj)
164{
165 grn_ctx_output_map_open(ctx, "table", 7);
166 {
167 grn_ctx_output_cstr(ctx, "id");
168 grn_ctx_output_uint64(ctx, grn_obj_id(ctx, obj));
169 grn_ctx_output_cstr(ctx, "name");
170 command_object_inspect_obj_name(ctx, obj);
171 grn_ctx_output_cstr(ctx, "type");
172 command_object_inspect_obj_type(ctx, obj->header.type);
173 grn_ctx_output_cstr(ctx, "key");
174 command_object_inspect_table_key(ctx, obj);
175 grn_ctx_output_cstr(ctx, "value");
176 command_object_inspect_table_value(ctx, obj);
177 grn_ctx_output_cstr(ctx, "n_records");
178 grn_ctx_output_uint64(ctx, grn_table_size(ctx, obj));
179 grn_ctx_output_cstr(ctx, "disk_usage");
180 command_object_inspect_disk_usage(ctx, obj);
181 }
182 grn_ctx_output_map_close(ctx);
183}
184
185static void
186command_object_inspect_column_name(grn_ctx *ctx, grn_obj *column)
187{
188 char name[GRN_TABLE_MAX_KEY_SIZE];
189 int name_size;
190
191 name_size = grn_column_name(ctx, column, name, GRN_TABLE_MAX_KEY_SIZE);
192 name[name_size] = '\0';
193 grn_ctx_output_str(ctx, name, name_size);
194}
195
196static void
197command_object_inspect_column_type_name(grn_ctx *ctx, grn_obj *column)
198{
199 switch (column->header.type) {
200 case GRN_COLUMN_FIX_SIZE :
201 case GRN_COLUMN_VAR_SIZE :
202 switch (column->header.flags & GRN_OBJ_COLUMN_TYPE_MASK) {
203 case GRN_OBJ_COLUMN_SCALAR :
204 grn_ctx_output_cstr(ctx, "scalar");
205 break;
206 case GRN_OBJ_COLUMN_VECTOR :
207 grn_ctx_output_cstr(ctx, "vector");
208 break;
209 }
210 break;
211 case GRN_COLUMN_INDEX :
212 grn_ctx_output_cstr(ctx, "index");
213 break;
214 default:
215 break;
216 }
217}
218
219static void
220command_object_inspect_column_type(grn_ctx *ctx, grn_obj *column)
221{
222 grn_ctx_output_map_open(ctx, "type", 2);
223 {
224 grn_ctx_output_cstr(ctx, "name");
225 command_object_inspect_column_type_name(ctx, column);
226
227 grn_ctx_output_cstr(ctx, "raw");
228 grn_ctx_output_map_open(ctx, "raw", 2);
229 {
230 grn_ctx_output_cstr(ctx, "id");
231 grn_ctx_output_uint64(ctx, column->header.type);
232 grn_ctx_output_cstr(ctx, "name");
233 grn_ctx_output_cstr(ctx, grn_obj_type_to_string(column->header.type));
234 }
235 grn_ctx_output_map_close(ctx);
236 }
237 grn_ctx_output_map_close(ctx);
238}
239
240static void
241command_object_inspect_column_index_value_statistics(grn_ctx *ctx,
242 grn_ii *ii)
243{
244 grn_ctx_output_map_open(ctx, "statistics", 11);
245 {
246 struct grn_ii_header *h = ii->header;
247
248 grn_ctx_output_cstr(ctx, "max_section_id");
249 grn_ctx_output_uint64(ctx, grn_ii_max_section(ii));
250
251 {
252 uint32_t max_id = 0;
253 uint32_t n_garbage_segments = 0;
254 uint32_t n_array_segments = 0;
255 uint32_t n_buffer_segments = 0;
256
257 grn_ctx_output_cstr(ctx, "n_garbage_segments");
258 {
259 uint32_t i;
260
261 for (i = h->bgqtail;
262 i != h->bgqhead;
263 i = ((i + 1) & (GRN_II_BGQSIZE - 1))) {
264 uint32_t id = h->bgqbody[i];
265 n_garbage_segments++;
266 if (id > max_id) { max_id = id; }
267 }
268 grn_ctx_output_uint64(ctx, n_garbage_segments);
269 }
270
271 grn_ctx_output_cstr(ctx, "max_array_segment_id");
272 grn_ctx_output_uint64(ctx, h->amax);
273 grn_ctx_output_cstr(ctx, "n_array_segments");
274 {
275 uint32_t i;
276
277 for (i = 0; i < GRN_II_MAX_LSEG; i++) {
278 uint32_t id = h->ainfo[i];
279 if (id != GRN_II_PSEG_NOT_ASSIGNED) {
280 if (id > max_id) { max_id = id; }
281 n_array_segments++;
282 }
283 }
284 grn_ctx_output_uint64(ctx, n_array_segments);
285 }
286
287 grn_ctx_output_cstr(ctx, "max_buffer_segment_id");
288 grn_ctx_output_uint64(ctx, h->bmax);
289 grn_ctx_output_cstr(ctx, "n_buffer_segments");
290 {
291 uint32_t i;
292
293 for (i = 0; i < GRN_II_MAX_LSEG; i++) {
294 uint32_t id = h->binfo[i];
295 if (id != GRN_II_PSEG_NOT_ASSIGNED) {
296 if (id > max_id) { max_id = id; }
297 n_buffer_segments++;
298 }
299 }
300 grn_ctx_output_uint64(ctx, n_buffer_segments);
301 }
302
303 grn_ctx_output_cstr(ctx, "max_in_use_physical_segment_id");
304 grn_ctx_output_uint64(ctx, max_id);
305
306 grn_ctx_output_cstr(ctx, "n_unmanaged_segments");
307 grn_ctx_output_uint64(ctx,
308 h->pnext -
309 n_array_segments -
310 n_buffer_segments -
311 n_garbage_segments);
312 }
313
314 {
315 grn_ctx_output_cstr(ctx, "total_chunk_size");
316 grn_ctx_output_uint64(ctx, h->total_chunk_size);
317 grn_ctx_output_cstr(ctx, "max_in_use_chunk_id");
318 {
319 uint32_t i;
320 uint32_t max_id;
321
322 for (max_id = 0, i = 0; i < (GRN_II_MAX_CHUNK >> 3); i++) {
323 uint8_t sub_chunk_info = h->chunks[i];
324 uint8_t bit;
325
326 if (sub_chunk_info == 0) {
327 continue;
328 }
329 for (bit = 0; bit < 8; bit++) {
330 if (sub_chunk_info & (1 << bit)) {
331 max_id = (i << 3) + sub_chunk_info;
332 }
333 }
334 }
335 grn_ctx_output_uint64(ctx, max_id);
336 }
337 grn_ctx_output_cstr(ctx, "n_garbage_chunks");
338 grn_ctx_output_array_open(ctx,
339 "n_garbage_chunks",
340 GRN_II_N_CHUNK_VARIATION);
341 {
342 uint32_t i;
343 for (i = 0; i <= GRN_II_N_CHUNK_VARIATION; i++) {
344 grn_ctx_output_uint64(ctx, h->ngarbages[i]);
345 }
346 }
347 grn_ctx_output_array_close(ctx);
348 }
349 }
350 grn_ctx_output_map_close(ctx);
351}
352
353static void
354command_object_inspect_column_data_value_compress(grn_ctx *ctx, grn_obj *column)
355{
356 const char *compress = NULL;
357 grn_column_flags column_flags;
358
359 column_flags = grn_column_get_flags(ctx, column);
360 switch (column_flags & GRN_OBJ_COMPRESS_MASK) {
361 case GRN_OBJ_COMPRESS_ZLIB :
362 compress = "zlib";
363 break;
364 case GRN_OBJ_COMPRESS_LZ4 :
365 compress = "lz4";
366 break;
367 case GRN_OBJ_COMPRESS_ZSTD :
368 compress = "zstd";
369 break;
370 default :
371 break;
372 }
373
374 if (compress) {
375 grn_ctx_output_cstr(ctx, compress);
376 } else {
377 grn_ctx_output_null(ctx);
378 }
379}
380
381static void
382command_object_inspect_column_value(grn_ctx *ctx, grn_obj *column)
383{
384 int n_elements = 1;
385 grn_bool is_index = (column->header.type == GRN_COLUMN_INDEX);
386
387 if (is_index) {
388 n_elements += 5;
389 } else {
390 n_elements += 1;
391 }
392 grn_ctx_output_map_open(ctx, "value", n_elements);
393 {
394 grn_id range_id;
395 grn_column_flags column_flags;
396
397 range_id = grn_obj_get_range(ctx, column);
398 column_flags = grn_column_get_flags(ctx, column);
399
400 grn_ctx_output_cstr(ctx, "type");
401 command_object_inspect_type(ctx, grn_ctx_at(ctx, range_id));
402 if (is_index) {
403 grn_ctx_output_cstr(ctx, "section");
404 grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_SECTION) != 0);
405 grn_ctx_output_cstr(ctx, "weight");
406 grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_WEIGHT) != 0);
407 grn_ctx_output_cstr(ctx, "position");
408 grn_ctx_output_bool(ctx, (column_flags & GRN_OBJ_WITH_POSITION) != 0);
409 grn_ctx_output_cstr(ctx, "size");
410 if ((column_flags & GRN_OBJ_INDEX_SMALL) != 0) {
411 grn_ctx_output_cstr(ctx, "small");
412 } else if ((column_flags & GRN_OBJ_INDEX_MEDIUM) != 0) {
413 grn_ctx_output_cstr(ctx, "medium");
414 } else {
415 grn_ctx_output_cstr(ctx, "normal");
416 }
417 grn_ctx_output_cstr(ctx, "statistics");
418 command_object_inspect_column_index_value_statistics(ctx,
419 (grn_ii *)column);
420 } else {
421 grn_ctx_output_cstr(ctx, "compress");
422 command_object_inspect_column_data_value_compress(ctx, column);
423 }
424 }
425 grn_ctx_output_map_close(ctx);
426}
427
428static void
429command_object_inspect_column_index_sources(grn_ctx *ctx, grn_obj *column)
430{
431 grn_obj *source_table;
432 grn_obj source_ids;
433 unsigned int i, n_ids;
434
435 source_table = grn_ctx_at(ctx, grn_obj_get_range(ctx, column));
436
437 GRN_RECORD_INIT(&source_ids, GRN_OBJ_VECTOR, GRN_ID_NIL);
438 grn_obj_get_info(ctx, column, GRN_INFO_SOURCE, &source_ids);
439
440 n_ids = GRN_BULK_VSIZE(&source_ids) / sizeof(grn_id);
441 grn_ctx_output_array_open(ctx, "sources", n_ids);
442 for (i = 0; i < n_ids; i++) {
443 grn_id source_id;
444 grn_obj *source;
445
446 source_id = GRN_RECORD_VALUE_AT(&source_ids, i);
447 source = grn_ctx_at(ctx, source_id);
448
449 grn_ctx_output_map_open(ctx, "source", 4);
450 {
451 grn_ctx_output_cstr(ctx, "id");
452 if (grn_obj_is_table(ctx, source)) {
453 grn_ctx_output_null(ctx);
454 } else {
455 grn_ctx_output_uint64(ctx, source_id);
456 }
457
458 grn_ctx_output_cstr(ctx, "name");
459 if (grn_obj_is_table(ctx, source)) {
460 grn_ctx_output_cstr(ctx, "_key");
461 } else {
462 command_object_inspect_column_name(ctx, source);
463 }
464
465 grn_ctx_output_cstr(ctx, "table");
466 command_object_inspect_table(ctx, source_table);
467
468 grn_ctx_output_cstr(ctx, "full_name");
469 if (grn_obj_is_table(ctx, source)) {
470 char name[GRN_TABLE_MAX_KEY_SIZE];
471 unsigned int name_size;
472 name_size = grn_obj_name(ctx, source, name, GRN_TABLE_MAX_KEY_SIZE);
473 name[name_size] = '\0';
474 grn_strcat(name, GRN_TABLE_MAX_KEY_SIZE, "._key");
475 grn_ctx_output_cstr(ctx, name);
476 } else {
477 command_object_inspect_obj_name(ctx, source);
478 }
479 }
480 grn_ctx_output_map_close(ctx);
481 }
482 grn_ctx_output_array_close(ctx);
483
484 GRN_OBJ_FIN(ctx, &source_ids);
485}
486
487static void
488command_object_inspect_column(grn_ctx *ctx, grn_obj *column)
489{
490 int n_elements = 7;
491 grn_bool is_index = (column->header.type == GRN_COLUMN_INDEX);
492
493 if (is_index) {
494 n_elements += 1;
495 }
496 grn_ctx_output_map_open(ctx, "column", n_elements);
497 {
498 grn_ctx_output_cstr(ctx, "id");
499 grn_ctx_output_uint64(ctx, grn_obj_id(ctx, column));
500 grn_ctx_output_cstr(ctx, "name");
501 command_object_inspect_column_name(ctx, column);
502 grn_ctx_output_cstr(ctx, "table");
503 command_object_inspect_table(ctx, grn_ctx_at(ctx, column->header.domain));
504 grn_ctx_output_cstr(ctx, "full_name");
505 command_object_inspect_obj_name(ctx, column);
506 grn_ctx_output_cstr(ctx, "type");
507 command_object_inspect_column_type(ctx, column);
508 grn_ctx_output_cstr(ctx, "value");
509 command_object_inspect_column_value(ctx, column);
510 if (is_index) {
511 grn_ctx_output_cstr(ctx, "sources");
512 command_object_inspect_column_index_sources(ctx, column);
513 }
514 grn_ctx_output_cstr(ctx, "disk_usage");
515 command_object_inspect_disk_usage(ctx, column);
516 }
517 grn_ctx_output_map_close(ctx);
518}
519
520static void
521command_object_inspect_db(grn_ctx *ctx, grn_obj *obj)
522{
523 grn_db *db = (grn_db *)obj;
524
525 grn_ctx_output_map_open(ctx, "database", 3);
526 {
527 grn_ctx_output_cstr(ctx, "type");
528 command_object_inspect_obj_type(ctx, obj->header.type);
529 grn_ctx_output_cstr(ctx, "name_table");
530 command_object_inspect_dispatch(ctx, db->keys);
531 grn_ctx_output_cstr(ctx, "disk_usage");
532 command_object_inspect_disk_usage(ctx, obj);
533 }
534 grn_ctx_output_map_close(ctx);
535}
536
537static void
538command_object_inspect_dispatch(grn_ctx *ctx, grn_obj *obj)
539{
540 switch (obj->header.type) {
541 case GRN_TYPE :
542 command_object_inspect_type(ctx, obj);
543 break;
544 case GRN_TABLE_HASH_KEY :
545 case GRN_TABLE_PAT_KEY :
546 case GRN_TABLE_DAT_KEY :
547 case GRN_TABLE_NO_KEY :
548 command_object_inspect_table(ctx, obj);
549 break;
550 case GRN_COLUMN_FIX_SIZE :
551 case GRN_COLUMN_VAR_SIZE :
552 case GRN_COLUMN_INDEX :
553 command_object_inspect_column(ctx, obj);
554 break;
555 case GRN_DB :
556 command_object_inspect_db(ctx, obj);
557 break;
558 default :
559 {
560 GRN_PLUGIN_ERROR(ctx,
561 GRN_FUNCTION_NOT_IMPLEMENTED,
562 "[object][inspect] unsupported type: <%s>(%#x)",
563 grn_obj_type_to_string(obj->header.type),
564 obj->header.type);
565 grn_ctx_output_null(ctx);
566 break;
567 }
568 }
569}
570
571static grn_obj *
572command_object_inspect(grn_ctx *ctx,
573 int nargs,
574 grn_obj **args,
575 grn_user_data *user_data)
576{
577 grn_obj *name;
578 grn_obj *target;
579
580 name = grn_plugin_proc_get_var(ctx, user_data, "name", -1);
581 if (GRN_TEXT_LEN(name) == 0) {
582 target = grn_ctx_db(ctx);
583 } else {
584 target = grn_ctx_get(ctx,
585 GRN_TEXT_VALUE(name),
586 GRN_TEXT_LEN(name));
587 if (!target) {
588 GRN_PLUGIN_ERROR(ctx,
589 GRN_INVALID_ARGUMENT,
590 "[object][inspect] nonexistent target: <%.*s>",
591 (int)GRN_TEXT_LEN(name),
592 GRN_TEXT_VALUE(name));
593 grn_ctx_output_null(ctx);
594 return NULL;
595 }
596 }
597
598 command_object_inspect_dispatch(ctx, target);
599
600 return NULL;
601}
602
603void
604grn_proc_init_object_inspect(grn_ctx *ctx)
605{
606 grn_expr_var vars[1];
607
608 grn_plugin_expr_var_init(ctx, &(vars[0]), "name", -1);
609 grn_plugin_command_create(ctx,
610 "object_inspect", -1,
611 command_object_inspect,
612 1,
613 vars);
614}
615