uint64_t session_id, unsigned int ignore_sent_flag)
{
ssize_t ret;
- struct lttng_viewer_stream send_stream;
struct lttng_ht_iter iter;
struct relay_viewer_stream *vstream;
cds_lfht_for_each_entry(viewer_streams_ht->ht, &iter.iter, vstream,
stream_n.node) {
struct ctf_trace *ctf_trace;
+ struct lttng_viewer_stream send_stream = {};
health_code_update();
rcu_read_lock();
cds_lfht_for_each_entry(session->ctf_traces_ht->ht, &iter.iter, ctf_trace,
node.node) {
+ bool trace_has_metadata_stream = false;
struct relay_stream *stream;
health_code_update();
continue;
}
+ /*
+ * Iterate over all the streams of the trace to see if we have a
+ * metadata stream.
+ */
+ cds_list_for_each_entry_rcu(
+ stream, &ctf_trace->stream_list, stream_node)
+ {
+ if (stream->is_metadata) {
+ trace_has_metadata_stream = true;
+ break;
+ }
+ }
+
+ /*
+ * If there is no metadata stream in this trace at the moment
+ * and we never sent one to the viewer, skip the trace. We
+ * accept that the viewer will not see this trace at all.
+ */
+ if (!trace_has_metadata_stream &&
+ !ctf_trace->metadata_stream_sent_to_viewer) {
+ ctf_trace_put(ctf_trace);
+ continue;
+ }
+
cds_list_for_each_entry_rcu(stream, &ctf_trace->stream_list, stream_node) {
struct relay_viewer_stream *vstream;
}
vstream = viewer_stream_get_by_id(stream->stream_handle);
if (!vstream) {
+ /*
+ * Save that we sent the metadata stream to the
+ * viewer. So that we know what trace the viewer
+ * is aware of.
+ */
+ if (stream->is_metadata) {
+ ctf_trace->metadata_stream_sent_to_viewer =
+ true;
+ }
vstream = viewer_stream_create(stream,
viewer_trace_chunk, seek_t);
if (!vstream) {
goto send_reply;
}
+ /*
+ * For any new stream, create it with LTTNG_VIEWER_SEEK_BEGINNING since
+ * that at this point the client is already attached to the session.Aany
+ * initial stream will have been created with the seek type at attach
+ * time (for now most readers use the LTTNG_VIEWER_SEEK_LAST on attach).
+ * Otherwise any event happening in a new stream between the attach and
+ * a call to viewer_get_new_streams will be "lost" (never received) from
+ * the viewer's point of view.
+ */
pthread_mutex_lock(&session->lock);
ret = make_viewer_streams(session,
conn->viewer_session->current_trace_chunk,
- LTTNG_VIEWER_SEEK_LAST, &nb_total, &nb_unsent,
+ LTTNG_VIEWER_SEEK_BEGINNING, &nb_total, &nb_unsent,
&nb_created, &closed);
if (ret < 0) {
goto error_unlock_session;
len = vstream->stream->metadata_received - vstream->metadata_sent;
if (len == 0) {
+ /*
+ * The live viewers expect to receive a NO_NEW_METADATA
+ * status before a stream disappears, otherwise they abort the
+ * entire live connection when receiving an error status.
+ */
reply.status = htobe32(LTTNG_VIEWER_NO_NEW_METADATA);
+ /*
+ * The live viewer considers a closed 0 byte metadata stream as
+ * an error.
+ */
+ if (vstream->metadata_sent > 0) {
+ vstream->stream->no_new_metadata_notified = true;
+ if (vstream->stream->closed) {
+ /* Release ownership for the viewer metadata stream. */
+ viewer_stream_put(vstream);
+ }
+ }
goto send_reply;
}
goto error;
}
vstream->metadata_sent += read_len;
- if (vstream->metadata_sent == vstream->stream->metadata_received
- && vstream->stream->closed) {
- /* Release ownership for the viewer metadata stream. */
- viewer_stream_put(vstream);
- }
-
reply.status = htobe32(LTTNG_VIEWER_METADATA_OK);
goto send_reply;