1 #include <stdio.h>
2 #include <string.h>
3 #include <stddef.h>
4 #include <inttypes.h>
5 #include <assert.h>
6 #include <stdint.h>
7 #include <stdbool.h>
8
9 #include "php_tarantool.h"
10 #include "tarantool_schema.h"
11 #include "tarantool_network.h"
12
13 #include "third_party/PMurHash.h"
14 #define MUR_SEED 13
15 #include "third_party/msgpuck.h"
16
mh_indexcmp_eq(const struct schema_index_value ** lval,const struct schema_index_value ** rval,void * arg)17 int mh_indexcmp_eq(
18 const struct schema_index_value **lval,
19 const struct schema_index_value **rval,
20 void *arg
21 ) {
22 (void )arg;
23 if ((*lval)->key.id_len != (*rval)->key.id_len)
24 return 0;
25 return !memcmp((*lval)->key.id, (*rval)->key.id, (*rval)->key.id_len);
26 }
27
mh_indexcmp_key_eq(const struct schema_key * key,const struct schema_index_value ** val,void * arg)28 int mh_indexcmp_key_eq(
29 const struct schema_key *key,
30 const struct schema_index_value **val,
31 void *arg
32 ) {
33 (void )arg;
34 if (key->id_len != (*val)->key.id_len)
35 return 0;
36 return !memcmp(key->id, (*val)->key.id, key->id_len);
37 }
38
39 #define mh_arg_t void *
40
41 #define mh_eq(a, b, arg) mh_indexcmp_eq(a, b, arg)
42 #define mh_eq_key(a, b, arg) mh_indexcmp_key_eq(a, b, arg)
43 #define mh_hash(x, arg) PMurHash32(MUR_SEED, (*x)->key.id, (*x)->key.id_len)
44 #define mh_hash_key(x, arg) PMurHash32(MUR_SEED, (x)->id, (x)->id_len);
45
46 #define mh_node_t struct schema_index_value *
47 #define mh_key_t struct schema_key *
48
49 #define MH_CALLOC(x, y) pecalloc((x), (y), 1)
50 #define MH_FREE(x) pefree((x), 1)
51
52 #define mh_name _schema_index
53 #define MH_SOURCE 1
54 #include "third_party/mhash.h"
55
56 static inline void
schema_field_value_free(struct schema_field_value * val)57 schema_field_value_free(struct schema_field_value *val) {
58 free(val->field_name);
59 }
60
61 static inline void
schema_index_value_free(const struct schema_index_value * val)62 schema_index_value_free(const struct schema_index_value *val) {
63 if (val) {
64 pefree(val->index_name, 1);
65 int i = 0;
66 for (i = val->index_parts_len; i > 0; --i)
67 schema_field_value_free(&(val->index_parts[i - 1]));
68 pefree(val->index_parts, 1);
69 }
70 }
71
72 static inline void
schema_index_free(struct mh_schema_index_t * schema)73 schema_index_free(struct mh_schema_index_t *schema) {
74 int pos = 0;
75 mh_int_t index_slot = 0;
76 mh_foreach(schema, pos) {
77 const struct schema_index_value *ivalue, *iv1 = NULL, *iv2 = NULL;
78 ivalue = *mh_schema_index_node(schema, pos);
79 do {
80 struct schema_key key_number = {
81 (void *)&(ivalue->index_number),
82 sizeof(uint32_t), 0
83 };
84 index_slot = mh_schema_index_find(schema, &key_number,
85 NULL);
86 if (index_slot == mh_end(schema))
87 break;
88 iv1 = *mh_schema_index_node(schema, index_slot);
89 mh_schema_index_del(schema, index_slot, NULL);
90 } while (0);
91 do {
92 struct schema_key key_string = {
93 ivalue->index_name,
94 ivalue->index_name_len, 0
95 };
96 index_slot = mh_schema_index_find(schema, &key_string,
97 NULL);
98 if (index_slot == mh_end(schema))
99 break;
100 iv2 = *mh_schema_index_node(schema, index_slot);
101 mh_schema_index_del(schema, index_slot, NULL);
102 } while (0);
103 schema_index_value_free(ivalue);
104 if (iv1) pefree((void *)iv1, 1);
105 if (iv2) pefree((void *)iv2, 1);
106 }
107 }
108
109 int
mh_spacecmp_eq(const struct schema_space_value ** lval,const struct schema_space_value ** rval,void * arg)110 mh_spacecmp_eq(
111 const struct schema_space_value **lval,
112 const struct schema_space_value **rval,
113 void *arg) {
114 (void )arg;
115 if ((*lval)->key.id_len != (*rval)->key.id_len)
116 return 0;
117 return !memcmp((*lval)->key.id, (*rval)->key.id, (*rval)->key.id_len);
118 }
119
120 int
mh_spacecmp_key_eq(const struct schema_key * key,const struct schema_space_value ** val,void * arg)121 mh_spacecmp_key_eq(
122 const struct schema_key *key,
123 const struct schema_space_value **val,
124 void *arg) {
125 (void )arg;
126 if (key->id_len != (*val)->key.id_len)
127 return 0;
128 return !memcmp(key->id, (*val)->key.id, key->id_len);
129 }
130
131 #define mh_arg_t void *
132
133 #define mh_eq(a, b, arg) mh_spacecmp_eq(a, b, arg)
134 #define mh_eq_key(a, b, arg) mh_spacecmp_key_eq(a, b, arg)
135 #define mh_hash(x, arg) PMurHash32(MUR_SEED, (*x)->key.id, (*x)->key.id_len)
136 #define mh_hash_key(x, arg) PMurHash32(MUR_SEED, x->id, x->id_len);
137
138 #define mh_node_t struct schema_space_value *
139 #define mh_key_t struct schema_key *
140
141 #define MH_CALLOC(x, y) pecalloc((x), (y), 1)
142 #define MH_FREE(x) pefree((x), 1)
143
144 #define mh_name _schema_space
145 #define MH_SOURCE 1
146 #define MH_DEBUG 1
147 #include "third_party/mhash.h"
148
149 static inline void
schema_space_value_free(const struct schema_space_value * val)150 schema_space_value_free(const struct schema_space_value *val) {
151 if (val) {
152 pefree(val->space_name, 1);
153 int i = 0;
154 for (i = val->schema_list_len; i > 0; --i)
155 schema_field_value_free(&(val->schema_list[i - 1]));
156 pefree(val->schema_list, 1);
157 if (val->index_hash) {
158 schema_index_free(val->index_hash);
159 mh_schema_index_delete(val->index_hash);
160 }
161 }
162 }
163
164 static inline void
schema_space_free(struct mh_schema_space_t * schema)165 schema_space_free(struct mh_schema_space_t *schema) {
166 int pos = 0;
167 mh_int_t space_slot = 0;
168 mh_foreach(schema, pos) {
169 const struct schema_space_value *svalue, *sv1 = NULL, *sv2 = NULL;
170 svalue = *mh_schema_space_node(schema, pos);
171 do {
172 struct schema_key key_number = {
173 (void *)&(svalue->space_number),
174 sizeof(uint32_t), 0
175 };
176 space_slot = mh_schema_space_find(schema, &key_number,
177 NULL);
178 if (space_slot == mh_end(schema))
179 break;
180 sv1 = *mh_schema_space_node(schema, space_slot);
181 mh_schema_space_del(schema, space_slot, NULL);
182 } while (0);
183 do {
184 struct schema_key key_string = {
185 svalue->space_name,
186 svalue->space_name_len, 0
187 };
188 space_slot = mh_schema_space_find(schema, &key_string,
189 NULL);
190 if (space_slot == mh_end(schema))
191 break;
192 sv2 = *mh_schema_space_node(schema, space_slot);
193 mh_schema_space_del(schema, space_slot, NULL);
194 } while (0);
195 schema_space_value_free(svalue);
196 if (sv1) pefree((void *)sv1, 1);
197 if (sv2) pefree((void *)sv2, 1);
198 }
199 }
200
parse_field_type(const char * sfield,size_t sfield_len)201 int parse_field_type(const char *sfield, size_t sfield_len) {
202 if (sfield_len == 3) {
203 if (tolower(sfield[0]) == 's' &&
204 tolower(sfield[1]) == 't' &&
205 tolower(sfield[2]) == 'r')
206 return FT_STR;
207 if (tolower(sfield[0]) == 'n' &&
208 tolower(sfield[1]) == 'u' &&
209 tolower(sfield[2]) == 'm')
210 return FT_NUM;
211 }
212 return FT_OTHER;
213 }
214
215 static inline int
parse_schema_space_value_value(struct schema_field_value * fld,const char ** tuple)216 parse_schema_space_value_value(struct schema_field_value *fld,
217 const char **tuple) {
218 uint32_t sfield_len = 0;
219 if (mp_typeof(**tuple) != MP_STR)
220 goto error;
221 const char *sfield = mp_decode_str(tuple, &sfield_len);
222 if (memcmp(sfield, "name", sfield_len) == 0) {
223 if (mp_typeof(**tuple) != MP_STR)
224 goto error;
225 sfield = mp_decode_str(tuple, &fld->field_name_len);
226 fld->field_name = pemalloc(fld->field_name_len, 1);
227 if (!fld->field_name)
228 goto error;
229 memcpy(fld->field_name, sfield, fld->field_name_len);
230 } else if (memcmp(sfield, "type", sfield_len) == 0) {
231 if (mp_typeof(**tuple) != MP_STR)
232 goto error;
233 sfield = mp_decode_str(tuple, &sfield_len);
234 fld->field_type = parse_field_type(sfield, sfield_len);
235 } else {
236 mp_next(tuple);
237 }
238 return 0;
239 error:
240 return -1;
241 }
242
243 static inline int
parse_schema_space_value(struct schema_space_value * space_string,const char ** tuple)244 parse_schema_space_value(struct schema_space_value *space_string,
245 const char **tuple) {
246 uint32_t fmp_tmp_len = 0;
247 if (mp_typeof(**tuple) != MP_ARRAY)
248 goto error;
249 uint32_t fmt_len = mp_decode_array(tuple);
250 space_string->schema_list_len = fmt_len;
251 space_string->schema_list = pecalloc(fmt_len,
252 sizeof(struct schema_field_value), 1);
253 if (space_string->schema_list == NULL)
254 goto error;
255 int i = 0;
256 for (i = 0; i < fmt_len; ++i) {
257 struct schema_field_value *val = &(space_string->schema_list[i]);
258 if (mp_typeof(**tuple) != MP_MAP)
259 goto error;
260 uint32_t arrsz = mp_decode_map(tuple);
261 while (arrsz-- > 0) {
262 if (parse_schema_space_value_value(val, tuple) < 0)
263 goto error;
264 }
265 val->field_number = i;
266 }
267 return 0;
268 error:
269 return -1;
270 }
271
272 static inline int
parse_schema_index_value(struct schema_index_value * index_string,const char ** tuple)273 parse_schema_index_value(struct schema_index_value *index_string,
274 const char **tuple) {
275 if (mp_typeof(**tuple) != MP_ARRAY)
276 goto error;
277 uint32_t part_count = mp_decode_array(tuple);
278 index_string->index_parts_len = part_count;
279 index_string->index_parts = pecalloc(part_count,
280 sizeof(struct schema_field_value),
281 1);
282 if (!index_string->index_parts)
283 goto error;
284 memset(index_string->index_parts, 0, part_count *
285 sizeof(struct schema_field_value));
286 int i = 0;
287 for (i = 0; i < part_count; ++i) {
288 if (mp_typeof(**tuple) != MP_ARRAY)
289 goto error;
290 if (mp_decode_array(tuple) != 2)
291 goto error;
292 struct schema_field_value *val = &(index_string->index_parts[i]);
293 if (mp_typeof(**tuple) != MP_UINT)
294 goto error;
295 val->field_number = mp_decode_uint(tuple);
296 uint32_t sfield_len = 0;
297 if (mp_typeof(**tuple) != MP_STR)
298 goto error;
299 const char *sfield = mp_decode_str(tuple, &sfield_len);
300 val->field_type = parse_field_type(sfield, sfield_len);
301 }
302 return 0;
303 error:
304 return -1;
305 }
306
307 static inline int
schema_add_space(struct mh_schema_space_t * schema,const char ** data)308 schema_add_space(
309 struct mh_schema_space_t *schema,
310 const char **data
311 ) {
312 const char *tuple = *data;
313 if (mp_typeof(*tuple) != MP_ARRAY)
314 goto error;
315 uint32_t tuple_len = mp_decode_array(&tuple);
316 if (tuple_len < 6)
317 goto error;
318 struct schema_space_value *space_number = NULL, *space_string = NULL;
319 space_string = pemalloc(sizeof(struct schema_space_value), 1);
320 if (space_string == NULL)
321 goto error;
322 memset(space_string, 0, sizeof(struct schema_space_value));
323 int pos = 0;
324 for (pos = 0; pos < tuple_len; ++pos) {
325 int error = 0;
326 switch (pos) {
327 /* space ID (uint) */
328 case 0:
329 if (mp_typeof(*tuple) != MP_UINT)
330 goto error;
331 space_string->space_number = mp_decode_uint(&tuple);
332 break;
333 /* owner ID (uint) */
334 case 1:
335 mp_next(&tuple);
336 break;
337 /* space name (str)*/
338 case 2:
339 if (mp_typeof(*tuple) != MP_STR)
340 goto error;
341 const char *space_name_tmp = mp_decode_str(&tuple,
342 &space_string->space_name_len);
343 space_string->space_name = pemalloc(
344 space_string->space_name_len, 1);
345 if (space_string->space_name == NULL)
346 goto error;
347 memcpy(space_string->space_name, space_name_tmp,
348 space_string->space_name_len);
349 break;
350 /* space engine (str) */
351 case 3:
352 mp_next(&tuple);
353 break;
354 /* field count (uint) */
355 case 4:
356 mp_next(&tuple);
357 break;
358 /* space flags (skipped, for now) */
359 case 5:
360 mp_next(&tuple);
361 break;
362 /*
363 * space format (array of maps)
364 * map's format is: {
365 * 'name' = <str>,
366 * 'type' = <str>
367 * }
368 */
369 case 6:
370 if (parse_schema_space_value(space_string, &tuple) < 0)
371 goto error;
372 break;
373 default:
374 break;
375 }
376 }
377 space_string->index_hash = mh_schema_index_new();
378 if (!space_string->index_hash)
379 goto error;
380 space_number = pemalloc(sizeof(struct schema_space_value), 1);
381 if (!space_number)
382 goto error;
383 memcpy(space_number, space_string, sizeof(struct schema_space_value));
384 space_string->key.id = space_string->space_name;
385 space_string->key.id_len = space_string->space_name_len;
386 space_number->key.id = (void *)&(space_number->space_number);
387 space_number->key.id_len = sizeof(uint32_t);
388 mh_schema_space_put(schema,
389 (const struct schema_space_value **)&space_string,
390 NULL, NULL);
391 mh_schema_space_put(schema,
392 (const struct schema_space_value **)&space_number,
393 NULL, NULL);
394 *data = tuple;
395 return 0;
396 error:
397 schema_space_value_free(space_string);
398 return -1;
399 }
400
401 int
tarantool_schema_add_spaces(struct tarantool_schema * schema_obj,const char * data,uint32_t size)402 tarantool_schema_add_spaces(
403 struct tarantool_schema *schema_obj,
404 const char *data,
405 uint32_t size
406 ) {
407 struct mh_schema_space_t *schema = schema_obj->space_hash;
408 const char *tuple = data;
409 if (mp_check(&tuple, tuple + size))
410 goto error;
411 tuple = data;
412 if (mp_typeof(*tuple) != MP_ARRAY)
413 goto error;
414 uint32_t space_count = mp_decode_array(&tuple);
415 while (space_count-- > 0) {
416 if (schema_add_space(schema, &tuple))
417 goto error;
418 }
419 return 0;
420 error:
421 return -1;
422 }
423
schema_add_index(struct mh_schema_space_t * schema,const char ** data)424 static inline int schema_add_index(
425 struct mh_schema_space_t *schema,
426 const char **data
427 ) {
428 uint32_t space_number = 0;
429 struct schema_key space_key;
430 const struct schema_space_value *space;
431 struct schema_index_value *index_string, *index_number;
432
433 const char *tuple = *data;
434 /* parse index tuple header */
435 if (mp_typeof(*tuple) != MP_ARRAY)
436 goto error;
437 int64_t tuple_len = mp_decode_array(&tuple);
438 if (tuple_len < 6)
439 goto error;
440
441 index_string = pemalloc(sizeof(struct schema_index_value), 1);
442 if (!index_string)
443 goto error;
444 memset(index_string, 0, sizeof(struct schema_index_value));
445 index_number = pemalloc(sizeof(struct schema_index_value), 1);
446 if (!index_number)
447 goto error;
448 memset(index_number, 0, sizeof(struct schema_index_value));
449 int pos = 0;
450 for (pos = 0; pos < tuple_len; ++pos) {
451 int error = 0;
452 switch (pos) {
453 /* space ID */
454 case 0:
455 if (mp_typeof(*tuple) != MP_UINT)
456 goto error;
457 space_key.number = mp_decode_uint(&tuple);
458 space_key.id = (void *)&(space_key.number);
459 space_key.id_len = sizeof(uint32_t);
460 break;
461 /* index ID */
462 case 1:
463 if (mp_typeof(*tuple) != MP_UINT)
464 goto error;
465 index_string->index_number = mp_decode_uint(&tuple);
466 break;
467 /* index name */
468 case 2:
469 if (mp_typeof(*tuple) != MP_STR)
470 goto error;
471 const char *index_name_tmp = mp_decode_str(&tuple,
472 &index_string->index_name_len);
473 index_string->index_name = pemalloc(
474 index_string->index_name_len, 1);
475 if (!index_string->index_name)
476 goto error;
477 memcpy(index_string->index_name, index_name_tmp,
478 index_string->index_name_len);
479 break;
480 /* index type */
481 case 3:
482 mp_next(&tuple);
483 break;
484 /* index opts */
485 case 4:
486 mp_next(&tuple);
487 break;
488 /* index parts */
489 case 5:
490 if (parse_schema_index_value(index_string, &tuple) < 0)
491 goto error;
492 break;
493 default:
494 break;
495 }
496 }
497 mh_int_t space_slot = mh_schema_space_find(schema, &space_key, NULL);
498 if (space_slot == mh_end(schema))
499 goto error;
500 space = *mh_schema_space_node(schema, space_slot);
501 memcpy(index_number, index_string, sizeof(struct schema_index_value));
502 index_string->key.id = index_string->index_name;
503 index_string->key.id_len = index_string->index_name_len;
504 index_number->key.id = (void *)&(index_number->index_number);
505 index_number->key.id_len = sizeof(uint32_t);
506 mh_schema_index_put(space->index_hash,
507 (const struct schema_index_value **)&index_string,
508 NULL, NULL);
509 mh_schema_index_put(space->index_hash,
510 (const struct schema_index_value **)&index_number,
511 NULL, NULL);
512 *data = tuple;
513 return 0;
514 error:
515 schema_index_value_free(index_string);
516 return -1;
517 }
518
519 int
tarantool_schema_add_indexes(struct tarantool_schema * schema_obj,const char * data,uint32_t size)520 tarantool_schema_add_indexes(
521 struct tarantool_schema *schema_obj,
522 const char *data,
523 uint32_t size
524 ) {
525 struct mh_schema_space_t *schema = schema_obj->space_hash;
526 const char *tuple = data;
527 if (mp_check(&tuple, tuple + size))
528 goto error;
529 tuple = data;
530 if (mp_typeof(*tuple) != MP_ARRAY)
531 goto error;
532 uint32_t space_count = mp_decode_array(&tuple);
533 while (space_count-- > 0) {
534 if (schema_add_index(schema, &tuple))
535 goto error;
536 }
537 return 0;
538 error:
539 return -1;
540 }
541
542 int32_t
tarantool_schema_get_sid_by_string(struct tarantool_schema * schema_obj,const char * space_name,uint32_t space_name_len)543 tarantool_schema_get_sid_by_string(
544 struct tarantool_schema *schema_obj, const char *space_name,
545 uint32_t space_name_len
546 ) {
547 struct mh_schema_space_t *schema = schema_obj->space_hash;
548 struct schema_key space_key = {
549 space_name,
550 space_name_len, 0
551 };
552 mh_int_t space_slot = mh_schema_space_find(schema, &space_key, NULL);
553 if (space_slot == mh_end(schema))
554 return -1;
555 const struct schema_space_value *space = *mh_schema_space_node(schema,
556 space_slot);
557 return space->space_number;
558 }
559
560 int32_t
tarantool_schema_get_iid_by_string(struct tarantool_schema * schema_obj,uint32_t sid,const char * index_name,uint32_t index_name_len)561 tarantool_schema_get_iid_by_string(
562 struct tarantool_schema *schema_obj, uint32_t sid,
563 const char *index_name, uint32_t index_name_len
564 ) {
565 struct mh_schema_space_t *schema = schema_obj->space_hash;
566 struct schema_key space_key = {
567 (void *)&sid,
568 sizeof(uint32_t), 0
569 };
570 mh_int_t space_slot = mh_schema_space_find(schema, &space_key, NULL);
571 if (space_slot == mh_end(schema))
572 return -1;
573 const struct schema_space_value *space = *mh_schema_space_node(schema,
574 space_slot);
575 struct schema_key index_key = {
576 index_name,
577 index_name_len, 0
578 };
579 mh_int_t index_slot = mh_schema_index_find(space->index_hash,
580 &index_key, NULL);
581 if (index_slot == mh_end(space->index_hash))
582 return -1;
583 const struct schema_index_value *index = *mh_schema_index_node(
584 space->index_hash, index_slot);
585 return index->index_number;
586 }
587
588 int32_t
tarantool_schema_get_fid_by_string(struct tarantool_schema * schema_obj,uint32_t sid,const char * field_name,uint32_t field_name_len)589 tarantool_schema_get_fid_by_string(
590 struct tarantool_schema *schema_obj, uint32_t sid,
591 const char *field_name, uint32_t field_name_len
592 ) {
593 struct mh_schema_space_t *schema = schema_obj->space_hash;
594 struct schema_key space_key = {
595 (void *)&sid,
596 sizeof(uint32_t), 0
597 };
598 mh_int_t space_slot = mh_schema_space_find(schema, &space_key, NULL);
599 if (space_slot == mh_end(schema))
600 return -1;
601 const struct schema_space_value *space = *mh_schema_space_node(schema,
602 space_slot);
603 int i = 0;
604 for (i = 0; i < space->schema_list_len; ++i) {
605 struct schema_field_value *val = &space->schema_list[i];
606 if (strncmp(val->field_name, field_name, field_name_len) == 0)
607 return val->field_number;
608 }
609 return -1;
610 }
611
tarantool_schema_new(int is_persistent)612 struct tarantool_schema *tarantool_schema_new(int is_persistent) {
613 struct tarantool_schema *obj = pemalloc(sizeof(struct tarantool_schema *), 1);
614 obj->space_hash = mh_schema_space_new();
615 return obj;
616 }
617
tarantool_schema_flush(struct tarantool_schema * obj)618 void tarantool_schema_flush(struct tarantool_schema *obj) {
619 schema_space_free(obj->space_hash);
620 }
621
tarantool_schema_delete(struct tarantool_schema * obj,int is_persistent)622 void tarantool_schema_delete(struct tarantool_schema *obj, int is_persistent) {
623 if (obj == NULL)
624 return;
625 schema_space_free(obj->space_hash);
626 mh_schema_space_delete(obj->space_hash);
627 pefree(obj, 1);
628 }
629