Fix: consumerd: consumed size miscomputed during statistics sampling
[lttng-tools.git] / src / common / actions / snapshot-session.cpp
1 /*
2 * Copyright (C) 2019 Simon Marchi <simon.marchi@efficios.com>
3 *
4 * SPDX-License-Identifier: LGPL-2.1-only
5 *
6 */
7
8 #include <common/error.hpp>
9 #include <common/macros.hpp>
10 #include <common/mi-lttng.hpp>
11 #include <common/payload-view.hpp>
12 #include <common/payload.hpp>
13 #include <common/snapshot.hpp>
14
15 #include <lttng/action/action-internal.hpp>
16 #include <lttng/action/rate-policy-internal.hpp>
17 #include <lttng/action/rate-policy.h>
18 #include <lttng/action/snapshot-session-internal.hpp>
19 #include <lttng/action/snapshot-session.h>
20 #include <lttng/snapshot-internal.hpp>
21 #include <lttng/snapshot.h>
22
23 #include <inttypes.h>
24
25 #define IS_SNAPSHOT_SESSION_ACTION(action) \
26 (lttng_action_get_type(action) == LTTNG_ACTION_TYPE_SNAPSHOT_SESSION)
27
28 namespace {
29 struct lttng_action_snapshot_session {
30 struct lttng_action parent;
31
32 /* Owned by this. */
33 char *session_name;
34
35 /*
36 * When non-NULL, use this custom output when taking the snapshot,
37 * rather than the session's registered snapshot output.
38 *
39 * Owned by this.
40 */
41 struct lttng_snapshot_output *output;
42 struct lttng_rate_policy *policy;
43 };
44
45 struct lttng_action_snapshot_session_comm {
46 /* All string lengths include the trailing \0. */
47 uint32_t session_name_len;
48 uint32_t snapshot_output_len;
49 uint32_t rate_policy_len;
50
51 /*
52 * Variable data (all strings are null-terminated):
53 *
54 * - session name string
55 * - snapshot output object
56 * - policy object
57 */
58 char data[];
59 } LTTNG_PACKED;
60 } /* namespace */
61
62 static const struct lttng_rate_policy *
63 lttng_action_snapshot_session_internal_get_rate_policy(const struct lttng_action *action);
64
65 static struct lttng_action_snapshot_session *
66 action_snapshot_session_from_action(struct lttng_action *action)
67 {
68 LTTNG_ASSERT(action);
69
70 return lttng::utils::container_of(action, &lttng_action_snapshot_session::parent);
71 }
72
73 static const struct lttng_action_snapshot_session *
74 action_snapshot_session_from_action_const(const struct lttng_action *action)
75 {
76 LTTNG_ASSERT(action);
77
78 return lttng::utils::container_of(action, &lttng_action_snapshot_session::parent);
79 }
80
81 static bool lttng_action_snapshot_session_validate(struct lttng_action *action)
82 {
83 bool valid = false;
84 struct lttng_action_snapshot_session *action_snapshot_session;
85
86 if (!action) {
87 goto end;
88 }
89
90 action_snapshot_session = action_snapshot_session_from_action(action);
91
92 /* A non-empty session name is mandatory. */
93 if (!action_snapshot_session->session_name ||
94 strlen(action_snapshot_session->session_name) == 0) {
95 goto end;
96 }
97
98 if (action_snapshot_session->output &&
99 !lttng_snapshot_output_validate(action_snapshot_session->output)) {
100 goto end;
101 }
102
103 valid = true;
104 end:
105 return valid;
106 }
107
108 static bool lttng_action_snapshot_session_is_equal(const struct lttng_action *_a,
109 const struct lttng_action *_b)
110 {
111 bool is_equal = false;
112 const struct lttng_action_snapshot_session *a, *b;
113
114 a = action_snapshot_session_from_action_const(_a);
115 b = action_snapshot_session_from_action_const(_b);
116
117 /* Action is not valid if this is not true. */
118 LTTNG_ASSERT(a->session_name);
119 LTTNG_ASSERT(b->session_name);
120 if (strcmp(a->session_name, b->session_name) != 0) {
121 goto end;
122 }
123
124 if (a->output && b->output && !lttng_snapshot_output_is_equal(a->output, b->output)) {
125 goto end;
126 } else if (!!a->output != !!b->output) {
127 goto end;
128 }
129
130 is_equal = lttng_rate_policy_is_equal(a->policy, b->policy);
131 end:
132 return is_equal;
133 }
134
135 static size_t serialize_strlen(const char *str)
136 {
137 return str ? strlen(str) + 1 : 0;
138 }
139
140 static int lttng_action_snapshot_session_serialize(struct lttng_action *action,
141 struct lttng_payload *payload)
142 {
143 struct lttng_action_snapshot_session *action_snapshot_session;
144 struct lttng_action_snapshot_session_comm comm = {};
145 int ret;
146 size_t size_before_comm;
147
148 LTTNG_ASSERT(action);
149 LTTNG_ASSERT(payload);
150
151 size_before_comm = payload->buffer.size;
152
153 action_snapshot_session = action_snapshot_session_from_action(action);
154 comm.session_name_len = serialize_strlen(action_snapshot_session->session_name);
155
156 /* Add header. */
157 ret = lttng_dynamic_buffer_append(&payload->buffer, &comm, sizeof(comm));
158 if (ret) {
159 goto end;
160 }
161
162 LTTNG_ASSERT(action_snapshot_session->session_name);
163 DBG("Serializing snapshot session action: session-name: %s",
164 action_snapshot_session->session_name);
165
166 /* Add session name. */
167 ret = lttng_dynamic_buffer_append(
168 &payload->buffer, action_snapshot_session->session_name, comm.session_name_len);
169 if (ret) {
170 goto end;
171 }
172
173 /* Serialize the snapshot output object, if any. */
174 if (action_snapshot_session->output) {
175 const size_t size_before_output = payload->buffer.size;
176 struct lttng_action_snapshot_session_comm *comm_in_payload;
177
178 ret = lttng_snapshot_output_serialize(action_snapshot_session->output, payload);
179 if (ret) {
180 goto end;
181 }
182
183 comm_in_payload =
184 (typeof(comm_in_payload)) (payload->buffer.data + size_before_comm);
185 /* Adjust action length in header. */
186 comm_in_payload->snapshot_output_len = payload->buffer.size - size_before_output;
187 }
188
189 /* Serialize the rate policy. */
190 {
191 const size_t size_before_output = payload->buffer.size;
192 struct lttng_action_snapshot_session_comm *comm_in_payload;
193
194 ret = lttng_rate_policy_serialize(action_snapshot_session->policy, payload);
195 if (ret) {
196 ret = -1;
197 goto end;
198 }
199
200 comm_in_payload =
201 (typeof(comm_in_payload)) (payload->buffer.data + size_before_comm);
202 /* Adjust rate policy length in header. */
203 comm_in_payload->rate_policy_len = payload->buffer.size - size_before_output;
204 }
205
206 end:
207 return ret;
208 }
209
210 static void lttng_action_snapshot_session_destroy(struct lttng_action *action)
211 {
212 struct lttng_action_snapshot_session *action_snapshot_session;
213
214 if (!action) {
215 goto end;
216 }
217
218 action_snapshot_session = action_snapshot_session_from_action(action);
219
220 free(action_snapshot_session->session_name);
221 lttng_snapshot_output_destroy(action_snapshot_session->output);
222 lttng_rate_policy_destroy(action_snapshot_session->policy);
223 free(action_snapshot_session);
224
225 end:
226 return;
227 }
228
229 ssize_t lttng_action_snapshot_session_create_from_payload(struct lttng_payload_view *view,
230 struct lttng_action **p_action)
231 {
232 ssize_t consumed_len;
233 const char *variable_data;
234 struct lttng_action *action;
235 enum lttng_action_status status;
236 struct lttng_snapshot_output *snapshot_output = nullptr;
237 struct lttng_rate_policy *policy = nullptr;
238 const struct lttng_action_snapshot_session_comm *comm;
239 const struct lttng_payload_view snapshot_session_comm_view =
240 lttng_payload_view_from_view(view, 0, sizeof(*comm));
241
242 action = lttng_action_snapshot_session_create();
243 if (!action) {
244 goto error;
245 }
246
247 if (!lttng_payload_view_is_valid(&snapshot_session_comm_view)) {
248 /* Payload not large enough to contain the header. */
249 goto error;
250 }
251
252 comm = (typeof(comm)) snapshot_session_comm_view.buffer.data;
253 variable_data = (const char *) &comm->data;
254
255 consumed_len = sizeof(struct lttng_action_snapshot_session_comm);
256
257 if (!lttng_buffer_view_contains_string(
258 &view->buffer, variable_data, comm->session_name_len)) {
259 goto error;
260 }
261
262 status = lttng_action_snapshot_session_set_session_name(action, variable_data);
263 if (status != LTTNG_ACTION_STATUS_OK) {
264 goto error;
265 }
266
267 variable_data += comm->session_name_len;
268 consumed_len += comm->session_name_len;
269
270 /* If there is a snapshot output object, deserialize it. */
271 if (comm->snapshot_output_len > 0) {
272 ssize_t snapshot_output_consumed_len;
273 enum lttng_action_status action_status;
274 struct lttng_payload_view snapshot_output_buffer_view =
275 lttng_payload_view_from_view(view, consumed_len, comm->snapshot_output_len);
276
277 if (!lttng_payload_view_is_valid(&snapshot_output_buffer_view)) {
278 ERR("Failed to create buffer view for snapshot output.");
279 goto error;
280 }
281
282 snapshot_output_consumed_len = lttng_snapshot_output_create_from_payload(
283 &snapshot_output_buffer_view, &snapshot_output);
284 if (snapshot_output_consumed_len != comm->snapshot_output_len) {
285 ERR("Failed to deserialize snapshot output object: "
286 "consumed-len: %zd, expected-len: %" PRIu32,
287 snapshot_output_consumed_len,
288 comm->snapshot_output_len);
289 goto error;
290 }
291
292 action_status = lttng_action_snapshot_session_set_output(action, snapshot_output);
293 if (action_status != LTTNG_ACTION_STATUS_OK) {
294 goto error;
295 }
296
297 /* Ownership has been transferred to the action. */
298 snapshot_output = nullptr;
299 }
300
301 variable_data += comm->snapshot_output_len;
302 consumed_len += comm->snapshot_output_len;
303
304 /* Rate policy. */
305 if (comm->rate_policy_len <= 0) {
306 ERR("Rate policy should be present.");
307 goto error;
308 }
309 {
310 ssize_t rate_policy_consumed_len;
311 struct lttng_payload_view policy_view =
312 lttng_payload_view_from_view(view, consumed_len, comm->rate_policy_len);
313
314 if (!lttng_payload_view_is_valid(&policy_view)) {
315 ERR("Failed to create buffer view for rate policy.");
316 goto error;
317 }
318
319 rate_policy_consumed_len =
320 lttng_rate_policy_create_from_payload(&policy_view, &policy);
321 if (rate_policy_consumed_len < 0) {
322 goto error;
323 }
324
325 if (rate_policy_consumed_len != comm->rate_policy_len) {
326 ERR("Failed to deserialize rate policy object: "
327 "consumed-len: %zd, expected-len: %" PRIu32,
328 rate_policy_consumed_len,
329 comm->rate_policy_len);
330 goto error;
331 }
332
333 status = lttng_action_snapshot_session_set_rate_policy(action, policy);
334 if (status != LTTNG_ACTION_STATUS_OK) {
335 goto error;
336 }
337 }
338
339 variable_data += comm->rate_policy_len;
340 consumed_len += comm->rate_policy_len;
341
342 *p_action = action;
343 action = nullptr;
344
345 goto end;
346
347 error:
348 consumed_len = -1;
349
350 end:
351 lttng_rate_policy_destroy(policy);
352 lttng_action_snapshot_session_destroy(action);
353 lttng_snapshot_output_destroy(snapshot_output);
354
355 return consumed_len;
356 }
357
358 static enum lttng_error_code
359 lttng_action_snapshot_session_mi_serialize(const struct lttng_action *action,
360 struct mi_writer *writer)
361 {
362 int ret;
363 enum lttng_error_code ret_code;
364 enum lttng_action_status status;
365 const char *session_name = nullptr;
366 const struct lttng_snapshot_output *output = nullptr;
367 const struct lttng_rate_policy *policy = nullptr;
368
369 LTTNG_ASSERT(action);
370 LTTNG_ASSERT(IS_SNAPSHOT_SESSION_ACTION(action));
371
372 status = lttng_action_snapshot_session_get_session_name(action, &session_name);
373 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
374 LTTNG_ASSERT(session_name != nullptr);
375
376 status = lttng_action_snapshot_session_get_rate_policy(action, &policy);
377 LTTNG_ASSERT(status == LTTNG_ACTION_STATUS_OK);
378 LTTNG_ASSERT(policy != nullptr);
379
380 /* Open action snapshot session element. */
381 ret = mi_lttng_writer_open_element(writer, mi_lttng_element_action_snapshot_session);
382 if (ret) {
383 goto mi_error;
384 }
385
386 /* Session name. */
387 ret = mi_lttng_writer_write_element_string(
388 writer, mi_lttng_element_session_name, session_name);
389 if (ret) {
390 goto mi_error;
391 }
392
393 /* Output if any. */
394 status = lttng_action_snapshot_session_get_output(action, &output);
395 if (status == LTTNG_ACTION_STATUS_OK) {
396 LTTNG_ASSERT(output != nullptr);
397 ret_code = lttng_snapshot_output_mi_serialize(output, writer);
398 if (ret_code != LTTNG_OK) {
399 goto end;
400 }
401 } else if (status != LTTNG_ACTION_STATUS_UNSET) {
402 /* This should not happen at this point. */
403 abort();
404 }
405
406 /* Rate policy. */
407 ret_code = lttng_rate_policy_mi_serialize(policy, writer);
408 if (ret_code != LTTNG_OK) {
409 goto end;
410 }
411
412 /* Close action_snapshot_session element. */
413 ret = mi_lttng_writer_close_element(writer);
414 if (ret) {
415 goto mi_error;
416 }
417
418 ret_code = LTTNG_OK;
419 goto end;
420
421 mi_error:
422 ret_code = LTTNG_ERR_MI_IO_FAIL;
423 end:
424 return ret_code;
425 }
426
427 struct lttng_action *lttng_action_snapshot_session_create(void)
428 {
429 struct lttng_action_snapshot_session *action_snapshot = nullptr;
430 struct lttng_rate_policy *policy = nullptr;
431 enum lttng_action_status status;
432
433 /* Create a every N = 1 rate policy. */
434 policy = lttng_rate_policy_every_n_create(1);
435 if (!policy) {
436 goto end;
437 }
438
439 action_snapshot = zmalloc<lttng_action_snapshot_session>();
440 if (!action_snapshot) {
441 goto end;
442 }
443
444 lttng_action_init(&action_snapshot->parent,
445 LTTNG_ACTION_TYPE_SNAPSHOT_SESSION,
446 lttng_action_snapshot_session_validate,
447 lttng_action_snapshot_session_serialize,
448 lttng_action_snapshot_session_is_equal,
449 lttng_action_snapshot_session_destroy,
450 lttng_action_snapshot_session_internal_get_rate_policy,
451 lttng_action_generic_add_error_query_results,
452 lttng_action_snapshot_session_mi_serialize);
453
454 status = lttng_action_snapshot_session_set_rate_policy(&action_snapshot->parent, policy);
455 if (status != LTTNG_ACTION_STATUS_OK) {
456 lttng_action_destroy(&action_snapshot->parent);
457 action_snapshot = nullptr;
458 goto end;
459 }
460
461 end:
462 lttng_rate_policy_destroy(policy);
463 return action_snapshot ? &action_snapshot->parent : nullptr;
464 }
465
466 enum lttng_action_status lttng_action_snapshot_session_set_session_name(struct lttng_action *action,
467 const char *session_name)
468 {
469 struct lttng_action_snapshot_session *action_snapshot_session;
470 enum lttng_action_status status;
471
472 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name ||
473 strlen(session_name) == 0) {
474 status = LTTNG_ACTION_STATUS_INVALID;
475 goto end;
476 }
477
478 action_snapshot_session = action_snapshot_session_from_action(action);
479
480 free(action_snapshot_session->session_name);
481
482 action_snapshot_session->session_name = strdup(session_name);
483 if (!action_snapshot_session->session_name) {
484 status = LTTNG_ACTION_STATUS_ERROR;
485 goto end;
486 }
487
488 status = LTTNG_ACTION_STATUS_OK;
489 end:
490 return status;
491 }
492
493 enum lttng_action_status
494 lttng_action_snapshot_session_get_session_name(const struct lttng_action *action,
495 const char **session_name)
496 {
497 const struct lttng_action_snapshot_session *action_snapshot_session;
498 enum lttng_action_status status;
499
500 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !session_name) {
501 status = LTTNG_ACTION_STATUS_INVALID;
502 goto end;
503 }
504
505 action_snapshot_session = action_snapshot_session_from_action_const(action);
506
507 if (action_snapshot_session->session_name) {
508 *session_name = action_snapshot_session->session_name;
509 status = LTTNG_ACTION_STATUS_OK;
510 } else {
511 status = LTTNG_ACTION_STATUS_UNSET;
512 }
513
514 end:
515
516 return status;
517 }
518
519 enum lttng_action_status
520 lttng_action_snapshot_session_set_output(struct lttng_action *action,
521 struct lttng_snapshot_output *output)
522 {
523 struct lttng_action_snapshot_session *action_snapshot_session;
524 enum lttng_action_status status;
525
526 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
527 status = LTTNG_ACTION_STATUS_INVALID;
528 goto end;
529 }
530
531 action_snapshot_session = action_snapshot_session_from_action(action);
532
533 lttng_snapshot_output_destroy(action_snapshot_session->output);
534 action_snapshot_session->output = output;
535
536 status = LTTNG_ACTION_STATUS_OK;
537
538 end:
539 return status;
540 }
541
542 enum lttng_action_status
543 lttng_action_snapshot_session_get_output(const struct lttng_action *action,
544 const struct lttng_snapshot_output **output)
545 {
546 const struct lttng_action_snapshot_session *action_snapshot_session;
547 enum lttng_action_status status;
548
549 if (!action || !IS_SNAPSHOT_SESSION_ACTION(action) || !output) {
550 status = LTTNG_ACTION_STATUS_INVALID;
551 goto end;
552 }
553
554 action_snapshot_session = action_snapshot_session_from_action_const(action);
555
556 if (action_snapshot_session->output) {
557 *output = action_snapshot_session->output;
558 status = LTTNG_ACTION_STATUS_OK;
559 } else {
560 status = LTTNG_ACTION_STATUS_UNSET;
561 }
562
563 end:
564 return status;
565 }
566
567 enum lttng_action_status
568 lttng_action_snapshot_session_set_rate_policy(struct lttng_action *action,
569 const struct lttng_rate_policy *policy)
570 {
571 enum lttng_action_status status;
572 struct lttng_action_snapshot_session *snapshot_session_action;
573 struct lttng_rate_policy *copy = nullptr;
574
575 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
576 status = LTTNG_ACTION_STATUS_INVALID;
577 goto end;
578 }
579
580 copy = lttng_rate_policy_copy(policy);
581 if (!copy) {
582 status = LTTNG_ACTION_STATUS_ERROR;
583 goto end;
584 }
585
586 snapshot_session_action = action_snapshot_session_from_action(action);
587
588 /* Free the previous rate policy .*/
589 lttng_rate_policy_destroy(snapshot_session_action->policy);
590
591 /* Assign the policy. */
592 snapshot_session_action->policy = copy;
593 status = LTTNG_ACTION_STATUS_OK;
594 copy = nullptr;
595
596 end:
597 lttng_rate_policy_destroy(copy);
598 return status;
599 }
600
601 enum lttng_action_status
602 lttng_action_snapshot_session_get_rate_policy(const struct lttng_action *action,
603 const struct lttng_rate_policy **policy)
604 {
605 enum lttng_action_status status;
606 const struct lttng_action_snapshot_session *snapshot_session_action;
607
608 if (!action || !policy || !IS_SNAPSHOT_SESSION_ACTION(action)) {
609 status = LTTNG_ACTION_STATUS_INVALID;
610 goto end;
611 }
612
613 snapshot_session_action = action_snapshot_session_from_action_const(action);
614
615 *policy = snapshot_session_action->policy;
616 status = LTTNG_ACTION_STATUS_OK;
617 end:
618 return status;
619 }
620
621 static const struct lttng_rate_policy *
622 lttng_action_snapshot_session_internal_get_rate_policy(const struct lttng_action *action)
623 {
624 const struct lttng_action_snapshot_session *_action;
625 _action = action_snapshot_session_from_action_const(action);
626
627 return _action->policy;
628 }
This page took 0.063313 seconds and 4 git commands to generate.