src.ctf.lttng-live: consider youngest only when timestamp is smaller
[babeltrace.git] / src / plugins / ctf / lttng-live / lttng-live.c
index df5639b1ca1c38a5480985c8e3b667686a2281d0..1962aa2de3e4fdd9a25ac88bd1208a21d2fd4fc0 100644 (file)
@@ -31,7 +31,7 @@
 #define BT_COMP_LOG_SELF_COMP self_comp
 #define BT_LOG_OUTPUT_LEVEL log_level
 #define BT_LOG_TAG "PLUGIN/SRC.CTF.LTTNG-LIVE"
-#include "plugins/comp-logging.h"
+#include "logging/comp-logging.h"
 
 #include <glib.h>
 #include <inttypes.h>
@@ -42,6 +42,8 @@
 #include "compat/compiler.h"
 #include <babeltrace2/types.h>
 
+#include "plugins/common/muxing/muxing.h"
+
 #include "data-stream.h"
 #include "metadata.h"
 #include "lttng-live.h"
@@ -793,6 +795,34 @@ end:
        return ret;
 }
 
+static
+enum lttng_live_iterator_status lttng_live_iterator_close_stream(
+               struct lttng_live_msg_iter *lttng_live_msg_iter,
+               struct lttng_live_stream_iterator *stream_iter,
+               bt_message **curr_msg)
+{
+       enum lttng_live_iterator_status live_status =
+               LTTNG_LIVE_ITERATOR_STATUS_OK;
+       /*
+        * The viewer has hung up on us so we are closing the stream. The
+        * `bt_msg_iter` should simply realize that it needs to close the
+        * stream properly by emitting the necessary stream end message.
+        */
+       enum bt_msg_iter_status status =
+               bt_msg_iter_get_next_message(stream_iter->msg_iter,
+                       lttng_live_msg_iter->self_msg_iter, curr_msg);
+
+       if (status == BT_MSG_ITER_STATUS_ERROR) {
+               live_status = LTTNG_LIVE_ITERATOR_STATUS_ERROR;
+               goto end;
+       }
+
+       BT_ASSERT(status == BT_MSG_ITER_STATUS_OK);
+
+end:
+       return live_status;
+}
+
 /*
  * helper function:
  *            handle_no_data_streams()
@@ -842,7 +872,7 @@ end:
  * When disconnected from relayd: try to re-connect endlessly.
  */
 static
-enum lttng_live_iterator_status lttng_live_iterator_next_on_stream(
+enum lttng_live_iterator_status lttng_live_iterator_next_msg_on_stream(
                struct lttng_live_msg_iter *lttng_live_msg_iter,
                struct lttng_live_stream_iterator *stream_iter,
                bt_message **curr_msg)
@@ -851,6 +881,17 @@ enum lttng_live_iterator_status lttng_live_iterator_next_on_stream(
        bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
        enum lttng_live_iterator_status live_status;
 
+       if (stream_iter->has_stream_hung_up) {
+               /*
+                * The stream has hung up and the stream was properly closed
+                * during the last call to the current function. Return _END
+                * status now so that this stream iterator is removed for the
+                * stream iterator list.
+                */
+               live_status = LTTNG_LIVE_ITERATOR_STATUS_END;
+               goto end;
+       }
+
 retry:
        print_stream_state(stream_iter);
        live_status = lttng_live_iterator_handle_new_streams_and_metadata(
@@ -860,7 +901,16 @@ retry:
        }
        live_status = lttng_live_iterator_next_handle_one_no_data_stream(
                        lttng_live_msg_iter, stream_iter);
+
        if (live_status != LTTNG_LIVE_ITERATOR_STATUS_OK) {
+               if (live_status == LTTNG_LIVE_ITERATOR_STATUS_END) {
+                       /*
+                        * We overwrite `live_status` since `curr_msg` is
+                        * likely set to a valid message in this function.
+                        */
+                       live_status = lttng_live_iterator_close_stream(
+                               lttng_live_msg_iter, stream_iter, curr_msg);
+               }
                goto end;
        }
        live_status = lttng_live_iterator_next_handle_one_quiescent_stream(
@@ -890,11 +940,11 @@ static
 enum lttng_live_iterator_status next_stream_iterator_for_trace(
                struct lttng_live_msg_iter *lttng_live_msg_iter,
                struct lttng_live_trace *live_trace,
-               struct lttng_live_stream_iterator **candidate_stream_iter)
+               struct lttng_live_stream_iterator **youngest_trace_stream_iter)
 {
-       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
+       struct lttng_live_stream_iterator *youngest_candidate_stream_iter = NULL;
        enum lttng_live_iterator_status stream_iter_status;;
-       int64_t curr_candidate_msg_ts = INT64_MAX;
+       int64_t youngest_candidate_msg_ts = INT64_MAX;
        uint64_t stream_iter_idx;
        bt_logging_level log_level = lttng_live_msg_iter->log_level;
        bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
@@ -914,6 +964,16 @@ enum lttng_live_iterator_status next_stream_iterator_for_trace(
                        g_ptr_array_index(live_trace->stream_iterators,
                                        stream_iter_idx);
 
+               /*
+                * Since we may remove elements from the GPtrArray as we
+                * iterate over it, it's possible to see the same element more
+                * than once.
+                */
+               if (stream_iter == youngest_candidate_stream_iter) {
+                       stream_iter_idx++;
+                       continue;
+               }
+
                /*
                 * Find if there is are now current message for this stream
                 * iterator get it.
@@ -921,7 +981,7 @@ enum lttng_live_iterator_status next_stream_iterator_for_trace(
                while (!stream_iter->current_msg) {
                        bt_message *msg = NULL;
                        int64_t curr_msg_ts_ns = INT64_MAX;
-                       stream_iter_status = lttng_live_iterator_next_on_stream(
+                       stream_iter_status = lttng_live_iterator_next_msg_on_stream(
                                        lttng_live_msg_iter, stream_iter, &msg);
 
                        BT_COMP_LOGD("live stream iterator returned status :%s",
@@ -971,18 +1031,50 @@ enum lttng_live_iterator_status next_stream_iterator_for_trace(
                        }
                }
 
-               if (!stream_iter_is_ended &&
-                               stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
-                       /*
-                        * Update the current best candidate message for the
-                        * stream iterator of thise live trace to be forwarded
-                        * downstream.
-                        */
-                       curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
-                       curr_candidate_stream_iter = stream_iter;
-               }
+               BT_ASSERT(stream_iter != youngest_candidate_stream_iter);
 
-               if (stream_iter_is_ended) {
+               if (!stream_iter_is_ended) {
+                       if (G_UNLIKELY(youngest_candidate_stream_iter == NULL) ||
+                                       stream_iter->current_msg_ts_ns < youngest_candidate_msg_ts) {
+                               /*
+                                * Update the current best candidate message
+                                * for the stream iterator of this live trace
+                                * to be forwarded downstream.
+                                */
+                               youngest_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                               youngest_candidate_stream_iter = stream_iter;
+                       } else if (stream_iter->current_msg_ts_ns == youngest_candidate_msg_ts) {
+                               /*
+                                * Order the messages in an arbitrary but
+                                * deterministic way.
+                                */
+                               BT_ASSERT(stream_iter != youngest_candidate_stream_iter);
+                               int ret = common_muxing_compare_messages(
+                                       stream_iter->current_msg,
+                                       youngest_candidate_stream_iter->current_msg);
+                               if (ret < 0) {
+                                       /*
+                                        * The `youngest_candidate_stream_iter->current_msg`
+                                        * should go first. Update the next
+                                        * iterator and the current timestamp.
+                                        */
+                                       youngest_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                                       youngest_candidate_stream_iter = stream_iter;
+                               } else if (ret == 0) {
+                                       /*
+                                        * Unable to pick which one should go
+                                        * first.
+                                        */
+                                       BT_COMP_LOGW("Cannot deterministically pick next live stream message iterator because they have identical next messages: "
+                                               "stream-iter-addr=%p"
+                                               "stream-iter-addr=%p",
+                                               stream_iter,
+                                               youngest_candidate_stream_iter);
+                               }
+                       }
+
+                       stream_iter_idx++;
+               } else {
                        /*
                         * The live stream iterator is ENDed. We remove that
                         * iterator from the list and we restart the iteration
@@ -992,13 +1084,11 @@ enum lttng_live_iterator_status next_stream_iterator_for_trace(
                        g_ptr_array_remove_index_fast(live_trace->stream_iterators,
                                stream_iter_idx);
                        stream_iter_idx = 0;
-               } else {
-                       stream_iter_idx++;
                }
        }
 
-       if (curr_candidate_stream_iter) {
-               *candidate_stream_iter = curr_candidate_stream_iter;
+       if (youngest_candidate_stream_iter) {
+               *youngest_trace_stream_iter = youngest_candidate_stream_iter;
                stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
        } else {
                /*
@@ -1017,12 +1107,14 @@ static
 enum lttng_live_iterator_status next_stream_iterator_for_session(
                struct lttng_live_msg_iter *lttng_live_msg_iter,
                struct lttng_live_session *session,
-               struct lttng_live_stream_iterator **candidate_session_stream_iter)
+               struct lttng_live_stream_iterator **youngest_session_stream_iter)
 {
+       bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
+       bt_logging_level log_level = lttng_live_msg_iter->log_level;
        enum lttng_live_iterator_status stream_iter_status;
        uint64_t trace_idx = 0;
-       int64_t curr_candidate_msg_ts = INT64_MAX;
-       struct lttng_live_stream_iterator *curr_candidate_stream_iter = NULL;
+       int64_t youngest_candidate_msg_ts = INT64_MAX;
+       struct lttng_live_stream_iterator *youngest_candidate_stream_iter = NULL;
 
        /*
         * Make sure we are attached to the session and look for new streams
@@ -1063,9 +1155,32 @@ enum lttng_live_iterator_status next_stream_iterator_for_session(
                if (!trace_is_ended) {
                        BT_ASSERT(stream_iter);
 
-                       if (stream_iter->current_msg_ts_ns <= curr_candidate_msg_ts) {
-                               curr_candidate_msg_ts = stream_iter->current_msg_ts_ns;
-                               curr_candidate_stream_iter = stream_iter;
+                       if (G_UNLIKELY(youngest_candidate_stream_iter == NULL) ||
+                                       stream_iter->current_msg_ts_ns < youngest_candidate_msg_ts) {
+                               youngest_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                               youngest_candidate_stream_iter = stream_iter;
+                       } else if (stream_iter->current_msg_ts_ns == youngest_candidate_msg_ts) {
+                               /*
+                                * Order the messages in an arbitrary but
+                                * deterministic way.
+                                */
+                               int ret = common_muxing_compare_messages(
+                                       stream_iter->current_msg,
+                                       youngest_candidate_stream_iter->current_msg);
+                               if (ret < 0) {
+                                       /*
+                                        * The `youngest_candidate_stream_iter->current_msg`
+                                        * should go first. Update the next iterator
+                                        * and the current timestamp.
+                                        */
+                                       youngest_candidate_msg_ts = stream_iter->current_msg_ts_ns;
+                                       youngest_candidate_stream_iter = stream_iter;
+                               } else if (ret == 0) {
+                                       /* Unable to pick which one should go first. */
+                                       BT_COMP_LOGW("Cannot deterministically pick next live stream message iterator because they have identical next messages: "
+                                               "stream-iter-addr=%p" "stream-iter-addr=%p",
+                                               stream_iter, youngest_candidate_stream_iter);
+                               }
                        }
                        trace_idx++;
                } else {
@@ -1073,8 +1188,8 @@ enum lttng_live_iterator_status next_stream_iterator_for_session(
                        trace_idx = 0;
                }
        }
-       if (curr_candidate_stream_iter) {
-               *candidate_session_stream_iter = curr_candidate_stream_iter;
+       if (youngest_candidate_stream_iter) {
+               *youngest_session_stream_iter = youngest_candidate_stream_iter;
                stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
        } else {
                /*
@@ -1114,6 +1229,8 @@ bt_component_class_message_iterator_next_method_status lttng_live_msg_iter_next(
                bt_self_message_iterator_get_data(self_msg_it);
        struct lttng_live_component *lttng_live =
                lttng_live_msg_iter->lttng_live_comp;
+       bt_self_component *self_comp = lttng_live_msg_iter->self_comp;
+       bt_logging_level log_level = lttng_live_msg_iter->log_level;
        enum lttng_live_iterator_status stream_iter_status;
        uint64_t session_idx;
 
@@ -1174,9 +1291,9 @@ bt_component_class_message_iterator_next_method_status lttng_live_msg_iter_next(
         * return it.
         */
        while (*count < capacity) {
-               struct lttng_live_stream_iterator *next_stream_iter = NULL,
-                                                 *candidate_stream_iter = NULL;
-               int64_t next_msg_ts_ns = INT64_MAX;
+               struct lttng_live_stream_iterator *youngest_stream_iter = NULL,
+                         *candidate_stream_iter = NULL;
+               int64_t youngest_msg_ts_ns = INT64_MAX;
 
                BT_ASSERT(lttng_live_msg_iter->sessions);
                session_idx = 0;
@@ -1225,35 +1342,65 @@ bt_component_class_message_iterator_next_method_status lttng_live_msg_iter_next(
                                goto end;
                        }
 
-                       if (candidate_stream_iter->current_msg_ts_ns <= next_msg_ts_ns) {
-                               next_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
-                               next_stream_iter = candidate_stream_iter;
+                       if (G_UNLIKELY(youngest_stream_iter == NULL) ||
+                                       candidate_stream_iter->current_msg_ts_ns < youngest_msg_ts_ns) {
+                               youngest_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
+                               youngest_stream_iter = candidate_stream_iter;
+                       } else if (candidate_stream_iter->current_msg_ts_ns == youngest_msg_ts_ns) {
+                               /*
+                                * The currently selected message to be sent
+                                * downstream next has the exact same timestamp
+                                * that of the current candidate message. We
+                                * must break the tie in a predictable manner.
+                                */
+                               BT_COMP_LOGD_STR("Two of the next message candidates have the same timestamps, pick one deterministically.");
+                               /*
+                                * Order the messages in an arbitrary but
+                                * deterministic way.
+                                */
+                               int ret = common_muxing_compare_messages(
+                                       candidate_stream_iter->current_msg,
+                                       youngest_stream_iter->current_msg);
+                               if (ret < 0) {
+                                       /*
+                                        * The `candidate_stream_iter->current_msg`
+                                        * should go first. Update the next
+                                        * iterator and the current timestamp.
+                                        */
+                                       youngest_msg_ts_ns = candidate_stream_iter->current_msg_ts_ns;
+                                       youngest_stream_iter = candidate_stream_iter;
+                               } else if (ret == 0) {
+                                       /* Unable to pick which one should go first. */
+                                       BT_COMP_LOGW("Cannot deterministically pick next live stream message iterator because they have identical next messages: "
+                                               "next-stream-iter-addr=%p" "candidate-stream-iter-addr=%p",
+                                               youngest_stream_iter, candidate_stream_iter);
+                               }
                        }
 
                        session_idx++;
                }
 
-               if (!next_stream_iter) {
+               if (!youngest_stream_iter) {
                        stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_AGAIN;
                        goto end;
                }
 
-               BT_ASSERT(next_stream_iter->current_msg);
+               BT_ASSERT(youngest_stream_iter->current_msg);
                /* Ensure monotonicity. */
                BT_ASSERT(lttng_live_msg_iter->last_msg_ts_ns <=
-                       next_stream_iter->current_msg_ts_ns);
+                       youngest_stream_iter->current_msg_ts_ns);
 
                /*
                 * Insert the next message to the message batch. This will set
                 * stream iterator current messsage to NULL so that next time
                 * we fetch the next message of that stream iterator
                 */
-               BT_MESSAGE_MOVE_REF(msgs[*count], next_stream_iter->current_msg);
+               BT_MESSAGE_MOVE_REF(msgs[*count], youngest_stream_iter->current_msg);
                (*count)++;
 
                /* Update the last timestamp in nanoseconds sent downstream. */
-               lttng_live_msg_iter->last_msg_ts_ns = next_msg_ts_ns;
-               next_stream_iter->current_msg_ts_ns = INT64_MAX;
+               lttng_live_msg_iter->last_msg_ts_ns = youngest_msg_ts_ns;
+               youngest_stream_iter->current_msg_ts_ns = INT64_MAX;
 
                stream_iter_status = LTTNG_LIVE_ITERATOR_STATUS_OK;
        }
@@ -1337,7 +1484,7 @@ bt_component_class_message_iterator_init_method_status lttng_live_msg_iter_init(
 
        lttng_live_msg_iter->viewer_connection =
                live_viewer_connection_create(lttng_live->params.url->str, false,
-                       lttng_live_msg_iter);
+                       lttng_live_msg_iter, log_level);
        if (!lttng_live_msg_iter->viewer_connection) {
                goto error;
        }
@@ -1372,6 +1519,17 @@ bt_component_class_message_iterator_init_method_status lttng_live_msg_iter_init(
                                SESS_NOT_FOUND_ACTION_END_STR,
                                lttng_live->params.url->str);
                        break;
+               case SESSION_NOT_FOUND_ACTION_UNKNOWN:
+               default:
+                       /* Fallthrough */
+                       BT_COMP_LOGE("Unknown action for session not found"
+                               "error. Fail the message iterator"
+                               "initialization because of %s=\"%s\" "
+                               "component parameter: url =\"%s\"",
+                               SESS_NOT_FOUND_ACTION_PARAM,
+                               SESS_NOT_FOUND_ACTION_FAIL_STR,
+                               lttng_live->params.url->str);
+                       break;
                }
        }
 
@@ -1413,7 +1571,8 @@ bt_component_class_query_method_status lttng_live_query_list_sessions(
 
        url = bt_value_string_get(url_value);
 
-       viewer_connection = live_viewer_connection_create(url, true, NULL);
+       viewer_connection = live_viewer_connection_create(url, true, NULL,
+               log_level);
        if (!viewer_connection) {
                goto error;
        }
@@ -1443,20 +1602,24 @@ end:
 BT_HIDDEN
 bt_component_class_query_method_status lttng_live_query(
                bt_self_component_class_source *comp_class,
-               const bt_query_executor *query_exec,
+               bt_private_query_executor *priv_query_exec,
                const char *object, const bt_value *params,
-               bt_logging_level log_level, const bt_value **result)
+               __attribute__((unused)) void *method_data,
+               const bt_value **result)
 {
        bt_component_class_query_method_status status =
                BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_OK;
        bt_self_component *self_comp = NULL;
+       bt_logging_level log_level = bt_query_executor_get_logging_level(
+               bt_private_query_executor_as_query_executor_const(
+                       priv_query_exec));
 
        if (strcmp(object, "sessions") == 0) {
                status = lttng_live_query_list_sessions(params, result,
                        log_level);
        } else {
                BT_COMP_LOGI("Unknown query object `%s`", object);
-               status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_INVALID_OBJECT;
+               status = BT_COMPONENT_CLASS_QUERY_METHOD_STATUS_UNKNOWN_OBJECT;
                goto end;
        }
 
@@ -1502,7 +1665,7 @@ enum session_not_found_action parse_session_not_found_action_param(
        } else if (strcmp(no_session_act_str, SESS_NOT_FOUND_ACTION_END_STR) == 0) {
                action = SESSION_NOT_FOUND_ACTION_END;
        } else {
-               action = -1;
+               action = SESSION_NOT_FOUND_ACTION_UNKNOWN;
        }
 
        return action;
@@ -1542,7 +1705,7 @@ struct lttng_live_component *lttng_live_component_create(const bt_value *params,
        if (value && bt_value_is_string(value)) {
                lttng_live->params.sess_not_found_act =
                        parse_session_not_found_action_param(value);
-               if (lttng_live->params.sess_not_found_act == -1) {
+               if (lttng_live->params.sess_not_found_act == SESSION_NOT_FOUND_ACTION_UNKNOWN) {
                        BT_COMP_LOGE("Unexpected value for `%s` parameter: "
                                "value=\"%s\"", SESS_NOT_FOUND_ACTION_PARAM,
                                bt_value_string_get(value));
This page took 0.031129 seconds and 4 git commands to generate.