X-Git-Url: https://git.lttng.org/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fcommon%2Fust-consumer%2Fust-consumer.c;h=147fe8aafe899a092a91ee8be58357786d7f074f;hp=a17c48f2f9ba2639fd39754550e8c1eacddacb86;hb=e9404c27e7cc9d841785e6c4292c1add19fbc1cc;hpb=fb83fe64f250bec7416f18891a8264450c61ead3 diff --git a/src/common/ust-consumer/ust-consumer.c b/src/common/ust-consumer/ust-consumer.c index a17c48f2f..147fe8aaf 100644 --- a/src/common/ust-consumer/ust-consumer.c +++ b/src/common/ust-consumer/ust-consumer.c @@ -1,6 +1,7 @@ /* * Copyright (C) 2011 - Julien Desfossez * Mathieu Desnoyers + * Copyright (C) 2017 - Jérémie Galarneau * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License, version 2 only, @@ -510,7 +511,7 @@ error_open: } /* Try to rmdir all directories under shm_path root. */ if (channel->root_shm_path[0]) { - (void) run_as_recursive_rmdir(channel->root_shm_path, + (void) run_as_rmdir_recursive(channel->root_shm_path, channel->uid, channel->gid); } free(stream_fds); @@ -767,7 +768,54 @@ static int flush_channel(uint64_t chan_key) health_code_update(); - ustctl_flush_buffer(stream->ustream, 1); + pthread_mutex_lock(&stream->lock); + if (!stream->quiescent) { + ustctl_flush_buffer(stream->ustream, 0); + stream->quiescent = true; + } + pthread_mutex_unlock(&stream->lock); + } +error: + rcu_read_unlock(); + return ret; +} + +/* + * Clear quiescent state from channel's streams using the given key to + * retrieve the channel. + * + * Return 0 on success else an LTTng error code. + */ +static int clear_quiescent_channel(uint64_t chan_key) +{ + int ret = 0; + struct lttng_consumer_channel *channel; + struct lttng_consumer_stream *stream; + struct lttng_ht *ht; + struct lttng_ht_iter iter; + + DBG("UST consumer clear quiescent channel key %" PRIu64, chan_key); + + rcu_read_lock(); + channel = consumer_find_channel(chan_key); + if (!channel) { + ERR("UST consumer clear quiescent channel %" PRIu64 " not found", chan_key); + ret = LTTNG_ERR_UST_CHAN_NOT_FOUND; + goto error; + } + + ht = consumer_data.stream_per_chan_id_ht; + + /* For each stream of the channel id, clear quiescent state. */ + cds_lfht_for_each_entry_duplicate(ht->ht, + ht->hash_fct(&channel->key, lttng_ht_seed), ht->match_fct, + &channel->key, &iter.iter, stream, node_channel_id.node) { + + health_code_update(); + + pthread_mutex_lock(&stream->lock); + stream->quiescent = false; + pthread_mutex_unlock(&stream->lock); } error: rcu_read_unlock(); @@ -1029,6 +1077,8 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id, DBG("UST consumer snapshot channel %" PRIu64, key); 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; health_code_update(); @@ -1062,7 +1112,13 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id, } } - ustctl_flush_buffer(stream->ustream, 1); + /* + * If tracing is active, we want to perform a "full" buffer flush. + * Else, if quiescent, it has already been done by the prior stop. + */ + if (!stream->quiescent) { + ustctl_flush_buffer(stream->ustream, 0); + } ret = lttng_ustconsumer_take_snapshot(stream); if (ret < 0) { @@ -1095,6 +1151,7 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id, while (consumed_pos < produced_pos) { ssize_t read_len; unsigned long len, padded_len; + int lost_packet = 0; health_code_update(); @@ -1108,6 +1165,15 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id, } DBG("UST 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; } @@ -1143,6 +1209,16 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id, goto error_close_stream; } 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; } /* Simply close the stream so we can use it on the next snapshot. */ @@ -1175,8 +1251,8 @@ error: * complete. */ int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset, - uint64_t len, struct lttng_consumer_channel *channel, - int timer, int wait) + uint64_t len, uint64_t version, + struct lttng_consumer_channel *channel, int timer, int wait) { int ret, ret_code = LTTCOMM_CONSUMERD_SUCCESS; char *metadata_str; @@ -1203,7 +1279,8 @@ int lttng_ustconsumer_recv_metadata(int sock, uint64_t key, uint64_t offset, health_code_update(); pthread_mutex_lock(&channel->metadata_cache->lock); - ret = consumer_metadata_cache_write(channel, offset, len, metadata_str); + ret = consumer_metadata_cache_write(channel, offset, len, version, + metadata_str); if (ret < 0) { /* Unable to handle metadata. Notify session daemon. */ ret_code = LTTCOMM_CONSUMERD_ERROR_METADATA; @@ -1425,8 +1502,17 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, consumer_timer_switch_start(channel, attr.switch_timer_interval); attr.switch_timer_interval = 0; } else { + int monitor_start_ret; + consumer_timer_live_start(channel, msg.u.ask_channel.live_timer_interval); + monitor_start_ret = consumer_timer_monitor_start( + channel, + msg.u.ask_channel.monitor_timer_interval); + if (monitor_start_ret < 0) { + ERR("Starting channel monitoring timer failed"); + goto end_channel_error; + } } health_code_update(); @@ -1449,6 +1535,9 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, if (channel->live_timer_enabled == 1) { consumer_timer_live_stop(channel); } + if (channel->monitor_timer_enabled == 1) { + consumer_timer_monitor_stop(channel); + } goto end_channel_error; } @@ -1559,12 +1648,25 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, goto end_msg_sessiond; } + case LTTNG_CONSUMER_CLEAR_QUIESCENT_CHANNEL: + { + int ret; + + ret = clear_quiescent_channel( + msg.u.clear_quiescent_channel.key); + if (ret != 0) { + ret_code = ret; + } + + goto end_msg_sessiond; + } case LTTNG_CONSUMER_PUSH_METADATA: { int ret; uint64_t len = msg.u.push_metadata.len; uint64_t key = msg.u.push_metadata.key; uint64_t offset = msg.u.push_metadata.target_offset; + uint64_t version = msg.u.push_metadata.version; struct lttng_consumer_channel *channel; DBG("UST consumer push metadata key %" PRIu64 " of len %" PRIu64, key, @@ -1615,7 +1717,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, health_code_update(); ret = lttng_ustconsumer_recv_metadata(sock, key, offset, - len, channel, 0, 1); + len, version, channel, 0, 1); if (ret < 0) { /* error receiving from sessiond */ goto error_fatal; @@ -1668,7 +1770,8 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, } case LTTNG_CONSUMER_DISCARDED_EVENTS: { - uint64_t ret; + int ret = 0; + uint64_t discarded_events; struct lttng_ht_iter iter; struct lttng_ht *ht; struct lttng_consumer_stream *stream; @@ -1689,13 +1792,13 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, * found (no events are dropped if the channel is not yet in * use). */ - ret = 0; + discarded_events = 0; cds_lfht_for_each_entry_duplicate(ht->ht, ht->hash_fct(&id, lttng_ht_seed), ht->match_fct, &id, &iter.iter, stream, node_session_id.node) { if (stream->chan->key == key) { - ret = stream->chan->discarded_events; + discarded_events = stream->chan->discarded_events; break; } } @@ -1708,7 +1811,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, health_code_update(); /* Send back returned value to session daemon */ - ret = lttcomm_send_unix_sock(sock, &ret, sizeof(ret)); + ret = lttcomm_send_unix_sock(sock, &discarded_events, sizeof(discarded_events)); if (ret < 0) { PERROR("send discarded events"); goto error_fatal; @@ -1718,7 +1821,8 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, } case LTTNG_CONSUMER_LOST_PACKETS: { - uint64_t ret; + int ret; + uint64_t lost_packets; struct lttng_ht_iter iter; struct lttng_ht *ht; struct lttng_consumer_stream *stream; @@ -1738,13 +1842,13 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, * to extract the information we need, we default to 0 if not * found (no packets lost if the channel is not yet in use). */ - ret = 0; + lost_packets = 0; cds_lfht_for_each_entry_duplicate(ht->ht, ht->hash_fct(&id, lttng_ht_seed), ht->match_fct, &id, &iter.iter, stream, node_session_id.node) { if (stream->chan->key == key) { - ret = stream->chan->lost_packets; + lost_packets = stream->chan->lost_packets; break; } } @@ -1757,7 +1861,8 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, health_code_update(); /* Send back returned value to session daemon */ - ret = lttcomm_send_unix_sock(sock, &ret, sizeof(ret)); + ret = lttcomm_send_unix_sock(sock, &lost_packets, + sizeof(lost_packets)); if (ret < 0) { PERROR("send lost packets"); goto error_fatal; @@ -1765,6 +1870,51 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx, break; } + case LTTNG_CONSUMER_SET_CHANNEL_MONITOR_PIPE: + { + int channel_monitor_pipe; + + ret_code = LTTCOMM_CONSUMERD_SUCCESS; + /* Successfully received the command's type. */ + ret = consumer_send_status_msg(sock, ret_code); + if (ret < 0) { + goto error_fatal; + } + + ret = lttcomm_recv_fds_unix_sock(sock, &channel_monitor_pipe, + 1); + if (ret != sizeof(channel_monitor_pipe)) { + ERR("Failed to receive channel monitor pipe"); + goto error_fatal; + } + + DBG("Received channel monitor pipe (%d)", channel_monitor_pipe); + ret = consumer_timer_thread_set_channel_monitor_pipe( + channel_monitor_pipe); + if (!ret) { + int flags; + + ret_code = LTTCOMM_CONSUMERD_SUCCESS; + /* Set the pipe as non-blocking. */ + ret = fcntl(channel_monitor_pipe, F_GETFL, 0); + if (ret == -1) { + PERROR("fcntl get flags of the channel monitoring pipe"); + goto error_fatal; + } + flags = ret; + + ret = fcntl(channel_monitor_pipe, F_SETFL, + flags | O_NONBLOCK); + if (ret == -1) { + PERROR("fcntl set O_NONBLOCK flag of the channel monitoring pipe"); + goto error_fatal; + } + DBG("Channel monitor pipe set as non-blocking"); + } else { + ret_code = LTTCOMM_CONSUMERD_ALREADY_SET; + } + goto end_msg_sessiond; + } default: break; } @@ -1846,7 +1996,7 @@ void *lttng_ustctl_get_mmap_base(struct lttng_consumer_stream *stream) } /* - * Take a snapshot for a specific fd + * Take a snapshot for a specific stream. * * Returns 0 on success, < 0 on error */ @@ -1858,6 +2008,20 @@ int lttng_ustconsumer_take_snapshot(struct lttng_consumer_stream *stream) return ustctl_snapshot(stream->ustream); } +/* + * Sample consumed and produced positions for a specific stream. + * + * Returns 0 on success, < 0 on error. + */ +int lttng_ustconsumer_sample_snapshot_positions( + struct lttng_consumer_stream *stream) +{ + assert(stream); + assert(stream->ustream); + + return ustctl_snapshot_sample_positions(stream->ustream); +} + /* * Get the produced position * @@ -1918,14 +2082,19 @@ int lttng_ustconsumer_get_sequence_number( } /* - * Called when the stream signal the consumer that it has hang up. + * Called when the stream signals the consumer that it has hung up. */ void lttng_ustconsumer_on_stream_hangup(struct lttng_consumer_stream *stream) { assert(stream); assert(stream->ustream); - ustctl_flush_buffer(stream->ustream, 0); + pthread_mutex_lock(&stream->lock); + if (!stream->quiescent) { + ustctl_flush_buffer(stream->ustream, 0); + stream->quiescent = true; + } + pthread_mutex_unlock(&stream->lock); stream->hangup_flush_done = 1; } @@ -1959,11 +2128,6 @@ void lttng_ustconsumer_del_channel(struct lttng_consumer_channel *chan) } } } - /* Try to rmdir all directories under shm_path root. */ - if (chan->root_shm_path[0]) { - (void) run_as_recursive_rmdir(chan->root_shm_path, - chan->uid, chan->gid); - } } void lttng_ustconsumer_free_channel(struct lttng_consumer_channel *chan) @@ -1973,6 +2137,11 @@ void lttng_ustconsumer_free_channel(struct lttng_consumer_channel *chan) consumer_metadata_cache_destroy(chan); ustctl_destroy_channel(chan->uchan); + /* Try to rmdir all directories under shm_path root. */ + if (chan->root_shm_path[0]) { + (void) run_as_rmdir_recursive(chan->root_shm_path, + chan->uid, chan->gid); + } free(chan->stream_fds); } @@ -2055,10 +2224,56 @@ static int get_index_values(struct ctf_packet_index *index, } index->stream_id = htobe64(index->stream_id); + ret = ustctl_get_instance_id(ustream, &index->stream_instance_id); + if (ret < 0) { + PERROR("ustctl_get_instance_id"); + goto error; + } + index->stream_instance_id = htobe64(index->stream_instance_id); + + ret = ustctl_get_sequence_number(ustream, &index->packet_seq_num); + if (ret < 0) { + PERROR("ustctl_get_sequence_number"); + goto error; + } + index->packet_seq_num = htobe64(index->packet_seq_num); + error: return ret; } +static +void metadata_stream_reset_cache(struct lttng_consumer_stream *stream, + struct consumer_metadata_cache *cache) +{ + DBG("Metadata stream update to version %" PRIu64, + cache->version); + stream->ust_metadata_pushed = 0; + stream->metadata_version = cache->version; + stream->reset_metadata_flag = 1; +} + +/* + * Check if the version of the metadata stream and metadata cache match. + * If the cache got updated, reset the metadata stream. + * The stream lock and metadata cache lock MUST be held. + * Return 0 on success, a negative value on error. + */ +static +int metadata_stream_check_version(struct lttng_consumer_stream *stream) +{ + int ret = 0; + struct consumer_metadata_cache *cache = stream->chan->metadata_cache; + + if (cache->version == stream->metadata_version) { + goto end; + } + metadata_stream_reset_cache(stream, cache); + +end: + return ret; +} + /* * Write up to one packet from the metadata cache to the channel. * @@ -2072,6 +2287,10 @@ int commit_one_metadata_packet(struct lttng_consumer_stream *stream) int ret; pthread_mutex_lock(&stream->chan->metadata_cache->lock); + ret = metadata_stream_check_version(stream); + if (ret < 0) { + goto end; + } if (stream->chan->metadata_cache->max_offset == stream->ust_metadata_pushed) { ret = 0; @@ -2126,10 +2345,10 @@ int lttng_ustconsumer_sync_metadata(struct lttng_consumer_local_data *ctx, * because we locked the metadata thread. */ ret = lttng_ustconsumer_request_metadata(ctx, metadata->chan, 0, 0); + pthread_mutex_lock(&metadata->lock); if (ret < 0) { goto end; } - pthread_mutex_lock(&metadata->lock); ret = commit_one_metadata_packet(metadata); if (ret <= 0) { @@ -2251,8 +2470,8 @@ int update_stream_stats(struct lttng_consumer_stream *stream) } if (discarded < stream->last_discarded_events) { /* - * Overflow has occured. We assume only one wrap-around - * has occured. + * Overflow has occurred. We assume only one wrap-around + * has occurred. */ stream->chan->discarded_events += (1ULL << (CAA_BITS_PER_LONG - 1)) - @@ -2349,6 +2568,8 @@ retry: index.offset = htobe64(stream->out_fd_offset); ret = get_index_values(&index, ustream); if (ret < 0) { + err = ustctl_put_subbuf(ustream); + assert(err == 0); goto end; } @@ -2356,6 +2577,8 @@ retry: ret = update_stream_stats(stream); if (ret < 0) { PERROR("kernctl_get_events_discarded"); + err = ustctl_put_subbuf(ustream); + assert(err == 0); goto end; } } else { @@ -2473,14 +2696,18 @@ int lttng_ustconsumer_on_recv_stream(struct lttng_consumer_stream *stream) stream->tracefile_size_current = 0; if (!stream->metadata_flag) { - ret = index_create_file(stream->chan->pathname, + struct lttng_index_file *index_file; + + 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 (!index_file) { goto error; } - stream->index_fd = ret; + assert(!stream->index_file); + stream->index_file = index_file; } } ret = 0; @@ -2655,7 +2882,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, struct lttcomm_metadata_request_msg request; struct lttcomm_consumer_msg msg; enum lttcomm_return_code ret_code = LTTCOMM_CONSUMERD_SUCCESS; - uint64_t len, key, offset; + uint64_t len, key, offset, version; int ret; assert(channel); @@ -2735,6 +2962,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, len = msg.u.push_metadata.len; key = msg.u.push_metadata.key; offset = msg.u.push_metadata.target_offset; + version = msg.u.push_metadata.version; assert(key == channel->key); if (len == 0) { @@ -2757,7 +2985,7 @@ int lttng_ustconsumer_request_metadata(struct lttng_consumer_local_data *ctx, health_code_update(); ret = lttng_ustconsumer_recv_metadata(ctx->consumer_metadata_socket, - key, offset, len, channel, timer, wait); + key, offset, len, version, channel, timer, wait); if (ret >= 0) { /* * Only send the status msg if the sessiond is alive meaning a positive