actions: introduce action group
authorSimon Marchi <simon.marchi@efficios.com>
Mon, 2 Dec 2019 21:41:52 +0000 (16:41 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 12 Jun 2020 22:12:05 +0000 (18:12 -0400)
This patch introduces action groups as a new kind of action.

When creating a trigger, it is only possible to attach a single action.
Action groups allow users to attach more than one action.

A group is created using lttng_action_group_create.  Actions are added
to it using lttng_action_group_add_action.  The group can then be used
in a trigger, like any other action.

The operations required to be implemented by actions (serialize,
create_from_buffer, validate) are implemented by executing the operation
on all elements.

Current limitations are:

- To avoid any cycle, it is not possible to add a group inside a group.

Signed-off-by: Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Signed-off-by: Jérémie Galarneau <jeremie.galarneau@efficios.com>
Signed-off-by: Simon Marchi <simon.marchi@efficios.com>
Change-Id: I2ae6aed21d9a6b45510d37a435773b1bd7d76528

include/Makefile.am
include/lttng/action/action.h
include/lttng/action/group-internal.h [new file with mode: 0644]
include/lttng/action/group.h [new file with mode: 0644]
include/lttng/lttng.h
src/common/Makefile.am
src/common/actions/action.c
src/common/actions/group.c [new file with mode: 0644]
src/common/actions/snapshot-session.c

index af89a3372d644b5ef621dba715ab5972a710aeea..baad620dda6bd0bafb5c1c498aa0f133c853111e 100644 (file)
@@ -121,6 +121,7 @@ lttnginclude_HEADERS = \
 
 lttngactioninclude_HEADERS= \
        lttng/action/action.h \
+       lttng/action/group.h \
        lttng/action/notify.h \
        lttng/action/rotate-session.h \
        lttng/action/snapshot-session.h \
@@ -147,6 +148,7 @@ noinst_HEADERS = \
        lttng/save-internal.h \
        lttng/load-internal.h \
        lttng/action/action-internal.h \
+       lttng/action/group-internal.h \
        lttng/action/notify-internal.h \
        lttng/action/rotate-session-internal.h \
        lttng/action/snapshot-session-internal.h \
index 3cd2460f80e6c698be3f2fe02734611e2301f007..1309f85bd9128c34baa566064f1849ba7bf41cd8 100644 (file)
@@ -21,6 +21,7 @@ enum lttng_action_type {
        LTTNG_ACTION_TYPE_STOP_SESSION = 2,
        LTTNG_ACTION_TYPE_ROTATE_SESSION = 3,
        LTTNG_ACTION_TYPE_SNAPSHOT_SESSION = 4,
+       LTTNG_ACTION_TYPE_GROUP = 5,
 };
 
 enum lttng_action_status {
diff --git a/include/lttng/action/group-internal.h b/include/lttng/action/group-internal.h
new file mode 100644 (file)
index 0000000..cddee55
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_ACTION_GROUP_INTERNAL_H
+#define LTTNG_ACTION_GROUP_INTERNAL_H
+
+#include <sys/types.h>
+
+#include <common/macros.h>
+
+struct lttng_action;
+struct lttng_payload_view;
+
+/*
+ * Create an action group from a payload view.
+ *
+ * On success, return the number of bytes consumed from `view`, and the created
+ * group in `*group`. On failure, return -1.
+ */
+LTTNG_HIDDEN
+extern ssize_t lttng_action_group_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_action **group);
+
+#endif /* LTTNG_ACTION_GROUP_INTERNAL_H */
diff --git a/include/lttng/action/group.h b/include/lttng/action/group.h
new file mode 100644 (file)
index 0000000..af1e732
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#ifndef LTTNG_ACTION_GROUP_H
+#define LTTNG_ACTION_GROUP_H
+
+struct lttng_action;
+struct lttng_action_group;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Create a newly allocated action group object.
+ *
+ * Returns a new action group on success, NULL on failure. This action group
+ * must be destroyed using lttng_action_group_destroy().
+ */
+extern struct lttng_action *lttng_action_group_create(void);
+
+/*
+ * Add an action to an lttng_action object of type LTTNG_ACTION_GROUP.
+ *
+ * The action group acquires a reference to the action. The action can be
+ * safely destroyed after calling this function. An action must not be
+ * modified after adding it to a group.
+ *
+ * Adding an action group to an action group is not supported.
+ */
+extern enum lttng_action_status lttng_action_group_add_action(
+               struct lttng_action *group, struct lttng_action *action);
+
+/*
+ * Get the number of actions in an action group.
+ */
+extern enum lttng_action_status lttng_action_group_get_count(
+               const struct lttng_action *group, unsigned int *count);
+
+/*
+ * Get an action from the action group at a given index.
+ *
+ * Note that the group maintains the ownership of the returned action.
+ * It must not be destroyed by the user, nor should it be held beyond
+ * the lifetime of the action group.
+ *
+ * Returns an action, or NULL on error.
+ */
+extern const struct lttng_action *lttng_action_group_get_at_index(
+               const struct lttng_action *group,
+               unsigned int index);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* LTTNG_ACTION_GROUP_H */
index f22fad5530294ebfa162f268d93262f8c4cfe991..6746d7bbf137de06df0e0ead5dd61dcf246b13f0 100644 (file)
@@ -17,6 +17,7 @@
 
 /* Include every LTTng ABI/API available. */
 #include <lttng/action/action.h>
+#include <lttng/action/group.h>
 #include <lttng/action/notify.h>
 #include <lttng/action/rotate-session.h>
 #include <lttng/action/snapshot-session.h>
index f8a207534bc0bd1425db36df2746578da618c461..32b28c82f57e4fc6e2c4d41772f39918363edc73 100644 (file)
@@ -28,6 +28,7 @@ EXTRA_DIST = mi-lttng-4.0.xsd
 
 libcommon_la_SOURCES = \
        actions/action.c \
+       actions/group.c \
        actions/notify.c \
        actions/rotate-session.c \
        actions/snapshot-session.c \
index 1a541ce469efc22381f198261a484b9df7ee4f26..a0347a34c66ee53abd7b1851bdc362b3fffe2c78 100644 (file)
@@ -8,6 +8,7 @@
 #include <assert.h>
 #include <common/error.h>
 #include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
 #include <lttng/action/notify-internal.h>
 #include <lttng/action/rotate-session-internal.h>
 #include <lttng/action/snapshot-session-internal.h>
@@ -19,6 +20,8 @@ static const char *lttng_action_type_string(enum lttng_action_type action_type)
        switch (action_type) {
        case LTTNG_ACTION_TYPE_UNKNOWN:
                return "UNKNOWN";
+       case LTTNG_ACTION_TYPE_GROUP:
+               return "GROUP";
        case LTTNG_ACTION_TYPE_NOTIFY:
                return "NOTIFY";
        case LTTNG_ACTION_TYPE_ROTATE_SESSION:
@@ -176,6 +179,9 @@ ssize_t lttng_action_create_from_payload(struct lttng_payload_view *view,
                create_from_payload_cb =
                                lttng_action_stop_session_create_from_payload;
                break;
+       case LTTNG_ACTION_TYPE_GROUP:
+               create_from_payload_cb = lttng_action_group_create_from_payload;
+               break;
        default:
                ERR("Failed to create action from payload, unhandled action type: action-type=%u (%s)",
                                action_comm->action_type,
diff --git a/src/common/actions/group.c b/src/common/actions/group.c
new file mode 100644 (file)
index 0000000..5931eb3
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
+ *
+ * SPDX-License-Identifier: LGPL-2.1-only
+ *
+ */
+
+#include <assert.h>
+#include <common/dynamic-array.h>
+#include <common/sessiond-comm/payload.h>
+#include <common/sessiond-comm/payload-view.h>
+#include <common/error.h>
+#include <common/macros.h>
+#include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
+#include <lttng/action/group.h>
+
+#define IS_GROUP_ACTION(action) \
+       (lttng_action_get_type_const(action) == LTTNG_ACTION_TYPE_GROUP)
+
+struct lttng_action_group {
+       struct lttng_action parent;
+
+       /* The array owns the action elements. */
+       struct lttng_dynamic_pointer_array actions;
+};
+
+struct lttng_action_group_comm {
+       uint32_t action_count;
+
+       /*
+        * Variable data: each element serialized sequentially.
+        */
+       char data[];
+} LTTNG_PACKED;
+
+static void destroy_lttng_action_group_element(void *ptr)
+{
+       struct lttng_action *element = (struct lttng_action *) ptr;
+
+       lttng_action_destroy(element);
+}
+
+static struct lttng_action_group *action_group_from_action(
+               const struct lttng_action *action)
+{
+       assert(action);
+
+       return container_of(action, struct lttng_action_group, parent);
+}
+
+static const struct lttng_action_group *action_group_from_action_const(
+               const struct lttng_action *action)
+{
+       assert(action);
+
+       return container_of(action, struct lttng_action_group, parent);
+}
+
+static bool lttng_action_group_validate(struct lttng_action *action)
+{
+       unsigned int i, count;
+       struct lttng_action_group *action_group;
+       bool valid;
+
+       assert(IS_GROUP_ACTION(action));
+
+       action_group = action_group_from_action(action);
+
+       count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
+
+       for (i = 0; i < count; i++) {
+               struct lttng_action *child =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               &action_group->actions, i);
+
+               assert(child);
+
+               if (!lttng_action_validate(child)) {
+                       valid = false;
+                       goto end;
+               }
+       }
+
+       valid = true;
+
+end:
+       return valid;
+}
+
+static bool lttng_action_group_is_equal(
+               const struct lttng_action *_a, const struct lttng_action *_b)
+{
+       bool is_equal = false;
+       unsigned int i;
+       unsigned int a_count, b_count;
+
+       if (lttng_action_group_get_count(_a, &a_count) !=
+                       LTTNG_ACTION_STATUS_OK) {
+               goto end;
+       }
+
+       if (lttng_action_group_get_count(_b, &b_count) !=
+                       LTTNG_ACTION_STATUS_OK) {
+               goto end;
+       }
+
+       if (a_count != b_count) {
+               goto end;
+       }
+
+       for (i = 0; i < a_count; i++) {
+               const struct lttng_action *child_a =
+                       lttng_action_group_get_at_index(_a, i);
+               const struct lttng_action *child_b =
+                       lttng_action_group_get_at_index(_b, i);
+
+               assert(child_a);
+               assert(child_b);
+
+               if (!lttng_action_is_equal(child_a, child_b)) {
+                       goto end;
+               }
+       }
+
+       is_equal = true;
+end:
+       return is_equal;
+}
+
+static int lttng_action_group_serialize(
+               struct lttng_action *action, struct lttng_payload *payload)
+{
+       struct lttng_action_group *action_group;
+       struct lttng_action_group_comm comm;
+       int ret;
+       unsigned int i, count;
+
+       assert(action);
+       assert(payload);
+       assert(IS_GROUP_ACTION(action));
+
+       action_group = action_group_from_action(action);
+
+       DBG("Serializing action group");
+
+       count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
+
+       comm.action_count = count;
+
+       ret = lttng_dynamic_buffer_append(
+                       &payload->buffer, &comm, sizeof(comm));
+       if (ret) {
+               ret = -1;
+               goto end;
+       }
+
+       for (i = 0; i < count; i++) {
+               struct lttng_action *child =
+                               lttng_dynamic_pointer_array_get_pointer(
+                                               &action_group->actions, i);
+
+               assert(child);
+
+               ret = lttng_action_serialize(child, payload);
+               if (ret) {
+                       goto end;
+               }
+       }
+
+       ret = 0;
+
+end:
+       return ret;
+}
+
+static void lttng_action_group_destroy(struct lttng_action *action)
+{
+       struct lttng_action_group *action_group;
+
+       if (!action) {
+               goto end;
+       }
+
+       action_group = action_group_from_action(action);
+       lttng_dynamic_pointer_array_reset(&action_group->actions);
+       free(action_group);
+
+end:
+       return;
+}
+
+ssize_t lttng_action_group_create_from_payload(
+               struct lttng_payload_view *view,
+               struct lttng_action **p_action)
+{
+       ssize_t consumed_len;
+       const struct lttng_action_group_comm *comm;
+       struct lttng_action *group;
+       struct lttng_action *child_action = NULL;
+       enum lttng_action_status status;
+       size_t i;
+
+       group = lttng_action_group_create();
+       if (!group) {
+               consumed_len = -1;
+               goto end;
+       }
+
+       comm = (typeof(comm)) view->buffer.data;
+
+       consumed_len = sizeof(struct lttng_action_group_comm);
+
+       for (i = 0; i < comm->action_count; i++) {
+               ssize_t consumed_len_child;
+               struct lttng_payload_view child_view =
+                               lttng_payload_view_from_view(view, consumed_len,
+                                               view->buffer.size - consumed_len);
+
+               consumed_len_child = lttng_action_create_from_payload(
+                               &child_view, &child_action);
+               if (consumed_len_child < 0) {
+                       consumed_len = -1;
+                       goto end;
+               }
+
+               status = lttng_action_group_add_action(group, child_action);
+               if (status != LTTNG_ACTION_STATUS_OK) {
+                       consumed_len = -1;
+                       goto end;
+               }
+
+               /* Transfer ownership to the action group. */
+               lttng_action_put(child_action);
+               child_action = NULL;
+
+               consumed_len += consumed_len_child;
+       }
+
+       *p_action = group;
+       group = NULL;
+
+end:
+       lttng_action_group_destroy(group);
+       return consumed_len;
+}
+
+struct lttng_action *lttng_action_group_create(void)
+{
+       struct lttng_action_group *action_group;
+       struct lttng_action *action;
+
+       action_group = zmalloc(sizeof(struct lttng_action_group));
+       if (!action_group) {
+               action = NULL;
+               goto end;
+       }
+
+       action = &action_group->parent;
+
+       lttng_action_init(action, LTTNG_ACTION_TYPE_GROUP,
+                       lttng_action_group_validate,
+                       lttng_action_group_serialize,
+                       lttng_action_group_is_equal,
+                       lttng_action_group_destroy);
+
+       lttng_dynamic_pointer_array_init(&action_group->actions,
+                       destroy_lttng_action_group_element);
+
+end:
+       return action;
+}
+
+enum lttng_action_status lttng_action_group_add_action(
+               struct lttng_action *group, struct lttng_action *action)
+{
+       struct lttng_action_group *action_group;
+       enum lttng_action_status status;
+       int ret;
+
+       if (!group || !IS_GROUP_ACTION(action) || !action) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       /*
+        * Don't allow adding groups in groups for now, since we're afraid of
+        * cycles.
+        */
+       if (IS_GROUP_ACTION(action)) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               goto end;
+       }
+
+       action_group = action_group_from_action(group);
+
+       ret = lttng_dynamic_pointer_array_add_pointer(&action_group->actions,
+                       action);
+       if (ret < 0) {
+               status = LTTNG_ACTION_STATUS_ERROR;
+               goto end;
+       }
+
+       /* Take ownership of the object. */
+       lttng_action_get(action);
+       status = LTTNG_ACTION_STATUS_OK;
+end:
+       return status;
+}
+
+enum lttng_action_status lttng_action_group_get_count(
+               const struct lttng_action *group, unsigned int *count)
+{
+       const struct lttng_action_group *action_group;
+       enum lttng_action_status status = LTTNG_ACTION_STATUS_OK;
+
+       if (!group || !IS_GROUP_ACTION(group)) {
+               status = LTTNG_ACTION_STATUS_INVALID;
+               *count = 0;
+               goto end;
+       }
+
+       action_group = action_group_from_action_const(group);
+       *count = lttng_dynamic_pointer_array_get_count(&action_group->actions);
+end:
+       return status;
+}
+
+const struct lttng_action *lttng_action_group_get_at_index(
+               const struct lttng_action *group, unsigned int index)
+{
+       unsigned int count;
+       const struct lttng_action_group *action_group;
+       const struct lttng_action * action = NULL;
+
+       if (lttng_action_group_get_count(group, &count) !=
+                       LTTNG_ACTION_STATUS_OK) {
+               goto end;
+       }
+
+       if (index >= count) {
+               goto end;
+       }
+
+       action_group = action_group_from_action_const(group);
+       action = lttng_dynamic_pointer_array_get_pointer(&action_group->actions,
+                       index);
+end:
+       return action;
+}
index 9e8e43577492b3f4d5bd0f3610fb529d7c37299a..058179633db411d6e29c42fc52c59af24b13fc94 100644 (file)
@@ -124,16 +124,9 @@ end:
        return is_equal;
 }
 
-static size_t serialize_strlen(const char *s)
+static size_t serialize_strlen(const char *str)
 {
-
-       size_t len = 0;
-
-       if (s) {
-               len = strlen(s) + 1;
-       }
-
-       return len;
+       return str ? strlen(str) + 1 : 0;
 }
 
 static int lttng_action_snapshot_session_serialize(
@@ -258,7 +251,7 @@ ssize_t lttng_action_snapshot_session_create_from_payload(
                                comm->snapshot_output_len);
 
                if (!snapshot_output_buffer_view.buffer.data) {
-                       fprintf(stderr, "Failed to create buffer view for snapshot output.\n");
+                       ERR("Failed to create buffer view for snapshot output.");
                        goto error;
                }
 
@@ -267,8 +260,7 @@ ssize_t lttng_action_snapshot_session_create_from_payload(
                                                &snapshot_output_buffer_view,
                                                &snapshot_output);
                if (snapshot_output_consumed_len != comm->snapshot_output_len) {
-                       fprintf(stderr,
-                                       "Failed to deserialize snapshot output object: "
+                       ERR("Failed to deserialize snapshot output object: "
                                        "consumed-len: %zd, expected-len: %" PRIu32,
                                        snapshot_output_consumed_len,
                                        comm->snapshot_output_len);
This page took 0.032765 seconds and 4 git commands to generate.