SoW-2020-0003: Trace Hit Counters
[lttng-tools.git] / src / common / map-key / map-key.c
diff --git a/src/common/map-key/map-key.c b/src/common/map-key/map-key.c
new file mode 100644 (file)
index 0000000..1cce2b1
--- /dev/null
@@ -0,0 +1,561 @@
+/*
+ * Copyright (C) 2021 Francis Deslauriers <francis.deslauriers@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <stdlib.h>
+#include <inttypes.h>
+
+#include <common/dynamic-array.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <common/payload.h>
+#include <common/payload-view.h>
+
+#include <lttng/map-key.h>
+#include <lttng/map-key-internal.h>
+
+#define TOKEN_VAR_EVENT_NAME "EVENT_NAME"
+#define TOKEN_VAR_PROVIDER_NAME "PROVIDER_NAME"
+
+static
+void destroy_map_key_token(void *ptr)
+{
+       struct lttng_map_key_token *token = (struct lttng_map_key_token *) ptr;
+       switch (token->type) {
+       case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+       {
+               struct lttng_map_key_token_string *token_string =
+                               (struct lttng_map_key_token_string *) token;
+               free(token_string->string);
+               break;
+       }
+       case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               break;
+       default:
+               abort();
+       }
+
+       free(token);
+}
+
+struct lttng_map_key *lttng_map_key_create(void)
+{
+        struct lttng_map_key *key = NULL;
+
+        key = zmalloc(sizeof(*key));
+        if (!key) {
+                return NULL;
+        }
+
+       urcu_ref_init(&key->ref);
+       lttng_dynamic_pointer_array_init(&key->tokens,
+                       destroy_map_key_token);
+
+       return key;
+}
+
+ssize_t lttng_map_key_create_from_payload(struct lttng_payload_view *src_view,
+               struct lttng_map_key **out_key)
+{
+       ssize_t ret, consumed_len;
+       uint32_t i;
+       const struct lttng_map_key_comm *comm;
+       struct lttng_map_key *key;
+
+       if (!src_view || !out_key) {
+               ret = -1;
+               goto end;
+       }
+
+       key = lttng_map_key_create();
+       if (!key) {
+               ret = -1;
+               goto end;
+       }
+
+       comm = (typeof(comm)) src_view->buffer.data;
+       consumed_len = sizeof(*comm);
+
+       assert(comm->token_count > 0);
+
+       for (i = 0; i < comm->token_count; i++) {
+               enum lttng_map_key_status key_status;
+               const struct lttng_map_key_token_comm *token_comm;
+               struct lttng_payload_view child_view =
+                               lttng_payload_view_from_view(src_view, consumed_len,
+                                               src_view->buffer.size - consumed_len);
+               if (!lttng_payload_view_is_valid(&child_view)) {
+                       ret = -1;
+                       goto end;
+               }
+
+               token_comm = (const struct lttng_map_key_token_comm *) child_view.buffer.data;
+
+               switch (token_comm->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       const char *str_val;
+                       const struct lttng_map_key_token_string_comm *comm;
+
+                       comm = (typeof(comm)) token_comm;
+                       str_val = (const char *) &comm->payload;
+
+                       if (!lttng_buffer_view_contains_string(&child_view.buffer,
+                                       str_val, comm->string_len)) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       key_status = lttng_map_key_append_token_string(key, str_val);
+                       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       consumed_len += sizeof(*comm) + comm->string_len;
+
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       const struct lttng_map_key_token_variable_comm *comm;
+
+                       comm = (typeof(comm)) token_comm;
+                       key_status = lttng_map_key_append_token_variable(key,
+                                       comm->var_type);
+                       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+                               ret = -1;
+                               goto end;
+                       }
+
+                       consumed_len += sizeof(*comm);
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+       *out_key = key;
+       ret = consumed_len;
+end:
+       return ret;
+}
+
+int lttng_map_key_serialize(const struct lttng_map_key *key,
+               struct lttng_payload *payload)
+{
+       int ret;
+       uint32_t i, nb_tokens;
+       enum lttng_map_key_status key_status;
+       struct lttng_map_key_comm comm = {0};
+
+       DBG("Serializing map key");
+
+       key_status = lttng_map_key_get_token_count(key, &nb_tokens);
+       if (key_status != LTTNG_MAP_KEY_STATUS_OK) {
+               ret = -1;
+               goto end;
+       }
+
+       if (nb_tokens == 0) {
+               ERR("Map key token number is zero");
+               ret = -1;
+               goto end;
+       }
+
+       DBG("Serializing map key token count: %" PRIu32, nb_tokens);
+       comm.token_count = nb_tokens;
+
+       ret = lttng_dynamic_buffer_append(&payload->buffer, &comm,
+                       sizeof(comm));
+       if (ret) {
+               goto end;
+       }
+
+       for (i = 0; i < nb_tokens; i++) {
+               uint8_t token_type;
+               const struct lttng_map_key_token *token =
+                               lttng_map_key_get_token_at_index(key, i);
+               DBG("Serializing map key token's type: %d", token->type);
+
+               token_type = (uint8_t) token->type;
+
+               switch (token->type) {
+               case LTTNG_MAP_KEY_TOKEN_TYPE_STRING:
+               {
+                       struct lttng_map_key_token_string *str_token =
+                                       (struct lttng_map_key_token_string *) token;
+                       struct lttng_map_key_token_string_comm comm = {0};
+                       uint32_t len = strlen(str_token->string) + 1;
+
+                       DBG("Serializing a string type key token");
+                       comm.parent_type = token_type;
+                       comm.string_len = len;
+
+                       /* Serialize the length, include the null character */
+                       DBG("Serializing map key token string length (include null character):"
+                               "%" PRIu32, len);
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                               &comm, sizeof(comm));
+                       if (ret) {
+                               goto end;
+                       }
+
+                       /* Serialize the string */
+                       DBG("Serializing map key token string's value: \"%s\"",
+                                       str_token->string);
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                                       str_token->string, len);
+                       if (ret) {
+                               goto end;
+                       }
+
+                       break;
+               }
+               case LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE:
+               {
+                       struct lttng_map_key_token_variable *var_token =
+                                       (struct lttng_map_key_token_variable *) token;
+                       struct lttng_map_key_token_variable_comm comm = {0};
+
+                       DBG("Serializing a variable type key token");
+
+                       comm.parent_type = token_type;
+                       comm.var_type = var_token->type;
+
+                       ret = lttng_dynamic_buffer_append(&payload->buffer,
+                                       &comm, sizeof(comm));
+                       if (ret) {
+                               goto end;
+                       }
+
+                       break;
+               }
+               default:
+                       abort();
+               }
+       }
+
+end:
+       return ret;
+}
+
+static inline
+bool token_variable_type_is_valid(enum lttng_map_key_token_variable_type var_type)
+{
+       switch (var_type) {
+       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME:
+       case LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME:
+               return true;
+       default:
+               return false;
+       }
+}
+
+static bool lttng_map_key_token_variable_is_equal(
+               const struct lttng_map_key_token *_a,
+               const struct lttng_map_key_token *_b)
+{
+       struct lttng_map_key_token_variable *a, *b;
+       assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+       assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+
+       a = container_of(_a, struct lttng_map_key_token_variable, parent);
+       b = container_of(_b, struct lttng_map_key_token_variable, parent);
+
+       return lttng_map_key_token_variable_get_type(a) ==
+                       lttng_map_key_token_variable_get_type(b);
+}
+
+enum lttng_map_key_status lttng_map_key_append_token_variable(
+               struct lttng_map_key *key,
+               enum lttng_map_key_token_variable_type var_type)
+{
+       int ret;
+       enum lttng_map_key_status status;
+       struct lttng_map_key_token_variable *token = NULL;
+
+       if (!token_variable_type_is_valid(var_type)) {
+               ERR("Invalid token variable type");
+               status = LTTNG_MAP_KEY_STATUS_INVALID;
+               goto end;
+       }
+
+       token = zmalloc(sizeof(*token));
+       if (!token) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE;
+       token->parent.equal = lttng_map_key_token_variable_is_equal;
+       token->type = var_type;
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &key->tokens, token);
+       if (ret) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+
+end:
+       return status;
+}
+
+static bool lttng_map_key_token_string_is_equal(
+               const struct lttng_map_key_token *_a,
+               const struct lttng_map_key_token *_b)
+{
+       struct lttng_map_key_token_string *a, *b;
+       const char *a_string, *b_string;
+
+       assert(_a->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+       assert(_b->type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+
+       a = container_of(_a, struct lttng_map_key_token_string, parent);
+       b = container_of(_b, struct lttng_map_key_token_string, parent);
+
+       a_string = lttng_map_key_token_string_get_string(a);
+       b_string = lttng_map_key_token_string_get_string(b);
+
+       return !strcmp(a_string, b_string);
+}
+
+enum lttng_map_key_status lttng_map_key_append_token_string(
+               struct lttng_map_key *key, const char *string)
+{
+       int ret;
+       enum lttng_map_key_status status;
+       struct lttng_map_key_token_string *token = NULL;
+
+
+       token = zmalloc(sizeof(*token));
+       if (!token) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       token->parent.type = LTTNG_MAP_KEY_TOKEN_TYPE_STRING;
+       token->parent.equal = lttng_map_key_token_string_is_equal;
+       token->string = strdup(string);
+       if (!token->string) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       ret = lttng_dynamic_pointer_array_add_pointer(
+                       &key->tokens, token);
+       if (ret) {
+               status = LTTNG_MAP_KEY_STATUS_ERROR;
+               goto end;
+       }
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_map_key_status lttng_map_key_get_token_count(
+               const struct lttng_map_key *key, unsigned int *count)
+{
+       enum lttng_map_key_status status;
+       if (!key || !count) {
+               status = LTTNG_MAP_KEY_STATUS_INVALID;
+               goto end;
+
+       }
+
+       *count = lttng_dynamic_pointer_array_get_count(
+                       &key->tokens);
+
+       status = LTTNG_MAP_KEY_STATUS_OK;
+end:
+       return status;
+}
+
+const struct lttng_map_key_token *
+lttng_map_key_get_token_at_index(const struct lttng_map_key *key,
+               unsigned int index)
+{
+       const struct lttng_map_key_token *token = NULL;
+       enum lttng_map_key_status status;
+       unsigned int count;
+
+       if (!key) {
+               goto end;
+       }
+
+       status = lttng_map_key_get_token_count(key, &count);
+       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       token = lttng_dynamic_pointer_array_get_pointer(&key->tokens,
+                       index);
+
+end:
+       return token;
+}
+
+enum lttng_map_key_token_variable_type lttng_map_key_token_variable_get_type(
+               const struct lttng_map_key_token_variable *token)
+{
+       assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_VARIABLE);
+
+       return token->type;
+}
+
+const char *lttng_map_key_token_string_get_string(
+               const struct lttng_map_key_token_string *token)
+{
+       assert(token->parent.type == LTTNG_MAP_KEY_TOKEN_TYPE_STRING);
+
+       return token->string;
+}
+
+void lttng_map_key_destroy(struct lttng_map_key *key)
+{
+       lttng_map_key_put(key);
+}
+
+LTTNG_HIDDEN
+struct lttng_map_key *lttng_map_key_parse_from_string(const char *_key_str)
+{
+       struct lttng_map_key *key = NULL;
+       enum lttng_map_key_status status;
+       char *key_str = NULL, *curr_pos;
+
+       key = lttng_map_key_create();
+       if (!key) {
+               goto end;
+       }
+
+       key_str = strdup(_key_str);
+
+       curr_pos = key_str;
+
+       curr_pos = strtok(curr_pos, "$}");
+       while (curr_pos) {
+               if (curr_pos[0] == '{') {
+                       if (strncmp(&curr_pos[1], TOKEN_VAR_EVENT_NAME, strlen(TOKEN_VAR_EVENT_NAME)) == 0) {
+                               status = lttng_map_key_append_token_variable(key,
+                                               LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_EVENT_NAME);
+                               if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                                       goto error;
+                               }
+                       } else if (strncmp(&curr_pos[1], TOKEN_VAR_PROVIDER_NAME, strlen(TOKEN_VAR_PROVIDER_NAME)) == 0) {
+                               status = lttng_map_key_append_token_variable(key,
+                                               LTTNG_MAP_KEY_TOKEN_VARIABLE_TYPE_PROVIDER_NAME);
+                               if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                                       goto error;
+                               }
+                       } else {
+                               goto error;
+                       }
+               } else {
+                       status = lttng_map_key_append_token_string(key, curr_pos);
+                       if (status != LTTNG_MAP_KEY_STATUS_OK) {
+                               goto error;
+                       }
+               }
+               curr_pos = strtok(NULL, "$}");
+       }
+       goto end;
+
+error:
+       lttng_map_key_destroy(key);
+       key = NULL;
+end:
+       free(key_str);
+
+       return key;
+}
+
+LTTNG_HIDDEN
+bool lttng_map_key_is_equal(
+               const struct lttng_map_key *a, const struct lttng_map_key *b)
+{
+       bool is_equal = false;
+       enum lttng_map_key_status status;
+       unsigned int a_count, b_count, i;
+
+       if (!!a != !!b) {
+               goto end;
+       }
+
+       if (a == NULL && b == NULL) {
+               is_equal = true;
+               goto end;
+       }
+
+       if (a == b) {
+               is_equal = true;
+               goto end;
+       }
+
+       status = lttng_map_key_get_token_count(a, &a_count);
+       assert(status == LTTNG_MAP_KEY_STATUS_OK);
+       status = lttng_map_key_get_token_count(b, &b_count);
+       assert(status == LTTNG_MAP_KEY_STATUS_OK);
+
+       if (a_count != b_count) {
+               goto end;
+       }
+
+       for (i = 0; i < a_count; i++) {
+               const struct lttng_map_key_token *token_a = NULL, *token_b = NULL;
+
+               token_a = lttng_map_key_get_token_at_index(a, i);
+               token_b = lttng_map_key_get_token_at_index(b, i);
+
+               /* JORAJ TODO: is order important for the map key token? */
+               if(token_a->type != token_b->type) {
+                       goto end;
+               }
+
+               if(!token_a->equal(token_a, token_b)) {
+                       goto end;
+               }
+       }
+
+       is_equal = true;
+
+end:
+       return is_equal;
+
+
+}
+
+static void map_key_destroy_ref(struct urcu_ref *ref)
+{
+       struct lttng_map_key *key = container_of(ref, struct lttng_map_key, ref);
+
+       lttng_dynamic_pointer_array_reset(&key->tokens);
+       free(key);
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_get(struct lttng_map_key *key)
+{
+       urcu_ref_get(&key->ref);
+}
+
+LTTNG_HIDDEN
+void lttng_map_key_put(struct lttng_map_key *key)
+{
+       if (!key) {
+               return;
+       }
+
+       urcu_ref_put(&key->ref, map_key_destroy_ref);
+}
This page took 0.02907 seconds and 5 git commands to generate.