* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
-#define _GNU_SOURCE
#define _LGPL_SOURCE
#include <assert.h>
#include <poll.h>
#include <common/pipe.h>
#include <common/relayd/relayd.h>
#include <common/utils.h>
-#include <common/consumer-stream.h>
+#include <common/consumer/consumer-stream.h>
#include <common/index/index.h>
-#include <common/consumer-timer.h>
+#include <common/consumer/consumer-timer.h>
#include "kernel-consumer.h"
ret = kernctl_snapshot(infd);
if (ret != 0) {
PERROR("Getting sub-buffer snapshot.");
- ret = -errno;
}
return ret;
ret = kernctl_snapshot_get_produced(infd, pos);
if (ret != 0) {
PERROR("kernctl_snapshot_get_produced");
- ret = -errno;
}
return ret;
ret = kernctl_snapshot_get_consumed(infd, pos);
if (ret != 0) {
PERROR("kernctl_snapshot_get_consumed");
- ret = -errno;
}
return ret;
struct lttng_consumer_local_data *ctx)
{
int ret;
- unsigned long consumed_pos, produced_pos;
struct lttng_consumer_channel *channel;
struct lttng_consumer_stream *stream;
}
cds_list_for_each_entry(stream, &channel->streams.head, send_node) {
+ /* Are we at a position _before_ the first available packet ? */
+ bool before_first_packet = true;
+ unsigned long consumed_pos, produced_pos;
health_code_update();
ret = kernctl_buffer_flush(stream->wait_fd);
if (ret < 0) {
ERR("Failed to flush kernel stream");
- ret = -errno;
goto end_unlock;
}
&stream->max_sb_size);
if (ret < 0) {
ERR("Getting kernel max_sb_size");
- ret = -errno;
goto end_unlock;
}
}
while (consumed_pos < produced_pos) {
ssize_t read_len;
unsigned long len, padded_len;
+ int lost_packet = 0;
health_code_update();
ret = kernctl_get_subbuf(stream->wait_fd, &consumed_pos);
if (ret < 0) {
- if (errno != EAGAIN) {
+ if (ret != -EAGAIN) {
PERROR("kernctl_get_subbuf snapshot");
- ret = -errno;
goto end_unlock;
}
DBG("Kernel consumer get subbuf failed. Skipping it.");
consumed_pos += stream->max_sb_size;
+
+ /*
+ * Start accounting lost packets only when we
+ * already have extracted packets (to match the
+ * content of the final snapshot).
+ */
+ if (!before_first_packet) {
+ lost_packet = 1;
+ }
continue;
}
ret = kernctl_get_subbuf_size(stream->wait_fd, &len);
if (ret < 0) {
ERR("Snapshot kernctl_get_subbuf_size");
- ret = -errno;
goto error_put_subbuf;
}
ret = kernctl_get_padded_subbuf_size(stream->wait_fd, &padded_len);
if (ret < 0) {
ERR("Snapshot kernctl_get_padded_subbuf_size");
- ret = -errno;
goto error_put_subbuf;
}
ret = kernctl_put_subbuf(stream->wait_fd);
if (ret < 0) {
ERR("Snapshot kernctl_put_subbuf");
- ret = -errno;
goto end_unlock;
}
consumed_pos += stream->max_sb_size;
+
+ /*
+ * Only account lost packets located between
+ * succesfully extracted packets (do not account before
+ * and after since they are not visible in the
+ * resulting snapshot).
+ */
+ stream->chan->lost_packets += lost_packet;
+ lost_packet = 0;
+ before_first_packet = false;
}
if (relayd_id == (uint64_t) -1ULL) {
error_put_subbuf:
ret = kernctl_put_subbuf(stream->wait_fd);
if (ret < 0) {
- ret = -errno;
ERR("Snapshot kernctl_put_subbuf error path");
}
end_unlock:
msg.u.channel.tracefile_count, 0,
msg.u.channel.monitor,
msg.u.channel.live_timer_interval,
- NULL);
+ NULL, NULL);
if (new_channel == NULL) {
lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_OUTFD_ERROR);
goto end_nosignal;
goto end_nosignal;
}
+ case LTTNG_CONSUMER_DISCARDED_EVENTS:
+ {
+ uint64_t ret;
+ struct lttng_consumer_channel *channel;
+ uint64_t id = msg.u.discarded_events.session_id;
+ uint64_t key = msg.u.discarded_events.channel_key;
+
+ DBG("Kernel consumer discarded events command for session id %"
+ PRIu64 ", channel key %" PRIu64, id, key);
+
+ channel = consumer_find_channel(key);
+ if (!channel) {
+ ERR("Kernel consumer discarded events channel %"
+ PRIu64 " not found", key);
+ ret = 0;
+ } else {
+ ret = channel->discarded_events;
+ }
+
+ health_code_update();
+
+ /* Send back returned value to session daemon */
+ ret = lttcomm_send_unix_sock(sock, &ret, sizeof(ret));
+ if (ret < 0) {
+ PERROR("send discarded events");
+ goto error_fatal;
+ }
+
+ break;
+ }
+ case LTTNG_CONSUMER_LOST_PACKETS:
+ {
+ uint64_t ret;
+ struct lttng_consumer_channel *channel;
+ uint64_t id = msg.u.lost_packets.session_id;
+ uint64_t key = msg.u.lost_packets.channel_key;
+
+ DBG("Kernel consumer lost packets command for session id %"
+ PRIu64 ", channel key %" PRIu64, id, key);
+
+ channel = consumer_find_channel(key);
+ if (!channel) {
+ ERR("Kernel consumer lost packets channel %"
+ PRIu64 " not found", key);
+ ret = 0;
+ } else {
+ ret = channel->lost_packets;
+ }
+
+ health_code_update();
+
+ /* Send back returned value to session daemon */
+ ret = lttcomm_send_unix_sock(sock, &ret, sizeof(ret));
+ if (ret < 0) {
+ PERROR("send lost packets");
+ goto error_fatal;
+ }
+
+ break;
+ }
default:
goto end_nosignal;
}
}
index->stream_id = htobe64(index->stream_id);
+ ret = kernctl_get_instance_id(infd, &index->stream_instance_id);
+ if (ret < 0) {
+ PERROR("kernctl_get_instance_id");
+ goto error;
+ }
+ index->stream_instance_id = htobe64(index->stream_instance_id);
+
+ ret = kernctl_get_sequence_number(infd, &index->packet_seq_num);
+ if (ret < 0) {
+ PERROR("kernctl_get_sequence_number");
+ goto error;
+ }
+ index->packet_seq_num = htobe64(index->packet_seq_num);
+
error:
return ret;
}
ret = kernctl_snapshot(metadata->wait_fd);
if (ret < 0) {
- if (errno != EAGAIN) {
+ if (ret != -EAGAIN) {
ERR("Sync metadata, taking kernel snapshot failed.");
goto end;
}
return ret;
}
+static
+int update_stream_stats(struct lttng_consumer_stream *stream)
+{
+ int ret;
+ uint64_t seq, discarded;
+
+ ret = kernctl_get_sequence_number(stream->wait_fd, &seq);
+ if (ret < 0) {
+ PERROR("kernctl_get_sequence_number");
+ goto end;
+ }
+
+ /*
+ * Start the sequence when we extract the first packet in case we don't
+ * start at 0 (for example if a consumer is not connected to the
+ * session immediately after the beginning).
+ */
+ if (stream->last_sequence_number == -1ULL) {
+ stream->last_sequence_number = seq;
+ } else if (seq > stream->last_sequence_number) {
+ stream->chan->lost_packets += seq -
+ stream->last_sequence_number - 1;
+ } else {
+ /* seq <= last_sequence_number */
+ ERR("Sequence number inconsistent : prev = %" PRIu64
+ ", current = %" PRIu64,
+ stream->last_sequence_number, seq);
+ ret = -1;
+ goto end;
+ }
+ stream->last_sequence_number = seq;
+
+ ret = kernctl_get_events_discarded(stream->wait_fd, &discarded);
+ if (ret < 0) {
+ PERROR("kernctl_get_events_discarded");
+ goto end;
+ }
+ if (discarded < stream->last_discarded_events) {
+ /*
+ * Overflow has occurred. We assume only one wrap-around
+ * has occurred.
+ */
+ stream->chan->discarded_events += (1ULL << (CAA_BITS_PER_LONG - 1)) -
+ stream->last_discarded_events + discarded;
+ } else {
+ stream->chan->discarded_events += discarded -
+ stream->last_discarded_events;
+ }
+ stream->last_discarded_events = discarded;
+ ret = 0;
+
+end:
+ return ret;
+}
+
+/*
+ * Check if the local version of the metadata stream matches with the version
+ * of the metadata stream in the kernel. If it was updated, set the reset flag
+ * on the stream.
+ */
+static
+int metadata_stream_check_version(int infd, struct lttng_consumer_stream *stream)
+{
+ int ret;
+ uint64_t cur_version;
+
+ ret = kernctl_get_metadata_version(infd, &cur_version);
+ if (ret < 0) {
+ ERR("Failed to get the metadata version");
+ goto end;
+ }
+
+ if (stream->metadata_version == cur_version) {
+ ret = 0;
+ goto end;
+ }
+
+ DBG("New metadata version detected");
+ stream->metadata_version = cur_version;
+ stream->reset_metadata_flag = 1;
+ ret = 0;
+
+end:
+ return ret;
+}
+
/*
* Consume data on a file descriptor and write it on a trace file.
*/
*/
DBG("Reserving sub buffer failed (everything is normal, "
"it is due to concurrency)");
- ret = -errno;
+ ret = err;
goto end;
}
PERROR("Getting sub-buffer len failed.");
err = kernctl_put_subbuf(infd);
if (err != 0) {
- if (errno == EFAULT) {
+ if (err == -EFAULT) {
PERROR("Error in unreserving sub buffer\n");
- } else if (errno == EIO) {
+ } else if (err == -EIO) {
/* Should never happen with newer LTTng versions */
PERROR("Reader has been pushed by the writer, last sub-buffer corrupted.");
}
- ret = -errno;
+ ret = err;
goto end;
}
- ret = -errno;
+ ret = err;
goto end;
}
if (ret < 0) {
err = kernctl_put_subbuf(infd);
if (err != 0) {
- if (errno == EFAULT) {
+ if (err == -EFAULT) {
PERROR("Error in unreserving sub buffer\n");
- } else if (errno == EIO) {
+ } else if (err == -EIO) {
/* Should never happen with newer LTTng versions */
PERROR("Reader has been pushed by the writer, last sub-buffer corrupted.");
}
- ret = -errno;
+ ret = err;
goto end;
}
goto end;
}
+ ret = update_stream_stats(stream);
+ if (ret < 0) {
+ goto end;
+ }
} else {
write_index = 0;
+ ret = metadata_stream_check_version(infd, stream);
+ if (ret < 0) {
+ goto end;
+ }
}
switch (stream->chan->output) {
PERROR("Getting sub-buffer len failed.");
err = kernctl_put_subbuf(infd);
if (err != 0) {
- if (errno == EFAULT) {
+ if (err == -EFAULT) {
PERROR("Error in unreserving sub buffer\n");
- } else if (errno == EIO) {
+ } else if (err == -EIO) {
/* Should never happen with newer LTTng versions */
PERROR("Reader has been pushed by the writer, last sub-buffer corrupted.");
}
- ret = -errno;
+ ret = err;
goto end;
}
- ret = -errno;
+ ret = err;
goto end;
}
err = kernctl_put_next_subbuf(infd);
if (err != 0) {
- if (errno == EFAULT) {
+ if (err == -EFAULT) {
PERROR("Error in unreserving sub buffer\n");
- } else if (errno == EIO) {
+ } else if (err == -EIO) {
/* Should never happen with newer LTTng versions */
PERROR("Reader has been pushed by the writer, last sub-buffer corrupted.");
}
- ret = -errno;
+ ret = err;
goto end;
}
/*
* In live, block until all the metadata is sent.
*/
+ pthread_mutex_lock(&stream->metadata_timer_lock);
+ assert(!stream->missed_metadata_flush);
+ stream->waiting_on_metadata = true;
+ pthread_mutex_unlock(&stream->metadata_timer_lock);
+
err = consumer_stream_sync_metadata(ctx, stream->session_id);
+
+ pthread_mutex_lock(&stream->metadata_timer_lock);
+ stream->waiting_on_metadata = false;
+ if (stream->missed_metadata_flush) {
+ stream->missed_metadata_flush = false;
+ pthread_mutex_unlock(&stream->metadata_timer_lock);
+ (void) consumer_flush_kernel_index(stream);
+ } else {
+ pthread_mutex_unlock(&stream->metadata_timer_lock);
+ }
if (err < 0) {
goto end;
}
ret = kernctl_get_mmap_len(stream->wait_fd, &mmap_len);
if (ret != 0) {
PERROR("kernctl_get_mmap_len");
- ret = -errno;
goto error_close_fd;
}
stream->mmap_len = (size_t) mmap_len;