test: unit: snapshot session action
[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
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
29typedef void (*firing_policy_destroy_cb)(
30 struct lttng_firing_policy *firing_policy);
31typedef int (*firing_policy_serialize_cb)(
32 struct lttng_firing_policy *firing_policy,
33 struct lttng_payload *payload);
34typedef bool (*firing_policy_equal_cb)(const struct lttng_firing_policy *a,
35 const struct lttng_firing_policy *b);
36typedef ssize_t (*firing_policy_create_from_payload_cb)(
37 struct lttng_payload_view *view,
38 struct lttng_firing_policy **firing_policy);
39typedef struct lttng_firing_policy *(*firing_policy_copy_cb)(
40 const struct lttng_firing_policy *source);
41
42struct 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
50struct lttng_firing_policy_every_n {
51 struct lttng_firing_policy parent;
52 uint64_t interval;
53};
54
55struct lttng_firing_policy_once_after_n {
56 struct lttng_firing_policy parent;
57 uint64_t threshold;
58};
59
60struct lttng_firing_policy_comm {
61 /* enum lttng_firing_policy_type */
62 int8_t firing_policy_type;
63} LTTNG_PACKED;
64
65struct lttng_firing_policy_once_after_n_comm {
66 uint64_t threshold;
67} LTTNG_PACKED;
68
69struct lttng_firing_policy_every_n_comm {
70 uint64_t interval;
71} LTTNG_PACKED;
72
73/* Forward declaration. */
74static 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
81LTTNG_HIDDEN
82const 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
95enum 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
101LTTNG_HIDDEN
102void 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
116void 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
125LTTNG_HIDDEN
126int 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 }
144end:
145 return ret;
146}
147
148static 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
181end:
182 return consumed_len;
183}
184
185static 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
218end:
219 return consumed_len;
220}
221
222LTTNG_HIDDEN
223ssize_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
293end:
294 return consumed_len;
295}
296
297LTTNG_HIDDEN
298bool 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);
318end:
319 return is_equal;
320}
321
322/* Every N */
323static const struct lttng_firing_policy_every_n *
324firing_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
333static 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
352static 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
368end:
369 return is_equal;
370}
371
372static 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
379static 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
393end:
394 return copy;
395}
396
397LTTNG_HIDDEN
398struct 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
417end:
418 return policy ? &policy->parent : NULL;
419}
420
421LTTNG_HIDDEN
422enum 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;
436end:
437
438 return status;
439}
440
441/* Once after N */
442
443static const struct lttng_firing_policy_once_after_n *
444firing_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
453static 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
474static 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
490end:
491 return is_equal;
492}
493
494static 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
501static 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
517end:
518 return copy;
519}
520
521LTTNG_HIDDEN
522struct 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
541end:
542 return policy ? &policy->parent : NULL;
543}
544
545LTTNG_HIDDEN
546enum 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
563end:
564 return status;
565}
566
567LTTNG_HIDDEN
568struct 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.042115 seconds and 4 git commands to generate.