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