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