From 90936dcf0968343f20b2f6fd365b9c015cdb9717 Mon Sep 17 00:00:00 2001 From: Julien Desfossez Date: Fri, 9 Feb 2018 14:53:32 -0500 Subject: [PATCH] Size-based rotation MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The user can now configure the desired size of each chunk, every time a chunk is bigger than the specified size, a rotation is automatically started. The size of a chunk is measured by polling from the monitoring thread, so the accuracy depends on the monitoring sampling rate. Signed-off-by: Julien Desfossez Signed-off-by: Jérémie Galarneau --- include/lttng/rotate-internal.h | 2 + include/lttng/rotation.h | 6 + src/bin/lttng-sessiond/cmd.c | 40 ++++- src/bin/lttng-sessiond/cmd.h | 6 +- src/bin/lttng-sessiond/main.c | 25 ++- src/bin/lttng-sessiond/notification-thread.c | 5 +- src/bin/lttng-sessiond/notification-thread.h | 8 +- src/bin/lttng-sessiond/rotate.c | 100 +++++++++++ src/bin/lttng-sessiond/rotate.h | 13 ++ src/bin/lttng-sessiond/rotation-thread.c | 169 ++++++++++++++++++- src/bin/lttng-sessiond/rotation-thread.h | 11 +- src/bin/lttng-sessiond/session.h | 5 + src/bin/lttng/commands/disable_rotation.c | 19 ++- src/bin/lttng/commands/enable_rotation.c | 34 +++- src/common/config/session-config.c | 119 +++++++------ src/lib/lttng-ctl/rotate.c | 9 +- 16 files changed, 496 insertions(+), 75 deletions(-) diff --git a/include/lttng/rotate-internal.h b/include/lttng/rotate-internal.h index 29ea8c835..f5e4dc950 100644 --- a/include/lttng/rotate-internal.h +++ b/include/lttng/rotate-internal.h @@ -48,6 +48,8 @@ struct lttng_rotation_schedule_attr { char session_name[LTTNG_NAME_MAX]; /* > 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; /* diff --git a/include/lttng/rotation.h b/include/lttng/rotation.h index 186cbd6f6..00d68d7e5 100644 --- a/include/lttng/rotation.h +++ b/include/lttng/rotation.h @@ -134,6 +134,12 @@ extern enum lttng_rotation_status lttng_rotation_schedule_attr_set_session_name( extern enum lttng_rotation_status lttng_rotation_schedule_attr_set_timer_period( struct lttng_rotation_schedule_attr *attr, uint64_t timer); +/* + * Set the size to rotate the session (bytes, -1ULL to disable). + */ +void lttng_rotation_schedule_attr_set_size( + struct lttng_rotation_schedule_attr *attr, uint64_t size); + /* * lttng rotate session handle functions. */ diff --git a/src/bin/lttng-sessiond/cmd.c b/src/bin/lttng-sessiond/cmd.c index 375324aec..e88d7a2f7 100644 --- a/src/bin/lttng-sessiond/cmd.c +++ b/src/bin/lttng-sessiond/cmd.c @@ -2953,7 +2953,8 @@ error: * * Called with session lock held. */ -int cmd_destroy_session(struct ltt_session *session, int wpipe) +int cmd_destroy_session(struct ltt_session *session, int wpipe, + struct notification_thread_handle *notification_thread_handle) { int ret; struct ltt_ust_session *usess; @@ -2975,6 +2976,11 @@ int cmd_destroy_session(struct ltt_session *session, int wpipe) sessiond_rotate_timer_stop(session); } + if (session->rotate_size) { + unsubscribe_session_consumed_size_rotation(session, notification_thread_handle); + session->rotate_size = 0; + } + /* * The rename of the current chunk is performed at stop, but if we rotated * the session after the previous stop command, we need to rename the @@ -4659,7 +4665,8 @@ end: * Return 0 on success or else an LTTNG_ERR code. */ int cmd_rotation_set_schedule(struct ltt_session *session, - uint64_t timer_us, uint64_t size) + uint64_t timer_us, uint64_t size, + struct notification_thread_handle *notification_thread_handle) { int ret; @@ -4683,6 +4690,14 @@ int cmd_rotation_set_schedule(struct ltt_session *session, goto end; } + if (size && size != -1ULL && session->rotate_size) { + ret = LTTNG_ERR_ROTATION_SIZE_SET; + goto end; + } else if (size == -1ULL && !session->rotate_size) { + ret = LTTNG_ERR_ROTATION_NO_SIZE_SET; + goto end; + } + if (timer_us && !session->rotate_timer_period) { if (timer_us > UINT_MAX) { ret = LTTNG_ERR_INVALID; @@ -4707,6 +4722,27 @@ int cmd_rotation_set_schedule(struct ltt_session *session, session->rotate_timer_period = 0; } + if (size > 0) { + if (size == -1ULL) { + ret = unsubscribe_session_consumed_size_rotation(session, + notification_thread_handle); + if (ret) { + ret = LTTNG_ERR_UNK; + goto end; + } + session->rotate_size = 0; + } else { + ret = subscribe_session_consumed_size_rotation(session, + size, notification_thread_handle); + if (ret) { + PERROR("Subscribe to session usage"); + ret = LTTNG_ERR_UNK; + goto end; + } + session->rotate_size = size; + } + } + ret = LTTNG_OK; goto end; diff --git a/src/bin/lttng-sessiond/cmd.h b/src/bin/lttng-sessiond/cmd.h index 25c4ad506..6a6c87eaa 100644 --- a/src/bin/lttng-sessiond/cmd.h +++ b/src/bin/lttng-sessiond/cmd.h @@ -34,7 +34,8 @@ int cmd_create_session_uri(char *name, struct lttng_uri *uris, size_t nb_uri, lttng_sock_cred *creds, unsigned int live_timer); int cmd_create_session_snapshot(char *name, struct lttng_uri *uris, size_t nb_uri, lttng_sock_cred *creds); -int cmd_destroy_session(struct ltt_session *session, int wpipe); +int cmd_destroy_session(struct ltt_session *session, int wpipe, + struct notification_thread_handle *notification_thread_handle); /* Channel commands */ int cmd_disable_channel(struct ltt_session *session, @@ -126,6 +127,7 @@ int cmd_rotate_get_info(struct ltt_session *session, 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); + uint64_t size, + struct notification_thread_handle *notification_thread_handle); #endif /* CMD_H */ diff --git a/src/bin/lttng-sessiond/main.c b/src/bin/lttng-sessiond/main.c index cec3a504a..4c885d7b7 100644 --- a/src/bin/lttng-sessiond/main.c +++ b/src/bin/lttng-sessiond/main.c @@ -595,7 +595,8 @@ static void sessiond_cleanup(void) /* Cleanup ALL session */ cds_list_for_each_entry_safe(sess, stmp, &session_list_ptr->head, list) { - cmd_destroy_session(sess, kernel_poll_pipe[1]); + cmd_destroy_session(sess, kernel_poll_pipe[1], + notification_thread_handle); } } @@ -3771,7 +3772,8 @@ error_add_context: } case LTTNG_DESTROY_SESSION: { - ret = cmd_destroy_session(cmd_ctx->session, kernel_poll_pipe[1]); + ret = cmd_destroy_session(cmd_ctx->session, kernel_poll_pipe[1], + notification_thread_handle); /* Set session to NULL so we do not unlock it after free. */ cmd_ctx->session = NULL; @@ -4200,7 +4202,8 @@ error_add_context: ret = cmd_rotation_set_schedule(cmd_ctx->session, cmd_ctx->lsm->u.rotate_setup.timer_us, - cmd_ctx->lsm->u.rotate_setup.size); + cmd_ctx->lsm->u.rotate_setup.size, + notification_thread_handle); if (ret < 0) { ret = -ret; goto error; @@ -5709,6 +5712,7 @@ int main(int argc, char **argv) struct timer_thread_parameters timer_thread_ctx; /* Queue of rotation jobs populated by the sessiond-timer. */ struct rotation_thread_timer_queue *rotation_timer_queue = NULL; + sem_t notification_thread_ready; init_kernel_workarounds(); @@ -6116,11 +6120,19 @@ int main(int argc, char **argv) goto exit_health; } + /* + * The rotation thread needs the notification thread to be ready before + * creating the rotate_notification_channel, so we use this semaphore as + * a rendez-vous point. + */ + sem_init(¬ification_thread_ready, 0, 0); + /* notification_thread_data acquires the pipes' read side. */ notification_thread_handle = notification_thread_handle_create( ust32_channel_monitor_pipe, ust64_channel_monitor_pipe, - kernel_channel_monitor_pipe); + kernel_channel_monitor_pipe, + ¬ification_thread_ready); if (!notification_thread_handle) { retval = -1; ERR("Failed to create notification thread shared data"); @@ -6158,7 +6170,9 @@ int main(int argc, char **argv) ust64_channel_rotate_pipe, kernel_channel_rotate_pipe, thread_quit_pipe[0], - rotation_timer_queue); + rotation_timer_queue, + notification_thread_handle, + ¬ification_thread_ready); if (!rotation_thread_handle) { retval = -1; ERR("Failed to create rotation thread shared data"); @@ -6346,6 +6360,7 @@ exit_dispatch: exit_client: exit_rotation: exit_notification: + sem_destroy(¬ification_thread_ready); ret = pthread_join(health_thread, &status); if (ret) { errno = ret; diff --git a/src/bin/lttng-sessiond/notification-thread.c b/src/bin/lttng-sessiond/notification-thread.c index 62d47ee54..a8acd6f24 100644 --- a/src/bin/lttng-sessiond/notification-thread.c +++ b/src/bin/lttng-sessiond/notification-thread.c @@ -85,7 +85,8 @@ end: struct notification_thread_handle *notification_thread_handle_create( struct lttng_pipe *ust32_channel_monitor_pipe, struct lttng_pipe *ust64_channel_monitor_pipe, - struct lttng_pipe *kernel_channel_monitor_pipe) + struct lttng_pipe *kernel_channel_monitor_pipe, + sem_t *notification_thread_ready) { int ret; struct notification_thread_handle *handle; @@ -141,6 +142,7 @@ struct notification_thread_handle *notification_thread_handle_create( } else { handle->channel_monitoring_pipes.kernel_consumer = -1; } + handle->notification_thread_ready = notification_thread_ready; end: return handle; error: @@ -432,6 +434,7 @@ int init_thread_state(struct notification_thread_handle *handle, if (!state->triggers_ht) { goto error; } + sem_post(handle->notification_thread_ready); end: return 0; error: diff --git a/src/bin/lttng-sessiond/notification-thread.h b/src/bin/lttng-sessiond/notification-thread.h index 011ffbfae..2169b2efb 100644 --- a/src/bin/lttng-sessiond/notification-thread.h +++ b/src/bin/lttng-sessiond/notification-thread.h @@ -26,6 +26,7 @@ #include #include #include +#include struct notification_thread_handle { /* @@ -47,6 +48,10 @@ struct notification_thread_handle { int ust64_consumer; int kernel_consumer; } channel_monitoring_pipes; + /* + * To inform the rotation thread we are ready. + */ + sem_t *notification_thread_ready; }; /** @@ -185,7 +190,8 @@ struct notification_thread_state { struct notification_thread_handle *notification_thread_handle_create( struct lttng_pipe *ust32_channel_monitor_pipe, struct lttng_pipe *ust64_channel_monitor_pipe, - struct lttng_pipe *kernel_channel_monitor_pipe); + struct lttng_pipe *kernel_channel_monitor_pipe, + sem_t *notification_thread_ready); void notification_thread_handle_destroy( struct notification_thread_handle *handle); diff --git a/src/bin/lttng-sessiond/rotate.c b/src/bin/lttng-sessiond/rotate.c index 4264cd4bd..bd6dbddf9 100644 --- a/src/bin/lttng-sessiond/rotate.c +++ b/src/bin/lttng-sessiond/rotate.c @@ -32,6 +32,7 @@ #include #include +#include #include #include "session.h" @@ -41,6 +42,7 @@ #include "health-sessiond.h" #include "cmd.h" #include "utils.h" +#include "notification-thread-commands.h" #include #include @@ -401,3 +403,101 @@ int relay_rotate_pending(struct ltt_session *session, uint64_t chunk_id) end: return ret; } + +int subscribe_session_consumed_size_rotation(struct ltt_session *session, uint64_t size, + struct notification_thread_handle *notification_thread_handle) +{ + int ret; + enum lttng_condition_status condition_status; + enum lttng_notification_channel_status nc_status; + struct lttng_action *action; + + session->rotate_condition = lttng_condition_session_consumed_size_create(); + if (!session->rotate_condition) { + ERR("Failed to create session consumed size condition object"); + ret = -1; + goto end; + } + + condition_status = lttng_condition_session_consumed_size_set_threshold( + session->rotate_condition, size); + if (condition_status != LTTNG_CONDITION_STATUS_OK) { + ERR("Could not set session consumed size condition threshold (size = %" PRIu64 ")", + size); + ret = -1; + goto end; + } + + condition_status = + lttng_condition_session_consumed_size_set_session_name( + session->rotate_condition, session->name); + if (condition_status != LTTNG_CONDITION_STATUS_OK) { + ERR("Could not set session consumed size condition session name (name = %s)", + session->name); + ret = -1; + goto end; + } + + action = lttng_action_notify_create(); + if (!action) { + ERR("Could not create notify action"); + ret = -1; + goto end; + } + + session->rotate_trigger = lttng_trigger_create(session->rotate_condition, + action); + if (!session->rotate_trigger) { + ERR("Could not create size-based rotation trigger"); + ret = -1; + goto end; + } + + nc_status = lttng_notification_channel_subscribe( + rotate_notification_channel, session->rotate_condition); + if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) { + ERR("Could not subscribe to session consumed size notification"); + ret = -1; + goto end; + } + + ret = notification_thread_command_register_trigger( + notification_thread_handle, session->rotate_trigger); + if (ret < 0 && ret != -LTTNG_ERR_TRIGGER_EXISTS) { + ERR("Register trigger, %s", lttng_strerror(ret)); + ret = -1; + goto end; + } + + ret = 0; + +end: + return ret; +} + +int unsubscribe_session_consumed_size_rotation(struct ltt_session *session, + struct notification_thread_handle *notification_thread_handle) +{ + int ret = 0; + enum lttng_notification_channel_status status; + + status = lttng_notification_channel_unsubscribe( + rotate_notification_channel, + session->rotate_condition); + if (status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) { + ERR("Session unsubscribe error: %d", (int) status); + ret = -1; + goto end; + } + + ret = notification_thread_command_unregister_trigger( + notification_thread_handle, session->rotate_trigger); + if (ret != LTTNG_OK) { + ERR("Session unregister trigger error: %d", ret); + goto end; + } + + ret = 0; +end: + return ret; +} diff --git a/src/bin/lttng-sessiond/rotate.h b/src/bin/lttng-sessiond/rotate.h index ea2383f2c..6dc3b7aa1 100644 --- a/src/bin/lttng-sessiond/rotate.h +++ b/src/bin/lttng-sessiond/rotate.h @@ -18,6 +18,7 @@ #ifndef ROTATE_H #define ROTATE_H +#include #include "rotation-thread.h" /* @@ -41,7 +42,9 @@ struct rotation_channel_info { struct cds_lfht_node rotate_channels_ht_node; }; + extern struct cds_lfht *channel_pending_rotate_ht; +extern struct lttng_notification_channel *rotate_notification_channel; unsigned long hash_channel_key(struct rotation_channel_key *key); @@ -60,4 +63,14 @@ int relay_rotate_pending(struct ltt_session *session, uint64_t chunk_id); int rotate_add_channel_pending(uint64_t key, enum lttng_domain_type domain, struct ltt_session *session); +/* + * Subscribe/unsubscribe the notification_channel from the rotation_thread to + * session usage notifications to perform size-based rotations. + */ +int subscribe_session_consumed_size_rotation(struct ltt_session *session, + uint64_t size, + struct notification_thread_handle *notification_thread_handle); +int unsubscribe_session_consumed_size_rotation(struct ltt_session *session, + struct notification_thread_handle *notification_thread_handle); + #endif /* ROTATE_H */ diff --git a/src/bin/lttng-sessiond/rotation-thread.c b/src/bin/lttng-sessiond/rotation-thread.c index ecccc7bb0..9f15ed06e 100644 --- a/src/bin/lttng-sessiond/rotation-thread.c +++ b/src/bin/lttng-sessiond/rotation-thread.c @@ -53,6 +53,8 @@ */ struct cds_lfht *channel_pending_rotate_ht; +struct lttng_notification_channel *rotate_notification_channel = NULL; + struct rotation_thread_state { struct lttng_poll_event events; }; @@ -143,7 +145,9 @@ struct rotation_thread_handle *rotation_thread_handle_create( struct lttng_pipe *ust64_channel_rotate_pipe, struct lttng_pipe *kernel_channel_rotate_pipe, int thread_quit_pipe, - struct rotation_thread_timer_queue *rotation_timer_queue) + struct rotation_thread_timer_queue *rotation_timer_queue, + struct notification_thread_handle *notification_thread_handle, + sem_t *notification_thread_ready) { struct rotation_thread_handle *handle; @@ -184,6 +188,8 @@ struct rotation_thread_handle *rotation_thread_handle_create( } handle->thread_quit_pipe = thread_quit_pipe; handle->rotation_timer_queue = rotation_timer_queue; + handle->notification_thread_handle = notification_thread_handle; + handle->notification_thread_ready = notification_thread_ready; end: return handle; @@ -257,6 +263,9 @@ void fini_thread_state(struct rotation_thread_state *state) { lttng_poll_clean(&state->events); cds_lfht_destroy(channel_pending_rotate_ht, NULL); + if (rotate_notification_channel) { + lttng_notification_channel_destroy(rotate_notification_channel); + } } static @@ -282,6 +291,25 @@ int init_thread_state(struct rotation_thread_handle *handle, goto end; } + /* + * We wait until the notification thread is ready to create the + * notification channel and add it to the poll_set. + */ + sem_wait(handle->notification_thread_ready); + rotate_notification_channel = lttng_notification_channel_create( + lttng_session_daemon_notification_endpoint); + if (!rotate_notification_channel) { + ERR("[rotation-thread] Could not create notification channel"); + ret = -1; + goto end; + } + ret = lttng_poll_add(&state->events, rotate_notification_channel->socket, + LPOLLIN | LPOLLERR); + if (ret < 0) { + ERR("[rotation-thread] Failed to add notification fd to pollset"); + goto end; + } + end: return ret; } @@ -328,7 +356,7 @@ int handle_channel_rotation_pipe(int fd, uint32_t revents, } DBG("[rotation-thread] Received notification for chan %" PRIu64 - ", domain %d\n", key, domain); + ", domain %d", key, domain); channel_info = lookup_channel_pending(key, domain); if (!channel_info) { @@ -566,6 +594,136 @@ end: return ret; } +int handle_condition( + const struct lttng_condition *condition, + const struct lttng_evaluation *evaluation, + struct notification_thread_handle *notification_thread_handle) +{ + int ret = 0; + const char *condition_session_name = NULL; + enum lttng_condition_type condition_type; + enum lttng_condition_status condition_status; + enum lttng_evaluation_status evaluation_status; + uint64_t consumed; + struct ltt_session *session; + + condition_type = lttng_condition_get_type(condition); + + if (condition_type != LTTNG_CONDITION_TYPE_SESSION_CONSUMED_SIZE) { + ret = -1; + ERR("[rotation-thread] Condition type and session usage type are not the same"); + goto end; + } + + /* Fetch info to test */ + condition_status = lttng_condition_session_consumed_size_get_session_name( + condition, &condition_session_name); + if (condition_status != LTTNG_CONDITION_STATUS_OK) { + ERR("[rotation-thread] Session name could not be fetched"); + ret = -1; + goto end; + } + evaluation_status = lttng_evaluation_session_consumed_size_get_consumed_size(evaluation, + &consumed); + if (evaluation_status != LTTNG_EVALUATION_STATUS_OK) { + ERR("[rotation-thread] Failed to get evaluation"); + ret = -1; + goto end; + } + + session_lock_list(); + session = session_find_by_name(condition_session_name); + if (!session) { + ret = -1; + session_unlock_list(); + ERR("[rotation-thread] Session \"%s\" not found", + condition_session_name); + goto end; + } + session_lock(session); + session_unlock_list(); + + ret = unsubscribe_session_consumed_size_rotation(session, + notification_thread_handle); + if (ret) { + goto end; + } + + ret = cmd_rotate_session(session, NULL); + if (ret == -LTTNG_ERR_ROTATION_PENDING) { + DBG("Rotate already pending, subscribe to the next threshold value"); + ret = 0; + } else if (ret != LTTNG_OK) { + ERR("[rotation-thread] Failed to rotate on size notification with error: %s", + lttng_strerror(ret)); + ret = -1; + goto end_unlock; + } + ret = subscribe_session_consumed_size_rotation(session, + consumed + session->rotate_size, + notification_thread_handle); + if (ret) { + ERR("[rotation-thread] Failed to subscribe to session consumed size condition"); + goto end_unlock; + } + ret = 0; + +end_unlock: + session_unlock(session); +end: + return ret; +} + +static +int handle_notification_channel(int fd, uint32_t revents, + struct rotation_thread_handle *handle, + struct rotation_thread_state *state) +{ + int ret; + struct lttng_notification *notification; + enum lttng_notification_channel_status status; + const struct lttng_evaluation *notification_evaluation; + const struct lttng_condition *notification_condition; + + /* Receive the next notification. */ + status = lttng_notification_channel_get_next_notification( + rotate_notification_channel, + ¬ification); + + switch (status) { + case LTTNG_NOTIFICATION_CHANNEL_STATUS_OK: + break; + case LTTNG_NOTIFICATION_CHANNEL_STATUS_NOTIFICATIONS_DROPPED: + /* Not an error, we will wait for the next one */ + ret = 0; + goto end;; + case LTTNG_NOTIFICATION_CHANNEL_STATUS_CLOSED: + ERR("Notification channel was closed"); + ret = -1; + goto end; + default: + /* Unhandled conditions / errors. */ + ERR("Unknown notification channel status"); + ret = -1; + goto end; + } + + notification_condition = lttng_notification_get_condition(notification); + notification_evaluation = lttng_notification_get_evaluation(notification); + + ret = handle_condition(notification_condition, notification_evaluation, + handle->notification_thread_handle); + +end: + lttng_notification_destroy(notification); + if (ret != 0) { + goto end; + } + + + return ret; +} + void *thread_rotation(void *data) { int ret; @@ -639,6 +797,13 @@ void *thread_rotation(void *data) ERR("[rotation-thread] Handle channel rotation pipe"); goto error; } + } else if (fd == rotate_notification_channel->socket) { + ret = handle_notification_channel(fd, revents, + handle, &state); + if (ret) { + ERR("[rotation-thread] Error occured while handling activity on notification channel socket"); + goto error; + } } } } diff --git a/src/bin/lttng-sessiond/rotation-thread.h b/src/bin/lttng-sessiond/rotation-thread.h index c7bca0c4b..41da6e044 100644 --- a/src/bin/lttng-sessiond/rotation-thread.h +++ b/src/bin/lttng-sessiond/rotation-thread.h @@ -26,6 +26,7 @@ #include #include #include +#include #include "session.h" /* @@ -49,7 +50,13 @@ struct rotation_thread_handle { int kernel_consumer; /* quit pipe */ int thread_quit_pipe; + struct rotation_thread_timer_queue *rotation_timer_queue; + + /* Access to the notification thread cmd_queue */ + struct notification_thread_handle *notification_thread_handle; + + sem_t *notification_thread_ready; }; struct rotation_thread_handle *rotation_thread_handle_create( @@ -57,7 +64,9 @@ struct rotation_thread_handle *rotation_thread_handle_create( struct lttng_pipe *ust64_channel_rotate_pipe, struct lttng_pipe *kernel_channel_rotate_pipe, int thread_quit_pipe, - struct rotation_thread_timer_queue *rotation_timer_queue); + struct rotation_thread_timer_queue *rotation_timer_queue, + struct notification_thread_handle *notification_thread_handle, + sem_t *notification_thread_ready); void rotation_thread_handle_destroy( struct rotation_thread_handle *handle); diff --git a/src/bin/lttng-sessiond/session.h b/src/bin/lttng-sessiond/session.h index e00e51cc6..ab9b1a9a4 100644 --- a/src/bin/lttng-sessiond/session.h +++ b/src/bin/lttng-sessiond/session.h @@ -186,6 +186,11 @@ struct ltt_session { * chunk. */ bool rotated_after_last_stop; + /* + * Condition and trigger for size-based rotations. + */ + struct lttng_condition *rotate_condition; + struct lttng_trigger *rotate_trigger; }; /* Prototypes */ diff --git a/src/bin/lttng/commands/disable_rotation.c b/src/bin/lttng/commands/disable_rotation.c index b0de06d9f..e917cbdc1 100644 --- a/src/bin/lttng/commands/disable_rotation.c +++ b/src/bin/lttng/commands/disable_rotation.c @@ -39,6 +39,7 @@ enum { OPT_HELP = 1, OPT_LIST_OPTIONS, OPT_TIMER, + OPT_SIZE, }; static struct poptOption long_options[] = { @@ -47,10 +48,11 @@ static struct poptOption long_options[] = { {"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) +static int setup_rotate(char *session_name, uint64_t timer, uint64_t size) { int ret = 0; struct lttng_rotation_schedule_attr *attr = NULL; @@ -86,6 +88,10 @@ static int setup_rotate(char *session_name, uint64_t timer) lttng_rotation_schedule_attr_set_timer_period(attr, timer); MSG("Disabling rotation timer on session %s", session_name); } + if (size == -1ULL) { + lttng_rotation_schedule_attr_set_size(attr, size); + MSG("Disabling rotation based on size on session %s", session_name); + } ret = lttng_rotation_set_schedule(attr); if (ret) { @@ -140,7 +146,7 @@ int cmd_disable_rotation(int argc, const char **argv) static poptContext pc; char *session_name = NULL; bool free_session_name = false; - uint64_t timer = 0; + uint64_t timer = 0, size = 0; pc = poptGetContext(NULL, argc, argv, long_options, 0); popt_ret = poptReadDefaultConfig(pc, 0); @@ -161,6 +167,9 @@ int cmd_disable_rotation(int argc, const char **argv) case OPT_TIMER: timer = -1ULL; break; + case OPT_SIZE: + size = -1ULL; + break; default: ret = CMD_UNDEFINED; goto end; @@ -203,12 +212,12 @@ int cmd_disable_rotation(int argc, const char **argv) } /* No config options, just rotate the session now */ - if (timer == 0) { - ERR("No timer given"); + 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); + command_ret = setup_rotate(session_name, timer, size); } if (command_ret) { diff --git a/src/bin/lttng/commands/enable_rotation.c b/src/bin/lttng/commands/enable_rotation.c index a746f016f..80fc495ba 100644 --- a/src/bin/lttng/commands/enable_rotation.c +++ b/src/bin/lttng/commands/enable_rotation.c @@ -40,6 +40,7 @@ enum { OPT_HELP = 1, OPT_LIST_OPTIONS, OPT_TIMER, + OPT_SIZE, }; static struct poptOption long_options[] = { @@ -48,10 +49,11 @@ static struct poptOption long_options[] = { {"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_INT, 0, OPT_TIMER, 0, 0}, + {"size", 0, POPT_ARG_INT, 0, OPT_SIZE, 0, 0}, {0, 0, 0, 0, 0, 0, 0} }; -static int setup_rotate(char *session_name, uint64_t timer) +static int setup_rotate(char *session_name, uint64_t timer, uint64_t size) { int ret = 0; struct lttng_rotation_schedule_attr *attr = NULL; @@ -93,6 +95,18 @@ static int setup_rotate(char *session_name, uint64_t timer) } } } + 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; + } + } + } ret = lttng_rotation_set_schedule(attr); if (ret) { @@ -147,8 +161,8 @@ int cmd_enable_rotation(int argc, const char **argv) static poptContext pc; char *session_name = NULL; char *opt_arg = NULL; - uint64_t timer = 0; bool free_session_name = false; + uint64_t timer = 0, size = 0; pc = poptGetContext(NULL, argc, argv, long_options, 0); popt_ret = poptReadDefaultConfig(pc, 0); @@ -181,6 +195,16 @@ int cmd_enable_rotation(int argc, const char **argv) } DBG("Rotation timer set to %" PRIu64, timer); 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; + } + DBG("Rotation size set to %" PRIu64, size); + break; default: ret = CMD_UNDEFINED; goto end; @@ -223,12 +247,12 @@ int cmd_enable_rotation(int argc, const char **argv) } /* No config options, just rotate the session now */ - if (timer == 0) { - ERR("No timer given"); + if (timer == 0 && size == 0) { + ERR("No timer or size given"); success = 0; command_ret = -1; } else { - command_ret = setup_rotate(session_name, timer); + command_ret = setup_rotate(session_name, timer, size); } if (command_ret) { diff --git a/src/common/config/session-config.c b/src/common/config/session-config.c index 49047b1d6..8b91f32d5 100644 --- a/src/common/config/session-config.c +++ b/src/common/config/session-config.c @@ -2519,12 +2519,14 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, { int ret, started = -1, snapshot_mode = -1; uint64_t live_timer_interval = UINT64_MAX, - rotation_timer_interval = 0; + rotation_timer_interval = 0, + rotation_size = 0; xmlChar *name = NULL; xmlChar *shm_path = NULL; xmlNodePtr domains_node = NULL; xmlNodePtr output_node = NULL; xmlNodePtr node; + xmlNodePtr attributes_child; struct lttng_domain *kernel_domain = NULL; struct lttng_domain *ust_domain = NULL; struct lttng_domain *jul_domain = NULL; @@ -2579,58 +2581,76 @@ int process_session_node(xmlNodePtr session_node, const char *session_name, } else { /* * attributes, snapshot_mode, live_timer_interval, rotation_size, - * rotation_timer_interval. */ - xmlNodePtr attributes_child = - xmlFirstElementChild(node); - - if (!strcmp((const char *) attributes_child->name, - config_element_snapshot_mode)) { - /* snapshot_mode */ - xmlChar *snapshot_mode_content = - xmlNodeGetContent(attributes_child); - if (!snapshot_mode_content) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } + * rotation_timer_interval. + */ + for (attributes_child = xmlFirstElementChild(node); attributes_child; + attributes_child = xmlNextElementSibling(attributes_child)) { + if (!strcmp((const char *) attributes_child->name, + config_element_snapshot_mode)) { + /* snapshot_mode */ + xmlChar *snapshot_mode_content = + xmlNodeGetContent(attributes_child); + if (!snapshot_mode_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } - ret = parse_bool(snapshot_mode_content, &snapshot_mode); - free(snapshot_mode_content); - if (ret) { - ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto error; - } - } else if (!strcmp((const char *) attributes_child->name, - config_element_live_timer_interval)) { - /* live_timer_interval */ - xmlChar *timer_interval_content = - xmlNodeGetContent(attributes_child); - if (!timer_interval_content) { - ret = -LTTNG_ERR_NOMEM; - goto error; - } + ret = parse_bool(snapshot_mode_content, &snapshot_mode); + free(snapshot_mode_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } + } else if (!strcmp((const char *) attributes_child->name, + config_element_live_timer_interval)) { + /* live_timer_interval */ + xmlChar *timer_interval_content = + xmlNodeGetContent(attributes_child); + if (!timer_interval_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } - ret = parse_uint(timer_interval_content, &live_timer_interval); - free(timer_interval_content); - if (ret) { - ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto error; + ret = parse_uint(timer_interval_content, &live_timer_interval); + free(timer_interval_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } - } - if (!strcmp((const char *) attributes_child->name, - config_element_rotation_timer_interval)) { - /* rotation_timer_interval */ - xmlChar *timer_interval_content = - xmlNodeGetContent(attributes_child); - if (!timer_interval_content) { - ret = -LTTNG_ERR_NOMEM; - goto error; + if (!strcmp((const char *) attributes_child->name, + config_element_rotation_timer_interval)) { + /* rotation_timer_interval */ + xmlChar *timer_interval_content = + xmlNodeGetContent(attributes_child); + if (!timer_interval_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } + + ret = parse_uint(timer_interval_content, &rotation_timer_interval); + free(timer_interval_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } + if (!strcmp((const char *) attributes_child->name, + config_element_rotation_size)) { + /* rotation_size */ + xmlChar *rotation_size_content = + xmlNodeGetContent(attributes_child); + if (!rotation_size_content) { + ret = -LTTNG_ERR_NOMEM; + goto error; + } - ret = parse_uint(timer_interval_content, &rotation_timer_interval); - free(timer_interval_content); - if (ret) { - ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; - goto error; + ret = parse_uint(rotation_size_content, &rotation_size); + free(rotation_size_content); + if (ret) { + ret = -LTTNG_ERR_LOAD_INVALID_CONFIG; + goto error; + } } } } @@ -2770,7 +2790,7 @@ domain_init_error: } } - if (rotation_timer_interval) { + if (rotation_timer_interval || rotation_size) { struct lttng_rotation_schedule_attr *rotation_attr = lttng_rotation_schedule_attr_create(); if (!rotation_attr) { @@ -2783,6 +2803,7 @@ domain_init_error: } lttng_rotation_schedule_attr_set_timer_period(rotation_attr, rotation_timer_interval); + lttng_rotation_schedule_attr_set_size(rotation_attr, rotation_size); ret = lttng_rotation_set_schedule(rotation_attr); lttng_rotation_schedule_attr_destroy(rotation_attr); if (ret) { diff --git a/src/lib/lttng-ctl/rotate.c b/src/lib/lttng-ctl/rotate.c index 9ad32f962..d9907cc67 100644 --- a/src/lib/lttng-ctl/rotate.c +++ b/src/lib/lttng-ctl/rotate.c @@ -149,6 +149,12 @@ end: return status; } +void lttng_rotation_schedule_attr_set_size( + struct lttng_rotation_schedule_attr *attr, uint64_t size) +{ + attr->size = size; +} + enum lttng_rotation_status lttng_rotation_handle_get_state( struct lttng_rotation_handle *rotation_handle, enum lttng_rotation_state *state) @@ -323,6 +329,7 @@ int lttng_rotation_set_schedule( lttng_ctl_copy_string(lsm.session.name, attr->session_name, sizeof(lsm.session.name)); lsm.u.rotate_setup.timer_us = attr->timer_us; + lsm.u.rotate_setup.size = attr->size; ret = lttng_ctl_ask_sessiond(&lsm, NULL); @@ -349,9 +356,7 @@ int lttng_rotation_schedule_get_timer_period(const char *session_name, } *rotate_timer = get_timer->rotate_timer; - ret = 0; - end: free(get_timer); return ret; -- 2.34.1