SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / common / map-key / map-key.c
1 /*
2 * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <stdlib.h>
9 #include <inttypes.h>
10
11 #include <common/dynamic-array.h>
12 #include <common/error.h>
13 #include <common/macros.h>
14 #include <common/payload.h>
15 #include <common/payload-view.h>
16
17 #include <lttng/map-key.h>
18 #include <lttng/map-key-internal.h>
19
20 #define TOKEN_VAR_EVENT_NAME "EVENT_NAME"
21 #define TOKEN_VAR_PROVIDER_NAME "PROVIDER_NAME"
22
23 static
24 void destroy_map_key_token(void *ptr)
25 {
26 struct lttng_map_key_token *token = (struct lttng_map_key_token *) ptr;
27 switch (token->type) {
28 case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
29 {
30 struct lttng_map_key_token_string *token_string =
31 (struct lttng_map_key_token_string *) token;
32 free(token_string->string);
33 break;
34 }
35 case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
36 break;
37 default:
38 abort();
39 }
40
41 free(token);
42 }
43
44 struct lttng_map_key *lttng_map_key_create(void)
45 {
46 struct lttng_map_key *key = NULL;
47
48 key = zmalloc(sizeof(*key));
49 if (!key) {
50 return NULL;
51 }
52
53 urcu_ref_init(&key->ref);
54 lttng_dynamic_pointer_array_init(&key->tokens,
55 destroy_map_key_token);
56
57 return key;
58 }
59
60 ssize_t lttng_map_key_create_from_payload(struct lttng_payload_view *src_view,
61 struct lttng_map_key **out_key)
62 {
63 ssize_t ret, consumed_len;
64 uint32_t i;
65 const struct lttng_map_key_comm *comm;
66 struct lttng_map_key *key;
67
68 if (!src_view || !out_key) {
69 ret = -1;
70 goto end;
71 }
72
73 key = lttng_map_key_create();
74 if (!key) {
75 ret = -1;
76 goto end;
77 }
78
79 comm = (typeof(comm)) src_view->buffer.data;
80 consumed_len = sizeof(*comm);
81
82 assert(comm->token_count > 0);
83
84 for (i = 0; i < comm->token_count; i++) {
85 enum lttng_map_key_status key_status;
86 const struct lttng_map_key_token_comm *token_comm;
87 struct lttng_payload_view child_view =
88 lttng_payload_view_from_view(src_view, consumed_len,
89 src_view->buffer.size - consumed_len);
90 if (!lttng_payload_view_is_valid(&child_view)) {
91 ret = -1;
92 goto end;
93 }
94
95 token_comm = (const struct lttng_map_key_token_comm *) child_view.buffer.data;
96
97 switch (token_comm->type) {
98 case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
99 {
100 const char *str_val;
101 const struct lttng_map_key_token_string_comm *comm;
102
103 comm = (typeof(comm)) token_comm;
104 str_val = (const char *) &comm->payload;
105
106 if (!lttng_buffer_view_contains_string(&child_view.buffer,
107 str_val, comm->string_len)) {
108 ret = -1;
109 goto end;
110 }
111
112 key_status = lttng_map_key_append_token_string(key, str_val);
113 if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
114 ret = -1;
115 goto end;
116 }
117
118 consumed_len += sizeof(*comm) + comm->string_len;
119
120 break;
121 }
122 case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
123 {
124 const struct lttng_map_key_token_variable_comm *comm;
125
126 comm = (typeof(comm)) token_comm;
127 key_status = lttng_map_key_append_token_variable(key,
128 comm->var_type);
129 if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
130 ret = -1;
131 goto end;
132 }
133
134 consumed_len += sizeof(*comm);
135 break;
136 }
137 default:
138 abort();
139 }
140 }
141
142 *out_key = key;
143 ret = consumed_len;
144 end:
145 return ret;
146 }
147
148 int lttng_map_key_serialize(const struct lttng_map_key *key,
149 struct lttng_payload *payload)
150 {
151 int ret;
152 uint32_t i, nb_tokens;
153 enum lttng_map_key_status key_status;
154 struct lttng_map_key_comm comm = {0};
155
156 DBG("Serializing map key");
157
158 key_status = lttng_map_key_get_token_count(key, &nb_tokens);
159 if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
160 ret = -1;
161 goto end;
162 }
163
164 if (nb_tokens == 0) {
165 ERR("Map key token number is zero");
166 ret = -1;
167 goto end;
168 }
169
170 DBG("Serializing map key token count: %" PRIu32, nb_tokens);
171 comm.token_count = nb_tokens;
172
173 ret = lttng_dynamic_buffer_append(&payload->buffer, &comm,
174 sizeof(comm));
175 if (ret) {
176 goto end;
177 }
178
179 for (i = 0; i < nb_tokens; i++) {
180 uint8_t token_type;
181 const struct lttng_map_key_token *token =
182 lttng_map_key_get_token_at_index(key, i);
183 DBG("Serializing map key token's type: %d", token->type);
184
185 token_type = (uint8_t) token->type;
186
187 switch (token->type) {
188 case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
189 {
190 struct lttng_map_key_token_string *str_token =
191 (struct lttng_map_key_token_string *) token;
192 struct lttng_map_key_token_string_comm comm = {0};
193 uint32_t len = strlen(str_token->string) + 1;
194
195 DBG("Serializing a string type key token");
196 comm.parent_type = token_type;
197 comm.string_len = len;
198
199 /* Serialize the length, include the null character */
200 DBG("Serializing map key token string length (include null character):"
201 "%" PRIu32, len);
202 ret = lttng_dynamic_buffer_append(&payload->buffer,
203 &comm, sizeof(comm));
204 if (ret) {
205 goto end;
206 }
207
208 /* Serialize the string */
209 DBG("Serializing map key token string's value: \"%s\"",
210 str_token->string);
211 ret = lttng_dynamic_buffer_append(&payload->buffer,
212 str_token->string, len);
213 if (ret) {
214 goto end;
215 }
216
217 break;
218 }
219 case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
220 {
221 struct lttng_map_key_token_variable *var_token =
222 (struct lttng_map_key_token_variable *) token;
223 struct lttng_map_key_token_variable_comm comm = {0};
224
225 DBG("Serializing a variable type key token");
226
227 comm.parent_type = token_type;
228 comm.var_type = var_token->type;
229
230 ret = lttng_dynamic_buffer_append(&payload->buffer,
231 &comm, sizeof(comm));
232 if (ret) {
233 goto end;
234 }
235
236 break;
237 }
238 default:
239 abort();
240 }
241 }
242
243 end:
244 return ret;
245 }
246
247 static inline
248 bool token_variable_type_is_valid(enum lttng_map_key_token_variable_type var_type)
249 {
250 switch (var_type) {
251 case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
252 case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
253 return true;
254 default:
255 return false;
256 }
257 }
258
259 static bool lttng_map_key_token_variable_is_equal(
260 const struct lttng_map_key_token *_a,
261 const struct lttng_map_key_token *_b)
262 {
263 struct lttng_map_key_token_variable *a, *b;
264 assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
265 assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
266
267 a = container_of(_a, struct lttng_map_key_token_variable, parent);
268 b = container_of(_b, struct lttng_map_key_token_variable, parent);
269
270 return lttng_map_key_token_variable_get_type(a) ==
271 lttng_map_key_token_variable_get_type(b);
272 }
273
274 enum lttng_map_key_status lttng_map_key_append_token_variable(
275 struct lttng_map_key *key,
276 enum lttng_map_key_token_variable_type var_type)
277 {
278 int ret;
279 enum lttng_map_key_status status;
280 struct lttng_map_key_token_variable *token = NULL;
281
282 if (!token_variable_type_is_valid(var_type)) {
283 ERR("Invalid token variable type");
284 status = LTTNG_MAP_KEY_STATUS_INVALID;
285 goto end;
286 }
287
288 token = zmalloc(sizeof(*token));
289 if (!token) {
290 status = LTTNG_MAP_KEY_STATUS_ERROR;
291 goto end;
292 }
293
294 token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE;
295 token->parent.equal = lttng_map_key_token_variable_is_equal;
296 token->type = var_type;
297
298 ret = lttng_dynamic_pointer_array_add_pointer(
299 &key->tokens, token);
300 if (ret) {
301 status = LTTNG_MAP_KEY_STATUS_ERROR;
302 goto end;
303 }
304
305 status = LTTNG_MAP_KEY_STATUS_OK;
306
307 end:
308 return status;
309 }
310
311 static bool lttng_map_key_token_string_is_equal(
312 const struct lttng_map_key_token *_a,
313 const struct lttng_map_key_token *_b)
314 {
315 struct lttng_map_key_token_string *a, *b;
316 const char *a_string, *b_string;
317
318 assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
319 assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
320
321 a = container_of(_a, struct lttng_map_key_token_string, parent);
322 b = container_of(_b, struct lttng_map_key_token_string, parent);
323
324 a_string = lttng_map_key_token_string_get_string(a);
325 b_string = lttng_map_key_token_string_get_string(b);
326
327 return !strcmp(a_string, b_string);
328 }
329
330 enum lttng_map_key_status lttng_map_key_append_token_string(
331 struct lttng_map_key *key, const char *string)
332 {
333 int ret;
334 enum lttng_map_key_status status;
335 struct lttng_map_key_token_string *token = NULL;
336
337
338 token = zmalloc(sizeof(*token));
339 if (!token) {
340 status = LTTNG_MAP_KEY_STATUS_ERROR;
341 goto end;
342 }
343
344 token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_STRING;
345 token->parent.equal = lttng_map_key_token_string_is_equal;
346 token->string = strdup(string);
347 if (!token->string) {
348 status = LTTNG_MAP_KEY_STATUS_ERROR;
349 goto end;
350 }
351
352 ret = lttng_dynamic_pointer_array_add_pointer(
353 &key->tokens, token);
354 if (ret) {
355 status = LTTNG_MAP_KEY_STATUS_ERROR;
356 goto end;
357 }
358
359 status = LTTNG_MAP_KEY_STATUS_OK;
360 end:
361 return status;
362 }
363
364 enum lttng_map_key_status lttng_map_key_get_token_count(
365 const struct lttng_map_key *key, unsigned int *count)
366 {
367 enum lttng_map_key_status status;
368 if (!key || !count) {
369 status = LTTNG_MAP_KEY_STATUS_INVALID;
370 goto end;
371
372 }
373
374 *count = lttng_dynamic_pointer_array_get_count(
375 &key->tokens);
376
377 status = LTTNG_MAP_KEY_STATUS_OK;
378 end:
379 return status;
380 }
381
382 const struct lttng_map_key_token *
383 lttng_map_key_get_token_at_index(const struct lttng_map_key *key,
384 unsigned int index)
385 {
386 const struct lttng_map_key_token *token = NULL;
387 enum lttng_map_key_status status;
388 unsigned int count;
389
390 if (!key) {
391 goto end;
392 }
393
394 status = lttng_map_key_get_token_count(key, &count);
395 if (status != LTTNG_MAP_KEY_STATUS_OK) {
396 goto end;
397 }
398
399 if (index >= count) {
400 goto end;
401 }
402
403 token = lttng_dynamic_pointer_array_get_pointer(&key->tokens,
404 index);
405
406 end:
407 return token;
408 }
409
410 enum lttng_map_key_token_variable_type lttng_map_key_token_variable_get_type(
411 const struct lttng_map_key_token_variable *token)
412 {
413 assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
414
415 return token->type;
416 }
417
418 const char *lttng_map_key_token_string_get_string(
419 const struct lttng_map_key_token_string *token)
420 {
421 assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
422
423 return token->string;
424 }
425
426 void lttng_map_key_destroy(struct lttng_map_key *key)
427 {
428 lttng_map_key_put(key);
429 }
430
431 LTTNG_HIDDEN
432 struct lttng_map_key *lttng_map_key_parse_from_string(const char *_key_str)
433 {
434 struct lttng_map_key *key = NULL;
435 enum lttng_map_key_status status;
436 char *key_str = NULL, *curr_pos;
437
438 key = lttng_map_key_create();
439 if (!key) {
440 goto end;
441 }
442
443 key_str = strdup(_key_str);
444
445 curr_pos = key_str;
446
447 curr_pos = strtok(curr_pos, "$}");
448 while (curr_pos) {
449 if (curr_pos[0] == '{') {
450 if (strncmp(&curr_pos[1], TOKEN_VAR_EVENT_NAME, strlen(TOKEN_VAR_EVENT_NAME)) == 0) {
451 status = lttng_map_key_append_token_variable(key,
452 LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME);
453 if (status != LTTNG_MAP_KEY_STATUS_OK) {
454 goto error;
455 }
456 } else if (strncmp(&curr_pos[1], TOKEN_VAR_PROVIDER_NAME, strlen(TOKEN_VAR_PROVIDER_NAME)) == 0) {
457 status = lttng_map_key_append_token_variable(key,
458 LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME);
459 if (status != LTTNG_MAP_KEY_STATUS_OK) {
460 goto error;
461 }
462 } else {
463 goto error;
464 }
465 } else {
466 status = lttng_map_key_append_token_string(key, curr_pos);
467 if (status != LTTNG_MAP_KEY_STATUS_OK) {
468 goto error;
469 }
470 }
471 curr_pos = strtok(NULL, "$}");
472 }
473 goto end;
474
475 error:
476 lttng_map_key_destroy(key);
477 key = NULL;
478 end:
479 free(key_str);
480
481 return key;
482 }
483
484 LTTNG_HIDDEN
485 bool lttng_map_key_is_equal(
486 const struct lttng_map_key *a, const struct lttng_map_key *b)
487 {
488 bool is_equal = false;
489 enum lttng_map_key_status status;
490 unsigned int a_count, b_count, i;
491
492 if (!!a != !!b) {
493 goto end;
494 }
495
496 if (a == NULL && b == NULL) {
497 is_equal = true;
498 goto end;
499 }
500
501 if (a == b) {
502 is_equal = true;
503 goto end;
504 }
505
506 status = lttng_map_key_get_token_count(a, &a_count);
507 assert(status == LTTNG_MAP_KEY_STATUS_OK);
508 status = lttng_map_key_get_token_count(b, &b_count);
509 assert(status == LTTNG_MAP_KEY_STATUS_OK);
510
511 if (a_count != b_count) {
512 goto end;
513 }
514
515 for (i = 0; i < a_count; i++) {
516 const struct lttng_map_key_token *token_a = NULL, *token_b = NULL;
517
518 token_a = lttng_map_key_get_token_at_index(a, i);
519 token_b = lttng_map_key_get_token_at_index(b, i);
520
521 /* JORAJ TODO: is order important for the map key token? */
522 if(token_a->type != token_b->type) {
523 goto end;
524 }
525
526 if(!token_a->equal(token_a, token_b)) {
527 goto end;
528 }
529 }
530
531 is_equal = true;
532
533 end:
534 return is_equal;
535
536
537 }
538
539 static void map_key_destroy_ref(struct urcu_ref *ref)
540 {
541 struct lttng_map_key *key = container_of(ref, struct lttng_map_key, ref);
542
543 lttng_dynamic_pointer_array_reset(&key->tokens);
544 free(key);
545 }
546
547 LTTNG_HIDDEN
548 void lttng_map_key_get(struct lttng_map_key *key)
549 {
550 urcu_ref_get(&key->ref);
551 }
552
553 LTTNG_HIDDEN
554 void lttng_map_key_put(struct lttng_map_key *key)
555 {
556 if (!key) {
557 return;
558 }
559
560 urcu_ref_put(&key->ref, map_key_destroy_ref);
561 }
This page took 0.045161 seconds and 5 git commands to generate.