+}
+
+void ls::rotation_thread::subscribe_session_consumed_size_rotation(ltt_session& session,
+ std::uint64_t size)
+{
+ const struct lttng_credentials session_creds = {
+ .uid = LTTNG_OPTIONAL_INIT_VALUE(session.uid),
+ .gid = LTTNG_OPTIONAL_INIT_VALUE(session.gid),
+ };
+
+ ASSERT_LOCKED(session.lock);
+
+ auto rotate_condition = lttng::make_unique_wrapper<lttng_condition, lttng_condition_put>(
+ lttng_condition_session_consumed_size_create());
+ if (!rotate_condition) {
+ LTTNG_THROW_POSIX("Failed to create session consumed size condition object", errno);
+ }
+
+ auto condition_status =
+ lttng_condition_session_consumed_size_set_threshold(rotate_condition.get(), size);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Could not set session consumed size condition threshold: size={}", size));
+ }
+
+ condition_status = lttng_condition_session_consumed_size_set_session_name(
+ rotate_condition.get(), session.name);
+ if (condition_status != LTTNG_CONDITION_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Could not set session consumed size condition session name: name=`{}`",
+ session.name));
+ }
+
+ auto notify_action = lttng::make_unique_wrapper<lttng_action, lttng_action_put>(
+ lttng_action_notify_create());
+ if (!notify_action) {
+ LTTNG_THROW_POSIX("Could not create notify action", errno);
+ }
+
+ LTTNG_ASSERT(!session.rotate_trigger);
+ /* trigger acquires its own reference to condition and action on success. */
+ auto trigger = lttng::make_unique_wrapper<lttng_trigger, lttng_trigger_put>(
+ lttng_trigger_create(rotate_condition.get(), notify_action.get()));
+ if (!trigger) {
+ LTTNG_THROW_POSIX("Could not create size-based rotation trigger", errno);
+ }
+
+ /* Ensure this trigger is not visible to external users. */
+ lttng_trigger_set_hidden(trigger.get());
+ lttng_trigger_set_credentials(trigger.get(), &session_creds);
+
+ auto nc_status = lttng_notification_channel_subscribe(_notification_channel.get(),
+ rotate_condition.get());
+ if (nc_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
+ LTTNG_THROW_ERROR("Could not subscribe to session consumed size notification");
+ }
+
+ /*
+ * Ensure any notification queued during the subscription are consumed by queueing an
+ * event.
+ */
+ _notification_channel_subscribtion_change_eventfd.increment();
+
+ const auto register_ret = notification_thread_command_register_trigger(
+ &_notification_thread_handle, trigger.get(), true);
+ if (register_ret != LTTNG_OK) {
+ LTTNG_THROW_CTL(
+ fmt::format(
+ "Failed to register trigger for automatic size-based rotation: session_name{}, size={}",
+ session.name,
+ size),
+ register_ret);
+ }
+
+ /* Ownership transferred to the session. */
+ session.rotate_trigger = trigger.release();
+}
+
+void ls::rotation_thread::unsubscribe_session_consumed_size_rotation(ltt_session& session)
+{
+ LTTNG_ASSERT(session.rotate_trigger);
+
+ const auto remove_session_trigger = lttng::make_scope_exit([&session]() noexcept {
+ lttng_trigger_put(session.rotate_trigger);
+ session.rotate_trigger = nullptr;
+ });
+
+ const auto unsubscribe_status = lttng_notification_channel_unsubscribe(
+ _notification_channel.get(),
+ lttng_trigger_get_const_condition(session.rotate_trigger));
+ if (unsubscribe_status != LTTNG_NOTIFICATION_CHANNEL_STATUS_OK) {
+ LTTNG_THROW_ERROR(fmt::format(
+ "Failed to unsubscribe from consumed size condition used to control automatic size-based rotations: session_name=`{}` return_code={}",
+ session.name,
+ static_cast<int>(unsubscribe_status)));
+ }
+
+ /*
+ * Ensure any notification queued during the un-subscription are consumed by queueing an
+ * event.
+ */
+ _notification_channel_subscribtion_change_eventfd.increment();
+
+ const auto unregister_status = notification_thread_command_unregister_trigger(
+ &_notification_thread_handle, session.rotate_trigger);
+ if (unregister_status != LTTNG_OK) {
+ LTTNG_THROW_CTL(
+ fmt::format(
+ "Failed to unregister trigger for automatic size-based rotation: session_name{}",
+ session.name),
+ unregister_status);
+ }