assert(session);
ASSERT_LOCKED(session->lock);
+ if (!viewer_trace_chunk) {
+ ERR("Internal error: viewer session associated with session \"%s\" has a NULL trace chunk",
+ session->session_name);
+ ret = -1;
+ goto error;
+ }
+
if (session->connection_closed) {
*closed = true;
}
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) {
error_unlock:
rcu_read_unlock();
+error:
return ret;
}
}
if (!viewer_session_is_attached(conn->viewer_session, session)) {
- send_streams = 0;
response.status = htobe32(LTTNG_VIEWER_NEW_STREAMS_ERR);
goto send_reply;
}
- send_streams = 1;
- response.status = htobe32(LTTNG_VIEWER_NEW_STREAMS_OK);
-
pthread_mutex_lock(&session->lock);
- if (!conn->viewer_session->current_trace_chunk &&
- session->current_trace_chunk) {
- ret = viewer_session_set_trace_chunk(conn->viewer_session,
- session->current_trace_chunk);
- if (ret) {
- goto error_unlock_session;
- }
- }
ret = make_viewer_streams(session,
conn->viewer_session->current_trace_chunk,
LTTNG_VIEWER_SEEK_LAST, &nb_total, &nb_unsent,
if (ret < 0) {
goto error_unlock_session;
}
- pthread_mutex_unlock(&session->lock);
+ send_streams = 1;
+ response.status = htobe32(LTTNG_VIEWER_NEW_STREAMS_OK);
/* Only send back the newly created streams with the unsent ones. */
nb_streams = nb_created + nb_unsent;
send_streams = 0;
response.streams_count = 0;
response.status = htobe32(LTTNG_VIEWER_NEW_STREAMS_HUP);
- goto send_reply;
+ goto send_reply_unlock;
}
+send_reply_unlock:
+ pthread_mutex_unlock(&session->lock);
send_reply:
health_code_update();
struct lttng_viewer_attach_session_request request;
struct lttng_viewer_attach_session_response response;
struct relay_session *session = NULL;
+ enum lttng_viewer_attach_return_code viewer_attach_status;
bool closed = false;
uint64_t session_id;
DBG("Attach session ID %" PRIu64 " received", session_id);
pthread_mutex_lock(&session->lock);
+ if (!session->current_trace_chunk) {
+ /*
+ * Session is either being destroyed or it never had a trace
+ * chunk created against it.
+ */
+ DBG("Session requested by live client has no current trace chunk, returning unknown session");
+ response.status = htobe32(LTTNG_VIEWER_ATTACH_UNK);
+ goto send_reply;
+ }
if (session->live_timer == 0) {
DBG("Not live session");
response.status = htobe32(LTTNG_VIEWER_ATTACH_NOT_LIVE);
}
send_streams = 1;
- ret = viewer_session_attach(conn->viewer_session, session);
- if (ret) {
- DBG("Already a viewer attached");
- response.status = htobe32(LTTNG_VIEWER_ATTACH_ALREADY);
+ viewer_attach_status = viewer_session_attach(conn->viewer_session,
+ session);
+ if (viewer_attach_status != LTTNG_VIEWER_ATTACH_OK) {
+ response.status = htobe32(viewer_attach_status);
goto send_reply;
}
goto send_reply;
}
- if (!conn->viewer_session->current_trace_chunk &&
- session->current_trace_chunk) {
- ret = viewer_session_set_trace_chunk(conn->viewer_session,
- session->current_trace_chunk);
- if (ret) {
- goto end_put_session;
- }
- }
ret = make_viewer_streams(session,
conn->viewer_session->current_trace_chunk, seek_type,
&nb_streams, NULL, NULL, &closed);
int ret = 0;
const uint32_t connection_major = rstream->trace->session->major;
const uint32_t connection_minor = rstream->trace->session->minor;
+ enum lttng_trace_chunk_status chunk_status;
if (vstream->index_file) {
goto end;
ret = -ENOENT;
goto end;
}
- vstream->index_file = lttng_index_file_create_from_trace_chunk_read_only(
+ chunk_status = lttng_index_file_create_from_trace_chunk_read_only(
vstream->stream_file.trace_chunk, rstream->path_name,
rstream->channel_name, rstream->tracefile_size,
vstream->current_tracefile_id,
lttng_to_index_major(connection_major, connection_minor),
- lttng_to_index_minor(connection_major, connection_minor));
- if (!vstream->index_file) {
- ret = -1;
+ lttng_to_index_minor(connection_major, connection_minor),
+ true, &vstream->index_file);
+ if (chunk_status != LTTNG_TRACE_CHUNK_STATUS_OK) {
+ if (chunk_status == LTTNG_TRACE_CHUNK_STATUS_NO_FILE) {
+ ret = -ENOENT;
+ } else {
+ ret = -1;
+ }
}
end:
{
int ret;
+ DBG("Check index status: index_received_seqcount %" PRIu64 " "
+ "index_sent_seqcount %" PRIu64 " "
+ "for stream %" PRIu64,
+ rstream->index_received_seqcount,
+ vstream->index_sent_seqcount,
+ vstream->stream->stream_handle);
if ((trace->session->connection_closed || rstream->closed)
&& rstream->index_received_seqcount
== vstream->index_sent_seqcount) {
index->status = htobe32(LTTNG_VIEWER_INDEX_INACTIVE);
index->timestamp_end = htobe64(rstream->beacon_ts_end);
index->stream_id = htobe64(rstream->ctf_stream_id);
+ DBG("Check index status: inactive with beacon, for stream %" PRIu64,
+ vstream->stream->stream_handle);
goto index_ready;
} else if (rstream->index_received_seqcount
== vstream->index_sent_seqcount) {
* we can only ask the client to retry later.
*/
index->status = htobe32(LTTNG_VIEWER_INDEX_RETRY);
+ DBG("Check index status: retry for stream %" PRIu64,
+ vstream->stream->stream_handle);
goto index_ready;
} else if (!tracefile_array_seq_in_file(rstream->tfa,
vstream->current_tracefile_id,
vstream->current_tracefile_id,
vstream->index_sent_seqcount)) {
index->status = htobe32(LTTNG_VIEWER_INDEX_RETRY);
+ DBG("Check index status: retry: "
+ "tracefile array sequence number %" PRIu64
+ " not in file for stream %" PRIu64,
+ vstream->index_sent_seqcount,
+ vstream->stream->stream_handle);
goto index_ready;
}
assert(tracefile_array_seq_in_file(rstream->tfa,
goto error_put;
}
+ /*
+ * It is possible the the file we are trying to open is
+ * missing if the stream has been closed (application exits with
+ * per-pid buffers) and a clear command has been performed.
+ */
status = lttng_trace_chunk_open_file(
vstream->stream_file.trace_chunk,
- file_path, O_RDONLY, 0, &fd);
+ file_path, O_RDONLY, 0, &fd, true);
if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
PERROR("Failed to open trace file for viewer stream");
goto error_put;
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;
}
+ /*
+ * It is possible the the metadata file we are trying to open is
+ * missing if the stream has been closed (application exits with
+ * per-pid buffers) and a clear command has been performed.
+ */
status = lttng_trace_chunk_open_file(
vstream->stream_file.trace_chunk,
- file_path, O_RDONLY, 0, &fd);
+ file_path, O_RDONLY, 0, &fd, true);
if (status != LTTNG_TRACE_CHUNK_STATUS_OK) {
PERROR("Failed to open metadata file for viewer stream");
goto error;
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;