#include <sys/types.h>
#include <urcu/ref.h>
+struct lttng_firing_policy;
+
typedef bool (*action_validate_cb)(struct lttng_action *action);
typedef void (*action_destroy_cb)(struct lttng_action *action);
typedef int (*action_serialize_cb)(struct lttng_action *action,
typedef ssize_t (*action_create_from_payload_cb)(
struct lttng_payload_view *view,
struct lttng_action **action);
+typedef const struct lttng_firing_policy *(*action_get_firing_policy_cb)(
+ const struct lttng_action *action);
struct lttng_action {
struct urcu_ref ref;
action_serialize_cb serialize;
action_equal_cb equal;
action_destroy_cb destroy;
+ action_get_firing_policy_cb get_firing_policy;
+
+ /* Internal use only. */
+
+ /* The number of time the actions was enqueued for execution. */
+ uint64_t execution_request_counter;
+ /*
+ * The number of time the action was actually executed.
+ * Action firing policy can impact on this number.
+ * */
+ uint64_t execution_counter;
+ /*
+ * The number of time the action execution failed.
+ */
+ uint64_t execution_failure_counter;
};
struct lttng_action_comm {
action_validate_cb validate,
action_serialize_cb serialize,
action_equal_cb equal,
- action_destroy_cb destroy);
+ action_destroy_cb destroy,
+ action_get_firing_policy_cb get_firing_policy);
LTTNG_HIDDEN
bool lttng_action_validate(struct lttng_action *action);
LTTNG_HIDDEN
const char* lttng_action_type_string(enum lttng_action_type action_type);
+LTTNG_HIDDEN
+void lttng_action_increase_execution_request_count(struct lttng_action *action);
+
+LTTNG_HIDDEN
+void lttng_action_increase_execution_count(struct lttng_action *action);
+
+LTTNG_HIDDEN
+void lttng_action_increase_execution_failure_count(struct lttng_action *action);
+
+LTTNG_HIDDEN
+bool lttng_action_should_execute(const struct lttng_action *action);
+
#endif /* LTTNG_ACTION_INTERNAL_H */
struct lttng_firing_policy *lttng_firing_policy_copy(
const struct lttng_firing_policy *source);
+LTTNG_HIDDEN
+bool lttng_firing_policy_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter);
+
#endif /* LTTNG_FIRING_POLICY */
struct lttng_payload_view *view,
struct lttng_action **group);
+LTTNG_HIDDEN
+extern struct lttng_action *lttng_action_group_borrow_mutable_at_index(
+ const struct lttng_action *group, unsigned int index);
+
#endif /* LTTNG_ACTION_GROUP_INTERNAL_H */
#include <common/macros.h>
#include <common/optional.h>
#include <lttng/action/action-internal.h>
+#include <lttng/action/group-internal.h>
#include <lttng/action/group.h>
#include <lttng/action/notify-internal.h>
#include <lttng/action/notify.h>
*/
typedef int (*action_executor_handler)(struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *action);
+ struct lttng_action *action);
static int action_executor_notify_handler(struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
-static int action_executor_start_session_handler(struct action_executor *executor,
+ struct lttng_action *);
+static int action_executor_start_session_handler(
+ struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
-static int action_executor_stop_session_handler(struct action_executor *executor,
+ struct lttng_action *);
+static int action_executor_stop_session_handler(
+ struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
-static int action_executor_rotate_session_handler(struct action_executor *executor,
+ struct lttng_action *);
+static int action_executor_rotate_session_handler(
+ struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
-static int action_executor_snapshot_session_handler(struct action_executor *executor,
+ struct lttng_action *);
+static int action_executor_snapshot_session_handler(
+ struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
+ struct lttng_action *);
static int action_executor_group_handler(struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
+ struct lttng_action *);
static int action_executor_generic_handler(struct action_executor *executor,
const struct action_work_item *,
- const struct lttng_action *);
+ struct lttng_action *);
static const action_executor_handler action_executors[] = {
[LTTNG_ACTION_TYPE_NOTIFY] = action_executor_notify_handler,
static int action_executor_notify_handler(struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
return notification_client_list_send_evaluation(work_item->client_list,
work_item->trigger,
client_handle_transmission_status, executor);
}
-static int action_executor_start_session_handler(struct action_executor *executor,
+static int action_executor_start_session_handler(
+ struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
int ret = 0;
const char *session_name;
WARN("Failed to start session `%s` on behalf of trigger `%s`: %s",
session_name, get_trigger_name(work_item->trigger),
lttng_strerror(-cmd_ret));
+ lttng_action_increase_execution_failure_count(action);
break;
}
return ret;
}
-static int action_executor_stop_session_handler(struct action_executor *executor,
+static int action_executor_stop_session_handler(
+ struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
int ret = 0;
const char *session_name;
DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
get_trigger_name(work_item->trigger));
+ lttng_action_increase_execution_failure_count(action);
goto error_unlock_list;
}
WARN("Failed to stop session `%s` on behalf of trigger `%s`: %s",
session_name, get_trigger_name(work_item->trigger),
lttng_strerror(-cmd_ret));
+ lttng_action_increase_execution_failure_count(action);
break;
}
return ret;
}
-static int action_executor_rotate_session_handler(struct action_executor *executor,
+static int action_executor_rotate_session_handler(
+ struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
int ret = 0;
const char *session_name;
DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
get_trigger_name(work_item->trigger));
+ lttng_action_increase_execution_failure_count(action);
goto error_unlock_list;
}
case LTTNG_ERR_ROTATION_PENDING:
DBG("Attempted to start a rotation of session `%s` on behalf of trigger `%s` but a rotation is already ongoing",
session_name, get_trigger_name(work_item->trigger));
+ lttng_action_increase_execution_failure_count(action);
break;
case LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP:
case LTTNG_ERR_ROTATION_AFTER_STOP_CLEAR:
WARN("Failed to start a rotation of session `%s` on behalf of trigger `%s`: %s",
session_name, get_trigger_name(work_item->trigger),
lttng_strerror(-cmd_ret));
+ lttng_action_increase_execution_failure_count(action);
break;
}
return ret;
}
-static int action_executor_snapshot_session_handler(struct action_executor *executor,
+static int action_executor_snapshot_session_handler(
+ struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
int ret = 0;
const char *session_name;
DBG("Failed to find session `%s` by name while executing `%s` action of trigger `%s`",
session_name, get_action_name(action),
get_trigger_name(work_item->trigger));
+ lttng_action_increase_execution_failure_count(action);
goto error_unlock_list;
}
WARN("Failed to record snapshot of session `%s` on behalf of trigger `%s`: %s",
session_name, get_trigger_name(work_item->trigger),
lttng_strerror(-cmd_ret));
+ lttng_action_increase_execution_failure_count(action);
break;
}
static int action_executor_group_handler(struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action_group)
+ struct lttng_action *action_group)
{
int ret = 0;
unsigned int i, count;
DBG("Action group has %u action%s", count, count != 1 ? "s" : "");
for (i = 0; i < count; i++) {
- const struct lttng_action *action =
- lttng_action_group_get_at_index(
+ struct lttng_action *action =
+ lttng_action_group_borrow_mutable_at_index(
action_group, i);
ret = action_executor_generic_handler(
static int action_executor_generic_handler(struct action_executor *executor,
const struct action_work_item *work_item,
- const struct lttng_action *action)
+ struct lttng_action *action)
{
+ int ret;
const enum lttng_action_type action_type = lttng_action_get_type(action);
assert(action_type != LTTNG_ACTION_TYPE_UNKNOWN);
+ lttng_action_increase_execution_request_count(action);
+ if (!lttng_action_should_execute(action)) {
+ DBG("Policy prevented execution of action `%s` of trigger `%s` action work item %" PRIu64,
+ get_action_name(action),
+ get_trigger_name(work_item->trigger),
+ work_item->id);
+ ret = 0;
+ goto end;
+ }
+
+ lttng_action_increase_execution_count(action);
DBG("Executing action `%s` of trigger `%s` action work item %" PRIu64,
get_action_name(action),
get_trigger_name(work_item->trigger),
work_item->id);
-
- return action_executors[action_type](
- executor, work_item, action);
+ ret = action_executors[action_type](executor, work_item, action);
+end:
+ return ret;
}
static int action_work_item_execute(struct action_executor *executor,
struct action_work_item *work_item)
{
int ret;
- const struct lttng_action *action =
- lttng_trigger_get_const_action(work_item->trigger);
+ struct lttng_action *action =
+ lttng_trigger_get_action(work_item->trigger);
DBG("Starting execution of action work item %" PRIu64 " of trigger `%s`",
work_item->id, get_trigger_name(work_item->trigger));
#include <assert.h>
#include <common/error.h>
#include <lttng/action/action-internal.h>
+#include <lttng/action/firing-policy-internal.h>
#include <lttng/action/group-internal.h>
#include <lttng/action/notify-internal.h>
#include <lttng/action/rotate-session-internal.h>
}
LTTNG_HIDDEN
-void lttng_action_init(
- struct lttng_action *action,
+void lttng_action_init(struct lttng_action *action,
enum lttng_action_type type,
action_validate_cb validate,
action_serialize_cb serialize,
action_equal_cb equal,
- action_destroy_cb destroy)
+ action_destroy_cb destroy,
+ action_get_firing_policy_cb get_firing_policy)
{
urcu_ref_init(&action->ref);
action->type = type;
action->serialize = serialize;
action->equal = equal;
action->destroy = destroy;
+ action->get_firing_policy = get_firing_policy;
+
+ action->execution_request_counter = 0;
+ action->execution_counter = 0;
+ action->execution_failure_counter = 0;
}
static
end:
return is_equal;
}
+
+LTTNG_HIDDEN
+void lttng_action_increase_execution_request_count(struct lttng_action *action)
+{
+ action->execution_request_counter++;
+}
+
+LTTNG_HIDDEN
+void lttng_action_increase_execution_count(struct lttng_action *action)
+{
+ action->execution_counter++;
+}
+
+LTTNG_HIDDEN
+void lttng_action_increase_execution_failure_count(struct lttng_action *action)
+{
+ action->execution_failure_counter++;
+}
+
+LTTNG_HIDDEN
+bool lttng_action_should_execute(const struct lttng_action *action)
+{
+ const struct lttng_firing_policy *policy = NULL;
+ bool execute = false;
+
+ if (action->get_firing_policy == NULL) {
+ execute = true;
+ goto end;
+ }
+
+ policy = action->get_firing_policy(action);
+ if (policy == NULL) {
+ execute = true;
+ goto end;
+ }
+
+ execute = lttng_firing_policy_should_execute(
+ policy, action->execution_request_counter);
+end:
+ return execute;
+}
firing_policy_destroy_cb destroy,
firing_policy_copy_cb copy);
+/* Forward declaration. Every n */
+static bool lttng_firing_policy_every_n_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter);
+
+/* Forward declaration. Once after N */
+static bool lttng_firing_policy_once_after_n_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter);
+
LTTNG_HIDDEN
const char *lttng_firing_policy_type_string(
enum lttng_firing_policy_type firing_policy_type)
return is_equal;
}
+LTTNG_HIDDEN
+bool lttng_firing_policy_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter)
+{
+ switch (policy->type) {
+ case LTTNG_FIRING_POLICY_TYPE_EVERY_N:
+ return lttng_firing_policy_every_n_should_execute(
+ policy, counter);
+ case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N:
+ return lttng_firing_policy_once_after_n_should_execute(
+ policy, counter);
+ default:
+ abort();
+ break;
+ }
+}
+
/* Every N */
static const struct lttng_firing_policy_every_n *
firing_policy_every_n_from_firing_policy_const(
{
struct lttng_firing_policy_every_n *policy = NULL;
+ if (interval == 0) {
+ /*
+ * An interval of 0 is invalid since it would never be fired.
+ */
+ goto end;
+ }
+
policy = zmalloc(sizeof(struct lttng_firing_policy_every_n));
if (!policy) {
goto end;
return status;
}
+static bool lttng_firing_policy_every_n_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter)
+{
+ const struct lttng_firing_policy_every_n *every_n_policy;
+ assert(policy);
+ bool execute = false;
+
+ every_n_policy = firing_policy_every_n_from_firing_policy_const(policy);
+
+ if (every_n_policy->interval == 0) {
+ abort();
+ }
+
+ execute = (counter % every_n_policy->interval) == 0;
+
+ DBG("Policy every N = %" PRIu64
+ ": execution %s. Execution count: %" PRIu64,
+ every_n_policy->interval,
+ execute ? "accepted" : "denied", counter);
+
+ return execute;
+}
+
/* Once after N */
static const struct lttng_firing_policy_once_after_n *
{
struct lttng_firing_policy_once_after_n *policy = NULL;
+ if (threshold == 0) {
+ /* threshold is expected to be > 0 */
+ goto end;
+ }
+
policy = zmalloc(sizeof(struct lttng_firing_policy_once_after_n));
if (!policy) {
goto end;
assert(source->copy);
return source->copy(source);
}
+
+static bool lttng_firing_policy_once_after_n_should_execute(
+ const struct lttng_firing_policy *policy, uint64_t counter)
+{
+ const struct lttng_firing_policy_once_after_n *once_after_n_policy;
+ bool execute = false;
+ assert(policy);
+
+ once_after_n_policy =
+ firing_policy_once_after_n_from_firing_policy_const(
+ policy);
+
+ execute = counter == once_after_n_policy->threshold;
+
+ DBG("Policy once after N = %" PRIu64
+ ": execution %s. Execution count: %" PRIu64,
+ once_after_n_policy->threshold,
+ execute ? "accepted" : "denied", counter);
+
+ return counter == once_after_n_policy->threshold;
+}
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_action_group_is_equal, lttng_action_group_destroy,
+ NULL);
lttng_dynamic_pointer_array_init(&action_group->actions,
destroy_lttng_action_group_element);
const struct lttng_action *lttng_action_group_get_at_index(
const struct lttng_action *group, unsigned int index)
+{
+ return lttng_action_group_borrow_mutable_at_index(group, index);
+}
+
+LTTNG_HIDDEN
+struct lttng_action *lttng_action_group_borrow_mutable_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;
+ struct lttng_action *action = NULL;
if (lttng_action_group_get_count(group, &count) !=
LTTNG_ACTION_STATUS_OK) {
return lttng_firing_policy_is_equal(_a->policy, _b->policy);
}
+static const struct lttng_firing_policy *
+lttng_action_notify_internal_get_firing_policy(
+ const struct lttng_action *action)
+{
+ const struct lttng_action_notify *_action;
+ _action = action_notify_from_action_const(action);
+
+ return _action->policy;
+}
+
struct lttng_action *lttng_action_notify_create(void)
{
struct lttng_firing_policy *policy = NULL;
lttng_action_init(¬ify->parent, LTTNG_ACTION_TYPE_NOTIFY, NULL,
lttng_action_notify_serialize,
lttng_action_notify_is_equal,
- lttng_action_notify_destroy);
+ lttng_action_notify_destroy,
+ lttng_action_notify_internal_get_firing_policy);
notify->policy = policy;
policy = NULL;
char data[];
} LTTNG_PACKED;
+static const struct lttng_firing_policy *
+lttng_action_rotate_session_internal_get_firing_policy(
+ const struct lttng_action *action);
+
static struct lttng_action_rotate_session *action_rotate_session_from_action(
struct lttng_action *action)
{
lttng_action_rotate_session_validate,
lttng_action_rotate_session_serialize,
lttng_action_rotate_session_is_equal,
- lttng_action_rotate_session_destroy);
+ lttng_action_rotate_session_destroy,
+ lttng_action_rotate_session_internal_get_firing_policy);
status = lttng_action_rotate_session_set_firing_policy(action, policy);
if (status != LTTNG_ACTION_STATUS_OK) {
end:
return status;
}
+
+static const struct lttng_firing_policy *
+lttng_action_rotate_session_internal_get_firing_policy(
+ const struct lttng_action *action)
+{
+ const struct lttng_action_rotate_session *_action;
+ _action = action_rotate_session_from_action_const(action);
+
+ return _action->policy;
+}
char data[];
} LTTNG_PACKED;
+static const struct lttng_firing_policy *
+lttng_action_snapshot_session_internal_get_firing_policy(
+ const struct lttng_action *action);
+
static struct lttng_action_snapshot_session *
action_snapshot_session_from_action(struct lttng_action *action)
{
lttng_action_snapshot_session_validate,
lttng_action_snapshot_session_serialize,
lttng_action_snapshot_session_is_equal,
- lttng_action_snapshot_session_destroy);
+ lttng_action_snapshot_session_destroy,
+ lttng_action_snapshot_session_internal_get_firing_policy);
status = lttng_action_snapshot_session_set_firing_policy(
action, policy);
end:
return status;
}
+
+static const struct lttng_firing_policy *
+lttng_action_snapshot_session_internal_get_firing_policy(
+ const struct lttng_action *action)
+{
+ const struct lttng_action_snapshot_session *_action;
+ _action = action_snapshot_session_from_action_const(action);
+
+ return _action->policy;
+}
char data[];
} LTTNG_PACKED;
+static const struct lttng_firing_policy *
+lttng_action_start_session_internal_get_firing_policy(
+ const struct lttng_action *action);
+
static struct lttng_action_start_session *action_start_session_from_action(
struct lttng_action *action)
{
lttng_action_start_session_validate,
lttng_action_start_session_serialize,
lttng_action_start_session_is_equal,
- lttng_action_start_session_destroy);
+ lttng_action_start_session_destroy,
+ lttng_action_start_session_internal_get_firing_policy);
status = lttng_action_start_session_set_firing_policy(action, policy);
if (status != LTTNG_ACTION_STATUS_OK) {
end:
return status;
}
+
+static const struct lttng_firing_policy *
+lttng_action_start_session_internal_get_firing_policy(
+ const struct lttng_action *action)
+{
+ const struct lttng_action_start_session *_action;
+ _action = action_start_session_from_action_const(action);
+
+ return _action->policy;
+}
char data[];
} LTTNG_PACKED;
+static const struct lttng_firing_policy *
+lttng_action_stop_session_internal_get_firing_policy(
+ const struct lttng_action *action);
+
static struct lttng_action_stop_session *action_stop_session_from_action(
struct lttng_action *action)
{
lttng_action_stop_session_validate,
lttng_action_stop_session_serialize,
lttng_action_stop_session_is_equal,
- lttng_action_stop_session_destroy);
+ lttng_action_stop_session_destroy,
+ lttng_action_stop_session_internal_get_firing_policy);
status = lttng_action_stop_session_set_firing_policy(action, policy);
if (status != LTTNG_ACTION_STATUS_OK) {
end:
return status;
}
+
+static const struct lttng_firing_policy *
+lttng_action_stop_session_internal_get_firing_policy(
+ const struct lttng_action *action)
+{
+ const struct lttng_action_stop_session *_action;
+ _action = action_stop_session_from_action_const(action);
+
+ return _action->policy;
+}