From 66ea93b10c703e1b3dda1e17109eed9138e4ece2 Mon Sep 17 00:00:00 2001 From: =?utf8?q?J=C3=A9r=C3=A9mie=20Galarneau?= Date: Mon, 6 Aug 2018 16:36:12 -0400 Subject: [PATCH] rotation-api: introduce rotation schedule descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The current rotation API is limited in that it imposes two types of automatic rotation. This change introduces rotation schedules, a more generic concept, that will eventually allow an arbitrary number of rotation schedules to be set on a session. Moreover, the API's design is now more aligned with the APIs that were recently added (i.e. use of opaque descriptors for commands that may require more parameters at some point). Signed-off-by: Jérémie Galarneau --- include/lttng/lttng-error.h | 16 +- include/lttng/rotate-internal.h | 69 +-- include/lttng/rotation.h | 181 ++++++-- src/bin/lttng-sessiond/cmd.c | 129 ++++-- src/bin/lttng-sessiond/cmd.h | 5 +- src/bin/lttng-sessiond/main.c | 64 +-- src/bin/lttng-sessiond/session.h | 3 +- src/bin/lttng/commands/disable_rotation.c | 289 ++++++++---- src/bin/lttng/commands/enable_rotation.c | 295 +++++++----- src/bin/lttng/commands/list.c | 164 +++++-- src/bin/lttng/commands/rotate.c | 6 +- src/common/config/session-config.c | 96 +++- src/common/error.c | 6 +- src/common/mi-lttng-3.0.xsd | 45 +- src/common/mi-lttng.c | 113 ++++- src/common/mi-lttng.h | 48 +- src/common/sessiond-comm/sessiond-comm.h | 95 ++-- src/lib/lttng-ctl/rotate.c | 425 ++++++++++++++---- .../tools/rotation/test_save_load_mi | 18 +- 19 files changed, 1489 insertions(+), 578 deletions(-) diff --git a/include/lttng/lttng-error.h b/include/lttng/lttng-error.h index 3c72aeeec..c6c2daec9 100644 --- a/include/lttng/lttng-error.h +++ b/include/lttng/lttng-error.h @@ -151,15 +151,13 @@ enum lttng_error_code { LTTNG_ERR_COMMAND_CANCELLED = 128, /* Command cancelled. */ LTTNG_ERR_ROTATION_PENDING = 129, /* Rotate already pending for this session. */ LTTNG_ERR_ROTATION_NOT_AVAILABLE = 130, /* Rotate feature not available for this type of session (e.g: live) */ - LTTNG_ERR_ROTATION_TIMER_SET = 131, /* Timer-based rotation schedule already set for this session. */ - LTTNG_ERR_ROTATION_SIZE_SET = 132, /* Size-based rotation schedule already set for this session. */ - LTTNG_ERR_ROTATION_NO_TIMER_SET = 133, /* No timer-based rotation schedule set for this session. */ - LTTNG_ERR_ROTATION_NO_SIZE_SET = 134, /* No size-based rotation schedule set for this session. */ - LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP = 135, /* Already rotated once after a stop. */ - LTTNG_ERR_ROTATION_WRONG_VERSION = 136, /* Session rotation not supported by this kernel tracer version */ - LTTNG_ERR_NO_SESSION_OUTPUT = 137, /* Session has no output configured. */ - LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY = 138, /* Rotate feature not available on the relay. */ - LTTNG_ERR_AGENT_TRACING_DISABLED = 139, /* Agent tracing disabled. */ + LTTNG_ERR_ROTATION_SCHEDULE_SET = 131, /* Schedule type already set for this session. */ + LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET = 132, /* No schedule of this type set for this session. */ + LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP = 133, /* Already rotated once after a stop. */ + LTTNG_ERR_ROTATION_WRONG_VERSION = 134, /* Session rotation not supported by this kernel tracer version */ + LTTNG_ERR_NO_SESSION_OUTPUT = 135, /* Session has no output configured. */ + LTTNG_ERR_ROTATION_NOT_AVAILABLE_RELAY = 136, /* Rotate feature not available on the relay. */ + LTTNG_ERR_AGENT_TRACING_DISABLED = 137, /* Agent tracing disabled. */ /* MUST be last element */ LTTNG_ERR_NR, /* Last element */ diff --git a/include/lttng/rotate-internal.h b/include/lttng/rotate-internal.h index 8d0823b7a..966f9f969 100644 --- a/include/lttng/rotate-internal.h +++ b/include/lttng/rotate-internal.h @@ -26,28 +26,6 @@ #include #include -/* - * Object used as input parameter to the rotate session API for immediate - * rotations. - * This is opaque to the public library. - */ -struct lttng_rotation_immediate_attr { - /* For the rotate pending request. */ - uint64_t rotate_id; -}; - -/* - * Object used as input parameter to the lttng_rotate_schedule API for - * automatic rotations. - * This is opaque to the public library. - */ -struct lttng_rotation_schedule_attr { - /* > 0 if a timer is set. */ - uint64_t timer_us; - /* > 0 if the session should rotate when it has written that many bytes. */ - uint64_t size; -} LTTNG_PACKED; - /* * Object returned by the rotate session API. * This is opaque to the public library. @@ -68,6 +46,35 @@ struct lttng_rotation_handle { struct lttng_trace_archive_location *archive_location; }; +struct lttng_rotation_schedule { + enum lttng_rotation_schedule_type type; +}; + +struct lttng_rotation_schedule_size_threshold { + struct lttng_rotation_schedule parent; + struct { + bool set; + uint64_t bytes; + } size; +}; + +struct lttng_rotation_schedule_periodic { + struct lttng_rotation_schedule parent; + struct { + bool set; + uint64_t us; + } period; +}; + +struct lttng_rotation_schedules { + /* + * Only one rotation schedule per type is supported for now. + * Schedules are owned by this object. + */ + unsigned int count; + struct lttng_rotation_schedule *schedules[2]; +}; + /* * Internal objects between lttng-ctl and the session daemon, the values * are then copied to the user's lttng_rotation_handle object. @@ -109,14 +116,16 @@ struct lttng_session_get_current_output_return { char path[LTTNG_PATH_MAX]; } LTTNG_PACKED; -/* For the LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD command. */ -struct lttng_rotation_schedule_get_timer_period { - uint64_t rotate_timer; -} LTTNG_PACKED; - -/* For the LTTNG_ROTATION_SCHEDULE_GET_SIZE command. */ -struct lttng_rotation_schedule_get_size { - uint64_t rotate_size; +/* For the LTTNG_SESSION_LIST_SCHEDULES command. */ +struct lttng_session_list_schedules_return { + struct { + uint8_t set; + uint64_t value; + } periodic; + struct { + uint8_t set; + uint64_t value; + } size; } LTTNG_PACKED; #endif /* LTTNG_ROTATE_INTERNAL_ABI_H */ diff --git a/include/lttng/rotation.h b/include/lttng/rotation.h index 6091a7b98..d13f3641a 100644 --- a/include/lttng/rotation.h +++ b/include/lttng/rotation.h @@ -68,51 +68,38 @@ enum lttng_rotation_status { LTTNG_ROTATION_STATUS_ERROR = -1, /* Invalid parameters provided. */ LTTNG_ROTATION_STATUS_INVALID = -2, + /* A schedule of this type is already set. */ + LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET = -3, + /* No such rotation schedule set. */ + LTTNG_ROTATION_STATUS_SCHEDULE_NOT_SET = -3, }; -/* - * Input parameter to the lttng_rotate_session command. - * - * An immediate rotation is performed as soon as possible by the tracers. - */ -struct lttng_rotation_immediate_attr; - -/* - * Input parameter to the lttng_rotate_schedule command. - */ -struct lttng_rotation_schedule_attr; - -/* - * Handle used to represent a specific rotation. - */ -struct lttng_rotation_handle; +enum lttng_rotation_schedule_type { + LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN = -1, + LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD = 0, + LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC = 1, +}; /* - * Return a newly allocated session rotation schedule descriptor object or NULL - * on error. - * - * The rotation schedule may be expressed as a size or as a time period. + * Descriptor of an immediate session rotation to be performed as soon as + * possible by the tracers. */ -extern struct lttng_rotation_schedule_attr * -lttng_rotation_schedule_attr_create(void); +struct lttng_rotation_immediate_descriptor; /* - * Destroy a given scheduled rotate session descriptor object. + * Session rotation schedule to add to a session. */ -extern void lttng_rotation_schedule_attr_destroy( - struct lttng_rotation_schedule_attr *attr); +struct lttng_rotation_schedule; /* - * Set the timer to periodically rotate the session (in µs). + * A set of lttng_rotation_schedule objects. */ -extern enum lttng_rotation_status lttng_rotation_schedule_attr_set_timer_period( - struct lttng_rotation_schedule_attr *attr, uint64_t timer); +struct lttng_rotation_schedules; /* - * Set the size to rotate the session (in bytes). + * Handle used to represent a specific rotation. */ -void lttng_rotation_schedule_attr_set_size( - struct lttng_rotation_schedule_attr *attr, uint64_t size); +struct lttng_rotation_handle; /* * lttng rotate session handle functions. @@ -154,41 +141,139 @@ extern void lttng_rotation_handle_destroy( * of the rotation with lttng_rotation_get_state(). The handle must be freed * by the caller with lttng_rotation_handle_destroy(). * - * Passing NULL as the immediate rotation attribute results in the default + * Passing NULL as the immediate rotation descriptor results in the default * options being used. * * Return 0 if the rotate action was successfully launched or a negative * LTTng error code on error. */ extern int lttng_rotate_session(const char *session_name, - struct lttng_rotation_immediate_attr *attr, + struct lttng_rotation_immediate_descriptor *descriptor, struct lttng_rotation_handle **rotation_handle); /* - * Configure a session to rotate according to a given schedule. + * Get the type of a rotation schedule object. + */ +extern enum lttng_rotation_schedule_type lttng_rotation_schedule_get_type( + const struct lttng_rotation_schedule *schedule); + +/* + * Return a newly allocated size-based session rotation schedule or NULL on + * error. + */ +extern struct lttng_rotation_schedule * +lttng_rotation_schedule_size_threshold_create(void); + +/* + * Get a session rotation schedule's size threshold. + * + * Returns LTTNG_ROTATION_STATUS_OK on success. + * LTTNG_ROTATION_STATUS_UNAVAILABLE is returned if the value is unset. + */ +extern enum lttng_rotation_status +lttng_rotation_schedule_size_threshold_get_threshold( + const struct lttng_rotation_schedule *schedule, + uint64_t *size_threshold_bytes); + +/* + * Set a session rotation schedule's size threshold. + */ +extern enum lttng_rotation_status +lttng_rotation_schedule_size_threshold_set_threshold( + struct lttng_rotation_schedule *schedule, + uint64_t size_threshold_bytes); + +/* + * Return a newly allocated periodic session rotation schedule or NULL on + * error. + */ +extern struct lttng_rotation_schedule * +lttng_rotation_schedule_periodic_create(void); + +/* + * Get a time-based session rotation schedule's period. + * + * Returns LTTNG_ROTATION_STATUS_OK on success. + * LTTNG_ROTATION_STATUS_UNAVAILABLE is returned if the value is unset. + */ +extern enum lttng_rotation_status lttng_rotation_schedule_periodic_get_period( + const struct lttng_rotation_schedule *schedule, + uint64_t *period_us); + +/* + * Set a time-based session rotation schedule's period. + */ +extern enum lttng_rotation_status lttng_rotation_schedule_periodic_set_period( + struct lttng_rotation_schedule *schedule, + uint64_t period_us); + +/* + * Destroy a rotation schedule. + */ +extern void lttng_rotation_schedule_destroy( + struct lttng_rotation_schedule *schedule); + +/* + * Destroy a set of rotation schedules. Pointers to any schedule contained + * in this set become invalid after this call. + */ +extern void lttng_rotation_schedules_destroy( + struct lttng_rotation_schedules *schedules); + +/* + * Get the number of schedules in a schedule set. + */ +extern enum lttng_rotation_status lttng_rotation_schedules_get_count( + const struct lttng_rotation_schedules *schedules, + unsigned int *count); + +/* + * Get a schedule from the set at a given index. + * + * Note that the set maintains the ownership of the returned schedule. + * It must not be destroyed by the user, nor should it be held beyond + * the lifetime of the schedules set. + * + * Returns a rotation schedule, or NULL on error. + */ +extern const struct lttng_rotation_schedule * +lttng_rotation_schedules_get_at_index( + const struct lttng_rotation_schedules *schedules, + unsigned int index); + +/* + * Add a session rotation schedule to a session. + * + * Note that the current implementation currently limits the rotation schedules + * associated to a given session to one per type. + * + * Returns LTTNG_ROTATION_STATUS_OK on success, + * LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET if a rotation of the same type + * is already set. */ -extern int lttng_rotation_set_schedule(const char *session_name, - struct lttng_rotation_schedule_attr *attr); +extern enum lttng_rotation_status lttng_session_add_rotation_schedule( + const char *session_name, + const struct lttng_rotation_schedule *schedule); /* - * Ask the sessiond for the value of the rotate timer (in micro-seconds) of the - * session. + * Remove a session rotation schedule from a session. * - * On success, return 0 and set the value or rotate_timer, on error return a - * negative value. + * Returns LTTNG_ROTATION_STATUS_OK on success, + * LTTNG_ROTATION_STATUS_SCHEDULE_INVALID if the provided schedule is + * not set. */ -extern int lttng_rotation_schedule_get_timer_period(const char *session_name, - uint64_t *rotate_timer); +extern enum lttng_rotation_status lttng_session_remove_rotation_schedule( + const char *session_name, + const struct lttng_rotation_schedule *schedule); /* - * Ask the sessiond for the value of the rotate size (in micro-seconds) of the - * session. + * Get the rotation schedules associated with a given session. * - * On success, return 0 and set the value or rotate_size, on error return - * a negative value. + * Returns LTTNG_OK on success, or a negative lttng error code on error. */ -extern int lttng_rotation_schedule_get_size(const char *session_name, - uint64_t *rotate_size); +extern int lttng_session_list_rotation_schedules( + const char *session_name, + struct lttng_rotation_schedules **schedules); #ifdef __cplusplus } diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 65a24e4dc..ba7dd3d4d 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -4799,15 +4799,19 @@ end: * Command LTTNG_ROTATION_SET_SCHEDULE from the lttng-ctl library. * * Configure the automatic rotation parameters. - * Set to -1ULL to disable them. + * 'activate' to true means activate the rotation schedule type with 'new_value'. + * 'activate' to false means deactivate the rotation schedule and validate that + * 'new_value' has the same value as the currently active value. * - * Return 0 on success or else an LTTNG_ERR code. + * Return 0 on success or else a positive LTTNG_ERR code. */ int cmd_rotation_set_schedule(struct ltt_session *session, - uint64_t timer_us, uint64_t size, + bool activate, enum lttng_rotation_schedule_type schedule_type, + uint64_t new_value, struct notification_thread_handle *notification_thread_handle) { int ret; + uint64_t *parameter_value; assert(session); @@ -4815,71 +4819,116 @@ int cmd_rotation_set_schedule(struct ltt_session *session, if (session->live_timer || session->snapshot_mode || !session->output_traces) { + DBG("Failing ROTATION_SET_SCHEDULE command as the rotation feature is not available for this session"); ret = LTTNG_ERR_ROTATION_NOT_AVAILABLE; goto end; } - /* Trying to override an already active timer. */ - if (timer_us && timer_us != -1ULL && session->rotate_timer_period) { - ret = LTTNG_ERR_ROTATION_TIMER_SET; + switch (schedule_type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + parameter_value = &session->rotate_size; + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + parameter_value = &session->rotate_timer_period; + if (new_value >= UINT_MAX) { + DBG("Failing ROTATION_SET_SCHEDULE command as the value requested for a periodic rotation schedule is invalid: %" PRIu64 " > %u (UINT_MAX)", + new_value, UINT_MAX); + ret = LTTNG_ERR_INVALID; + goto end; + } + break; + default: + WARN("Failing ROTATION_SET_SCHEDULE command on unknown schedule type"); + ret = LTTNG_ERR_INVALID; goto end; - /* Trying to disable an inactive timer. */ - } else if (timer_us == -1ULL && !session->rotate_timer_period) { - ret = LTTNG_ERR_ROTATION_NO_TIMER_SET; + } + + /* Improper use of the API. */ + if (new_value == -1ULL) { + WARN("Failing ROTATION_SET_SCHEDULE command as the value requested is -1"); + ret = LTTNG_ERR_INVALID; goto end; } - if (size && size != -1ULL && session->rotate_size) { - ret = LTTNG_ERR_ROTATION_SIZE_SET; + /* + * As indicated in struct ltt_session's comments, a value of == 0 means + * this schedule rotation type is not in use. + * + * Reject the command if we were asked to activate a schedule that was + * already active. + */ + if (activate && *parameter_value != 0) { + DBG("Failing ROTATION_SET_SCHEDULE (activate) command as the schedule is already active"); + ret = LTTNG_ERR_ROTATION_SCHEDULE_SET; goto end; - } else if (size == -1ULL && !session->rotate_size) { - ret = LTTNG_ERR_ROTATION_NO_SIZE_SET; + } + + /* + * Reject the command if we were asked to deactivate a schedule that was + * not active. + */ + if (!activate && *parameter_value == 0) { + DBG("Failing ROTATION_SET_SCHEDULE (deactivate) command as the schedule is already inactive"); + ret = LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET; goto end; } - if (timer_us && !session->rotate_timer_period) { - if (timer_us > UINT_MAX) { - ret = LTTNG_ERR_INVALID; - goto end; - } + /* + * Reject the command if we were asked to deactivate a schedule that + * doesn't exist. + */ + if (!activate && *parameter_value != new_value) { + DBG("Failing ROTATION_SET_SCHEDULE (deactivate) command as an inexistant schedule was provided"); + ret = LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET; + goto end; + } - session->rotate_timer_period = timer_us; - /* - * Only start the timer if the session is active, otherwise - * it will be started when the session starts. - */ - if (session->active) { - ret = sessiond_rotate_timer_start(session, timer_us); + *parameter_value = activate ? new_value : 0; + + switch (schedule_type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + if (activate && session->active) { + /* + * Only start the timer if the session is active, + * otherwise it will be started when the session starts. + */ + ret = sessiond_rotate_timer_start(session, new_value); if (ret) { - ERR("Failed to enable rotate timer"); + ERR("Failed to enable session rotation timer in ROTATION_SET_SCHEDULE command"); ret = LTTNG_ERR_UNK; goto end; } + } else { + ret = sessiond_rotate_timer_stop(session); + if (ret) { + ERR("Failed to disable session rotation timer in ROTATION_SET_SCHEDULE command"); + ret = LTTNG_ERR_UNK; + } } - } else if (timer_us == -1ULL && session->rotate_timer_period > 0) { - sessiond_rotate_timer_stop(session); - session->rotate_timer_period = 0; - } - - if (size > 0) { - if (size == -1ULL) { - ret = unsubscribe_session_consumed_size_rotation(session, - notification_thread_handle); + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + if (activate) { + ret = subscribe_session_consumed_size_rotation(session, + new_value, notification_thread_handle); if (ret) { + ERR("Failed to enable consumed-size notification in ROTATION_SET_SCHEDULE command"); ret = LTTNG_ERR_UNK; goto end; } - session->rotate_size = 0; } else { - ret = subscribe_session_consumed_size_rotation(session, - size, notification_thread_handle); + ret = unsubscribe_session_consumed_size_rotation(session, + notification_thread_handle); if (ret) { - PERROR("Subscribe to session usage"); + ERR("Failed to disable consumed-size notification in ROTATION_SET_SCHEDULE command"); ret = LTTNG_ERR_UNK; goto end; } - session->rotate_size = size; + } + break; + default: + /* Would have been caught before. */ + abort(); } ret = LTTNG_OK; diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index 79ff689c3..16c07f78e 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -140,8 +140,9 @@ int cmd_rotate_get_info(struct ltt_session *session, uint64_t rotate_id); int cmd_session_get_current_output(struct ltt_session *session, struct lttng_session_get_current_output_return *output_return); -int cmd_rotation_set_schedule(struct ltt_session *session, uint64_t timer_us, - uint64_t size, +int cmd_rotation_set_schedule(struct ltt_session *session, + bool activate, enum lttng_rotation_schedule_type schedule_type, + uint64_t value, struct notification_thread_handle *notification_thread_handle); const struct cmd_completion_handler *cmd_pop_completion_handler(void); diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index 5e644a72d..e8f05cecf 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -3000,8 +3000,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_ROTATION_GET_INFO: case LTTNG_SESSION_GET_CURRENT_OUTPUT: case LTTNG_ROTATION_SET_SCHEDULE: - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: need_domain = 0; break; default: @@ -3046,8 +3045,7 @@ static int process_client_msg(struct command_ctx *cmd_ctx, int sock, case LTTNG_DATA_PENDING: case LTTNG_ROTATE_SESSION: case LTTNG_ROTATION_GET_INFO: - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: break; default: /* Setup lttng message with no payload */ @@ -4226,15 +4224,24 @@ error_add_context: } case LTTNG_ROTATION_SET_SCHEDULE: { + bool set_schedule; + enum lttng_rotation_schedule_type schedule_type; + uint64_t value; + if (cmd_ctx->session->kernel_session && !check_rotate_compatible()) { DBG("Kernel tracer version does not support session rotations"); ret = LTTNG_ERR_ROTATION_WRONG_VERSION; goto error; } + set_schedule = cmd_ctx->lsm->u.rotation_set_schedule.set == 1; + schedule_type = (enum lttng_rotation_schedule_type) cmd_ctx->lsm->u.rotation_set_schedule.type; + value = cmd_ctx->lsm->u.rotation_set_schedule.value; + ret = cmd_rotation_set_schedule(cmd_ctx->session, - cmd_ctx->lsm->u.rotate_setup.timer_us, - cmd_ctx->lsm->u.rotate_setup.size, + set_schedule, + schedule_type, + value, notification_thread_handle); if (ret != LTTNG_OK) { goto error; @@ -4242,42 +4249,17 @@ error_add_context: break; } - case LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD: + case LTTNG_SESSION_LIST_ROTATION_SCHEDULES: { - struct lttng_rotation_schedule_get_timer_period *get_timer; - - get_timer = zmalloc(sizeof(struct lttng_rotation_schedule_get_timer_period)); - if (!get_timer) { - ret = ENOMEM; - goto error; - } - get_timer->rotate_timer = cmd_ctx->session->rotate_timer_period; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_timer, - sizeof(struct lttng_rotation_schedule_get_timer_period)); - free(get_timer); - if (ret < 0) { - ret = -ret; - goto error; - } - - ret = LTTNG_OK; - break; - } - case LTTNG_ROTATION_SCHEDULE_GET_SIZE: - { - struct lttng_rotation_schedule_get_size *get_size; - - get_size = zmalloc(sizeof(struct lttng_rotation_schedule_get_size)); - if (!get_size) { - ret = ENOMEM; - goto error; - } - get_size->rotate_size = cmd_ctx->session->rotate_size; - - ret = setup_lttng_msg_no_cmd_header(cmd_ctx, get_size, - sizeof(struct lttng_rotation_schedule_get_size)); - free(get_size); + struct lttng_session_list_schedules_return schedules = { + .periodic.set = !!cmd_ctx->session->rotate_timer_period, + .periodic.value = cmd_ctx->session->rotate_timer_period, + .size.set = !!cmd_ctx->session->rotate_size, + .size.value = cmd_ctx->session->rotate_size, + }; + + ret = setup_lttng_msg_no_cmd_header(cmd_ctx, &schedules, + sizeof(schedules)); if (ret < 0) { ret = -ret; goto error; diff --git a/src/bin/lttng-sessiond/session.h b/src/bin/lttng-sessiond/session.h index 92e7a11ad..371b30d6b 100644 --- a/src/bin/lttng-sessiond/session.h +++ b/src/bin/lttng-sessiond/session.h @@ -189,8 +189,9 @@ struct ltt_session { /* Timer to periodically rotate a session. */ bool rotate_timer_enabled; timer_t rotate_timer; + /* Value for periodic rotations, 0 if disabled. */ uint64_t rotate_timer_period; - /* Value for size-based rotation, 0 if disabled. */ + /* Value for size-based rotations, 0 if disabled. */ uint64_t rotate_size; /* * Keep a state if this session was rotated after the last stop command. diff --git a/src/bin/lttng/commands/disable_rotation.c b/src/bin/lttng/commands/disable_rotation.c index b179e91ce..30dfaa169 100644 --- a/src/bin/lttng/commands/disable_rotation.c +++ b/src/bin/lttng/commands/disable_rotation.c @@ -50,104 +50,177 @@ enum { static struct poptOption long_options[] = { /* longName, shortName, argInfo, argPtr, value, descrip, argDesc */ - {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, - {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, - {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, + {"help", 'h', POPT_ARG_NONE, 0, OPT_HELP, 0, 0}, + {"list-options", 0, POPT_ARG_NONE, NULL, OPT_LIST_OPTIONS, NULL, NULL}, + {"session", 's', POPT_ARG_STRING, &opt_session_name, 0, 0, 0}, {"timer", 0, POPT_ARG_NONE, 0, OPT_TIMER, 0, 0}, {"size", 0, POPT_ARG_NONE, 0, OPT_SIZE, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; -static int setup_rotate(char *session_name, uint64_t timer, uint64_t size) +static const char *schedule_type_str[] = { + [LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC] = "periodic", + [LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD] = "size-based", +}; + +static const struct lttng_rotation_schedule *get_schedule( + const char *session_name, + const struct lttng_rotation_schedules *schedules, + enum lttng_rotation_schedule_type schedule_type) { - int ret = 0; - struct lttng_rotation_schedule_attr *attr = NULL; + unsigned int count, i; + enum lttng_rotation_status status; + const struct lttng_rotation_schedule *ret = NULL; - attr = lttng_rotation_schedule_attr_create(); - if (!attr) { - goto error; + status = lttng_rotation_schedules_get_count(schedules, &count); + if (status != LTTNG_ROTATION_STATUS_OK) { + ERR("Unable to determine the number of rotation schedules of session %s", + session_name); + goto end; } - if (lttng_opt_mi) { - /* Open rotation_schedule element */ - ret = mi_lttng_writer_open_element(writer, - config_element_rotation_schedule); - if (ret) { - goto error; + for (i = 0; i < count; i++) { + const struct lttng_rotation_schedule *schedule = NULL; + + schedule = lttng_rotation_schedules_get_at_index(schedules, i); + if (!schedule) { + ERR("Unable to retrieve rotation schedule at index %u", + i); + goto end; } - } - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_session_name, session_name); - if (ret) { - goto error; + if (lttng_rotation_schedule_get_type(schedule) == + schedule_type) { + ret = schedule; + break; } } - if (timer == -1ULL) { - lttng_rotation_schedule_attr_set_timer_period(attr, timer); - MSG("Disabling rotation timer on session %s", session_name); + if (!ret) { + ERR("No %s rotation schedule active on session %s", + schedule_type_str[schedule_type], session_name); } - if (size == -1ULL) { - lttng_rotation_schedule_attr_set_size(attr, size); - MSG("Disabling rotation based on size on session %s", session_name); +end: + return ret; +} + +static struct lttng_rotation_schedule *create_empty_schedule( + enum lttng_rotation_schedule_type type) +{ + struct lttng_rotation_schedule *schedule = NULL; + + switch (type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + schedule = lttng_rotation_schedule_periodic_create(); + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + schedule = lttng_rotation_schedule_size_threshold_create(); + break; + default: + abort(); } + return schedule; +} - ret = lttng_rotation_set_schedule(session_name, attr); - if (ret) { - ERR("%s", lttng_strerror(ret)); - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_rotate_status, "error"); - if (ret) { - goto end; - } - /* Close rotation_schedule element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { - goto end; - } - } +static enum cmd_error_code remove_schedule(const char *session_name, + enum lttng_rotation_schedule_type schedule_type) +{ + enum cmd_error_code cmd_ret; + int ret; + const struct lttng_rotation_schedule *schedule = NULL; + struct lttng_rotation_schedules *schedules = NULL; + enum lttng_rotation_status status; + const char *schedule_type_name; + struct lttng_rotation_schedule *empty_schedule = NULL; + + switch (schedule_type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + break; + default: + ERR("Unknown schedule type"); + abort(); + } + + schedule_type_name = schedule_type_str[schedule_type]; + + ret = lttng_session_list_rotation_schedules(session_name, &schedules); + if (ret != LTTNG_OK) { + ERR("Failed to list rotation schedules of session %s", + session_name); goto error; } - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_rotate_status, "success"); - if (ret) { - goto end; + schedule = get_schedule(session_name, schedules, schedule_type); + if (!schedule) { + cmd_ret = CMD_ERROR; + /* + * get_schedule() logs its own errors. + * A temporaty schedule is created to serialize an MI rotation + * schedule descriptor of the appropriate type that has no + * attributes set. + */ + empty_schedule = create_empty_schedule(schedule_type); + if (!empty_schedule) { + goto error; } + goto skip_removal; + } - /* Close rotation_schedule element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { - goto end; - } + status = lttng_session_remove_rotation_schedule(session_name, schedule); + switch (status) { + case LTTNG_ROTATION_STATUS_OK: + MSG("Disabled %s rotation on session %s", + schedule_type_name, session_name); + cmd_ret = CMD_SUCCESS; + break; + case LTTNG_ROTATION_STATUS_SCHEDULE_NOT_SET: + ERR("No %s rotation schedule set on session %s", + schedule_type_name, + session_name); + cmd_ret = CMD_ERROR; + break; + case LTTNG_ROTATION_STATUS_ERROR: + case LTTNG_ROTATION_STATUS_INVALID: + default: + ERR("Failed to disable %s rotation schedule on session %s", + schedule_type_name, session_name); + cmd_ret = CMD_ERROR; + break; } - ret = 0; - goto end; +skip_removal: + if (lttng_opt_mi) { + ret = mi_lttng_rotation_schedule_result(writer, + schedule ? schedule : empty_schedule, + cmd_ret == CMD_SUCCESS); + if (ret < 0) { + goto error; + } + } -error: - ret = -1; end: - return ret; + lttng_rotation_schedules_destroy(schedules); + lttng_rotation_schedule_destroy(empty_schedule); + return cmd_ret; +error: + cmd_ret = CMD_ERROR; + goto end; } /* * cmd_disable_rotation * - * The 'enable-rotation ' first level command + * The 'disable-rotation ' first level command */ int cmd_disable_rotation(int argc, const char **argv) { - int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; - int popt_ret; + int popt_ret, opt, ret = 0; + enum cmd_error_code cmd_ret = CMD_SUCCESS; static poptContext pc; char *session_name = NULL; bool free_session_name = false; - uint64_t timer = 0, size = 0; + bool periodic_rotation = false, size_rotation = false; pc = poptGetContext(NULL, argc, argv, long_options, 0); popt_ret = poptReadDefaultConfig(pc, 0); @@ -166,10 +239,10 @@ int cmd_disable_rotation(int argc, const char **argv) list_cmd_options(stdout, long_options); goto end; case OPT_TIMER: - timer = -1ULL; + periodic_rotation = true; break; case OPT_SIZE: - size = -1ULL; + size_rotation = true; break; default: ret = CMD_UNDEFINED; @@ -180,7 +253,7 @@ int cmd_disable_rotation(int argc, const char **argv) if (opt_session_name == NULL) { session_name = get_session_name(); if (session_name == NULL) { - goto end; + goto error; } free_session_name = true; } else { @@ -191,77 +264,103 @@ int cmd_disable_rotation(int argc, const char **argv) if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); if (!writer) { - ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } /* Open command element */ ret = mi_lttng_writer_command_open(writer, mi_lttng_element_command_disable_rotation); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } /* Open output element */ ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_output); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } } - /* No config options, just rotate the session now */ - if (timer == 0 && size == 0) { - ERR("Missing timer period (--timer) or size limit (--size) option"); - success = 0; - command_ret = -1; - } else { - command_ret = setup_rotate(session_name, timer, size); + if (!periodic_rotation && !size_rotation) { + ERR("No session rotation schedule type provided."); + cmd_ret = CMD_ERROR; + goto close_command; } - if (command_ret) { - ERR("%s", lttng_strerror(command_ret)); - success = 0; + if (lttng_opt_mi) { + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_rotation_schedule_results); + if (ret) { + goto error; + } + + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_session_name, + session_name); + if (ret) { + goto error; + } } + if (periodic_rotation) { + /* + * Continue processing even on error as multiple schedules can + * be specified at once. + */ + cmd_ret = remove_schedule(session_name, + LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC); + } + + if (size_rotation) { + enum lttng_error_code tmp_ret; + + /* Don't overwrite cmd_ret if it already indicates an error. */ + tmp_ret = remove_schedule(session_name, + LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD); + cmd_ret = cmd_ret ? cmd_ret : tmp_ret; + } + + if (lttng_opt_mi) { + /* Close rotation schedule results element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto error; + } + } + +close_command: /* Mi closing */ if (lttng_opt_mi) { /* Close output element */ ret = mi_lttng_writer_close_element(writer); if (ret) { - goto end; + goto error; } /* Success ? */ ret = mi_lttng_writer_write_element_bool(writer, - mi_lttng_element_command_success, success); + mi_lttng_element_command_success, + cmd_ret == CMD_SUCCESS); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } /* Command element close */ ret = mi_lttng_writer_command_close(writer); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } } end: - /* Mi clean-up */ - if (writer && mi_lttng_writer_destroy(writer)) { - /* Preserve original error code */ - ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; - } - - /* Overwrite ret if an error occurred with start_tracing */ - ret = command_ret ? command_ret : ret; + (void) mi_lttng_writer_destroy(writer); poptFreeContext(pc); if (free_session_name) { free(session_name); } - return ret; + return cmd_ret; +error: + cmd_ret = CMD_ERROR; + goto end; } diff --git a/src/bin/lttng/commands/enable_rotation.c b/src/bin/lttng/commands/enable_rotation.c index 81a55b24c..3c2bd787e 100644 --- a/src/bin/lttng/commands/enable_rotation.c +++ b/src/bin/lttng/commands/enable_rotation.c @@ -59,95 +59,109 @@ static struct poptOption long_options[] = { {0, 0, 0, 0, 0, 0, 0} }; -static int setup_rotate(char *session_name, uint64_t timer, uint64_t size) -{ - int ret = 0; - struct lttng_rotation_schedule_attr *attr = NULL; +static const char *schedule_type_str[] = { + [LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC] = "periodic", + [LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD] = "size-based", +}; - attr = lttng_rotation_schedule_attr_create(); - if (!attr) { - goto error; - } +static enum cmd_error_code add_schedule(const char *session_name, + enum lttng_rotation_schedule_type schedule_type, uint64_t value) +{ + enum cmd_error_code ret = CMD_SUCCESS; + struct lttng_rotation_schedule *schedule = NULL; + enum lttng_rotation_status status; + const char *schedule_type_name; - if (lttng_opt_mi) { - /* Open rotation_schedule element */ - ret = mi_lttng_writer_open_element(writer, - config_element_rotation_schedule); - if (ret) { - goto error; + switch (schedule_type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + schedule = lttng_rotation_schedule_periodic_create(); + if (!schedule) { + ret = CMD_ERROR; + goto end; } - - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_session_name, session_name); - if (ret) { - goto error; + status = lttng_rotation_schedule_periodic_set_period(schedule, + value); + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + schedule = lttng_rotation_schedule_size_threshold_create(); + if (!schedule) { + ret = CMD_ERROR; + goto end; } + status = lttng_rotation_schedule_size_threshold_set_threshold( + schedule, value); + break; + default: + ERR("Unknown schedule type"); + abort(); } - if (timer) { - lttng_rotation_schedule_attr_set_timer_period(attr, timer); - MSG("Configuring session %s to rotate every %" PRIu64 " us", - session_name, timer); - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_unsigned_int(writer, - config_element_rotation_timer_interval, timer); - if (ret) { - goto end; - } - } - } - if (size) { - lttng_rotation_schedule_attr_set_size(attr, size); - MSG("Configuring session %s to rotate every %" PRIu64 " bytes written", - session_name, size); - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_unsigned_int(writer, - config_element_rotation_size, size); - if (ret) { - goto end; - } - } + schedule_type_name = schedule_type_str[schedule_type]; + + switch (status) { + case LTTNG_ROTATION_STATUS_OK: + break; + case LTTNG_ROTATION_STATUS_INVALID: + ERR("Invalid value for %s option", schedule_type_name); + ret = CMD_ERROR; + goto end; + default: + ERR("Unknown error occured setting %s rotation schedule", + schedule_type_name); + ret = CMD_ERROR; + goto end; } - ret = lttng_rotation_set_schedule(session_name, attr); - if (ret) { - ERR("%s", lttng_strerror(ret)); - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_rotate_status, "error"); - if (ret) { - goto end; - } - /* Close rotation_schedule element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { - goto end; - } + status = lttng_session_add_rotation_schedule(session_name, schedule); + switch (status) { + case LTTNG_ROTATION_STATUS_OK: + ret = CMD_SUCCESS; + switch (schedule_type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + MSG("Enabled %s rotations every %" PRIu64 " µs on session %s", + schedule_type_name, value, session_name); + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + MSG("Enabled %s rotations every %" PRIu64 " bytes written on session %s", + schedule_type_name, value, session_name); + break; + default: + abort(); } - goto error; + break; + case LTTNG_ROTATION_STATUS_INVALID: + ERR("Invalid parameter for %s rotation schedule", + schedule_type_name); + ret = CMD_ERROR; + break; + case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET: + ERR("A %s rotation schedule is already set on session %s", + schedule_type_name, + session_name); + ret = CMD_ERROR; + break; + case LTTNG_ROTATION_STATUS_ERROR: + default: + ERR("Failed to enable %s rotation schedule on session %s", + schedule_type_name, + session_name); + ret = CMD_ERROR; + break; } if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_string(writer, - mi_lttng_element_rotate_status, "success"); - if (ret) { - goto end; - } + int mi_ret; - /* Close rotation_schedule element */ - ret = mi_lttng_writer_close_element(writer); - if (ret) { + mi_ret = mi_lttng_rotation_schedule_result(writer, + schedule, ret == CMD_SUCCESS); + if (mi_ret < 0) { + ret = CMD_ERROR; goto end; } } - ret = 0; - goto end; - -error: - ret = -1; end: - lttng_rotation_schedule_attr_destroy(attr); + lttng_rotation_schedule_destroy(schedule); return ret; } @@ -158,20 +172,20 @@ end: */ int cmd_enable_rotation(int argc, const char **argv) { - int opt, ret = CMD_SUCCESS, command_ret = CMD_SUCCESS, success = 1; - int popt_ret; + int popt_ret, opt, ret = 0; + enum cmd_error_code cmd_ret = CMD_SUCCESS; static poptContext pc; char *session_name = NULL; char *opt_arg = NULL; bool free_session_name = false; - uint64_t timer = 0, size = 0; + uint64_t timer_us = 0, size_bytes = 0; + bool periodic_rotation = false, size_rotation = false; pc = poptGetContext(NULL, argc, argv, long_options, 0); popt_ret = poptReadDefaultConfig(pc, 0); if (popt_ret) { - ret = CMD_ERROR; ERR("poptReadDefaultConfig"); - goto end; + goto error; } while ((opt = poptGetNextOpt(pc)) != -1) { @@ -186,29 +200,34 @@ int cmd_enable_rotation(int argc, const char **argv) errno = 0; opt_arg = poptGetOptArg(pc); if (errno != 0 || !isdigit(opt_arg[0])) { - ERR("Wrong value for --timer option: %s", opt_arg); - ret = CMD_ERROR; - goto end; + ERR("Invalid value for --timer option: %s", opt_arg); + goto error; + } + if (utils_parse_time_suffix(opt_arg, &timer_us) < 0) { + ERR("Invalid value for --timer option: %s", opt_arg); + goto error; } - if (utils_parse_time_suffix(opt_arg, &timer) < 0 || timer == 0) { - ERR("Wrong value for --timer option: %s", opt_arg); - ret = CMD_ERROR; - goto end; + if (periodic_rotation) { + ERR("Only one periodic rotation schedule may be set on a session."); + goto error; } - DBG("Rotation timer set to %" PRIu64, timer); + periodic_rotation = true; break; case OPT_SIZE: errno = 0; opt_arg = poptGetOptArg(pc); - if (utils_parse_size_suffix(opt_arg, &size) < 0 || !size) { - ERR("Wrong value for --size option: %s", opt_arg); - ret = CMD_ERROR; - goto end; + if (utils_parse_size_suffix(opt_arg, &size_bytes) < 0) { + ERR("Invalid value for --size option: %s", opt_arg); + goto error; } - DBG("Rotation size set to %" PRIu64, size); + if (size_rotation) { + ERR("Only one size-based rotation schedule may be set on a session."); + goto error; + } + size_rotation = true; break; default: - ret = CMD_UNDEFINED; + cmd_ret = CMD_UNDEFINED; goto end; } } @@ -216,7 +235,7 @@ int cmd_enable_rotation(int argc, const char **argv) if (opt_session_name == NULL) { session_name = get_session_name(); if (session_name == NULL) { - goto end; + goto error; } free_session_name = true; } else { @@ -227,76 +246,106 @@ int cmd_enable_rotation(int argc, const char **argv) if (lttng_opt_mi) { writer = mi_lttng_writer_create(fileno(stdout), lttng_opt_mi); if (!writer) { - ret = -LTTNG_ERR_NOMEM; - goto end; + goto error; } /* Open command element */ ret = mi_lttng_writer_command_open(writer, mi_lttng_element_command_enable_rotation); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } /* Open output element */ ret = mi_lttng_writer_open_element(writer, mi_lttng_element_command_output); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } } - /* No config options, just rotate the session now */ - if (timer == 0 && size == 0) { - ERR("No timer or size given"); - success = 0; - command_ret = -1; - } else { - command_ret = setup_rotate(session_name, timer, size); + if (!periodic_rotation && !size_rotation) { + ERR("No session rotation schedule parameter provided."); + cmd_ret = CMD_ERROR; + goto close_command; } - if (command_ret) { - ERR("%s", lttng_strerror(command_ret)); - success = 0; + if (lttng_opt_mi) { + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_rotation_schedule_results); + if (ret) { + goto error; + } + + ret = mi_lttng_writer_write_element_string(writer, + mi_lttng_element_session_name, + session_name); + if (ret) { + goto error; + } } + if (periodic_rotation) { + /* + * Continue processing even on error as multiple schedules can + * be specified at once. + */ + cmd_ret = add_schedule(session_name, + LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC, + timer_us); + } + + if (size_rotation) { + enum lttng_error_code tmp_ret; + + /* Don't overwrite cmd_ret if it already indicates an error. */ + tmp_ret = add_schedule(session_name, + LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD, + size_bytes); + cmd_ret = cmd_ret ? cmd_ret : tmp_ret; + } + + if (lttng_opt_mi) { + /* Close rotation schedule results element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto error; + } + } + +close_command: /* Mi closing */ if (lttng_opt_mi) { - /* Close output element */ + /* Close output element */ ret = mi_lttng_writer_close_element(writer); if (ret) { - goto end; + goto error; } + /* Success ? */ ret = mi_lttng_writer_write_element_bool(writer, - mi_lttng_element_command_success, success); + mi_lttng_element_command_success, + cmd_ret == CMD_SUCCESS); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } /* Command element close */ ret = mi_lttng_writer_command_close(writer); if (ret) { - ret = CMD_ERROR; - goto end; + goto error; } } end: - /* Mi clean-up */ - if (writer && mi_lttng_writer_destroy(writer)) { - /* Preserve original error code */ - ret = ret ? ret : -LTTNG_ERR_MI_IO_FAIL; - } - - /* Overwrite ret if an error occurred with start_tracing */ - ret = command_ret ? command_ret : ret; + (void) mi_lttng_writer_destroy(writer); poptFreeContext(pc); if (free_session_name) { free(session_name); } - return ret; + return cmd_ret; + +error: + cmd_ret = CMD_ERROR; + goto end; } diff --git a/src/bin/lttng/commands/list.c b/src/bin/lttng/commands/list.c index e05134cbb..a4ee96e9e 100644 --- a/src/bin/lttng/commands/list.c +++ b/src/bin/lttng/commands/list.c @@ -1520,55 +1520,165 @@ end: return ret; } +static enum cmd_error_code print_periodic_rotation_schedule( + const struct lttng_rotation_schedule *schedule) +{ + enum cmd_error_code ret; + enum lttng_rotation_status status; + uint64_t value; + + status = lttng_rotation_schedule_periodic_get_period(schedule, + &value); + if (status != LTTNG_ROTATION_STATUS_OK) { + ERR("Failed to retrieve period parameter from periodic rotation schedule."); + ret = CMD_ERROR; + goto end; + } + + MSG(" timer period: %" PRIu64" µs", value); + if (lttng_opt_mi) { + int mi_ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_rotation_timer_interval, value); + + if (mi_ret) { + ret = CMD_ERROR; + goto end; + } + } + + ret = CMD_SUCCESS; +end: + return ret; +} + +static enum cmd_error_code print_size_threshold_rotation_schedule( + const struct lttng_rotation_schedule *schedule) +{ + enum cmd_error_code ret; + enum lttng_rotation_status status; + uint64_t value; + + status = lttng_rotation_schedule_size_threshold_get_threshold(schedule, + &value); + if (status != LTTNG_ROTATION_STATUS_OK) { + ERR("Failed to retrieve size parameter from size-based rotation schedule."); + ret = CMD_ERROR; + goto end; + } + + MSG(" size threshold: %" PRIu64" bytes", value); + if (lttng_opt_mi) { + int mi_ret = mi_lttng_writer_write_element_unsigned_int(writer, + config_element_rotation_size, value); + + if (mi_ret) { + ret = CMD_ERROR; + goto end; + } + } + + ret = CMD_SUCCESS; +end: + return ret; +} + +static enum cmd_error_code print_rotation_schedule( + const struct lttng_rotation_schedule *schedule) +{ + enum cmd_error_code ret; + + switch (lttng_rotation_schedule_get_type(schedule)) { + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + ret = print_size_threshold_rotation_schedule(schedule); + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + ret = print_periodic_rotation_schedule(schedule); + break; + default: + ret = CMD_ERROR; + } + return ret; +} + /* - * List the rotate settings (timer/size if any). + * List the automatic rotation settings. */ -static int list_rotate_settings(const char *session_name) +static enum cmd_error_code list_rotate_settings(const char *session_name) { int ret; - uint64_t size, timer; - - ret = lttng_rotation_schedule_get_timer_period(session_name, &timer); - if (ret) { + enum cmd_error_code cmd_ret = CMD_SUCCESS; + unsigned int count, i; + struct lttng_rotation_schedules *schedules = NULL; + enum lttng_rotation_status status; + + ret = lttng_session_list_rotation_schedules(session_name, &schedules); + if (ret != LTTNG_OK) { + ERR("Failed to list session rotation schedules: %s", lttng_strerror(ret)); + cmd_ret = CMD_ERROR; goto end; } - ret = lttng_rotation_schedule_get_size(session_name, &size); - if (ret) { + status = lttng_rotation_schedules_get_count(schedules, &count); + if (status != LTTNG_ROTATION_STATUS_OK) { + ERR("Failed to retrieve the number of session rotation schedules."); + cmd_ret = CMD_ERROR; goto end; } - if (!timer && !size) { - ret = 0; + if (count == 0) { + cmd_ret = CMD_SUCCESS; goto end; } - _MSG("Automatic rotation schedule settings:\n"); - - if (timer) { - _MSG(" timer period: %" PRIu64" µs\n", timer); - if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_unsigned_int(writer, - config_element_rotation_timer_interval, timer); - if (ret) { - goto end; - } + MSG("Automatic rotation schedules:"); + if (lttng_opt_mi) { + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_rotation_schedules); + if (ret) { + cmd_ret = CMD_ERROR; + goto end; } } - if (size) { - _MSG(" size threshold: %" PRIu64" bytes\n", size); + + for (i = 0; i < count; i++) { + enum cmd_error_code tmp_ret = CMD_SUCCESS; + const struct lttng_rotation_schedule *schedule; + + schedule = lttng_rotation_schedules_get_at_index(schedules, i); + if (!schedule) { + ERR("Failed to retrieve session rotation schedule."); + cmd_ret = CMD_ERROR; + goto end; + } + if (lttng_opt_mi) { - ret = mi_lttng_writer_write_element_unsigned_int(writer, - config_element_rotation_size, size); + ret = mi_lttng_rotation_schedule(writer, schedule); if (ret) { - goto end; + tmp_ret = CMD_ERROR; } + } else { + tmp_ret = print_rotation_schedule(schedule); } + + /* + * Report an error if the serialization of any of the + * descriptors failed. + */ + cmd_ret = cmd_ret ? cmd_ret : tmp_ret; } - _MSG("\n"); + _MSG("\n"); + if (lttng_opt_mi) { + /* Close the rotation_schedules element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + cmd_ret = CMD_ERROR; + goto end; + } + } end: - return ret; + lttng_rotation_schedules_destroy(schedules); + return cmd_ret; } /* diff --git a/src/bin/lttng/commands/rotate.c b/src/bin/lttng/commands/rotate.c index 68bc59a33..1e4677ffd 100644 --- a/src/bin/lttng/commands/rotate.c +++ b/src/bin/lttng/commands/rotate.c @@ -377,7 +377,7 @@ int cmd_rotate(int argc, const char **argv) /* Open rotations element */ ret = mi_lttng_writer_open_element(writer, - mi_lttng_element_rotations); + mi_lttng_element_rotation_schedules); if (ret) { goto end; } @@ -391,12 +391,12 @@ int cmd_rotate(int argc, const char **argv) /* Mi closing */ if (lttng_opt_mi) { - /* Close rotations element */ + /* Close rotations element */ ret = mi_lttng_writer_close_element(writer); if (ret) { goto end; } - /* Close output element */ + /* Close output element */ ret = mi_lttng_writer_close_element(writer); if (ret) { goto end; diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 244fbd5cc..ffe7b14ed 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -2554,6 +2554,82 @@ end: return ret; } +static +int add_periodic_rotation(const char *name, uint64_t time_us) +{ + int ret; + enum lttng_rotation_status status; + struct lttng_rotation_schedule *periodic = + lttng_rotation_schedule_periodic_create(); + + if (!periodic) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + status = lttng_rotation_schedule_periodic_set_period(periodic, + time_us); + if (status != LTTNG_ROTATION_STATUS_OK) { + ret = -LTTNG_ERR_INVALID; + goto error; + } + + status = lttng_session_add_rotation_schedule(name, periodic); + switch (status) { + case LTTNG_ROTATION_STATUS_OK: + ret = LTTNG_OK; + break; + case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET: + case LTTNG_ROTATION_STATUS_INVALID: + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + break; + default: + ret = -LTTNG_ERR_UNK; + break; + } +error: + lttng_rotation_schedule_destroy(periodic); + return ret; +} + +static +int add_size_rotation(const char *name, uint64_t size_bytes) +{ + int ret; + enum lttng_rotation_status status; + struct lttng_rotation_schedule *size = + lttng_rotation_schedule_size_threshold_create(); + + if (!size) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + status = lttng_rotation_schedule_size_threshold_set_threshold(size, + size_bytes); + if (status != LTTNG_ROTATION_STATUS_OK) { + ret = -LTTNG_ERR_INVALID; + goto error; + } + + status = lttng_session_add_rotation_schedule(name, size); + switch (status) { + case LTTNG_ROTATION_STATUS_OK: + ret = LTTNG_OK; + break; + case LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET: + case LTTNG_ROTATION_STATUS_INVALID: + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + break; + default: + ret = -LTTNG_ERR_UNK; + break; + } +error: + lttng_rotation_schedule_destroy(size); + return ret; +} + static int process_session_node(xmlNodePtr session_node, const char *session_name, int overwrite, @@ -2830,21 +2906,17 @@ domain_init_error: } } - if (rotation_timer_interval || rotation_size) { - struct lttng_rotation_schedule_attr *rotation_attr = - lttng_rotation_schedule_attr_create(); - - if (!rotation_attr) { + if (rotation_timer_interval) { + ret = add_periodic_rotation((const char *) name, + rotation_timer_interval); + if (ret < 0) { goto error; } - lttng_rotation_schedule_attr_set_timer_period(rotation_attr, - rotation_timer_interval); - lttng_rotation_schedule_attr_set_size(rotation_attr, + } + if (rotation_size) { + ret = add_size_rotation((const char *) name, rotation_size); - ret = lttng_rotation_set_schedule((const char *) name, - rotation_attr); - lttng_rotation_schedule_attr_destroy(rotation_attr); - if (ret) { + if (ret < 0) { goto error; } } diff --git a/src/common/error.c b/src/common/error.c index aebcaa915..b288b90ba 100644 --- a/src/common/error.c +++ b/src/common/error.c @@ -192,10 +192,8 @@ static const char *error_string_array[] = { [ ERROR_INDEX(LTTNG_ERR_COMMAND_CANCELLED) ] = "Command cancelled", [ ERROR_INDEX(LTTNG_ERR_ROTATION_PENDING) ] = "Rotation already pending for this session", [ ERROR_INDEX(LTTNG_ERR_ROTATION_NOT_AVAILABLE) ] = "Rotation feature not available for this session's creation mode", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_TIMER_SET) ] = "Automatic timer-based rotation schedule already set for this session", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_SIZE_SET) ] = "Automatic size-based rotation schedule already set for this session", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_NO_TIMER_SET) ] = "No automatic timer-based rotation schedule set for this session", - [ ERROR_INDEX(LTTNG_ERR_ROTATION_NO_SIZE_SET) ] = "No automatic size-based rotation schedule set for this session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_SCHEDULE_SET) ] = "A session rotation schedule of this type is already set on the session", + [ ERROR_INDEX(LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET) ] = "No session rotation schedule of this type is set on the session", [ ERROR_INDEX(LTTNG_ERR_ROTATION_MULTIPLE_AFTER_STOP) ] = "Session was already rotated once since it became inactive", [ ERROR_INDEX(LTTNG_ERR_ROTATION_WRONG_VERSION) ] = "Session rotation is not supported by this kernel tracer version", [ ERROR_INDEX(LTTNG_ERR_NO_SESSION_OUTPUT) ] = "Session has no output", diff --git a/src/common/mi-lttng-3.0.xsd b/src/common/mi-lttng-3.0.xsd index f9ca71094..9c1a293af 100644 --- a/src/common/mi-lttng-3.0.xsd +++ b/src/common/mi-lttng-3.0.xsd @@ -402,6 +402,27 @@ THE SOFTWARE. + + + + + + + + + + + + + + + + + + + + + @@ -419,8 +440,7 @@ THE SOFTWARE. - - + @@ -572,26 +592,23 @@ THE SOFTWARE. - - - + - + + - - + + - - - - + + @@ -613,8 +630,8 @@ THE SOFTWARE. - - + + diff --git a/src/common/mi-lttng.c b/src/common/mi-lttng.c index e8236d841..d5148bcb5 100644 --- a/src/common/mi-lttng.c +++ b/src/common/mi-lttng.c @@ -186,9 +186,15 @@ LTTNG_HIDDEN const char * const mi_lttng_element_session_name = "session_name"; /* String related to rotate command */ LTTNG_HIDDEN const char * const mi_lttng_element_rotation = "rotation"; -LTTNG_HIDDEN const char * const mi_lttng_element_rotations = "rotations"; LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status = "status"; LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule = "rotation_schedule"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedules = "rotation_schedules"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_result = "rotation_schedule_result"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_results = "rotation_schedule_results"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_periodic = "periodic"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_periodic_time_us = "time_us"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_size_threshold = "size_threshold"; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_size_threshold_bytes = "bytes"; /* String related to add-context command */ LTTNG_HIDDEN const char * const mi_lttng_element_context_symbol = "symbol"; @@ -1837,3 +1843,108 @@ int mi_lttng_snapshot_record(struct mi_writer *writer, end: return ret; } + +LTTNG_HIDDEN +int mi_lttng_rotation_schedule(struct mi_writer *writer, + const struct lttng_rotation_schedule *schedule) +{ + int ret = 0; + enum lttng_rotation_status status; + uint64_t value; + const char *element_name; + const char *value_name; + bool empty_schedule = false; + + switch (lttng_rotation_schedule_get_type(schedule)) { + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + status = lttng_rotation_schedule_periodic_get_period(schedule, + &value); + element_name = mi_lttng_element_rotation_schedule_periodic; + value_name = mi_lttng_element_rotation_schedule_periodic_time_us; + break; + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + status = lttng_rotation_schedule_size_threshold_get_threshold( + schedule, &value); + element_name = mi_lttng_element_rotation_schedule_size_threshold; + value_name = mi_lttng_element_rotation_schedule_size_threshold_bytes; + break; + default: + ret = -1; + goto end; + } + + if (status != LTTNG_ROTATION_STATUS_OK) { + if (status == LTTNG_ROTATION_STATUS_UNAVAILABLE) { + empty_schedule = true; + } else { + ret = -1; + goto end; + } + } + + ret = mi_lttng_writer_open_element(writer, element_name); + if (ret) { + goto end; + } + + if (!empty_schedule) { + ret = mi_lttng_writer_write_element_unsigned_int(writer, + value_name, value); + if (ret) { + goto end; + } + } + + /* Close schedule descriptor element. */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } +end: + return ret; +} + +LTTNG_HIDDEN +int mi_lttng_rotation_schedule_result(struct mi_writer *writer, + const struct lttng_rotation_schedule *schedule, + bool success) +{ + int ret = 0; + + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_rotation_schedule_result); + if (ret) { + goto end; + } + + ret = mi_lttng_writer_open_element(writer, + mi_lttng_element_rotation_schedule); + if (ret) { + goto end; + } + + ret = mi_lttng_rotation_schedule(writer, schedule); + if (ret) { + goto end; + } + + /* Close rotation_schedule element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } + + ret = mi_lttng_writer_write_element_bool(writer, + mi_lttng_element_command_success, success); + if (ret) { + goto end; + } + + /* Close rotation_schedule_result element */ + ret = mi_lttng_writer_close_element(writer); + if (ret) { + goto end; + } +end: + return ret; +} diff --git a/src/common/mi-lttng.h b/src/common/mi-lttng.h index df7a68a02..37136a8db 100644 --- a/src/common/mi-lttng.h +++ b/src/common/mi-lttng.h @@ -192,9 +192,15 @@ LTTNG_HIDDEN const char * const mi_lttng_element_session_name; /* String related to rotate command */ LTTNG_HIDDEN const char * const mi_lttng_element_rotation; -LTTNG_HIDDEN const char * const mi_lttng_element_rotations; LTTNG_HIDDEN const char * const mi_lttng_element_rotate_status; LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedules; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_periodic; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_periodic_time_us; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_size_threshold; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_size_threshold_bytes; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_result; +LTTNG_HIDDEN const char * const mi_lttng_element_rotation_schedule_results; /* String related to add-context command */ LTTNG_HIDDEN extern const char * const mi_lttng_element_context_symbol; @@ -806,4 +812,44 @@ int mi_lttng_snapshot_record(struct mi_writer *writer, const char *current_session_name, const char *url, const char *cmdline_ctrl_url, const char *cmdline_data_url); +/* + * Machine interface representation of a session rotation schedule. + * + * The machine interface serializes the provided schedule as one of the choices + * from 'rotation_schedule_type'. + * + * writer: An instance of a machine interface writer. + * + * schedule: An lttng rotation schedule descriptor object. + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_rotation_schedule(struct mi_writer *writer, + const struct lttng_rotation_schedule *schedule); + +/* + * Machine interface of a session rotation schedule result. + * This is an element that is part of the output of the enable-rotation and + * disable-rotation commands. + * + * The machine interface provides the following information: + * - schedule: the session rotation schedule descriptor. + * - success: whether the sub-command succeeded. + * + * writer: An instance of a machine interface writer. + * + * session_name: The session to which the command applies. + * + * schedule: An lttng rotation schedule descriptor object. + * + * success: Whether the sub-command suceeded. + * + * Returns zero if the element's value could be written. + * Negative values indicate an error. + */ +int mi_lttng_rotation_schedule_result(struct mi_writer *writer, + const struct lttng_rotation_schedule *schedule, + bool success); + #endif /* _MI_LTTNG_H */ diff --git a/src/common/sessiond-comm/sessiond-comm.h b/src/common/sessiond-comm/sessiond-comm.h index 59f7482eb..2cd66f46f 100644 --- a/src/common/sessiond-comm/sessiond-comm.h +++ b/src/common/sessiond-comm/sessiond-comm.h @@ -58,55 +58,54 @@ enum lttcomm_sessiond_command { /* Tracer command */ - LTTNG_ADD_CONTEXT = 0, + LTTNG_ADD_CONTEXT = 0, /* LTTNG_CALIBRATE used to be here */ - LTTNG_DISABLE_CHANNEL = 2, - LTTNG_DISABLE_EVENT = 3, - LTTNG_LIST_SYSCALLS = 4, - LTTNG_ENABLE_CHANNEL = 5, - LTTNG_ENABLE_EVENT = 6, + LTTNG_DISABLE_CHANNEL = 2, + LTTNG_DISABLE_EVENT = 3, + LTTNG_LIST_SYSCALLS = 4, + LTTNG_ENABLE_CHANNEL = 5, + LTTNG_ENABLE_EVENT = 6, /* 7 */ /* Session daemon command */ - LTTNG_CREATE_SESSION = 8, - LTTNG_DESTROY_SESSION = 9, - LTTNG_LIST_CHANNELS = 10, - LTTNG_LIST_DOMAINS = 11, - LTTNG_LIST_EVENTS = 12, - LTTNG_LIST_SESSIONS = 13, - LTTNG_LIST_TRACEPOINTS = 14, - LTTNG_REGISTER_CONSUMER = 15, - LTTNG_START_TRACE = 16, - LTTNG_STOP_TRACE = 17, - LTTNG_LIST_TRACEPOINT_FIELDS = 18, + LTTNG_CREATE_SESSION = 8, + LTTNG_DESTROY_SESSION = 9, + LTTNG_LIST_CHANNELS = 10, + LTTNG_LIST_DOMAINS = 11, + LTTNG_LIST_EVENTS = 12, + LTTNG_LIST_SESSIONS = 13, + LTTNG_LIST_TRACEPOINTS = 14, + LTTNG_REGISTER_CONSUMER = 15, + LTTNG_START_TRACE = 16, + LTTNG_STOP_TRACE = 17, + LTTNG_LIST_TRACEPOINT_FIELDS = 18, /* Consumer */ - LTTNG_DISABLE_CONSUMER = 19, - LTTNG_ENABLE_CONSUMER = 20, - LTTNG_SET_CONSUMER_URI = 21, + LTTNG_DISABLE_CONSUMER = 19, + LTTNG_ENABLE_CONSUMER = 20, + LTTNG_SET_CONSUMER_URI = 21, /* 22 */ /* 23 */ - LTTNG_DATA_PENDING = 24, - LTTNG_SNAPSHOT_ADD_OUTPUT = 25, - LTTNG_SNAPSHOT_DEL_OUTPUT = 26, - LTTNG_SNAPSHOT_LIST_OUTPUT = 27, - LTTNG_SNAPSHOT_RECORD = 28, - LTTNG_CREATE_SESSION_SNAPSHOT = 29, - LTTNG_CREATE_SESSION_LIVE = 30, - LTTNG_SAVE_SESSION = 31, - LTTNG_TRACK_PID = 32, - LTTNG_UNTRACK_PID = 33, - LTTNG_LIST_TRACKER_PIDS = 34, - LTTNG_SET_SESSION_SHM_PATH = 40, - LTTNG_REGENERATE_METADATA = 41, - LTTNG_REGENERATE_STATEDUMP = 42, - LTTNG_REGISTER_TRIGGER = 43, - LTTNG_UNREGISTER_TRIGGER = 44, - LTTNG_ROTATE_SESSION = 45, - LTTNG_ROTATION_GET_INFO = 46, - LTTNG_ROTATION_SET_SCHEDULE = 47, - LTTNG_SESSION_GET_CURRENT_OUTPUT = 48, - LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD = 49, - LTTNG_ROTATION_SCHEDULE_GET_SIZE = 50, + LTTNG_DATA_PENDING = 24, + LTTNG_SNAPSHOT_ADD_OUTPUT = 25, + LTTNG_SNAPSHOT_DEL_OUTPUT = 26, + LTTNG_SNAPSHOT_LIST_OUTPUT = 27, + LTTNG_SNAPSHOT_RECORD = 28, + LTTNG_CREATE_SESSION_SNAPSHOT = 29, + LTTNG_CREATE_SESSION_LIVE = 30, + LTTNG_SAVE_SESSION = 31, + LTTNG_TRACK_PID = 32, + LTTNG_UNTRACK_PID = 33, + LTTNG_LIST_TRACKER_PIDS = 34, + LTTNG_SET_SESSION_SHM_PATH = 40, + LTTNG_REGENERATE_METADATA = 41, + LTTNG_REGENERATE_STATEDUMP = 42, + LTTNG_REGISTER_TRIGGER = 43, + LTTNG_UNREGISTER_TRIGGER = 44, + LTTNG_ROTATE_SESSION = 45, + LTTNG_ROTATION_GET_INFO = 46, + LTTNG_ROTATION_SET_SCHEDULE = 47, + LTTNG_SESSION_GET_CURRENT_OUTPUT = 48, + LTTNG_SESSION_LIST_ROTATION_SCHEDULES = 49, }; enum lttcomm_relayd_command { @@ -340,9 +339,15 @@ struct lttcomm_session_msg { uint64_t rotation_id; } LTTNG_PACKED get_rotation_info; struct { - uint64_t timer_us; - uint64_t size; - } LTTNG_PACKED rotate_setup; + /* enum lttng_rotation_schedule_type */ + uint8_t type; + /* + * If set == 1, set schedule to value, if set == 0, + * clear this schedule type. + */ + uint8_t set; + uint64_t value; + } LTTNG_PACKED rotation_set_schedule; } u; } LTTNG_PACKED; diff --git a/src/lib/lttng-ctl/rotate.c b/src/lib/lttng-ctl/rotate.c index f32c69be1..5c5b1b70c 100644 --- a/src/lib/lttng-ctl/rotate.c +++ b/src/lib/lttng-ctl/rotate.c @@ -28,19 +28,6 @@ #include "lttng-ctl-helper.h" -struct lttng_rotation_schedule_attr *lttng_rotation_schedule_attr_create(void) -{ - return zmalloc(sizeof(struct lttng_rotation_schedule_attr)); -} - -void lttng_rotation_schedule_attr_destroy(struct lttng_rotation_schedule_attr *attr) -{ - if (attr) { - free(attr); - attr = NULL; - } -} - static enum lttng_rotation_status ask_rotation_info( struct lttng_rotation_handle *rotation_handle, @@ -77,28 +64,6 @@ end: } -enum lttng_rotation_status lttng_rotation_schedule_attr_set_timer_period( - struct lttng_rotation_schedule_attr *attr, - uint64_t timer) -{ - enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; - - if (!attr) { - status = LTTNG_ROTATION_STATUS_INVALID; - goto end; - } - - attr->timer_us = timer; -end: - return status; -} - -void lttng_rotation_schedule_attr_set_size( - struct lttng_rotation_schedule_attr *attr, uint64_t size) -{ - attr->size = size; -} - static struct lttng_trace_archive_location * create_trace_archive_location_from_get_info( @@ -221,8 +186,7 @@ void lttng_rotation_handle_destroy( static int init_rotation_handle(struct lttng_rotation_handle *rotation_handle, const char *session_name, - struct lttng_rotate_session_return *rotate_return, - struct lttng_rotation_immediate_attr *attr) + struct lttng_rotate_session_return *rotate_return) { int ret; @@ -243,7 +207,7 @@ end: * Return 0 on success else a negative LTTng error code. */ int lttng_rotate_session(const char *session_name, - struct lttng_rotation_immediate_attr *attr, + struct lttng_rotation_immediate_descriptor *descriptor, struct lttng_rotation_handle **rotation_handle) { struct lttcomm_session_msg lsm; @@ -280,8 +244,7 @@ int lttng_rotate_session(const char *session_name, goto end; } - init_rotation_handle(*rotation_handle, session_name, rotate_return, - attr); + init_rotation_handle(*rotation_handle, session_name, rotate_return); ret = 0; @@ -291,21 +254,39 @@ end: } /* - * Configure the automatic rotate parameters. + * Update the automatic rotation parameters. + * 'add' as true enables the provided schedule, false removes the shedule. + * + * The external API makes it appear as though arbitrary schedules can + * be added or removed at will. However, the session daemon is + * currently limited to one schedule per type (per session). + * + * The additional flexibility of the public API is offered for future + * rotation schedules that could indicate more precise criteria than + * size and time (e.g. a domain) where it could make sense to add + * multiple schedules of a given type to a session. + * + * Hence, the exact schedule that the user wishes to remove (and not + * just its type) must be passed so that the session daemon can + * validate that is exists before clearing it. */ -int lttng_rotation_set_schedule(const char *session_name, - struct lttng_rotation_schedule_attr *attr) +static +enum lttng_rotation_status lttng_rotation_update_schedule( + const char *session_name, + const struct lttng_rotation_schedule *schedule, + bool add) { struct lttcomm_session_msg lsm; + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; int ret; - if (!attr || !session_name) { - ret = -LTTNG_ERR_INVALID; + if (!session_name || !schedule) { + status = LTTNG_ROTATION_STATUS_INVALID; goto end; } if (strlen(session_name) >= sizeof(lsm.session.name)) { - ret = -LTTNG_ERR_INVALID; + status = LTTNG_ROTATION_STATUS_INVALID; goto end; } @@ -313,62 +294,356 @@ int lttng_rotation_set_schedule(const char *session_name, lsm.cmd_type = LTTNG_ROTATION_SET_SCHEDULE; lttng_ctl_copy_string(lsm.session.name, session_name, sizeof(lsm.session.name)); - lsm.u.rotate_setup.timer_us = attr->timer_us; - lsm.u.rotate_setup.size = attr->size; + + lsm.u.rotation_set_schedule.type = (uint32_t) schedule->type; + switch (schedule->type) { + case LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD: + { + status = lttng_rotation_schedule_size_threshold_get_threshold( + schedule, &lsm.u.rotation_set_schedule.value); + if (status != LTTNG_ROTATION_STATUS_OK) { + goto end; + } + + lsm.u.rotation_set_schedule.set = !!add; + break; + } + case LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC: + { + status = lttng_rotation_schedule_periodic_get_period( + schedule, &lsm.u.rotation_set_schedule.value); + if (status != LTTNG_ROTATION_STATUS_OK) { + goto end; + } + + lsm.u.rotation_set_schedule.set = !!add; + break; + } + default: + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } ret = lttng_ctl_ask_sessiond(&lsm, NULL); + if (ret >= 0) { + goto end; + } + + switch (-ret) { + case LTTNG_ERR_ROTATION_SCHEDULE_SET: + status = LTTNG_ROTATION_STATUS_SCHEDULE_ALREADY_SET; + break; + case LTTNG_ERR_ROTATION_SCHEDULE_NOT_SET: + status = LTTNG_ROTATION_STATUS_INVALID; + break; + default: + status = LTTNG_ROTATION_STATUS_ERROR; + } end: - return ret; + return status; +} + +static +struct lttng_rotation_schedules *lttng_rotation_schedules_create(void) +{ + return zmalloc(sizeof(struct lttng_rotation_schedules)); } -int lttng_rotation_schedule_get_timer_period(const char *session_name, - uint64_t *rotate_timer) +static +void lttng_schedules_add(struct lttng_rotation_schedules *schedules, + struct lttng_rotation_schedule *schedule) +{ + schedules->schedules[schedules->count++] = schedule; +} + +static +int get_schedules(const char *session_name, + struct lttng_rotation_schedules **_schedules) { - struct lttcomm_session_msg lsm; - struct lttng_rotation_schedule_get_timer_period *get_timer = NULL; int ret; + struct lttcomm_session_msg lsm; + struct lttng_session_list_schedules_return *schedules_comm; + struct lttng_rotation_schedules *schedules = NULL; + struct lttng_rotation_schedule *periodic = NULL, *size = NULL; memset(&lsm, 0, sizeof(lsm)); - lsm.cmd_type = LTTNG_ROTATION_SCHEDULE_GET_TIMER_PERIOD; + lsm.cmd_type = LTTNG_SESSION_LIST_ROTATION_SCHEDULES; lttng_ctl_copy_string(lsm.session.name, session_name, sizeof(lsm.session.name)); - ret = lttng_ctl_ask_sessiond(&lsm, (void **) &get_timer); + ret = lttng_ctl_ask_sessiond(&lsm, (void **) &schedules_comm); if (ret < 0) { - ret = -1; goto end; } - *rotate_timer = get_timer->rotate_timer; - ret = 0; + schedules = lttng_rotation_schedules_create(); + if (!schedules) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + if (schedules_comm->periodic.set == 1) { + enum lttng_rotation_status status; + + periodic = lttng_rotation_schedule_periodic_create(); + if (!periodic) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + status = lttng_rotation_schedule_periodic_set_period( + periodic, schedules_comm->periodic.value); + if (status != LTTNG_ROTATION_STATUS_OK) { + /* + * This would imply that the session daemon returned + * an invalid periodic rotation schedule value. + */ + ret = -LTTNG_ERR_UNK; + goto end; + } + + lttng_schedules_add(schedules, periodic); + periodic = NULL; + } + + if (schedules_comm->size.set == 1) { + enum lttng_rotation_status status; + + size = lttng_rotation_schedule_size_threshold_create(); + if (!size) { + ret = -LTTNG_ERR_NOMEM; + goto end; + } + + status = lttng_rotation_schedule_size_threshold_set_threshold( + size, schedules_comm->size.value); + if (status != LTTNG_ROTATION_STATUS_OK) { + /* + * This would imply that the session daemon returned + * an invalid size threshold schedule value. + */ + ret = -LTTNG_ERR_UNK; + goto end; + } + + lttng_schedules_add(schedules, size); + size = NULL; + } + + ret = LTTNG_OK; end: - free(get_timer); + free(schedules_comm); + free(periodic); + free(size); + *_schedules = schedules; return ret; } -int lttng_rotation_schedule_get_size(const char *session_name, - uint64_t *rotate_size) +enum lttng_rotation_schedule_type lttng_rotation_schedule_get_type( + const struct lttng_rotation_schedule *schedule) { - struct lttcomm_session_msg lsm; - struct lttng_rotation_schedule_get_size *get_size = NULL; - int ret; + return schedule ? schedule->type : LTTNG_ROTATION_SCHEDULE_TYPE_UNKNOWN; +} - memset(&lsm, 0, sizeof(lsm)); - lsm.cmd_type = LTTNG_ROTATION_SCHEDULE_GET_SIZE; - lttng_ctl_copy_string(lsm.session.name, session_name, - sizeof(lsm.session.name)); +struct lttng_rotation_schedule * +lttng_rotation_schedule_size_threshold_create(void) +{ + struct lttng_rotation_schedule_size_threshold *schedule; - ret = lttng_ctl_ask_sessiond(&lsm, (void **) &get_size); - if (ret < 0) { - ret = -1; + schedule = zmalloc(sizeof(*schedule)); + if (!schedule) { goto end; } - *rotate_size = get_size->rotate_size; + schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_SIZE_THRESHOLD; +end: + return &schedule->parent; +} + +enum lttng_rotation_status +lttng_rotation_schedule_size_threshold_get_threshold( + const struct lttng_rotation_schedule *schedule, + uint64_t *size_threshold_bytes) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + struct lttng_rotation_schedule_size_threshold *size_schedule; - ret = 0; + if (!schedule || !size_threshold_bytes) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + + size_schedule = container_of(schedule, + struct lttng_rotation_schedule_size_threshold, + parent); + if (size_schedule->size.set) { + *size_threshold_bytes = size_schedule->size.bytes; + } else { + status = LTTNG_ROTATION_STATUS_UNAVAILABLE; + goto end; + } +end: + return status; +} + +enum lttng_rotation_status +lttng_rotation_schedule_size_threshold_set_threshold( + struct lttng_rotation_schedule *schedule, + uint64_t size_threshold_bytes) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + struct lttng_rotation_schedule_size_threshold *size_schedule; + + if (!schedule || size_threshold_bytes == 0 || + size_threshold_bytes == -1ULL) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + size_schedule = container_of(schedule, + struct lttng_rotation_schedule_size_threshold, + parent); + size_schedule->size.bytes = size_threshold_bytes; + size_schedule->size.set = true; end: - free(get_size); - return ret; + return status; +} + +struct lttng_rotation_schedule * +lttng_rotation_schedule_periodic_create(void) +{ + struct lttng_rotation_schedule_periodic *schedule; + + schedule = zmalloc(sizeof(*schedule)); + if (!schedule) { + goto end; + } + + schedule->parent.type = LTTNG_ROTATION_SCHEDULE_TYPE_PERIODIC; +end: + return &schedule->parent; +} + +enum lttng_rotation_status +lttng_rotation_schedule_periodic_get_period( + const struct lttng_rotation_schedule *schedule, + uint64_t *period_us) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + struct lttng_rotation_schedule_periodic *periodic_schedule; + + if (!schedule || !period_us) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + + periodic_schedule = container_of(schedule, + struct lttng_rotation_schedule_periodic, + parent); + if (periodic_schedule->period.set) { + *period_us = periodic_schedule->period.us; + } else { + status = LTTNG_ROTATION_STATUS_UNAVAILABLE; + goto end; + } +end: + return status; +} + +enum lttng_rotation_status +lttng_rotation_schedule_periodic_set_period( + struct lttng_rotation_schedule *schedule, + uint64_t period_us) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + struct lttng_rotation_schedule_periodic *periodic_schedule; + + if (!schedule || period_us == 0 || period_us == -1ULL) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + + periodic_schedule = container_of(schedule, + struct lttng_rotation_schedule_periodic, + parent); + periodic_schedule->period.us = period_us; + periodic_schedule->period.set = true; +end: + return status; +} + +void lttng_rotation_schedule_destroy(struct lttng_rotation_schedule *schedule) +{ + if (!schedule) { + return; + } + free(schedule); +} + +void lttng_rotation_schedules_destroy( + struct lttng_rotation_schedules *schedules) +{ + unsigned int i; + + if (!schedules) { + return; + } + + for (i = 0; i < schedules->count; i++) { + lttng_rotation_schedule_destroy(schedules->schedules[i]); + } + free(schedules); +} + + +enum lttng_rotation_status lttng_rotation_schedules_get_count( + const struct lttng_rotation_schedules *schedules, + unsigned int *count) +{ + enum lttng_rotation_status status = LTTNG_ROTATION_STATUS_OK; + + if (!schedules || !count) { + status = LTTNG_ROTATION_STATUS_INVALID; + goto end; + } + + *count = schedules->count; +end: + return status; +} + +const struct lttng_rotation_schedule *lttng_rotation_schedules_get_at_index( + const struct lttng_rotation_schedules *schedules, + unsigned int index) +{ + const struct lttng_rotation_schedule *schedule = NULL; + + if (!schedules || index >= schedules->count) { + goto end; + } + + schedule = schedules->schedules[index]; +end: + return schedule; +} + +enum lttng_rotation_status lttng_session_add_rotation_schedule( + const char *session_name, + const struct lttng_rotation_schedule *schedule) +{ + return lttng_rotation_update_schedule(session_name, schedule, true); +} + +enum lttng_rotation_status lttng_session_remove_rotation_schedule( + const char *session_name, + const struct lttng_rotation_schedule *schedule) +{ + return lttng_rotation_update_schedule(session_name, schedule, false); +} + +int lttng_session_list_rotation_schedules( + const char *session_name, + struct lttng_rotation_schedules **schedules) +{ + return get_schedules(session_name, schedules); } diff --git a/tests/regression/tools/rotation/test_save_load_mi b/tests/regression/tools/rotation/test_save_load_mi index e8971bb6d..494d375f6 100755 --- a/tests/regression/tools/rotation/test_save_load_mi +++ b/tests/regression/tools/rotation/test_save_load_mi @@ -36,7 +36,11 @@ XML_EXTRACT="$TESTDIR/regression/tools/mi/extract_xml" XPATH_CMD_OUTPUT="//lttng:command/lttng:output" XPATH_SESSION="$XPATH_CMD_OUTPUT/lttng:sessions/lttng:session" -XPATH_ROTATE_SETUP="$XPATH_CMD_OUTPUT/lttng:rotation_schedule" +XPATH_ENABLE_ROTATE_TIMER="$XPATH_CMD_OUTPUT/lttng:rotation_schedule_results/lttng:rotation_schedule_result/lttng:rotation_schedule/lttng:periodic/lttng:time_us" +XPATH_ENABLE_ROTATE_SIZE="$XPATH_CMD_OUTPUT/lttng:rotation_schedule_results/lttng:rotation_schedule_result/lttng:rotation_schedule/lttng:size_threshold/lttng:bytes" + +XPATH_LIST_ROTATE_TIMER="$XPATH_SESSION/lttng:rotation_schedules/lttng:periodic/lttng:time_us" +XPATH_LIST_ROTATE_SIZE="$XPATH_SESSION/lttng:rotation_schedules/lttng:size_threshold/lttng:bytes" function test_save_load_mi () { @@ -55,7 +59,7 @@ function test_save_load_mi () $XML_VALIDATE ${tmp_xml_output} ok $? "Valid lttng enable-rotation timer XML" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_ROTATE_SETUP}/lttng:rotation_schedule_timer_period) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_ENABLE_ROTATE_TIMER}) test $value = 500000 ok $? "Found the right rotation timer value in XML" @@ -64,7 +68,7 @@ function test_save_load_mi () $XML_VALIDATE ${tmp_xml_output} ok $? "Valid lttng enable-rotation size XML" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_ROTATE_SETUP}/lttng:rotation_schedule_size) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_ENABLE_ROTATE_SIZE}) test $value = 512000 ok $? "Found the right rotation size value in XML" @@ -73,11 +77,11 @@ function test_save_load_mi () $XML_VALIDATE ${tmp_xml_output} ok $? "Valid lttng list XML" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_SESSION}/lttng:rotation_schedule_timer_period) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_LIST_ROTATE_TIMER}) test $value = 500000 ok $? "Found the right rotation timer value in list XML" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_SESSION}/lttng:rotation_schedule_size) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_LIST_ROTATE_SIZE}) test $value = 512000 ok $? "Found the right rotation size value in list XML" @@ -93,11 +97,11 @@ function test_save_load_mi () $XML_VALIDATE ${tmp_xml_output} ok $? "Valid lttng list XML after load" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_SESSION}/lttng:rotation_schedule_timer_period) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_LIST_ROTATE_TIMER}) test $value = 500000 ok $? "Found the right rotation timer value in list XML after load" - value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_SESSION}/lttng:rotation_schedule_size) + value=$($XML_EXTRACT ${tmp_xml_output} ${XPATH_LIST_ROTATE_SIZE}) test $value = 512000 ok $? "Found the right rotation size value in list XML after load" -- 2.34.1