From: Jonathan Rajotte Date: Fri, 2 Apr 2021 01:20:23 +0000 (-0400) Subject: Introduce firing policy object X-Git-Tag: v2.13.0-rc1~102 X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=commitdiff_plain;h=347f2c91cf45bc224d43465e4f3b279a0028f428 Introduce firing policy object Change-Id: I436ce58d083cd70178a51d0d9ebfddc814f2cd15 Signed-off-by: Jonathan Rajotte Signed-off-by: Jérémie Galarneau --- diff --git a/include/Makefile.am b/include/Makefile.am index 994c51166..a75f6c3d2 100644 --- a/include/Makefile.am +++ b/include/Makefile.am @@ -130,7 +130,8 @@ lttngactioninclude_HEADERS= \ lttng/action/rotate-session.h \ lttng/action/snapshot-session.h \ lttng/action/start-session.h \ - lttng/action/stop-session.h + lttng/action/stop-session.h \ + lttng/action/firing-policy.h lttngconditioninclude_HEADERS= \ lttng/condition/condition.h \ @@ -162,6 +163,7 @@ noinst_HEADERS = \ lttng/action/snapshot-session-internal.h \ lttng/action/start-session-internal.h \ lttng/action/stop-session-internal.h \ + lttng/action/firing-policy-internal.h \ lttng/channel-internal.h \ lttng/condition/buffer-usage-internal.h \ lttng/condition/condition-internal.h \ diff --git a/include/lttng/action/firing-policy-internal.h b/include/lttng/action/firing-policy-internal.h new file mode 100644 index 000000000..0fd62ee99 --- /dev/null +++ b/include/lttng/action/firing-policy-internal.h @@ -0,0 +1,36 @@ +/* + * Copyright (C) 2021 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_FIRING_POLICY_INTERNAL_H +#define LTTNG_FIRING_POLICY_INTERNAL_H + +#include +#include +#include +#include + +LTTNG_HIDDEN +int lttng_firing_policy_serialize(struct lttng_firing_policy *firing_policy, + struct lttng_payload *buf); + +LTTNG_HIDDEN +ssize_t lttng_firing_policy_create_from_payload(struct lttng_payload_view *view, + struct lttng_firing_policy **firing_policy); + +LTTNG_HIDDEN +bool lttng_firing_policy_is_equal(const struct lttng_firing_policy *a, + const struct lttng_firing_policy *b); + +LTTNG_HIDDEN +const char *lttng_firing_policy_type_string( + enum lttng_firing_policy_type firing_policy_type); + +LTTNG_HIDDEN +struct lttng_firing_policy *lttng_firing_policy_copy( + const struct lttng_firing_policy *source); + +#endif /* LTTNG_FIRING_POLICY */ diff --git a/include/lttng/action/firing-policy.h b/include/lttng/action/firing-policy.h new file mode 100644 index 000000000..6c0924fa1 --- /dev/null +++ b/include/lttng/action/firing-policy.h @@ -0,0 +1,98 @@ +/* + * Copyright (C) 2021 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#ifndef LTTNG_FIRING_POLICY_H +#define LTTNG_FIRING_POLICY_H + +#include +#include + +struct lttng_firing_policy; + +#ifdef __cplusplus +extern "C" { +#endif + +enum lttng_firing_policy_status { + LTTNG_FIRING_POLICY_STATUS_OK = 0, + LTTNG_FIRING_POLICY_STATUS_ERROR = -1, + LTTNG_FIRING_POLICY_STATUS_UNKNOWN = -2, + LTTNG_FIRING_POLICY_STATUS_INVALID = -3, + LTTNG_FIRING_POLICY_STATUS_UNSET = -4, + LTTNG_FIRING_POLICY_STATUS_UNSUPPORTED = -5, +}; + +enum lttng_firing_policy_type { + LTTNG_FIRING_POLICY_TYPE_UNKNOWN = -1, + LTTNG_FIRING_POLICY_TYPE_EVERY_N = 0, + LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N = 1, +}; + +/* + * Get the type of a firing policy. + */ +extern enum lttng_firing_policy_type lttng_firing_policy_get_type( + const struct lttng_firing_policy *policy); + +/* + * Create a firing_policy of type `every n`. + * + * A `every n` firing policy will carry the execution of an action only when the + * action was ready for execution for a multiple of N. + * + * Returns a firing_policy object on success, NULL on error. + * firing_policy objects must be destroyed using the + * lttng_firing_policy_destroy() function. + */ +extern struct lttng_firing_policy *lttng_firing_policy_every_n_create( + uint64_t interval); + +/* + * Get the interval of a every N firing policy. + * + * Returns LTTNG_FIRING_POLICY_STATUS_OK and a sets the interval. + * on success, LTTNG_FIRING_POLICY_STATUS_INVALID if an invalid + * parameter is passed. + */ +extern enum lttng_firing_policy_status lttng_firing_policy_every_n_get_interval( + const struct lttng_firing_policy *policy, uint64_t *interval); + +/* + * Create a firing_policy of type `once after N`. + * + * A `once after N` firing policy will carry the execution of an action only + * when the action was ready for execution at least N times and will only be + * carried one time. + * + * Returns a firing_policy object on success, NULL on error. + * firing_policy objects must be destroyed using the + * lttng_firing_policy_destroy() function. + */ +extern struct lttng_firing_policy *lttng_firing_policy_once_after_n_create( + uint64_t threshold); + +/* + * Get the threshold of a once after N firing policy. + * + * Returns LTTNG_FIRING_POLICY_STATUS_OK and sets the threshold. + * on success, LTTNG_FIRING_POLICY_STATUS_INVALID if an invalid + * parameter is passed. + */ +extern enum lttng_firing_policy_status +lttng_firing_policy_once_after_n_get_threshold( + const struct lttng_firing_policy *policy, uint64_t *threshold); + +/* + * Destroy (frees) a firing policy object. + */ +extern void lttng_firing_policy_destroy(struct lttng_firing_policy *policy); + +#ifdef __cplusplus +} +#endif + +#endif /* LTTNG_FIRING_POLICY_H */ diff --git a/include/lttng/lttng.h b/include/lttng/lttng.h index 5cdf1aa83..9d1592177 100644 --- a/include/lttng/lttng.h +++ b/include/lttng/lttng.h @@ -17,6 +17,7 @@ /* Include every LTTng ABI/API available. */ #include +#include #include #include #include @@ -24,8 +25,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -36,7 +37,6 @@ #include #include #include -#include #include #include #include @@ -44,13 +44,14 @@ #include #include #include +#include #include #include #include #include #include -#include #include +#include #include #include #include diff --git a/src/common/Makefile.am b/src/common/Makefile.am index 2dca5a4a3..f564d3835 100644 --- a/src/common/Makefile.am +++ b/src/common/Makefile.am @@ -41,6 +41,7 @@ libcommon_la_SOURCES = \ actions/snapshot-session.c \ actions/start-session.c \ actions/stop-session.c \ + actions/firing-policy.c \ buffer-view.h buffer-view.c \ common.h \ conditions/buffer-usage.c \ diff --git a/src/common/actions/firing-policy.c b/src/common/actions/firing-policy.c new file mode 100644 index 000000000..6152d61d8 --- /dev/null +++ b/src/common/actions/firing-policy.c @@ -0,0 +1,573 @@ +/* + * Copyright (C) 2021 Jonathan Rajotte + * + * SPDX-License-Identifier: LGPL-2.1-only + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define IS_EVERY_N_FIRING_POLICY(policy) \ + (lttng_firing_policy_get_type(policy) == \ + LTTNG_FIRING_POLICY_TYPE_EVERY_N) + +#define IS_ONCE_AFTER_N_FIRING_POLICY(policy) \ + (lttng_firing_policy_get_type(policy) == \ + LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N) + +typedef void (*firing_policy_destroy_cb)( + struct lttng_firing_policy *firing_policy); +typedef int (*firing_policy_serialize_cb)( + struct lttng_firing_policy *firing_policy, + struct lttng_payload *payload); +typedef bool (*firing_policy_equal_cb)(const struct lttng_firing_policy *a, + const struct lttng_firing_policy *b); +typedef ssize_t (*firing_policy_create_from_payload_cb)( + struct lttng_payload_view *view, + struct lttng_firing_policy **firing_policy); +typedef struct lttng_firing_policy *(*firing_policy_copy_cb)( + const struct lttng_firing_policy *source); + +struct lttng_firing_policy { + enum lttng_firing_policy_type type; + firing_policy_serialize_cb serialize; + firing_policy_equal_cb equal; + firing_policy_destroy_cb destroy; + firing_policy_copy_cb copy; +}; + +struct lttng_firing_policy_every_n { + struct lttng_firing_policy parent; + uint64_t interval; +}; + +struct lttng_firing_policy_once_after_n { + struct lttng_firing_policy parent; + uint64_t threshold; +}; + +struct lttng_firing_policy_comm { + /* enum lttng_firing_policy_type */ + int8_t firing_policy_type; +} LTTNG_PACKED; + +struct lttng_firing_policy_once_after_n_comm { + uint64_t threshold; +} LTTNG_PACKED; + +struct lttng_firing_policy_every_n_comm { + uint64_t interval; +} LTTNG_PACKED; + +/* Forward declaration. */ +static void lttng_firing_policy_init(struct lttng_firing_policy *firing_policy, + enum lttng_firing_policy_type type, + firing_policy_serialize_cb serialize, + firing_policy_equal_cb equal, + firing_policy_destroy_cb destroy, + firing_policy_copy_cb copy); + +LTTNG_HIDDEN +const char *lttng_firing_policy_type_string( + enum lttng_firing_policy_type firing_policy_type) +{ + switch (firing_policy_type) { + case LTTNG_FIRING_POLICY_TYPE_EVERY_N: + return "EVERY-N"; + case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N: + return "ONCE-AFTER-N"; + default: + return "???"; + } +} + +enum lttng_firing_policy_type lttng_firing_policy_get_type( + const struct lttng_firing_policy *policy) +{ + return policy ? policy->type : LTTNG_FIRING_POLICY_TYPE_UNKNOWN; +} + +LTTNG_HIDDEN +void lttng_firing_policy_init(struct lttng_firing_policy *firing_policy, + enum lttng_firing_policy_type type, + firing_policy_serialize_cb serialize, + firing_policy_equal_cb equal, + firing_policy_destroy_cb destroy, + firing_policy_copy_cb copy) +{ + firing_policy->type = type; + firing_policy->serialize = serialize; + firing_policy->equal = equal; + firing_policy->destroy = destroy; + firing_policy->copy = copy; +} + +void lttng_firing_policy_destroy(struct lttng_firing_policy *firing_policy) +{ + if (!firing_policy) { + return; + } + + firing_policy->destroy(firing_policy); +} + +LTTNG_HIDDEN +int lttng_firing_policy_serialize(struct lttng_firing_policy *firing_policy, + struct lttng_payload *payload) +{ + int ret; + const struct lttng_firing_policy_comm firing_policy_comm = { + .firing_policy_type = (int8_t) firing_policy->type, + }; + + ret = lttng_dynamic_buffer_append(&payload->buffer, &firing_policy_comm, + sizeof(firing_policy_comm)); + if (ret) { + goto end; + } + + ret = firing_policy->serialize(firing_policy, payload); + if (ret) { + goto end; + } +end: + return ret; +} + +static ssize_t lttng_firing_policy_once_after_n_create_from_payload( + struct lttng_payload_view *view, + struct lttng_firing_policy **firing_policy) +{ + ssize_t consumed_len = -1; + struct lttng_firing_policy *policy = NULL; + const struct lttng_firing_policy_once_after_n_comm *comm; + const struct lttng_payload_view comm_view = + lttng_payload_view_from_view(view, 0, sizeof(*comm)); + + if (!view || !firing_policy) { + consumed_len = -1; + goto end; + } + + if (!lttng_payload_view_is_valid(&comm_view)) { + /* Payload not large enough to contain the header. */ + consumed_len = -1; + goto end; + } + + comm = (const struct lttng_firing_policy_once_after_n_comm *) + comm_view.buffer.data; + + policy = lttng_firing_policy_once_after_n_create(comm->threshold); + if (policy == NULL) { + consumed_len = -1; + goto end; + } + + *firing_policy = policy; + consumed_len = sizeof(*comm); + +end: + return consumed_len; +} + +static ssize_t lttng_firing_policy_every_n_create_from_payload( + struct lttng_payload_view *view, + struct lttng_firing_policy **firing_policy) +{ + ssize_t consumed_len = -1; + struct lttng_firing_policy *policy = NULL; + const struct lttng_firing_policy_every_n_comm *comm; + const struct lttng_payload_view comm_view = + lttng_payload_view_from_view(view, 0, sizeof(*comm)); + + if (!view || !firing_policy) { + consumed_len = -1; + goto end; + } + + if (!lttng_payload_view_is_valid(&comm_view)) { + /* Payload not large enough to contain the header. */ + consumed_len = -1; + goto end; + } + + comm = (const struct lttng_firing_policy_every_n_comm *) + comm_view.buffer.data; + + policy = lttng_firing_policy_every_n_create(comm->interval); + if (policy == NULL) { + consumed_len = -1; + goto end; + } + + *firing_policy = policy; + consumed_len = sizeof(*comm); + +end: + return consumed_len; +} + +LTTNG_HIDDEN +ssize_t lttng_firing_policy_create_from_payload(struct lttng_payload_view *view, + struct lttng_firing_policy **firing_policy) +{ + ssize_t consumed_len, specific_firing_policy_consumed_len; + firing_policy_create_from_payload_cb create_from_payload_cb; + const struct lttng_firing_policy_comm *firing_policy_comm; + const struct lttng_payload_view firing_policy_comm_view = + lttng_payload_view_from_view( + view, 0, sizeof(*firing_policy_comm)); + + if (!view || !firing_policy) { + consumed_len = -1; + goto end; + } + + if (!lttng_payload_view_is_valid(&firing_policy_comm_view)) { + /* Payload not large enough to contain the header. */ + consumed_len = -1; + goto end; + } + + firing_policy_comm = + (const struct lttng_firing_policy_comm *) + firing_policy_comm_view.buffer.data; + + DBG("Create firing_policy from payload: firing-policy-type=%s", + lttng_firing_policy_type_string( + firing_policy_comm->firing_policy_type)); + + switch (firing_policy_comm->firing_policy_type) { + case LTTNG_FIRING_POLICY_TYPE_EVERY_N: + create_from_payload_cb = + lttng_firing_policy_every_n_create_from_payload; + break; + case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N: + create_from_payload_cb = + lttng_firing_policy_once_after_n_create_from_payload; + break; + default: + ERR("Failed to create firing-policy from payload, unhandled firing-policy type: firing-policy-type=%u (%s)", + firing_policy_comm->firing_policy_type, + lttng_firing_policy_type_string(firing_policy_comm->firing_policy_type)); + consumed_len = -1; + goto end; + } + + { + /* + * Create buffer view for the firing_policy-type-specific data. + */ + struct lttng_payload_view specific_firing_policy_view = + lttng_payload_view_from_view(view, + sizeof(struct lttng_firing_policy_comm), + -1); + + specific_firing_policy_consumed_len = create_from_payload_cb( + &specific_firing_policy_view, firing_policy); + } + + if (specific_firing_policy_consumed_len < 0) { + ERR("Failed to create specific firing_policy from buffer"); + consumed_len = -1; + goto end; + } + + assert(*firing_policy); + + consumed_len = sizeof(struct lttng_firing_policy_comm) + + specific_firing_policy_consumed_len; + +end: + return consumed_len; +} + +LTTNG_HIDDEN +bool lttng_firing_policy_is_equal(const struct lttng_firing_policy *a, + const struct lttng_firing_policy *b) +{ + bool is_equal = false; + + if (!a || !b) { + goto end; + } + + if (a->type != b->type) { + goto end; + } + + if (a == b) { + is_equal = true; + goto end; + } + + assert(a->equal); + is_equal = a->equal(a, b); +end: + return is_equal; +} + +/* Every N */ +static const struct lttng_firing_policy_every_n * +firing_policy_every_n_from_firing_policy_const( + const struct lttng_firing_policy *policy) +{ + assert(policy); + + return container_of(policy, const struct lttng_firing_policy_every_n, + parent); +} + +static int lttng_firing_policy_every_n_serialize( + struct lttng_firing_policy *policy, + struct lttng_payload *payload) +{ + int ret; + const struct lttng_firing_policy_every_n *every_n_policy; + struct lttng_firing_policy_every_n_comm comm = {}; + + assert(policy); + assert(payload); + + every_n_policy = firing_policy_every_n_from_firing_policy_const(policy); + comm.interval = every_n_policy->interval; + + ret = lttng_dynamic_buffer_append( + &payload->buffer, &comm, sizeof(comm)); + return ret; +} + +static bool lttng_firing_policy_every_n_is_equal( + const struct lttng_firing_policy *_a, + const struct lttng_firing_policy *_b) +{ + bool is_equal = false; + const struct lttng_firing_policy_every_n *a, *b; + + a = firing_policy_every_n_from_firing_policy_const(_a); + b = firing_policy_every_n_from_firing_policy_const(_b); + + if (a->interval != b->interval) { + goto end; + } + + is_equal = true; + +end: + return is_equal; +} + +static void lttng_firing_policy_every_n_destroy( + struct lttng_firing_policy *policy) +{ + /* Nothing type-specific to release. */ + free(policy); +} + +static struct lttng_firing_policy *lttng_firing_policy_every_n_copy( + const struct lttng_firing_policy *source) +{ + struct lttng_firing_policy *copy = NULL; + const struct lttng_firing_policy_every_n *every_n_policy; + + if (!source) { + goto end; + } + + every_n_policy = firing_policy_every_n_from_firing_policy_const(source); + copy = lttng_firing_policy_every_n_create( + every_n_policy->interval); + +end: + return copy; +} + +LTTNG_HIDDEN +struct lttng_firing_policy *lttng_firing_policy_every_n_create( + uint64_t interval) +{ + struct lttng_firing_policy_every_n *policy = NULL; + + policy = zmalloc(sizeof(struct lttng_firing_policy_every_n)); + if (!policy) { + goto end; + } + + lttng_firing_policy_init(&policy->parent, + LTTNG_FIRING_POLICY_TYPE_EVERY_N, + lttng_firing_policy_every_n_serialize, + lttng_firing_policy_every_n_is_equal, + lttng_firing_policy_every_n_destroy, + lttng_firing_policy_every_n_copy); + + policy->interval = interval; + +end: + return policy ? &policy->parent : NULL; +} + +LTTNG_HIDDEN +enum lttng_firing_policy_status lttng_firing_policy_every_n_get_interval( + const struct lttng_firing_policy *policy, uint64_t *interval) +{ + const struct lttng_firing_policy_every_n *every_n_policy; + enum lttng_firing_policy_status status; + + if (!policy || !IS_EVERY_N_FIRING_POLICY(policy) || !interval) { + status = LTTNG_FIRING_POLICY_STATUS_INVALID; + goto end; + } + + every_n_policy = firing_policy_every_n_from_firing_policy_const(policy); + *interval = every_n_policy->interval; + status = LTTNG_FIRING_POLICY_STATUS_OK; +end: + + return status; +} + +/* Once after N */ + +static const struct lttng_firing_policy_once_after_n * +firing_policy_once_after_n_from_firing_policy_const( + const struct lttng_firing_policy *policy) +{ + assert(policy); + + return container_of(policy, struct lttng_firing_policy_once_after_n, + parent); +} + +static int lttng_firing_policy_once_after_n_serialize( + struct lttng_firing_policy *policy, + struct lttng_payload *payload) +{ + int ret; + const struct lttng_firing_policy_once_after_n *once_after_n_policy; + struct lttng_firing_policy_once_after_n_comm comm = {}; + + assert(policy); + assert(payload); + + once_after_n_policy = + firing_policy_once_after_n_from_firing_policy_const( + policy); + comm.threshold = once_after_n_policy->threshold; + + ret = lttng_dynamic_buffer_append( + &payload->buffer, &comm, sizeof(comm)); + return ret; +} + +static bool lttng_firing_policy_once_after_n_is_equal( + const struct lttng_firing_policy *_a, + const struct lttng_firing_policy *_b) +{ + bool is_equal = false; + const struct lttng_firing_policy_once_after_n *a, *b; + + a = firing_policy_once_after_n_from_firing_policy_const(_a); + b = firing_policy_once_after_n_from_firing_policy_const(_b); + + if (a->threshold != b->threshold) { + goto end; + } + + is_equal = true; + +end: + return is_equal; +} + +static void lttng_firing_policy_once_after_n_destroy( + struct lttng_firing_policy *policy) +{ + /* Nothing type specific to release. */ + free(policy); +} + +static struct lttng_firing_policy *lttng_firing_policy_once_after_n_copy( + const struct lttng_firing_policy *source) +{ + struct lttng_firing_policy *copy = NULL; + const struct lttng_firing_policy_once_after_n *once_after_n_policy; + + if (!source) { + goto end; + } + + once_after_n_policy = + firing_policy_once_after_n_from_firing_policy_const( + source); + copy = lttng_firing_policy_once_after_n_create( + once_after_n_policy->threshold); + +end: + return copy; +} + +LTTNG_HIDDEN +struct lttng_firing_policy *lttng_firing_policy_once_after_n_create( + uint64_t threshold) +{ + struct lttng_firing_policy_once_after_n *policy = NULL; + + policy = zmalloc(sizeof(struct lttng_firing_policy_once_after_n)); + if (!policy) { + goto end; + } + + lttng_firing_policy_init(&policy->parent, + LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N, + lttng_firing_policy_once_after_n_serialize, + lttng_firing_policy_once_after_n_is_equal, + lttng_firing_policy_once_after_n_destroy, + lttng_firing_policy_once_after_n_copy); + + policy->threshold = threshold; + +end: + return policy ? &policy->parent : NULL; +} + +LTTNG_HIDDEN +enum lttng_firing_policy_status lttng_firing_policy_once_after_n_get_threshold( + const struct lttng_firing_policy *policy, uint64_t *threshold) +{ + const struct lttng_firing_policy_once_after_n *once_after_n_policy; + enum lttng_firing_policy_status status; + + if (!policy || !IS_ONCE_AFTER_N_FIRING_POLICY(policy) || !threshold) { + status = LTTNG_FIRING_POLICY_STATUS_INVALID; + goto end; + } + + once_after_n_policy = + firing_policy_once_after_n_from_firing_policy_const( + policy); + *threshold = once_after_n_policy->threshold; + status = LTTNG_FIRING_POLICY_STATUS_OK; + +end: + return status; +} + +LTTNG_HIDDEN +struct lttng_firing_policy *lttng_firing_policy_copy( + const struct lttng_firing_policy *source) +{ + assert(source->copy); + return source->copy(source); +}