Force usage of assert() condition when NDEBUG is defined
[lttng-tools.git] / src / common / actions / firing-policy.c
CommitLineData
347f2c91
JR
1/*
2 * Copyright (C) 2021 Jonathan Rajotte <jonathan.rajotte-julien@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
347f2c91
JR
8#include <common/buffer-view.h>
9#include <common/dynamic-buffer.h>
10#include <common/error.h>
11#include <common/macros.h>
12#include <common/payload-view.h>
13#include <common/payload.h>
14#include <limits.h>
15#include <lttng/action/firing-policy-internal.h>
16#include <lttng/action/firing-policy.h>
17#include <stdbool.h>
18#include <sys/types.h>
19
20#define IS_EVERY_N_FIRING_POLICY(policy) \
21 (lttng_firing_policy_get_type(policy) == \
22 LTTNG_FIRING_POLICY_TYPE_EVERY_N)
23
24#define IS_ONCE_AFTER_N_FIRING_POLICY(policy) \
25 (lttng_firing_policy_get_type(policy) == \
26 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N)
27
28typedef void (*firing_policy_destroy_cb)(
29 struct lttng_firing_policy *firing_policy);
30typedef int (*firing_policy_serialize_cb)(
31 struct lttng_firing_policy *firing_policy,
32 struct lttng_payload *payload);
33typedef bool (*firing_policy_equal_cb)(const struct lttng_firing_policy *a,
34 const struct lttng_firing_policy *b);
35typedef ssize_t (*firing_policy_create_from_payload_cb)(
36 struct lttng_payload_view *view,
37 struct lttng_firing_policy **firing_policy);
38typedef struct lttng_firing_policy *(*firing_policy_copy_cb)(
39 const struct lttng_firing_policy *source);
40
41struct lttng_firing_policy {
42 enum lttng_firing_policy_type type;
43 firing_policy_serialize_cb serialize;
44 firing_policy_equal_cb equal;
45 firing_policy_destroy_cb destroy;
46 firing_policy_copy_cb copy;
47};
48
49struct lttng_firing_policy_every_n {
50 struct lttng_firing_policy parent;
51 uint64_t interval;
52};
53
54struct lttng_firing_policy_once_after_n {
55 struct lttng_firing_policy parent;
56 uint64_t threshold;
57};
58
59struct lttng_firing_policy_comm {
60 /* enum lttng_firing_policy_type */
61 int8_t firing_policy_type;
62} LTTNG_PACKED;
63
64struct lttng_firing_policy_once_after_n_comm {
65 uint64_t threshold;
66} LTTNG_PACKED;
67
68struct lttng_firing_policy_every_n_comm {
69 uint64_t interval;
70} LTTNG_PACKED;
71
72/* Forward declaration. */
73static void lttng_firing_policy_init(struct lttng_firing_policy *firing_policy,
74 enum lttng_firing_policy_type type,
75 firing_policy_serialize_cb serialize,
76 firing_policy_equal_cb equal,
77 firing_policy_destroy_cb destroy,
78 firing_policy_copy_cb copy);
79
2d57482c
JR
80/* Forward declaration. Every n */
81static bool lttng_firing_policy_every_n_should_execute(
82 const struct lttng_firing_policy *policy, uint64_t counter);
83
84/* Forward declaration. Once after N */
85static bool lttng_firing_policy_once_after_n_should_execute(
86 const struct lttng_firing_policy *policy, uint64_t counter);
87
347f2c91
JR
88LTTNG_HIDDEN
89const char *lttng_firing_policy_type_string(
90 enum lttng_firing_policy_type firing_policy_type)
91{
92 switch (firing_policy_type) {
93 case LTTNG_FIRING_POLICY_TYPE_EVERY_N:
94 return "EVERY-N";
95 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N:
96 return "ONCE-AFTER-N";
97 default:
98 return "???";
99 }
100}
101
102enum lttng_firing_policy_type lttng_firing_policy_get_type(
103 const struct lttng_firing_policy *policy)
104{
105 return policy ? policy->type : LTTNG_FIRING_POLICY_TYPE_UNKNOWN;
106}
107
108LTTNG_HIDDEN
109void lttng_firing_policy_init(struct lttng_firing_policy *firing_policy,
110 enum lttng_firing_policy_type type,
111 firing_policy_serialize_cb serialize,
112 firing_policy_equal_cb equal,
113 firing_policy_destroy_cb destroy,
114 firing_policy_copy_cb copy)
115{
116 firing_policy->type = type;
117 firing_policy->serialize = serialize;
118 firing_policy->equal = equal;
119 firing_policy->destroy = destroy;
120 firing_policy->copy = copy;
121}
122
123void lttng_firing_policy_destroy(struct lttng_firing_policy *firing_policy)
124{
125 if (!firing_policy) {
126 return;
127 }
128
129 firing_policy->destroy(firing_policy);
130}
131
132LTTNG_HIDDEN
133int lttng_firing_policy_serialize(struct lttng_firing_policy *firing_policy,
134 struct lttng_payload *payload)
135{
136 int ret;
137 const struct lttng_firing_policy_comm firing_policy_comm = {
138 .firing_policy_type = (int8_t) firing_policy->type,
139 };
140
141 ret = lttng_dynamic_buffer_append(&payload->buffer, &firing_policy_comm,
142 sizeof(firing_policy_comm));
143 if (ret) {
144 goto end;
145 }
146
147 ret = firing_policy->serialize(firing_policy, payload);
148 if (ret) {
149 goto end;
150 }
151end:
152 return ret;
153}
154
155static ssize_t lttng_firing_policy_once_after_n_create_from_payload(
156 struct lttng_payload_view *view,
157 struct lttng_firing_policy **firing_policy)
158{
159 ssize_t consumed_len = -1;
160 struct lttng_firing_policy *policy = NULL;
161 const struct lttng_firing_policy_once_after_n_comm *comm;
162 const struct lttng_payload_view comm_view =
163 lttng_payload_view_from_view(view, 0, sizeof(*comm));
164
165 if (!view || !firing_policy) {
166 consumed_len = -1;
167 goto end;
168 }
169
170 if (!lttng_payload_view_is_valid(&comm_view)) {
171 /* Payload not large enough to contain the header. */
172 consumed_len = -1;
173 goto end;
174 }
175
176 comm = (const struct lttng_firing_policy_once_after_n_comm *)
177 comm_view.buffer.data;
178
179 policy = lttng_firing_policy_once_after_n_create(comm->threshold);
180 if (policy == NULL) {
181 consumed_len = -1;
182 goto end;
183 }
184
185 *firing_policy = policy;
186 consumed_len = sizeof(*comm);
187
188end:
189 return consumed_len;
190}
191
192static ssize_t lttng_firing_policy_every_n_create_from_payload(
193 struct lttng_payload_view *view,
194 struct lttng_firing_policy **firing_policy)
195{
196 ssize_t consumed_len = -1;
197 struct lttng_firing_policy *policy = NULL;
198 const struct lttng_firing_policy_every_n_comm *comm;
199 const struct lttng_payload_view comm_view =
200 lttng_payload_view_from_view(view, 0, sizeof(*comm));
201
202 if (!view || !firing_policy) {
203 consumed_len = -1;
204 goto end;
205 }
206
207 if (!lttng_payload_view_is_valid(&comm_view)) {
208 /* Payload not large enough to contain the header. */
209 consumed_len = -1;
210 goto end;
211 }
212
213 comm = (const struct lttng_firing_policy_every_n_comm *)
214 comm_view.buffer.data;
215
216 policy = lttng_firing_policy_every_n_create(comm->interval);
217 if (policy == NULL) {
218 consumed_len = -1;
219 goto end;
220 }
221
222 *firing_policy = policy;
223 consumed_len = sizeof(*comm);
224
225end:
226 return consumed_len;
227}
228
229LTTNG_HIDDEN
230ssize_t lttng_firing_policy_create_from_payload(struct lttng_payload_view *view,
231 struct lttng_firing_policy **firing_policy)
232{
233 ssize_t consumed_len, specific_firing_policy_consumed_len;
234 firing_policy_create_from_payload_cb create_from_payload_cb;
235 const struct lttng_firing_policy_comm *firing_policy_comm;
236 const struct lttng_payload_view firing_policy_comm_view =
237 lttng_payload_view_from_view(
238 view, 0, sizeof(*firing_policy_comm));
239
240 if (!view || !firing_policy) {
241 consumed_len = -1;
242 goto end;
243 }
244
245 if (!lttng_payload_view_is_valid(&firing_policy_comm_view)) {
246 /* Payload not large enough to contain the header. */
247 consumed_len = -1;
248 goto end;
249 }
250
251 firing_policy_comm =
252 (const struct lttng_firing_policy_comm *)
253 firing_policy_comm_view.buffer.data;
254
255 DBG("Create firing_policy from payload: firing-policy-type=%s",
256 lttng_firing_policy_type_string(
257 firing_policy_comm->firing_policy_type));
258
259 switch (firing_policy_comm->firing_policy_type) {
260 case LTTNG_FIRING_POLICY_TYPE_EVERY_N:
261 create_from_payload_cb =
262 lttng_firing_policy_every_n_create_from_payload;
263 break;
264 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N:
265 create_from_payload_cb =
266 lttng_firing_policy_once_after_n_create_from_payload;
267 break;
268 default:
269 ERR("Failed to create firing-policy from payload, unhandled firing-policy type: firing-policy-type=%u (%s)",
270 firing_policy_comm->firing_policy_type,
271 lttng_firing_policy_type_string(firing_policy_comm->firing_policy_type));
272 consumed_len = -1;
273 goto end;
274 }
275
276 {
277 /*
278 * Create buffer view for the firing_policy-type-specific data.
279 */
280 struct lttng_payload_view specific_firing_policy_view =
281 lttng_payload_view_from_view(view,
282 sizeof(struct lttng_firing_policy_comm),
283 -1);
284
285 specific_firing_policy_consumed_len = create_from_payload_cb(
286 &specific_firing_policy_view, firing_policy);
287 }
288
289 if (specific_firing_policy_consumed_len < 0) {
290 ERR("Failed to create specific firing_policy from buffer");
291 consumed_len = -1;
292 goto end;
293 }
294
a0377dfe 295 LTTNG_ASSERT(*firing_policy);
347f2c91
JR
296
297 consumed_len = sizeof(struct lttng_firing_policy_comm) +
298 specific_firing_policy_consumed_len;
299
300end:
301 return consumed_len;
302}
303
304LTTNG_HIDDEN
305bool lttng_firing_policy_is_equal(const struct lttng_firing_policy *a,
306 const struct lttng_firing_policy *b)
307{
308 bool is_equal = false;
309
310 if (!a || !b) {
311 goto end;
312 }
313
314 if (a->type != b->type) {
315 goto end;
316 }
317
318 if (a == b) {
319 is_equal = true;
320 goto end;
321 }
322
a0377dfe 323 LTTNG_ASSERT(a->equal);
347f2c91
JR
324 is_equal = a->equal(a, b);
325end:
326 return is_equal;
327}
328
2d57482c
JR
329LTTNG_HIDDEN
330bool lttng_firing_policy_should_execute(
331 const struct lttng_firing_policy *policy, uint64_t counter)
332{
333 switch (policy->type) {
334 case LTTNG_FIRING_POLICY_TYPE_EVERY_N:
335 return lttng_firing_policy_every_n_should_execute(
336 policy, counter);
337 case LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N:
338 return lttng_firing_policy_once_after_n_should_execute(
339 policy, counter);
340 default:
341 abort();
342 break;
343 }
344}
345
347f2c91
JR
346/* Every N */
347static const struct lttng_firing_policy_every_n *
348firing_policy_every_n_from_firing_policy_const(
349 const struct lttng_firing_policy *policy)
350{
a0377dfe 351 LTTNG_ASSERT(policy);
347f2c91
JR
352
353 return container_of(policy, const struct lttng_firing_policy_every_n,
354 parent);
355}
356
357static int lttng_firing_policy_every_n_serialize(
358 struct lttng_firing_policy *policy,
359 struct lttng_payload *payload)
360{
361 int ret;
362 const struct lttng_firing_policy_every_n *every_n_policy;
363 struct lttng_firing_policy_every_n_comm comm = {};
364
a0377dfe
FD
365 LTTNG_ASSERT(policy);
366 LTTNG_ASSERT(payload);
347f2c91
JR
367
368 every_n_policy = firing_policy_every_n_from_firing_policy_const(policy);
369 comm.interval = every_n_policy->interval;
370
371 ret = lttng_dynamic_buffer_append(
372 &payload->buffer, &comm, sizeof(comm));
373 return ret;
374}
375
376static bool lttng_firing_policy_every_n_is_equal(
377 const struct lttng_firing_policy *_a,
378 const struct lttng_firing_policy *_b)
379{
380 bool is_equal = false;
381 const struct lttng_firing_policy_every_n *a, *b;
382
383 a = firing_policy_every_n_from_firing_policy_const(_a);
384 b = firing_policy_every_n_from_firing_policy_const(_b);
385
386 if (a->interval != b->interval) {
387 goto end;
388 }
389
390 is_equal = true;
391
392end:
393 return is_equal;
394}
395
396static void lttng_firing_policy_every_n_destroy(
397 struct lttng_firing_policy *policy)
398{
399 /* Nothing type-specific to release. */
400 free(policy);
401}
402
403static struct lttng_firing_policy *lttng_firing_policy_every_n_copy(
404 const struct lttng_firing_policy *source)
405{
406 struct lttng_firing_policy *copy = NULL;
407 const struct lttng_firing_policy_every_n *every_n_policy;
408
409 if (!source) {
410 goto end;
411 }
412
413 every_n_policy = firing_policy_every_n_from_firing_policy_const(source);
414 copy = lttng_firing_policy_every_n_create(
415 every_n_policy->interval);
416
417end:
418 return copy;
419}
420
421LTTNG_HIDDEN
422struct lttng_firing_policy *lttng_firing_policy_every_n_create(
423 uint64_t interval)
424{
425 struct lttng_firing_policy_every_n *policy = NULL;
426
2d57482c
JR
427 if (interval == 0) {
428 /*
429 * An interval of 0 is invalid since it would never be fired.
430 */
431 goto end;
432 }
433
347f2c91
JR
434 policy = zmalloc(sizeof(struct lttng_firing_policy_every_n));
435 if (!policy) {
436 goto end;
437 }
438
439 lttng_firing_policy_init(&policy->parent,
440 LTTNG_FIRING_POLICY_TYPE_EVERY_N,
441 lttng_firing_policy_every_n_serialize,
442 lttng_firing_policy_every_n_is_equal,
443 lttng_firing_policy_every_n_destroy,
444 lttng_firing_policy_every_n_copy);
445
446 policy->interval = interval;
447
448end:
449 return policy ? &policy->parent : NULL;
450}
451
452LTTNG_HIDDEN
453enum lttng_firing_policy_status lttng_firing_policy_every_n_get_interval(
454 const struct lttng_firing_policy *policy, uint64_t *interval)
455{
456 const struct lttng_firing_policy_every_n *every_n_policy;
457 enum lttng_firing_policy_status status;
458
459 if (!policy || !IS_EVERY_N_FIRING_POLICY(policy) || !interval) {
460 status = LTTNG_FIRING_POLICY_STATUS_INVALID;
461 goto end;
462 }
463
464 every_n_policy = firing_policy_every_n_from_firing_policy_const(policy);
465 *interval = every_n_policy->interval;
466 status = LTTNG_FIRING_POLICY_STATUS_OK;
467end:
468
469 return status;
470}
471
2d57482c
JR
472static bool lttng_firing_policy_every_n_should_execute(
473 const struct lttng_firing_policy *policy, uint64_t counter)
474{
475 const struct lttng_firing_policy_every_n *every_n_policy;
a0377dfe 476 LTTNG_ASSERT(policy);
2d57482c
JR
477 bool execute = false;
478
479 every_n_policy = firing_policy_every_n_from_firing_policy_const(policy);
480
481 if (every_n_policy->interval == 0) {
482 abort();
483 }
484
485 execute = (counter % every_n_policy->interval) == 0;
486
487 DBG("Policy every N = %" PRIu64
488 ": execution %s. Execution count: %" PRIu64,
489 every_n_policy->interval,
490 execute ? "accepted" : "denied", counter);
491
492 return execute;
493}
494
347f2c91
JR
495/* Once after N */
496
497static const struct lttng_firing_policy_once_after_n *
498firing_policy_once_after_n_from_firing_policy_const(
499 const struct lttng_firing_policy *policy)
500{
a0377dfe 501 LTTNG_ASSERT(policy);
347f2c91
JR
502
503 return container_of(policy, struct lttng_firing_policy_once_after_n,
504 parent);
505}
506
507static int lttng_firing_policy_once_after_n_serialize(
508 struct lttng_firing_policy *policy,
509 struct lttng_payload *payload)
510{
511 int ret;
512 const struct lttng_firing_policy_once_after_n *once_after_n_policy;
513 struct lttng_firing_policy_once_after_n_comm comm = {};
514
a0377dfe
FD
515 LTTNG_ASSERT(policy);
516 LTTNG_ASSERT(payload);
347f2c91
JR
517
518 once_after_n_policy =
519 firing_policy_once_after_n_from_firing_policy_const(
520 policy);
521 comm.threshold = once_after_n_policy->threshold;
522
523 ret = lttng_dynamic_buffer_append(
524 &payload->buffer, &comm, sizeof(comm));
525 return ret;
526}
527
528static bool lttng_firing_policy_once_after_n_is_equal(
529 const struct lttng_firing_policy *_a,
530 const struct lttng_firing_policy *_b)
531{
532 bool is_equal = false;
533 const struct lttng_firing_policy_once_after_n *a, *b;
534
535 a = firing_policy_once_after_n_from_firing_policy_const(_a);
536 b = firing_policy_once_after_n_from_firing_policy_const(_b);
537
538 if (a->threshold != b->threshold) {
539 goto end;
540 }
541
542 is_equal = true;
543
544end:
545 return is_equal;
546}
547
548static void lttng_firing_policy_once_after_n_destroy(
549 struct lttng_firing_policy *policy)
550{
551 /* Nothing type specific to release. */
552 free(policy);
553}
554
555static struct lttng_firing_policy *lttng_firing_policy_once_after_n_copy(
556 const struct lttng_firing_policy *source)
557{
558 struct lttng_firing_policy *copy = NULL;
559 const struct lttng_firing_policy_once_after_n *once_after_n_policy;
560
561 if (!source) {
562 goto end;
563 }
564
565 once_after_n_policy =
566 firing_policy_once_after_n_from_firing_policy_const(
567 source);
568 copy = lttng_firing_policy_once_after_n_create(
569 once_after_n_policy->threshold);
570
571end:
572 return copy;
573}
574
575LTTNG_HIDDEN
576struct lttng_firing_policy *lttng_firing_policy_once_after_n_create(
577 uint64_t threshold)
578{
579 struct lttng_firing_policy_once_after_n *policy = NULL;
580
2d57482c
JR
581 if (threshold == 0) {
582 /* threshold is expected to be > 0 */
583 goto end;
584 }
585
347f2c91
JR
586 policy = zmalloc(sizeof(struct lttng_firing_policy_once_after_n));
587 if (!policy) {
588 goto end;
589 }
590
591 lttng_firing_policy_init(&policy->parent,
592 LTTNG_FIRING_POLICY_TYPE_ONCE_AFTER_N,
593 lttng_firing_policy_once_after_n_serialize,
594 lttng_firing_policy_once_after_n_is_equal,
595 lttng_firing_policy_once_after_n_destroy,
596 lttng_firing_policy_once_after_n_copy);
597
598 policy->threshold = threshold;
599
600end:
601 return policy ? &policy->parent : NULL;
602}
603
604LTTNG_HIDDEN
605enum lttng_firing_policy_status lttng_firing_policy_once_after_n_get_threshold(
606 const struct lttng_firing_policy *policy, uint64_t *threshold)
607{
608 const struct lttng_firing_policy_once_after_n *once_after_n_policy;
609 enum lttng_firing_policy_status status;
610
611 if (!policy || !IS_ONCE_AFTER_N_FIRING_POLICY(policy) || !threshold) {
612 status = LTTNG_FIRING_POLICY_STATUS_INVALID;
613 goto end;
614 }
615
616 once_after_n_policy =
617 firing_policy_once_after_n_from_firing_policy_const(
618 policy);
619 *threshold = once_after_n_policy->threshold;
620 status = LTTNG_FIRING_POLICY_STATUS_OK;
621
622end:
623 return status;
624}
625
626LTTNG_HIDDEN
627struct lttng_firing_policy *lttng_firing_policy_copy(
628 const struct lttng_firing_policy *source)
629{
a0377dfe 630 LTTNG_ASSERT(source->copy);
347f2c91
JR
631 return source->copy(source);
632}
2d57482c
JR
633
634static bool lttng_firing_policy_once_after_n_should_execute(
635 const struct lttng_firing_policy *policy, uint64_t counter)
636{
637 const struct lttng_firing_policy_once_after_n *once_after_n_policy;
638 bool execute = false;
a0377dfe 639 LTTNG_ASSERT(policy);
2d57482c
JR
640
641 once_after_n_policy =
642 firing_policy_once_after_n_from_firing_policy_const(
643 policy);
644
645 execute = counter == once_after_n_policy->threshold;
646
647 DBG("Policy once after N = %" PRIu64
648 ": execution %s. Execution count: %" PRIu64,
649 once_after_n_policy->threshold,
650 execute ? "accepted" : "denied", counter);
651
652 return counter == once_after_n_policy->threshold;
653}
This page took 0.048836 seconds and 4 git commands to generate.