trigger: introduce firing policies
authorJonathan Rajotte <jonathan.rajotte-julien@efficios.com>
Thu, 23 Jan 2020 19:14:14 +0000 (14:14 -0500)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Fri, 20 Nov 2020 21:50:05 +0000 (16:50 -0500)
A firing policy controls the rate of firing of a trigger.

Two firing policy mode are implemented:
    LTTNG_TRIGGER_FIRING_POLICY_FIRE_EVERY_N
       The triggers's actions are executed every N times the
       condition occurs.
    LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N
       The triggers's actions are executed once the condition was met N
       times.

Firing policies will be moved to the specific `action` objects
in a follow-up commit as not all actions can implement the firing
policies.

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

include/lttng/trigger/trigger-internal.h
include/lttng/trigger/trigger.h
src/common/trigger.c

index 6942ece78d7a88d9b15a2585fdb200e43f0261f8..87368476958f08186e5f907545764bc3a6376086 100644 (file)
@@ -30,6 +30,11 @@ struct lttng_trigger {
        char *name;
        /* For now only the uid portion of the credentials is used. */
        struct lttng_credentials creds;
+       struct {
+               enum lttng_trigger_firing_policy type;
+               uint64_t threshold;
+               uint64_t current_count;
+       } firing_policy;
        /*
         * Internal use only.
         * The unique token passed to the tracer to identify an event-rule
@@ -55,6 +60,10 @@ struct lttng_trigger_comm {
        uint32_t length;
        /* Includes '\0' terminator. */
        uint32_t name_length;
+       /* Firing policy. */
+       /* Maps to enum lttng_trigger_firing_policy. */
+       uint8_t firing_policy_type;
+       uint64_t firing_policy_threshold;
        /* A null-terminated name, a condition, and an action follow. */
        char payload[];
 } LTTNG_PACKED;
@@ -161,4 +170,18 @@ LTTNG_HIDDEN
 void lttng_trigger_set_credentials(struct lttng_trigger *trigger,
                const struct lttng_credentials *creds);
 
+
+/*
+ * Fire the trigger.
+ * Increments the occurrence count.
+ */
+LTTNG_HIDDEN
+void lttng_trigger_fire(struct lttng_trigger *trigger);
+
+/*
+ * Check if the trigger would fire.
+ */
+LTTNG_HIDDEN
+bool lttng_trigger_should_fire(const struct lttng_trigger *trigger);
+
 #endif /* LTTNG_TRIGGER_INTERNAL_H */
index b8e6080d9519a7edaaab43ca291c7c45f56e685d..a0c312ddd1e92e2efdb94c6affcbb942696198ff 100644 (file)
@@ -9,6 +9,7 @@
 #define LTTNG_TRIGGER_H
 
 #include <sys/types.h>
+#include <inttypes.h>
 
 struct lttng_action;
 struct lttng_condition;
@@ -35,6 +36,11 @@ enum lttng_trigger_status {
        LTTNG_TRIGGER_STATUS_PERMISSION_DENIED = -6,
 };
 
+enum lttng_trigger_firing_policy {
+       LTTNG_TRIGGER_FIRING_POLICY_EVERY_N = 0,
+       LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N = 1,
+};
+
 /*
  * Create a trigger object associating a condition and an action.
  *
@@ -127,6 +133,37 @@ extern enum lttng_trigger_status lttng_trigger_get_name(
 extern enum lttng_trigger_status lttng_trigger_set_name(
                struct lttng_trigger *trigger, const char *name);
 
+/*
+ * Set the trigger firing policy.
+ *
+ * This is optional. By default a trigger is set to fire each time the
+ * associated condition occurs.
+ *
+ * Threshold is the number of times the condition must be hit before the policy
+ * is enacted.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success, LTTNG_TRIGGER_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_set_firing_policy(
+               struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy policy_type,
+               uint64_t threshold);
+
+/*
+ * Get the trigger firing policy.
+ *
+ * Threshold is the number of time the condition must be hit before the policy is
+ * enacted.
+ *
+ * Return LTTNG_TRIGGER_STATUS_OK on success, LTTNG_TRIGGER_STATUS_INVALID
+ * if invalid parameters are passed.
+ */
+extern enum lttng_trigger_status lttng_trigger_get_firing_policy(
+               const struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy *policy_type,
+               uint64_t *threshold);
+
 /*
  * Destroy (frees) a trigger object.
  */
index e038fa81a052d71fe3952afaae96c96982a23ae3..8c43fdbd8aaa8aa7f7ad1fda253ea8701c7f751c 100644 (file)
@@ -55,6 +55,9 @@ struct lttng_trigger *lttng_trigger_create(
 
        urcu_ref_init(&trigger->ref);
 
+       trigger->firing_policy.type = LTTNG_TRIGGER_FIRING_POLICY_EVERY_N;
+       trigger->firing_policy.threshold = 1;
+
        lttng_condition_get(condition);
        trigger->condition = condition;
 
@@ -126,6 +129,23 @@ void lttng_trigger_destroy(struct lttng_trigger *trigger)
        lttng_trigger_put(trigger);
 }
 
+static bool is_firing_policy_valid(enum lttng_trigger_firing_policy policy)
+{
+       bool valid = false;
+
+       switch (policy) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               valid = true;
+               break;
+       default:
+               valid = false;
+               break;
+       }
+
+       return valid;
+}
+
 LTTNG_HIDDEN
 ssize_t lttng_trigger_create_from_payload(
                struct lttng_payload_view *src_view,
@@ -136,6 +156,8 @@ ssize_t lttng_trigger_create_from_payload(
        struct lttng_action *action = NULL;
        const struct lttng_trigger_comm *trigger_comm;
        const char *name = NULL;
+       uint64_t firing_policy_threshold;
+       enum lttng_trigger_firing_policy firing_policy;
        struct lttng_credentials creds = {
                .uid = LTTNG_OPTIONAL_INIT_UNSET,
                .gid = LTTNG_OPTIONAL_INIT_UNSET,
@@ -170,6 +192,13 @@ ssize_t lttng_trigger_create_from_payload(
 
        offset += sizeof(*trigger_comm);
 
+       firing_policy = trigger_comm->firing_policy_type;
+       if (!is_firing_policy_valid(firing_policy)) {
+               ret =-1;
+               goto end;
+       }
+
+       firing_policy_threshold = trigger_comm->firing_policy_threshold;
        if (trigger_comm->name_length != 0) {
                /* Name. */
                const struct lttng_payload_view name_view =
@@ -258,6 +287,19 @@ ssize_t lttng_trigger_create_from_payload(
                }
        }
 
+       /* Set the policy. */
+       {
+               const enum lttng_trigger_status status =
+                               lttng_trigger_set_firing_policy(trigger,
+                                               firing_policy,
+                                               firing_policy_threshold);
+
+               if (status != LTTNG_TRIGGER_STATUS_OK) {
+                       ret = -1;
+                       goto end;
+               }
+       }
+
        ret = offset;
 
 error:
@@ -299,6 +341,8 @@ int lttng_trigger_serialize(const struct lttng_trigger *trigger,
        }
 
        trigger_comm.name_length = size_name;
+       trigger_comm.firing_policy_type = (uint8_t) trigger->firing_policy.type;
+       trigger_comm.firing_policy_threshold = (uint64_t) trigger->firing_policy.threshold;
 
        header_offset = payload->buffer.size;
        ret = lttng_dynamic_buffer_append(&payload->buffer, &trigger_comm,
@@ -337,6 +381,14 @@ LTTNG_HIDDEN
 bool lttng_trigger_is_equal(
                const struct lttng_trigger *a, const struct lttng_trigger *b)
 {
+       if (a->firing_policy.type != b->firing_policy.type) {
+               return false;
+       }
+
+       if (a->firing_policy.threshold != b->firing_policy.threshold) {
+               return false;
+       }
+
        /*
         * Name is not taken into account since it is cosmetic only.
         */
@@ -738,3 +790,94 @@ enum lttng_trigger_status lttng_trigger_get_owner_uid(
 end:
        return ret;
 }
+
+enum lttng_trigger_status lttng_trigger_set_firing_policy(
+               struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy policy_type,
+               uint64_t threshold)
+{
+       enum lttng_trigger_status ret = LTTNG_TRIGGER_STATUS_OK;
+       assert(trigger);
+
+       if (threshold < 1) {
+               ret = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       trigger->firing_policy.type = policy_type;
+       trigger->firing_policy.threshold = threshold;
+
+end:
+       return ret;
+}
+
+enum lttng_trigger_status lttng_trigger_get_firing_policy(
+               const struct lttng_trigger *trigger,
+               enum lttng_trigger_firing_policy *policy_type,
+               uint64_t *threshold)
+{
+       enum lttng_trigger_status status = LTTNG_TRIGGER_STATUS_OK;
+
+       if (!trigger || !policy_type || !threshold) {
+               status = LTTNG_TRIGGER_STATUS_INVALID;
+               goto end;
+       }
+
+       *policy_type = trigger->firing_policy.type;
+       *threshold = trigger->firing_policy.threshold;
+
+end:
+       return status;
+}
+
+LTTNG_HIDDEN
+bool lttng_trigger_should_fire(const struct lttng_trigger *trigger)
+{
+       bool ready_to_fire = false;
+
+       assert(trigger);
+
+       switch (trigger->firing_policy.type) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+               if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
+                       ready_to_fire = true;
+               }
+               break;
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               if (trigger->firing_policy.current_count < trigger->firing_policy.threshold) {
+                       ready_to_fire = true;
+               }
+               break;
+       default:
+               abort();
+       };
+
+       return ready_to_fire;
+}
+
+LTTNG_HIDDEN
+void lttng_trigger_fire(struct lttng_trigger *trigger)
+{
+       assert(trigger);
+
+       trigger->firing_policy.current_count++;
+
+       switch (trigger->firing_policy.type) {
+       case LTTNG_TRIGGER_FIRING_POLICY_EVERY_N:
+               if (trigger->firing_policy.current_count == trigger->firing_policy.threshold) {
+                       trigger->firing_policy.current_count = 0;
+               }
+
+               break;
+       case LTTNG_TRIGGER_FIRING_POLICY_ONCE_AFTER_N:
+               /*
+                * TODO:
+                * As an optimisation, deactivate the trigger condition and
+                * remove any checks in the traced application or kernel since
+                * the trigger will never fire again.
+                */
+               break;
+       default:
+               abort();
+       };
+}
This page took 0.031147 seconds and 5 git commands to generate.