X-Git-Url: https://git.liburcu.org/?a=blobdiff_plain;f=src%2Fcommon%2Fconsumer%2Fconsumer-stream.c;h=0f60dfd08e3a3e1b264d445698d8ace2e727ec0d;hb=7a843330fa4fb0e5f7139970b9b3f38292bc45c8;hp=0c6dc8f518bbaf54af0c04fb352d52400e7feac1;hpb=131e541fdfe17635e9915489bac2139fb14c7349;p=lttng-tools.git diff --git a/src/common/consumer/consumer-stream.c b/src/common/consumer/consumer-stream.c index 0c6dc8f51..0f60dfd08 100644 --- a/src/common/consumer/consumer-stream.c +++ b/src/common/consumer/consumer-stream.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2011 Julien Desfossez + * Copyright (C) 2011 EfficiOS Inc. * Copyright (C) 2011 Mathieu Desnoyers * Copyright (C) 2013 David Goulet * @@ -14,14 +14,15 @@ #include #include +#include +#include +#include #include #include +#include #include #include #include -#include -#include -#include #include "consumer-stream.h" @@ -51,6 +52,12 @@ static void consumer_stream_data_unlock_all(struct lttng_consumer_stream *stream pthread_mutex_unlock(&stream->chan->lock); } +static void consumer_stream_data_assert_locked_all(struct lttng_consumer_stream *stream) +{ + ASSERT_LOCKED(stream->lock); + ASSERT_LOCKED(stream->chan->lock); +} + static void consumer_stream_metadata_lock_all(struct lttng_consumer_stream *stream) { consumer_stream_data_lock_all(stream); @@ -63,6 +70,12 @@ static void consumer_stream_metadata_unlock_all(struct lttng_consumer_stream *st consumer_stream_data_unlock_all(stream); } +static void consumer_stream_metadata_assert_locked_all(struct lttng_consumer_stream *stream) +{ + ASSERT_LOCKED(stream->metadata_rdv_lock); + consumer_stream_data_assert_locked_all(stream); +} + /* Only used for data streams. */ static int consumer_stream_update_stats(struct lttng_consumer_stream *stream, const struct stream_subbuffer *subbuf) @@ -151,9 +164,40 @@ static ssize_t consumer_stream_consume_mmap( const unsigned long padding_size = subbuffer->info.data.padded_subbuf_size - subbuffer->info.data.subbuf_size; - - return lttng_consumer_on_read_subbuffer_mmap( + const ssize_t written_bytes = lttng_consumer_on_read_subbuffer_mmap( stream, &subbuffer->buffer.buffer, padding_size); + + if (stream->net_seq_idx == -1ULL) { + /* + * When writing on disk, check that only the subbuffer (no + * padding) was written to disk. + */ + if (written_bytes != subbuffer->info.data.padded_subbuf_size) { + DBG("Failed to write the entire padded subbuffer on disk (written_bytes: %zd, padded subbuffer size %lu)", + written_bytes, + subbuffer->info.data.padded_subbuf_size); + } + } else { + /* + * When streaming over the network, check that the entire + * subbuffer including padding was successfully written. + */ + if (written_bytes != subbuffer->info.data.subbuf_size) { + DBG("Failed to write only the subbuffer over the network (written_bytes: %zd, subbuffer size %lu)", + written_bytes, + subbuffer->info.data.subbuf_size); + } + } + + /* + * If `lttng_consumer_on_read_subbuffer_mmap()` returned an error, pass + * it along to the caller, else return zero. + */ + if (written_bytes < 0) { + ERR("Error reading mmap subbuffer: %zd", written_bytes); + } + + return written_bytes; } static ssize_t consumer_stream_consume_splice( @@ -161,8 +205,24 @@ static ssize_t consumer_stream_consume_splice( struct lttng_consumer_stream *stream, const struct stream_subbuffer *subbuffer) { - return lttng_consumer_on_read_subbuffer_splice(ctx, stream, - subbuffer->info.data.padded_subbuf_size, 0); + const ssize_t written_bytes = lttng_consumer_on_read_subbuffer_splice( + ctx, stream, subbuffer->info.data.padded_subbuf_size, 0); + + if (written_bytes != subbuffer->info.data.padded_subbuf_size) { + DBG("Failed to write the entire padded subbuffer (written_bytes: %zd, padded subbuffer size %lu)", + written_bytes, + subbuffer->info.data.padded_subbuf_size); + } + + /* + * If `lttng_consumer_on_read_subbuffer_splice()` returned an error, + * pass it along to the caller, else return zero. + */ + if (written_bytes < 0) { + ERR("Error reading splice subbuffer: %zd", written_bytes); + } + + return written_bytes; } static int consumer_stream_send_index( @@ -196,6 +256,7 @@ static int do_sync_metadata(struct lttng_consumer_stream *metadata, struct lttng_consumer_local_data *ctx) { int ret; + enum sync_metadata_status status; assert(metadata); assert(metadata->metadata_flag); @@ -243,7 +304,7 @@ static int do_sync_metadata(struct lttng_consumer_stream *metadata, /* * Empty the metadata cache and flush the current stream. */ - ret = lttng_kconsumer_sync_metadata(metadata); + status = lttng_kconsumer_sync_metadata(metadata); break; case LTTNG_CONSUMER32_UST: case LTTNG_CONSUMER64_UST: @@ -251,18 +312,23 @@ static int do_sync_metadata(struct lttng_consumer_stream *metadata, * Ask the sessiond if we have new metadata waiting and update the * consumer metadata cache. */ - ret = lttng_ustconsumer_sync_metadata(ctx, metadata); + status = lttng_ustconsumer_sync_metadata(ctx, metadata); break; default: - assert(0); - ret = -1; - break; + abort(); } - /* - * Error or no new metadata, we exit here. - */ - if (ret <= 0 || ret == ENODATA) { + + switch (status) { + case SYNC_METADATA_STATUS_NEW_DATA: + break; + case SYNC_METADATA_STATUS_NO_DATA: + ret = 0; goto end_unlock_mutex; + case SYNC_METADATA_STATUS_ERROR: + ret = -1; + goto end_unlock_mutex; + default: + abort(); } /* @@ -284,7 +350,7 @@ static int do_sync_metadata(struct lttng_consumer_stream *metadata, */ pthread_cond_wait(&metadata->metadata_rdv, &metadata->metadata_rdv_lock); pthread_mutex_unlock(&metadata->metadata_rdv_lock); - } while (ret == EAGAIN); + } while (status == SYNC_METADATA_STATUS_NEW_DATA); /* Success */ return 0; @@ -350,6 +416,7 @@ static int consumer_stream_sync_metadata_index( const struct stream_subbuffer *subbuffer, struct lttng_consumer_local_data *ctx) { + bool missed_metadata_flush; int ret; /* Block until all the metadata is sent. */ @@ -362,18 +429,34 @@ static int consumer_stream_sync_metadata_index( pthread_mutex_lock(&stream->metadata_timer_lock); stream->waiting_on_metadata = false; - if (stream->missed_metadata_flush) { + missed_metadata_flush = stream->missed_metadata_flush; + if (missed_metadata_flush) { stream->missed_metadata_flush = false; - pthread_mutex_unlock(&stream->metadata_timer_lock); - (void) stream->read_subbuffer_ops.send_live_beacon(stream); - } else { - pthread_mutex_unlock(&stream->metadata_timer_lock); } + pthread_mutex_unlock(&stream->metadata_timer_lock); if (ret < 0) { goto end; } ret = consumer_stream_send_index(stream, subbuffer, ctx); + /* + * Send the live inactivity beacon to handle the situation where + * the live timer is prevented from sampling this stream + * because the stream lock was being held while this stream is + * waiting on metadata. This ensures live viewer progress in the + * unlikely scenario where a live timer would be prevented from + * locking a stream lock repeatedly due to a steady flow of + * incoming metadata, for a stream which is mostly inactive. + * + * It is important to send the inactivity beacon packet to + * relayd _after_ sending the index associated with the data + * that was just sent, otherwise this can cause live viewers to + * observe timestamps going backwards between an inactivity + * beacon and a following trace packet. + */ + if (missed_metadata_flush) { + (void) stream->read_subbuffer_ops.send_live_beacon(stream); + } end: return ret; } @@ -426,13 +509,14 @@ struct lttng_consumer_stream *consumer_stream_create( goto end; } + rcu_read_lock(); + if (trace_chunk && !lttng_trace_chunk_get(trace_chunk)) { ERR("Failed to acquire trace chunk reference during the creation of a stream"); ret = -1; goto error; } - rcu_read_lock(); stream->chan = channel; stream->key = stream_key; stream->trace_chunk = trace_chunk; @@ -446,6 +530,8 @@ struct lttng_consumer_stream *consumer_stream_create( stream->index_file = NULL; stream->last_sequence_number = -1ULL; stream->rotate_position = -1ULL; + /* Buffer is created with an open packet. */ + stream->opened_packet_in_current_trace_chunk = true; pthread_mutex_init(&stream->lock, NULL); pthread_mutex_init(&stream->metadata_timer_lock, NULL); @@ -503,12 +589,16 @@ struct lttng_consumer_stream *consumer_stream_create( consumer_stream_metadata_lock_all; stream->read_subbuffer_ops.unlock = consumer_stream_metadata_unlock_all; + stream->read_subbuffer_ops.assert_locked = + consumer_stream_metadata_assert_locked_all; stream->read_subbuffer_ops.pre_consume_subbuffer = metadata_stream_check_version; } else { stream->read_subbuffer_ops.lock = consumer_stream_data_lock_all; stream->read_subbuffer_ops.unlock = consumer_stream_data_unlock_all; + stream->read_subbuffer_ops.assert_locked = + consumer_stream_data_assert_locked_all; stream->read_subbuffer_ops.pre_consume_subbuffer = consumer_stream_update_stats; if (channel->is_live) { @@ -831,6 +921,7 @@ void consumer_stream_destroy(struct lttng_consumer_stream *stream, * If the stream is not visible globally, this needs to be done * outside of the consumer data lock section. */ + destroy_close_stream(stream); free_chan = unref_channel(stream); }