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