Add logging to notification API error paths
[lttng-tools.git] / src / common / buffer-usage.c
CommitLineData
f42dcd79
JG
1/*
2 * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
3 *
4 * This library is free software; you can redistribute it and/or modify it
5 * under the terms of the GNU Lesser General Public License, version 2.1 only,
6 * as published by the Free Software Foundation.
7 *
8 * This library is distributed in the hope that it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
11 * for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public License
14 * along with this library; if not, write to the Free Software Foundation,
15 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
16 */
17
18#include <lttng/condition/condition-internal.h>
19#include <lttng/condition/buffer-usage-internal.h>
20#include <common/macros.h>
45fdf591 21#include <common/error.h>
f42dcd79
JG
22#include <assert.h>
23
24static
25bool is_usage_condition(struct lttng_condition *condition)
26{
27 enum lttng_condition_type type = lttng_condition_get_type(condition);
28
29 return type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW ||
30 type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
31}
32
33static
e892d3f7 34bool is_usage_evaluation(struct lttng_evaluation *evaluation)
f42dcd79 35{
e892d3f7
JG
36 enum lttng_condition_type type = lttng_evaluation_get_type(evaluation);
37
38 return type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW ||
39 type == LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH;
f42dcd79
JG
40}
41
42static
43void lttng_condition_buffer_usage_destroy(struct lttng_condition *condition)
44{
45 struct lttng_condition_buffer_usage *usage;
46
47 usage = container_of(condition, struct lttng_condition_buffer_usage,
48 parent);
49
50 free(usage->session_name);
51 free(usage->channel_name);
52 free(usage);
53}
54
55static
56bool lttng_condition_buffer_usage_validate(struct lttng_condition *condition)
57{
58 bool valid = false;
59 struct lttng_condition_buffer_usage *usage;
60
61 if (!condition) {
62 goto end;
63 }
64
65 usage = container_of(condition, struct lttng_condition_buffer_usage,
66 parent);
67 if (!usage->session_name) {
45fdf591 68 ERR("Invalid buffer condition: a target session name must be set.");
f42dcd79
JG
69 goto end;
70 }
71 if (!usage->channel_name) {
45fdf591 72 ERR("Invalid buffer condition: a target channel name must be set.");
f42dcd79
JG
73 goto end;
74 }
75 if (!usage->threshold_percent.set && !usage->threshold_bytes.set) {
45fdf591 76 ERR("Invalid buffer condition: a threshold must be set.");
f42dcd79
JG
77 goto end;
78 }
79
80 valid = true;
81end:
82 return valid;
83}
84
2a38b722
JG
85static
86ssize_t lttng_condition_buffer_usage_serialize(struct lttng_condition *condition,
87 char *buf)
88{
89 struct lttng_condition_buffer_usage *usage;
90 ssize_t size;
91 size_t session_name_len, channel_name_len;
92
93 if (!condition || !is_usage_condition(condition)) {
94 size = -1;
95 goto end;
96 }
97
45fdf591 98 DBG("Serializing buffer usage condition");
2a38b722
JG
99 usage = container_of(condition, struct lttng_condition_buffer_usage,
100 parent);
101 size = sizeof(struct lttng_condition_buffer_usage_comm);
102 session_name_len = strlen(usage->session_name) + 1;
103 channel_name_len = strlen(usage->channel_name) + 1;
104 size += session_name_len + channel_name_len;
105 if (buf) {
106 struct lttng_condition_buffer_usage_comm usage_comm = {
107 .threshold_set_in_bytes = usage->threshold_bytes.set ? 1 : 0,
108 .session_name_len = session_name_len,
109 .channel_name_len = channel_name_len,
110 .domain_type = (int8_t) usage->domain.type,
111 };
112
113 if (usage->threshold_bytes.set) {
114 usage_comm.threshold.bytes =
115 usage->threshold_bytes.value;
116 } else {
117 usage_comm.threshold.percent =
118 usage->threshold_percent.value;
119 }
120
121 memcpy(buf, &usage_comm, sizeof(usage_comm));
122 buf += sizeof(usage_comm);
123 memcpy(buf, usage->session_name, session_name_len);
124 buf += session_name_len;
125 memcpy(buf, usage->channel_name, channel_name_len);
126 buf += channel_name_len;
127 }
128end:
129 return size;
130}
131
f42dcd79
JG
132static
133struct lttng_condition *lttng_condition_buffer_usage_create(
134 enum lttng_condition_type type)
135{
136 struct lttng_condition_buffer_usage *condition;
137
138 condition = zmalloc(sizeof(struct lttng_condition_buffer_usage));
139 if (!condition) {
140 goto end;
141 }
142
143 condition->parent.type = type;
144 condition->parent.validate = lttng_condition_buffer_usage_validate;
2a38b722 145 condition->parent.serialize = lttng_condition_buffer_usage_serialize;
f42dcd79
JG
146 condition->parent.destroy = lttng_condition_buffer_usage_destroy;
147end:
148 return &condition->parent;
149}
150
151struct lttng_condition *lttng_condition_buffer_usage_low_create(void)
152{
153 return lttng_condition_buffer_usage_create(
154 LTTNG_CONDITION_TYPE_BUFFER_USAGE_LOW);
155}
156
157struct lttng_condition *lttng_condition_buffer_usage_high_create(void)
158{
159 return lttng_condition_buffer_usage_create(
160 LTTNG_CONDITION_TYPE_BUFFER_USAGE_HIGH);
161}
162
0883d500
JG
163static
164ssize_t init_from_buffer(struct lttng_condition *condition, const char *buf)
165{
166 ssize_t ret, condition_size;
167 enum lttng_condition_status status;
168 enum lttng_domain_type domain_type;
169 struct lttng_condition_buffer_usage_comm *condition_comm =
170 (struct lttng_condition_buffer_usage_comm *) buf;
171 const char *session_name, *channel_name;
172
173 if (condition_comm->threshold_set_in_bytes) {
174 status = lttng_condition_buffer_usage_set_threshold(condition,
175 condition_comm->threshold.bytes);
176 } else {
177 status = lttng_condition_buffer_usage_set_threshold_percentage(
178 condition, condition_comm->threshold.percent);
179 }
180 if (status != LTTNG_CONDITION_STATUS_OK) {
45fdf591 181 ERR("Failed to initialize buffer usage condition threshold");
0883d500
JG
182 ret = -1;
183 goto end;
184 }
185
186 if (condition_comm->domain_type <= LTTNG_DOMAIN_NONE ||
187 condition_comm->domain_type > LTTNG_DOMAIN_PYTHON) {
188 /* Invalid domain value. */
45fdf591
JG
189 ERR("Invalid domain type value (%i) found in condition buffer",
190 (int) condition_comm->domain_type);
0883d500
JG
191 ret = -1;
192 goto end;
193 }
194
195 domain_type = (enum lttng_domain_type) condition_comm->domain_type;
196 status = lttng_condition_buffer_usage_set_domain_type(condition,
197 domain_type);
198 if (status != LTTNG_CONDITION_STATUS_OK) {
45fdf591 199 ERR("Failed to set buffer usage condition domain");
0883d500
JG
200 ret = -1;
201 goto end;
202 }
203
204 session_name = buf + sizeof(struct lttng_condition_buffer_usage_comm);
205 channel_name = session_name + condition_comm->session_name_len;
206
207 status = lttng_condition_buffer_usage_set_session_name(condition,
208 session_name);
209 if (status != LTTNG_CONDITION_STATUS_OK) {
45fdf591 210 ERR("Failed to set buffer usage session name");
0883d500
JG
211 ret = -1;
212 goto end;
213 }
214
215 status = lttng_condition_buffer_usage_set_channel_name(condition,
216 channel_name);
217 if (status != LTTNG_CONDITION_STATUS_OK) {
45fdf591 218 ERR("Failed to set buffer usage channel name");
0883d500
JG
219 ret = -1;
220 goto end;
221 }
222
223 if (!lttng_condition_validate(condition)) {
224 ret = -1;
225 goto end;
226 }
227
228 condition_size = sizeof(*condition_comm);
229 condition_size += (ssize_t) condition_comm->session_name_len;
230 condition_size += (ssize_t) condition_comm->channel_name_len;
231 ret = condition_size;
232end:
233 return ret;
234}
235
236LTTNG_HIDDEN
237ssize_t lttng_condition_buffer_usage_low_create_from_buffer(const char *buf,
238 struct lttng_condition **_condition)
239{
240 ssize_t ret;
241 struct lttng_condition *condition =
242 lttng_condition_buffer_usage_low_create();
243
244 if (!_condition || !condition) {
245 ret = -1;
246 goto error;
247 }
248
45fdf591 249 DBG("Initializing low buffer usage condition from buffer");
0883d500
JG
250 ret = init_from_buffer(condition, buf);
251 if (ret < 0) {
252 goto error;
253 }
254
255 *_condition = condition;
256 return ret;
257error:
258 lttng_condition_destroy(condition);
259 return ret;
260}
261
262LTTNG_HIDDEN
263ssize_t lttng_condition_buffer_usage_high_create_from_buffer(const char *buf,
264 struct lttng_condition **_condition)
265{
266 ssize_t ret;
267 struct lttng_condition *condition =
268 lttng_condition_buffer_usage_high_create();
269
270 if (!_condition || !condition) {
271 ret = -1;
272 goto error;
273 }
274
45fdf591 275 DBG("Initializing high buffer usage condition from buffer");
0883d500
JG
276 ret = init_from_buffer(condition, buf);
277 if (ret < 0) {
278 goto error;
279 }
280
281 *_condition = condition;
282 return ret;
283error:
284 lttng_condition_destroy(condition);
285 return ret;
286}
287
f42dcd79
JG
288enum lttng_condition_status
289lttng_condition_buffer_usage_get_threshold_percentage(
290 struct lttng_condition *condition, double *threshold_percent)
291{
292 struct lttng_condition_buffer_usage *usage;
293 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
294
295 if (!condition || !is_usage_condition(condition) ||
296 !threshold_percent) {
297 status = LTTNG_CONDITION_STATUS_INVALID;
298 goto end;
299 }
300
301 usage = container_of(condition, struct lttng_condition_buffer_usage,
302 parent);
303 if (!usage->threshold_percent.set) {
304 status = LTTNG_CONDITION_STATUS_UNSET;
305 goto end;
306 }
307 *threshold_percent = usage->threshold_percent.value;
308end:
309 return status;
310}
311
312/* threshold_percent expressed as [0.0, 1.0]. */
313enum lttng_condition_status
314lttng_condition_buffer_usage_set_threshold_percentage(
315 struct lttng_condition *condition, double threshold_percent)
316{
317 struct lttng_condition_buffer_usage *usage;
318 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
319
320 if (!condition || !is_usage_condition(condition) ||
321 threshold_percent < 0.0 || threshold_percent > 1.0) {
322 status = LTTNG_CONDITION_STATUS_INVALID;
323 goto end;
324 }
325
326 usage = container_of(condition, struct lttng_condition_buffer_usage,
327 parent);
328 usage->threshold_percent.set = true;
329 usage->threshold_bytes.set = false;
330 usage->threshold_percent.value = threshold_percent;
331end:
332 return status;
333}
334
335enum lttng_condition_status
336lttng_condition_buffer_usage_get_threshold(
337 struct lttng_condition *condition, uint64_t *threshold_bytes)
338{
339 struct lttng_condition_buffer_usage *usage;
340 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
341
342 if (!condition || !is_usage_condition(condition) || !threshold_bytes) {
343 status = LTTNG_CONDITION_STATUS_INVALID;
344 goto end;
345 }
346
347 usage = container_of(condition, struct lttng_condition_buffer_usage,
348 parent);
349 if (!usage->threshold_bytes.set) {
350 status = LTTNG_CONDITION_STATUS_UNSET;
351 goto end;
352 }
353 *threshold_bytes = usage->threshold_bytes.value;
354end:
355 return status;
356}
357
358enum lttng_condition_status
359lttng_condition_buffer_usage_set_threshold(
360 struct lttng_condition *condition, uint64_t threshold_bytes)
361{
362 struct lttng_condition_buffer_usage *usage;
363 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
364
365 if (!condition || !is_usage_condition(condition)) {
366 status = LTTNG_CONDITION_STATUS_INVALID;
367 goto end;
368 }
369
370 usage = container_of(condition, struct lttng_condition_buffer_usage,
371 parent);
372 usage->threshold_percent.set = false;
373 usage->threshold_bytes.set = true;
374 usage->threshold_bytes.value = threshold_bytes;
375end:
376 return status;
377}
378
379enum lttng_condition_status
380lttng_condition_buffer_usage_get_session_name(
381 struct lttng_condition *condition, const char **session_name)
382{
383 struct lttng_condition_buffer_usage *usage;
384 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
385
386 if (!condition || !is_usage_condition(condition) || !session_name) {
387 status = LTTNG_CONDITION_STATUS_INVALID;
388 goto end;
389 }
390
391 usage = container_of(condition, struct lttng_condition_buffer_usage,
392 parent);
393 if (!usage->session_name) {
394 status = LTTNG_CONDITION_STATUS_UNSET;
395 goto end;
396 }
397 *session_name = usage->session_name;
398end:
399 return status;
400}
401
402extern enum lttng_condition_status
403lttng_condition_buffer_usage_set_session_name(
404 struct lttng_condition *condition, const char *session_name)
405{
406 struct lttng_condition_buffer_usage *usage;
407 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
408
409 if (!condition || !is_usage_condition(condition) || !session_name ||
410 strlen(session_name) == 0) {
411 status = LTTNG_CONDITION_STATUS_INVALID;
412 goto end;
413 }
414
415 usage = container_of(condition, struct lttng_condition_buffer_usage,
416 parent);
417 usage->session_name = strdup(session_name);
418 if (!usage->session_name) {
419 status = LTTNG_CONDITION_STATUS_ERROR;
420 goto end;
421 }
422end:
423 return status;
424}
425
426enum lttng_condition_status
427lttng_condition_buffer_usage_get_channel_name(
428 struct lttng_condition *condition, const char **channel_name)
429{
430 struct lttng_condition_buffer_usage *usage;
431 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
432
433 if (!condition || !is_usage_condition(condition) || !channel_name) {
434 status = LTTNG_CONDITION_STATUS_INVALID;
435 goto end;
436 }
437
438 usage = container_of(condition, struct lttng_condition_buffer_usage,
439 parent);
440 if (!usage->channel_name) {
441 status = LTTNG_CONDITION_STATUS_UNSET;
442 goto end;
443 }
444 *channel_name = usage->channel_name;
445end:
446 return status;
447}
448
449extern enum lttng_condition_status
450lttng_condition_buffer_usage_set_channel_name(
451 struct lttng_condition *condition, const char *channel_name)
452{
453 struct lttng_condition_buffer_usage *usage;
454 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
455
456 if (!condition || !is_usage_condition(condition) || !channel_name ||
457 strlen(channel_name) == 0) {
458 status = LTTNG_CONDITION_STATUS_INVALID;
459 goto end;
460 }
461
462 usage = container_of(condition, struct lttng_condition_buffer_usage,
463 parent);
464 usage->channel_name = strdup(channel_name);
465 if (!usage->channel_name) {
466 status = LTTNG_CONDITION_STATUS_ERROR;
467 goto end;
468 }
469end:
470 return status;
471}
472
473extern enum lttng_condition_status
474lttng_condition_buffer_usage_get_domain_type(
475 struct lttng_condition *condition, enum lttng_domain_type *type)
476{
477 struct lttng_condition_buffer_usage *usage;
478 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
479
480 if (!condition || !is_usage_condition(condition) || !type) {
481 status = LTTNG_CONDITION_STATUS_INVALID;
482 goto end;
483 }
484
485 usage = container_of(condition, struct lttng_condition_buffer_usage,
486 parent);
487 if (!usage->domain.set) {
488 status = LTTNG_CONDITION_STATUS_UNSET;
489 goto end;
490 }
491 *type = usage->domain.type;
492end:
493 return status;
494}
495
496extern enum lttng_condition_status
497lttng_condition_buffer_usage_set_domain_type(
498 struct lttng_condition *condition, enum lttng_domain_type type)
499{
500 struct lttng_condition_buffer_usage *usage;
501 enum lttng_condition_status status = LTTNG_CONDITION_STATUS_OK;
502
503 if (!condition || !is_usage_condition(condition) ||
504 type == LTTNG_DOMAIN_NONE) {
505 status = LTTNG_CONDITION_STATUS_INVALID;
506 goto end;
507 }
508
509 usage = container_of(condition, struct lttng_condition_buffer_usage,
510 parent);
511 usage->domain.set = true;
512 usage->domain.type = type;
513end:
514 return status;
515}
e892d3f7
JG
516
517static
518void lttng_evaluation_buffer_usage_destroy(
519 struct lttng_evaluation *evaluation)
520{
521 struct lttng_evaluation_buffer_usage *usage;
522
523 usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
524 parent);
525 free(usage);
526}
527
528LTTNG_HIDDEN
529struct lttng_evaluation *lttng_evaluation_buffer_usage_create(uint64_t use,
530 uint64_t capacity)
531{
532 struct lttng_evaluation_buffer_usage *usage;
533
534 usage = zmalloc(sizeof(struct lttng_evaluation_buffer_usage));
535 if (!usage) {
536 goto end;
537 }
538
539 usage->buffer_use = use;
540 usage->buffer_capacity = capacity;
541 usage->parent.destroy = lttng_evaluation_buffer_usage_destroy;
542end:
543 return &usage->parent;
544}
545
546/*
547 * Get the sampled buffer usage which caused the associated condition to
548 * evaluate to "true".
549 */
550enum lttng_evaluation_status
551lttng_evaluation_buffer_usage_get_usage_percentage(
552 struct lttng_evaluation *evaluation, double *usage_percent)
553{
554 struct lttng_evaluation_buffer_usage *usage;
555 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
556
557 if (!evaluation || !is_usage_evaluation(evaluation) || !usage_percent) {
558 status = LTTNG_EVALUATION_STATUS_INVALID;
559 goto end;
560 }
561
562 usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
563 parent);
564 *usage_percent = (double) usage->buffer_use /
565 (double) usage->buffer_capacity;
566end:
567 return status;
568}
569
570enum lttng_evaluation_status
571lttng_evaluation_buffer_usage_get_usage(struct lttng_evaluation *evaluation,
572 uint64_t *usage_bytes)
573{
574 struct lttng_evaluation_buffer_usage *usage;
575 enum lttng_evaluation_status status = LTTNG_EVALUATION_STATUS_OK;
576
577 if (!evaluation || !is_usage_evaluation(evaluation) || !usage_bytes) {
578 status = LTTNG_EVALUATION_STATUS_INVALID;
579 goto end;
580 }
581
582 usage = container_of(evaluation, struct lttng_evaluation_buffer_usage,
583 parent);
584 *usage_bytes = usage->buffer_use;
585end:
586 return status;
587}
This page took 0.04593 seconds and 5 git commands to generate.