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 */
#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.
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.
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 */
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.
* 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
}
* 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);
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;
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);
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:
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 */
}
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;
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;
/* 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.
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);
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;
if (opt_session_name == NULL) {
session_name = get_session_name();
if (session_name == NULL) {
- goto end;
+ goto error;
}
free_session_name = true;
} else {
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;
}
{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;
}
*/
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) {
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;
}
}
if (opt_session_name == NULL) {
session_name = get_session_name();
if (session_name == NULL) {
- goto end;
+ goto error;
}
free_session_name = true;
} else {
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;
}
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;
}
/*
/* Open rotations element */
ret = mi_lttng_writer_open_element(writer,
- mi_lttng_element_rotations);
+ mi_lttng_element_rotation_schedules);
if (ret) {
goto end;
}
/* 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;
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,
}
}
- 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;
}
}
[ 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",
</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" />
<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>
<!-- 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>
<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>
/* 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";
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;
+}
/* 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;
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 */
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 {
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;
#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,
}
-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(
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;
* 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;
goto end;
}
- init_rotation_handle(*rotation_handle, session_name, rotate_return,
- attr);
+ init_rotation_handle(*rotation_handle, session_name, rotate_return);
ret = 0;
}
/*
- * 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;
}
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);
}
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 ()
{
$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"
$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"
$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"
$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"