rotation-api: introduce rotation schedule descriptors
authorJérémie Galarneau <jeremie.galarneau@efficios.com>
Mon, 6 Aug 2018 20:36:12 +0000 (16:36 -0400)
committerJérémie Galarneau <jeremie.galarneau@efficios.com>
Wed, 15 Aug 2018 22:06:16 +0000 (18:06 -0400)
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 <jeremie.galarneau@efficios.com>
19 files changed:
include/lttng/lttng-error.h
include/lttng/rotate-internal.h
include/lttng/rotation.h
src/bin/lttng-sessiond/cmd.c
src/bin/lttng-sessiond/cmd.h
src/bin/lttng-sessiond/main.c
src/bin/lttng-sessiond/session.h
src/bin/lttng/commands/disable_rotation.c
src/bin/lttng/commands/enable_rotation.c
src/bin/lttng/commands/list.c
src/bin/lttng/commands/rotate.c
src/common/config/session-config.c
src/common/error.c
src/common/mi-lttng-3.0.xsd
src/common/mi-lttng.c
src/common/mi-lttng.h
src/common/sessiond-comm/sessiond-comm.h
src/lib/lttng-ctl/rotate.c
tests/regression/tools/rotation/test_save_load_mi

index 3c72aeeec58525b3ff5711765f0391a56d831ec8..c6c2daec975dbf36ac36a2af8f4e3cba1748e1da 100644 (file)
@@ -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 */
index 8d0823b7a8e42f05e5731fbc9dc58c54e344ce8a..966f9f969fe5c8bcbf895d02ad7374a65aa80987 100644 (file)
 #include <lttng/rotation.h>
 #include <common/macros.h>
 
-/*
- * 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 */
index 6091a7b988078039f73d641a6329cd6045f21701..d13f3641a2dfba3dbf878c89f20ab5fac56a62d9 100644 (file)
@@ -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
 }
index 65a24e4dcdbd492e3abe14969a6f92be45e5486c..ba7dd3d4dd9452b92328547f7f09e24a7e389cf1 100644 (file)
@@ -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;
index 79ff689c33c970ab25298aed7e9699bea58def83..16c07f78e66d78e25491e8e033c5c0c52c6c628d 100644 (file)
@@ -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);
index 5e644a72d9f821ec638d31e752542fa42cf2cffb..e8f05cecf2694dc8048c4540950611d265097145 100644 (file)
@@ -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;
index 92e7a11ad430dfe7c05a7a9ce28f4a66ddebb278..371b30d6be856444ac3afbcfaffe707d0a43a0cb 100644 (file)
@@ -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.
index b179e91ce33e8f91e94a3d741d9ef7a0a34e03ab..30dfaa1691db929295cce3cba2a0ef921fd06c57 100644 (file)
@@ -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 <options>' first level command
+ *  The 'disable-rotation <options>' 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;
 }
index 81a55b24c8aaec4810cec9ce54bcbc1621d1a6ea..3c2bd787ecefc40b940fe511b6db27f9af153985 100644 (file)
@@ -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;
 }
index e05134cbb2d518f6f1dbfcea9ffa0fc151fd71e8..a4ee96e9e0f2b1843a9696f28e8f822cb84c0b51 100644 (file)
@@ -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;
 }
 
 /*
index 68bc59a33bf59037cd827a694637a530f5724c06..1e4677ffd18bb4503dd6b64f295536fe24e4c327 100644 (file)
@@ -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;
index 244fbd5cc5c05f85e0bcaef9a00c345e634f02dc..ffe7b14ed59cb0cca2dd23fe4075e5bc48a637ae 100644 (file)
@@ -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;
                }
        }
index aebcaa91529268268cf06f787febc407a05a488c..b288b90baa723505b42be3f8b87ca54d0a93206f 100644 (file)
@@ -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",
index f9ca71094ec355f14209dbaad29e400d7071b08e..9c1a293afe78bfab1e5092781057a0d71d79c9a5 100644 (file)
@@ -402,6 +402,27 @@ THE SOFTWARE.
                </xs:sequence>
        </xs:complexType>
 
+       <xs:complexType name="periodic_rotation_schedule_type">
+               <xs:all>
+                       <xs:element name="time_us" type="tns:uint64_type" minOccurs="0" />
+               </xs:all>
+       </xs:complexType>
+
+       <xs:complexType name="size_threshold_rotation_schedule_type">
+               <xs:all>
+                       <xs:element name="bytes" type="tns:uint64_type" minOccurs="0" />
+               </xs:all>
+       </xs:complexType>
+
+       <xs:complexType name="rotation_schedule_type">
+               <xs:sequence>
+                       <xs:choice maxOccurs="unbounded">
+                               <xs:element name="periodic" type="tns:periodic_rotation_schedule_type" maxOccurs="unbounded" />
+                               <xs:element name="size_threshold" type="tns:size_threshold_rotation_schedule_type" maxOccurs="unbounded" />
+                       </xs:choice>
+               </xs:sequence>
+       </xs:complexType>
+
        <xs:complexType name="channels_type">
                <xs:sequence>
                        <xs:element name="channel" type="tns:channel_type" minOccurs="0" maxOccurs="unbounded" />
@@ -419,8 +440,7 @@ THE SOFTWARE.
                        <xs:element name="channels" type="tns:channels_type" minOccurs="0" />
                        <xs:element name="domains" type="tns:domains_type" minOccurs="0" />
                        <xs:element name="snapshots" type="tns:snapshots_type" minOccurs="0" />
-                       <xs:element name="rotation_schedule_size" type="tns:uint64_type" default="0" minOccurs="0" /> <!-- bytes -->
-                       <xs:element name="rotation_schedule_timer_period" type="tns:uint64_type" default="0" minOccurs="0" /> <!-- usec -->
+                       <xs:element name="rotation_schedules" type="tns:rotation_schedule_type" minOccurs="0" />
                </xs:all>
        </xs:complexType>
 
@@ -572,26 +592,23 @@ THE SOFTWARE.
        <!-- Maps to the rotate command -->
        <xs:complexType name="rotation_type">
                <xs:all>
-                       <xs:element name="session_name" type="tns:name_type" minOccurs="0" />
                        <xs:element name="status" type="xs:string" />
                        <xs:element name="path" type="xs:string" minOccurs="0" />
                </xs:all>
        </xs:complexType>
 
-       <!-- Maps to an array of rotations -->
-       <xs:complexType name="rotations_type">
+       <xs:complexType name="rotation_schedule_result_type">
                <xs:sequence>
-                       <xs:element name="rotation" type="tns:rotation_type" minOccurs="0" maxOccurs="unbounded" />
+                       <xs:element name="rotation_schedule" type="tns:rotation_schedule_type" minOccurs="1" />
+                       <xs:element name="success" type="xs:boolean" minOccurs="1"/>
                </xs:sequence>
        </xs:complexType>
 
-       <!-- Maps to the enable-rotation command -->
-       <xs:complexType name="rotation_schedule_type">
+       <!-- Maps to the enable/disable-rotation commands -->
+       <xs:complexType name="rotation_schedule_cmd_type">
                <xs:sequence>
-                       <xs:element name="session_name" type="tns:name_type" minOccurs="0" />
-                       <xs:element name="rotation_schedule_size" type="tns:uint64_type" default="0" minOccurs="0" /> <!-- bytes -->
-                       <xs:element name="rotation_schedule_timer_period" type="tns:uint64_type" default="0" minOccurs="0" /> <!-- usec -->
-                       <xs:element name="status" type="xs:string" minOccurs="0"/>
+                       <xs:element name="session_name" type="tns:name_type" minOccurs="1" />
+                       <xs:element name="rotation_schedule_result" type="tns:rotation_schedule_result_type" minOccurs="1" maxOccurs="unbounded" />
                </xs:sequence>
        </xs:complexType>
 
@@ -613,8 +630,8 @@ THE SOFTWARE.
                        <xs:element name="targets" type="tns:targets_type" minOccurs="0" />
                        <xs:element name="metadata_action" type="tns:metadata_cmd_type" minOccurs="0" />
                        <xs:element name="regenerate_action" type="tns:regenerate_cmd_type" minOccurs="0" />
-                       <xs:element name="rotations" type="tns:rotations_type" minOccurs="0" />
-                       <xs:element name="rotation_schedule" type="tns:rotation_schedule_type" minOccurs="0" />
+                       <xs:element name="rotation" type="tns:rotation_type" minOccurs="0" />
+                       <xs:element name="rotation_schedule_results" type="tns:rotation_schedule_cmd_type" minOccurs="0" />
                </xs:choice>
        </xs:complexType>
 
index e8236d841300650a4f8b68b92a8dbf6e6ac5416e..d5148bcb58376cc09e24978e2f5de06fee9c028f 100644 (file)
@@ -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;
+}
index df7a68a02cdade0f8755c4c0f623945968cbd261..37136a8dbed4417ee0088baa9ea3e7cedeb68b30 100644 (file)
@@ -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 */
index 59f7482eb729915ff6aceed83750a4732882d1c1..2cd66f46fc77abd46b15b94781f4f299329502c3 100644 (file)
 
 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;
 
index f32c69be18d10bc07c0c8294ff808aee23f50333..5c5b1b70cc05b2eecee78809cce1309d716b9a14 100644 (file)
 
 #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);
 }
index e8971bb6d10fe6e2238cccc373dca40f40acf631..494d375f6fd701c5eb80c5fb8ba19fd9e67db053 100755 (executable)
@@ -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"
 
This page took 0.06195 seconds and 4 git commands to generate.