#include <common/consumer/consumer-stream.h>
#include <common/consumer/consumer-testpoint.h>
#include <common/align.h>
+#include <common/consumer/consumer-metadata-cache.h>
struct lttng_consumer_global_data consumer_data = {
.stream_count = 0,
stream->session_id = session_id;
stream->monitor = monitor;
stream->endpoint_status = CONSUMER_ENDPOINT_ACTIVE;
- stream->index_fd = -1;
+ stream->index_file = NULL;
+ stream->last_sequence_number = -1ULL;
pthread_mutex_init(&stream->lock, NULL);
pthread_mutex_init(&stream->metadata_timer_lock, NULL);
CDS_INIT_LIST_HEAD(&channel->streams.head);
- DBG("Allocated channel (key %" PRIu64 ")", channel->key)
+ DBG("Allocated channel (key %" PRIu64 ")", channel->key);
end:
return channel;
*/
static int update_poll_array(struct lttng_consumer_local_data *ctx,
struct pollfd **pollfd, struct lttng_consumer_stream **local_stream,
- struct lttng_ht *ht)
+ struct lttng_ht *ht, int *nb_inactive_fd)
{
int i = 0;
struct lttng_ht_iter iter;
assert(local_stream);
DBG("Updating poll fd array");
+ *nb_inactive_fd = 0;
rcu_read_lock();
cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
/*
* just after the check. However, this is OK since the stream(s) will
* be deleted once the thread is notified that the end point state has
* changed where this function will be called back again.
+ *
+ * We track the number of inactive FDs because they still need to be
+ * closed by the polling thread after a wakeup on the data_pipe or
+ * metadata_pipe.
*/
if (stream->state != LTTNG_CONSUMER_ACTIVE_STREAM ||
stream->endpoint_status == CONSUMER_ENDPOINT_INACTIVE) {
+ (*nb_inactive_fd)++;
continue;
}
/*
DBG("Consumer flag that it should quit");
}
+
+/*
+ * Flush pending writes to trace output disk file.
+ */
+static
void lttng_consumer_sync_trace_file(struct lttng_consumer_stream *stream,
off_t orig_offset)
{
+ int ret;
int outfd = stream->out_fd;
/*
* defined. So it can be expected to lead to lower throughput in
* streaming.
*/
- posix_fadvise(outfd, orig_offset - stream->max_sb_size,
+ ret = posix_fadvise(outfd, orig_offset - stream->max_sb_size,
stream->max_sb_size, POSIX_FADV_DONTNEED);
+ if (ret && ret != -ENOSYS) {
+ errno = ret;
+ PERROR("posix_fadvise on fd %i", outfd);
+ }
}
/*
mmap_base = stream->mmap_base;
ret = kernctl_get_mmap_read_offset(stream->wait_fd, &mmap_offset);
if (ret < 0) {
- ret = -errno;
PERROR("tracer ctl get_mmap_read_offset");
goto end;
}
if (stream->metadata_flag) {
/* Metadata requires the control socket. */
pthread_mutex_lock(&relayd->ctrl_sock_mutex);
+ if (stream->reset_metadata_flag) {
+ ret = relayd_reset_metadata(&relayd->control_sock,
+ stream->relayd_stream_id,
+ stream->metadata_version);
+ if (ret < 0) {
+ relayd_hang_up = 1;
+ goto write_error;
+ }
+ stream->reset_metadata_flag = 0;
+ }
netlen += sizeof(struct lttcomm_relayd_metadata_payload);
}
/* No streaming, we have to set the len with the full padding */
len += padding;
+ if (stream->metadata_flag && stream->reset_metadata_flag) {
+ ret = utils_truncate_stream_file(stream->out_fd, 0);
+ if (ret < 0) {
+ ERR("Reset metadata file");
+ goto end;
+ }
+ stream->reset_metadata_flag = 0;
+ }
+
/*
* Check if we need to change the tracefile before writing the packet.
*/
}
outfd = stream->out_fd;
- if (stream->index_fd >= 0) {
- ret = index_create_file(stream->chan->pathname,
+ if (stream->index_file) {
+ lttng_index_file_put(stream->index_file);
+ stream->index_file = lttng_index_file_create(stream->chan->pathname,
stream->name, stream->uid, stream->gid,
stream->chan->tracefile_size,
- stream->tracefile_count_current);
- if (ret < 0) {
+ stream->tracefile_count_current,
+ CTF_INDEX_MAJOR, CTF_INDEX_MINOR);
+ if (!stream->index_file) {
goto end;
}
- stream->index_fd = ret;
}
/* Reset current size because we just perform a rotation. */
lttng_sync_file_range(outfd, stream->out_fd_offset, len,
SYNC_FILE_RANGE_WRITE);
stream->out_fd_offset += len;
+ lttng_consumer_sync_trace_file(stream, orig_offset);
}
- lttng_consumer_sync_trace_file(stream, orig_offset);
write_error:
/*
*/
pthread_mutex_lock(&relayd->ctrl_sock_mutex);
+ if (stream->reset_metadata_flag) {
+ ret = relayd_reset_metadata(&relayd->control_sock,
+ stream->relayd_stream_id,
+ stream->metadata_version);
+ if (ret < 0) {
+ relayd_hang_up = 1;
+ goto write_error;
+ }
+ stream->reset_metadata_flag = 0;
+ }
ret = write_relayd_metadata_id(splice_pipe[1], stream, relayd,
padding);
if (ret < 0) {
/* No streaming, we have to set the len with the full padding */
len += padding;
+ if (stream->metadata_flag && stream->reset_metadata_flag) {
+ ret = utils_truncate_stream_file(stream->out_fd, 0);
+ if (ret < 0) {
+ ERR("Reset metadata file");
+ goto end;
+ }
+ stream->reset_metadata_flag = 0;
+ }
/*
* Check if we need to change the tracefile before writing the packet.
*/
}
outfd = stream->out_fd;
- if (stream->index_fd >= 0) {
- ret = close(stream->index_fd);
- if (ret < 0) {
- PERROR("Closing index");
- goto end;
- }
- stream->index_fd = -1;
- ret = index_create_file(stream->chan->pathname,
+ if (stream->index_file) {
+ lttng_index_file_put(stream->index_file);
+ stream->index_file = lttng_index_file_create(stream->chan->pathname,
stream->name, stream->uid, stream->gid,
stream->chan->tracefile_size,
- stream->tracefile_count_current);
- if (ret < 0) {
- written = ret;
+ stream->tracefile_count_current,
+ CTF_INDEX_MAJOR, CTF_INDEX_MINOR);
+ if (!stream->index_file) {
goto end;
}
- stream->index_fd = ret;
}
/* Reset current size because we just perform a rotation. */
stream->output_written += ret_splice;
written += ret_splice;
}
- lttng_consumer_sync_trace_file(stream, orig_offset);
+ if (!relayd) {
+ lttng_consumer_sync_trace_file(stream, orig_offset);
+ }
goto end;
write_error:
pthread_mutex_lock(&consumer_data.lock);
pthread_mutex_lock(&stream->chan->lock);
pthread_mutex_lock(&stream->lock);
+ if (stream->chan->metadata_cache) {
+ /* Only applicable to userspace consumers. */
+ pthread_mutex_lock(&stream->chan->metadata_cache->lock);
+ }
/* Remove any reference to that stream. */
consumer_stream_delete(stream, ht);
*/
stream->chan->metadata_stream = NULL;
+ if (stream->chan->metadata_cache) {
+ pthread_mutex_unlock(&stream->chan->metadata_cache->lock);
+ }
pthread_mutex_unlock(&stream->lock);
pthread_mutex_unlock(&stream->chan->lock);
pthread_mutex_unlock(&consumer_data.lock);
lttng_ht_add_unique_u64(ht, &stream->node);
- lttng_ht_add_unique_u64(consumer_data.stream_per_chan_id_ht,
+ lttng_ht_add_u64(consumer_data.stream_per_chan_id_ht,
&stream->node_channel_id);
/*
DBG("Metadata poll return from wait with %d fd(s)",
LTTNG_POLL_GETNB(&events));
health_poll_exit();
- DBG("Metadata event catched in thread");
+ DBG("Metadata event caught in thread");
if (ret < 0) {
if (errno == EINTR) {
- ERR("Poll EINTR catched");
+ ERR("Poll EINTR caught");
goto restart;
}
if (LTTNG_POLL_GETNB(&events) == 0) {
len = ctx->on_buffer_ready(stream, ctx);
/*
* We don't check the return value here since if we get
- * a negative len, it means an error occured thus we
+ * a negative len, it means an error occurred thus we
* simply remove it from the poll set and free the
* stream.
*/
len = ctx->on_buffer_ready(stream, ctx);
/*
* We don't check the return value here since if we get
- * a negative len, it means an error occured thus we
+ * a negative len, it means an error occurred thus we
* simply remove it from the poll set and free the
* stream.
*/
struct lttng_consumer_stream **local_stream = NULL, *new_stream = NULL;
/* local view of consumer_data.fds_count */
int nb_fd = 0;
+ /* Number of FDs with CONSUMER_ENDPOINT_INACTIVE but still open. */
+ int nb_inactive_fd = 0;
struct lttng_consumer_local_data *ctx = data;
ssize_t len;
goto end;
}
ret = update_poll_array(ctx, &pollfd, local_stream,
- data_ht);
+ data_ht, &nb_inactive_fd);
if (ret < 0) {
ERR("Error in allocating pollfd or local_outfds");
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_POLL_ERROR);
pthread_mutex_unlock(&consumer_data.lock);
/* No FDs and consumer_quit, consumer_cleanup the thread */
- if (nb_fd == 0 && consumer_quit == 1) {
+ if (nb_fd == 0 && consumer_quit == 1 && nb_inactive_fd == 0) {
err = 0; /* All is OK */
goto end;
}
DBG("Channel poll return from wait with %d fd(s)",
LTTNG_POLL_GETNB(&events));
health_poll_exit();
- DBG("Channel event catched in thread");
+ DBG("Channel event caught in thread");
if (ret < 0) {
if (errno == EINTR) {
- ERR("Poll EINTR catched");
+ ERR("Poll EINTR caught");
goto restart;
}
if (LTTNG_POLL_GETNB(&events) == 0) {