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 
8 #include <msgpuck.h>
9 
10 #include <tarantool/tnt_reply.h>
11 #include <tarantool/tnt_stream.h>
12 #include <tarantool/tnt_buf.h>
13 #include <tarantool/tnt_object.h>
14 #include <tarantool/tnt_proto.h>
15 #include <tarantool/tnt_schema.h>
16 #include <tarantool/tnt_mem.h>
17 #include <tarantool/tnt_select.h>
18 
19 #include "tnt_assoc.h"
20 
21 static inline void
tnt_schema_ival_free(struct tnt_schema_ival * val)22 tnt_schema_ival_free(struct tnt_schema_ival *val) {
23 	if (val) tnt_mem_free((void *)val->name);
24 	tnt_mem_free(val);
25 }
26 
27 static inline void
tnt_schema_index_free(struct mh_assoc_t * schema)28 tnt_schema_index_free(struct mh_assoc_t *schema) {
29 	mh_int_t pos = 0;
30 	mh_int_t index_slot = 0;
31 	mh_foreach(schema, pos) {
32 		struct tnt_schema_ival *ival =
33 			(*mh_assoc_node(schema, pos))->data;
34 		struct assoc_val *av1 = NULL, *av2 = NULL;
35 		do {
36 			struct assoc_key key_number = {
37 				(void *)&(ival->number),
38 				sizeof(uint32_t)
39 			};
40 			index_slot = mh_assoc_find(schema, &key_number, NULL);
41 			if (index_slot == mh_end(schema))
42 				break;
43 			av1 = *mh_assoc_node(schema, index_slot);
44 			mh_assoc_del(schema, index_slot, NULL);
45 		} while (0);
46 		do {
47 			struct assoc_key key_string = {
48 				ival->name,
49 				ival->name_len
50 			};
51 			index_slot = mh_assoc_find(schema, &key_string, NULL);
52 			if (index_slot == mh_end(schema))
53 				break;
54 			av2 = *mh_assoc_node(schema, index_slot);
55 			mh_assoc_del(schema, index_slot, NULL);
56 		} while (0);
57 		tnt_schema_ival_free(ival);
58 		if (av1) tnt_mem_free((void *)av1);
59 		if (av2) tnt_mem_free((void *)av2);
60 	}
61 }
62 
63 static inline void
tnt_schema_sval_free(struct tnt_schema_sval * val)64 tnt_schema_sval_free(struct tnt_schema_sval *val) {
65 	if (val) {
66 		tnt_mem_free(val->name);
67 		if (val->index) {
68 			tnt_schema_index_free(val->index);
69 			mh_assoc_delete(val->index);
70 		}
71 	}
72 	tnt_mem_free(val);
73 }
74 
75 static inline void
tnt_schema_space_free(struct mh_assoc_t * schema)76 tnt_schema_space_free(struct mh_assoc_t *schema) {
77 	mh_int_t pos = 0;
78 	mh_int_t space_slot = 0;
79 	mh_foreach(schema, pos) {
80 		struct tnt_schema_sval *sval = NULL;
81 		sval = (*mh_assoc_node(schema, pos))->data;
82 		struct assoc_val *av1 = NULL, *av2 = NULL;
83 		do {
84 			struct assoc_key key_number = {
85 				(void *)&(sval->number),
86 				sizeof(uint32_t)
87 			};
88 			space_slot = mh_assoc_find(schema, &key_number, NULL);
89 			if (space_slot == mh_end(schema))
90 				break;
91 			av1 = *mh_assoc_node(schema, space_slot);
92 			mh_assoc_del(schema, space_slot, NULL);
93 		} while (0);
94 		do {
95 			struct assoc_key key_string = {
96 				sval->name,
97 				sval->name_len
98 			};
99 			space_slot = mh_assoc_find(schema, &key_string, NULL);
100 			if (space_slot == mh_end(schema))
101 				break;
102 			av2 = *mh_assoc_node(schema, space_slot);
103 			mh_assoc_del(schema, space_slot, NULL);
104 		} while (0);
105 		tnt_schema_sval_free(sval);
106 		if (av1) tnt_mem_free((void *)av1);
107 		if (av2) tnt_mem_free((void *)av2);
108 	}
109 }
110 
111 static inline int
tnt_schema_add_space(struct mh_assoc_t * schema,const char ** data)112 tnt_schema_add_space(struct mh_assoc_t *schema, const char **data)
113 {
114 	struct tnt_schema_sval *space = NULL;
115 	struct assoc_val *space_string = NULL, *space_number = NULL;
116 	const char *tuple = *data;
117 	if (mp_typeof(*tuple) != MP_ARRAY)
118 		goto error;
119 	uint32_t tuple_len = mp_decode_array(&tuple); (void )tuple_len;
120 	space = tnt_mem_alloc(sizeof(struct tnt_schema_sval));
121 	if (!space)
122 		goto error;
123 	memset(space, 0, sizeof(struct tnt_schema_sval));
124 	if (mp_typeof(*tuple) != MP_UINT)
125 		goto error;
126 	space->number = mp_decode_uint(&tuple);
127 	mp_next(&tuple); /* skip owner id */
128 	if (mp_typeof(*tuple) != MP_STR)
129 		goto error;
130 	const char *name_tmp = mp_decode_str(&tuple, &space->name_len);
131 	space->name = tnt_mem_alloc(space->name_len);
132 	if (!space->name)
133 		goto error;
134 	memcpy(space->name, name_tmp, space->name_len);
135 
136 	space->index = mh_assoc_new();
137 	if (!space->index)
138 		goto error;
139 	space_string = tnt_mem_alloc(sizeof(struct assoc_val));
140 	if (!space_string)
141 		goto error;
142 	space_string->key.id     = space->name;
143 	space_string->key.id_len = space->name_len;
144 	space_string->data = space;
145 	space_number = tnt_mem_alloc(sizeof(struct assoc_val));
146 	if (!space_number)
147 		goto error;
148 	space_number->key.id = (void *)&(space->number);
149 	space_number->key.id_len = sizeof(space->number);
150 	space_number->data = space;
151 	mh_assoc_put(schema, (const struct assoc_val **)&space_string,
152 		     NULL, NULL);
153 	mh_assoc_put(schema, (const struct assoc_val **)&space_number,
154 		     NULL, NULL);
155 	mp_next(data);
156 	return 0;
157 error:
158 	mp_next(data);
159 	tnt_schema_sval_free(space);
160 	if (space_string) tnt_mem_free(space_string);
161 	if (space_number) tnt_mem_free(space_number);
162 	return -1;
163 }
164 
tnt_schema_add_spaces(struct tnt_schema * schema_obj,struct tnt_reply * r)165 int tnt_schema_add_spaces(struct tnt_schema *schema_obj, struct tnt_reply *r) {
166 	struct mh_assoc_t *schema = schema_obj->space_hash;
167 	const char *tuple = r->data;
168 	if (mp_check(&tuple, tuple + (r->data_end - r->data)))
169 		return -1;
170 	tuple = r->data;
171 	if (mp_typeof(*tuple) != MP_ARRAY)
172 		return -1;
173 	uint32_t space_count = mp_decode_array(&tuple);
174 	while (space_count-- > 0) {
175 		if (tnt_schema_add_space(schema, &tuple))
176 			return -1;
177 	}
178 	return 0;
179 }
180 
181 static inline int
tnt_schema_add_index(struct mh_assoc_t * schema,const char ** data)182 tnt_schema_add_index(struct mh_assoc_t *schema, const char **data) {
183 	const struct tnt_schema_sval *space = NULL;
184 	struct tnt_schema_ival *index = NULL;
185 	struct assoc_val *index_number = NULL, *index_string = NULL;
186 	const char *tuple = *data;
187 	if (mp_typeof(*tuple) != MP_ARRAY)
188 		goto error;
189 	int64_t tuple_len = mp_decode_array(&tuple); (void )tuple_len;
190 	uint32_t space_number = mp_decode_uint(&tuple);
191 	if (mp_typeof(*tuple) != MP_UINT)
192 		goto error;
193 	struct assoc_key space_key = {
194 		(void *)&(space_number),
195 		sizeof(uint32_t)
196 	};
197 	mh_int_t space_slot = mh_assoc_find(schema, &space_key, NULL);
198 	if (space_slot == mh_end(schema))
199 		return -1;
200 	space = (*mh_assoc_node(schema, space_slot))->data;
201 	index = tnt_mem_alloc(sizeof(struct tnt_schema_ival));
202 	if (!index)
203 		goto error;
204 	memset(index, 0, sizeof(struct tnt_schema_ival));
205 	if (mp_typeof(*tuple) != MP_UINT)
206 		goto error;
207 	index->number = mp_decode_uint(&tuple);
208 	if (mp_typeof(*tuple) != MP_STR)
209 		goto error;
210 	const char *name_tmp = mp_decode_str(&tuple, &index->name_len);
211 	index->name = tnt_mem_alloc(index->name_len);
212 	if (!index->name)
213 		goto error;
214 	memcpy((void *)index->name, name_tmp, index->name_len);
215 
216 	index_string = tnt_mem_alloc(sizeof(struct assoc_val));
217 	if (!index_string) goto error;
218 	index_string->key.id     = index->name;
219 	index_string->key.id_len = index->name_len;
220 	index_string->data = index;
221 	index_number = tnt_mem_alloc(sizeof(struct assoc_val));
222 	if (!index_number) goto error;
223 	index_number->key.id     = (void *)&(index->number);
224 	index_number->key.id_len = sizeof(uint32_t);
225 	index_number->data = index;
226 	mh_assoc_put(space->index, (const struct assoc_val **)&index_string,
227 		     NULL, NULL);
228 	mh_assoc_put(space->index, (const struct assoc_val **)&index_number,
229 		     NULL, NULL);
230 	mp_next(data);
231 	return 0;
232 error:
233 	mp_next(data);
234 	if (index_string) tnt_mem_free(index_string);
235 	if (index_number) tnt_mem_free(index_number);
236 	tnt_schema_ival_free(index);
237 	return -1;
238 }
239 
tnt_schema_add_indexes(struct tnt_schema * schema_obj,struct tnt_reply * r)240 int tnt_schema_add_indexes(struct tnt_schema *schema_obj, struct tnt_reply *r) {
241 	struct mh_assoc_t *schema = schema_obj->space_hash;
242 	const char *tuple = r->data;
243 	if (mp_check(&tuple, tuple + (r->data_end - r->data)))
244 		return -1;
245 	tuple = r->data;
246 	if (mp_typeof(*tuple) != MP_ARRAY)
247 		return -1;
248 	uint32_t space_count = mp_decode_array(&tuple);
249 	while (space_count-- > 0) {
250 		if (tnt_schema_add_index(schema, &tuple))
251 			return -1;
252 	}
253 	return 0;
254 }
255 
tnt_schema_stosid(struct tnt_schema * schema_obj,const char * name,uint32_t name_len)256 int32_t tnt_schema_stosid(struct tnt_schema *schema_obj, const char *name,
257 			  uint32_t name_len) {
258 	struct mh_assoc_t *schema = schema_obj->space_hash;
259 	struct assoc_key space_key = {name, name_len};
260 	mh_int_t space_slot = mh_assoc_find(schema, &space_key, NULL);
261 	if (space_slot == mh_end(schema))
262 		return -1;
263 	const struct tnt_schema_sval *space =
264 		(*mh_assoc_node(schema, space_slot))->data;
265 	return space->number;
266 }
267 
tnt_schema_stoiid(struct tnt_schema * schema_obj,uint32_t sid,const char * name,uint32_t name_len)268 int32_t tnt_schema_stoiid(struct tnt_schema *schema_obj, uint32_t sid,
269 			  const char *name, uint32_t name_len) {
270 	struct mh_assoc_t *schema = schema_obj->space_hash;
271 	struct assoc_key space_key = {(void *)&sid, sizeof(uint32_t)};
272 	mh_int_t space_slot = mh_assoc_find(schema, &space_key, NULL);
273 	if (space_slot == mh_end(schema))
274 		return -1;
275 	const struct tnt_schema_sval *space =
276 		(*mh_assoc_node(schema, space_slot))->data;
277 	struct assoc_key index_key = {name, name_len};
278 	mh_int_t index_slot = mh_assoc_find(space->index, &index_key, NULL);
279 	if (index_slot == mh_end(space->index))
280 		return -1;
281 	const struct tnt_schema_ival *index =
282 		(*mh_assoc_node(space->index, index_slot))->data;
283 	return index->number;
284 }
285 
tnt_schema_new(struct tnt_schema * s)286 struct tnt_schema *tnt_schema_new(struct tnt_schema *s) {
287 	int alloc = (s == NULL);
288 	if (!s) {
289 		s = tnt_mem_alloc(sizeof(struct tnt_schema));
290 		if (!s) return NULL;
291 	}
292 	s->space_hash = mh_assoc_new();
293 	s->alloc = alloc;
294 	return s;
295 }
296 
tnt_schema_flush(struct tnt_schema * obj)297 void tnt_schema_flush(struct tnt_schema *obj) {
298 	tnt_schema_space_free(obj->space_hash);
299 }
300 
tnt_schema_free(struct tnt_schema * obj)301 void tnt_schema_free(struct tnt_schema *obj) {
302 	if (obj == NULL)
303 		return;
304 	tnt_schema_space_free(obj->space_hash);
305 	mh_assoc_delete(obj->space_hash);
306 }
307 
308 ssize_t
tnt_get_space(struct tnt_stream * s)309 tnt_get_space(struct tnt_stream *s)
310 {
311 	struct tnt_stream *obj = tnt_object(NULL);
312 	if (obj == NULL)
313 		return -1;
314 
315 	tnt_object_add_array(obj, 0);
316 	ssize_t retval = tnt_select(s, tnt_vsp_space, tnt_vin_name,
317 				    UINT32_MAX, 0, TNT_ITER_ALL, obj);
318 	tnt_stream_free(obj);
319 	return retval;
320 }
321 
322 ssize_t
tnt_get_index(struct tnt_stream * s)323 tnt_get_index(struct tnt_stream *s)
324 {
325 	struct tnt_stream *obj = tnt_object(NULL);
326 	if (obj == NULL)
327 		return -1;
328 
329 	tnt_object_add_array(obj, 0);
330 	ssize_t retval = tnt_select(s, tnt_vsp_index, tnt_vin_name,
331 				    UINT32_MAX, 0, TNT_ITER_ALL, obj);
332 	tnt_stream_free(obj);
333 	return retval;
334 }
335