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