Keep read-only copies of fields from the channel to the stream
[lttng-tools.git] / src / common / ust-consumer / ust-consumer.c
index a66f305cd02e433f41bf31d0591c0e545d524a1a..00937a44dd0172882e03c2ea21d361a1597449c8 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * Copyright (C) 2011 - Julien Desfossez <julien.desfossez@polymtl.ca>
  *                      Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
+ * Copyright (C) 2017 - Jérémie Galarneau <jeremie.galarneau@efficios.com>
  *
  * 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,
@@ -50,7 +51,6 @@
 
 extern struct lttng_consumer_global_data consumer_data;
 extern int consumer_poll_timeout;
-extern volatile int consumer_quit;
 
 /*
  * Free channel object and all streams associated with it. This MUST be used
@@ -184,6 +184,7 @@ static struct lttng_consumer_stream *allocate_stream(int cpu, int key,
                goto error;
        }
 
+       consumer_stream_update_channel_attributes(stream, channel);
        stream->chan = channel;
 
 error:
@@ -206,28 +207,21 @@ static int send_stream_to_thread(struct lttng_consumer_stream *stream,
 
        /* Get the right pipe where the stream will be sent. */
        if (stream->metadata_flag) {
-               ret = consumer_add_metadata_stream(stream);
-               if (ret) {
-                       ERR("Consumer add metadata stream %" PRIu64 " failed.",
-                                       stream->key);
-                       goto error;
-               }
+               consumer_add_metadata_stream(stream);
                stream_pipe = ctx->consumer_metadata_pipe;
        } else {
-               ret = consumer_add_data_stream(stream);
-               if (ret) {
-                       ERR("Consumer add stream %" PRIu64 " failed.",
-                                       stream->key);
-                       goto error;
-               }
+               consumer_add_data_stream(stream);
                stream_pipe = ctx->consumer_data_pipe;
        }
 
        /*
         * From this point on, the stream's ownership has been moved away from
-        * the channel and becomes globally visible.
+        * the channel and it becomes globally visible. Hence, remove it from
+        * the local stream list to prevent the stream from being both local and
+        * global.
         */
        stream->globally_visible = 1;
+       cds_list_del(&stream->send_node);
 
        ret = lttng_pipe_write(stream_pipe, &stream, sizeof(stream));
        if (ret < 0) {
@@ -239,7 +233,9 @@ static int send_stream_to_thread(struct lttng_consumer_stream *stream,
                } else {
                        consumer_del_stream_for_data(stream);
                }
+               goto error;
        }
+
 error:
        return ret;
 }
@@ -510,7 +506,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);
@@ -721,14 +717,8 @@ static int send_streams_to_thread(struct lttng_consumer_channel *channel,
                         * If we are unable to send the stream to the thread, there is
                         * a big problem so just stop everything.
                         */
-                       /* Remove node from the channel stream list. */
-                       cds_list_del(&stream->send_node);
                        goto error;
                }
-
-               /* Remove node from the channel stream list. */
-               cds_list_del(&stream->send_node);
-
        }
 
 error:
@@ -831,6 +821,7 @@ static int close_metadata(uint64_t chan_key)
 {
        int ret = 0;
        struct lttng_consumer_channel *channel;
+       unsigned int channel_monitor;
 
        DBG("UST consumer close metadata key %" PRIu64, chan_key);
 
@@ -849,13 +840,48 @@ static int close_metadata(uint64_t chan_key)
 
        pthread_mutex_lock(&consumer_data.lock);
        pthread_mutex_lock(&channel->lock);
-
+       channel_monitor = channel->monitor;
        if (cds_lfht_is_node_deleted(&channel->node.node)) {
                goto error_unlock;
        }
 
        lttng_ustconsumer_close_metadata(channel);
+       pthread_mutex_unlock(&channel->lock);
+       pthread_mutex_unlock(&consumer_data.lock);
 
+       /*
+        * The ownership of a metadata channel depends on the type of
+        * session to which it belongs. In effect, the monitor flag is checked
+        * to determine if this metadata channel is in "snapshot" mode or not.
+        *
+        * In the non-snapshot case, the metadata channel is created along with
+        * a single stream which will remain present until the metadata channel
+        * is destroyed (on the destruction of its session). In this case, the
+        * metadata stream in "monitored" by the metadata poll thread and holds
+        * the ownership of its channel.
+        *
+        * Closing the metadata will cause the metadata stream's "metadata poll
+        * pipe" to be closed. Closing this pipe will wake-up the metadata poll
+        * thread which will teardown the metadata stream which, in return,
+        * deletes the metadata channel.
+        *
+        * In the snapshot case, the metadata stream is created and destroyed
+        * on every snapshot record. Since the channel doesn't have an owner
+        * other than the session daemon, it is safe to destroy it immediately
+        * on reception of the CLOSE_METADATA command.
+        */
+       if (!channel_monitor) {
+               /*
+                * The channel and consumer_data locks must be
+                * released before this call since consumer_del_channel
+                * re-acquires the channel and consumer_data locks to teardown
+                * the channel and queue its reclamation by the "call_rcu"
+                * worker thread.
+                */
+               consumer_del_channel(channel);
+       }
+
+       return ret;
 error_unlock:
        pthread_mutex_unlock(&channel->lock);
        pthread_mutex_unlock(&consumer_data.lock);
@@ -918,6 +944,10 @@ static int setup_metadata(struct lttng_consumer_local_data *ctx, uint64_t key)
                }
        }
 
+       /*
+        * Ownership of metadata stream is passed along. Freeing is handled by
+        * the callee.
+        */
        ret = send_streams_to_thread(metadata, ctx);
        if (ret < 0) {
                /*
@@ -925,7 +955,7 @@ static int setup_metadata(struct lttng_consumer_local_data *ctx, uint64_t key)
                 * a big problem so just stop everything.
                 */
                ret = LTTCOMM_CONSUMERD_FATAL;
-               goto error;
+               goto send_streams_error;
        }
        /* List MUST be empty after or else it could be reused. */
        assert(cds_list_empty(&metadata->streams.head));
@@ -943,6 +973,7 @@ error:
        consumer_stream_destroy(metadata->metadata_stream, NULL);
        cds_list_del(&metadata->metadata_stream->send_node);
        metadata->metadata_stream = NULL;
+send_streams_error:
 error_no_stream:
 end:
        return ret;
@@ -1076,9 +1107,6 @@ 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();
 
                /* Lock stream because we are about to change its state. */
@@ -1104,14 +1132,14 @@ static int snapshot_channel(uint64_t key, char *path, uint64_t relayd_id,
                        DBG("UST consumer snapshot stream %s/%s (%" PRIu64 ")", path,
                                        stream->name, stream->key);
                }
-               if (relayd_id != -1ULL) {
-                       ret = consumer_send_relayd_streams_sent(relayd_id);
-                       if (ret < 0) {
-                               goto error_unlock;
-                       }
-               }
 
-               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) {
@@ -1144,7 +1172,6 @@ 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();
 
@@ -1158,15 +1185,7 @@ 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;
-                               }
+                               stream->chan->lost_packets++;
                                continue;
                        }
 
@@ -1202,16 +1221,6 @@ 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. */
@@ -1348,7 +1357,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
        case LTTNG_CONSUMER_ADD_RELAYD_SOCKET:
        {
                /* Session daemon status message are handled in the following call. */
-               ret = consumer_add_relayd_socket(msg.u.relayd_sock.net_index,
+               consumer_add_relayd_socket(msg.u.relayd_sock.net_index,
                                msg.u.relayd_sock.type, ctx, sock, consumer_sockpoll,
                                &msg.u.relayd_sock.sock, msg.u.relayd_sock.session_id,
                                msg.u.relayd_sock.relayd_session_id);
@@ -1449,6 +1458,7 @@ int lttng_ustconsumer_recv_cmd(struct lttng_consumer_local_data *ctx,
                attr.read_timer_interval = msg.u.ask_channel.read_timer_interval;
                attr.chan_id = msg.u.ask_channel.chan_id;
                memcpy(attr.uuid, msg.u.ask_channel.uuid, sizeof(attr.uuid));
+               attr.blocking_timeout= msg.u.ask_channel.blocking_timeout;
 
                /* Match channel buffer type to the UST abi. */
                switch (msg.u.ask_channel.output) {
@@ -1495,8 +1505,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();
@@ -1519,6 +1538,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;
                }
 
@@ -1851,6 +1873,97 @@ 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;
+       }
+       case LTTNG_CONSUMER_ROTATE_RENAME:
+       {
+               DBG("Consumer rename session %" PRIu64 " after rotation",
+                               msg.u.rotate_rename.session_id);
+               ret = lttng_consumer_rotate_rename(msg.u.rotate_rename.old_path,
+                               msg.u.rotate_rename.new_path,
+                               msg.u.rotate_rename.uid,
+                               msg.u.rotate_rename.gid,
+                               msg.u.rotate_rename.relayd_id);
+               if (ret < 0) {
+                       ERR("Rotate rename failed");
+                       ret_code = LTTCOMM_CONSUMERD_CHAN_NOT_FOUND;
+               }
+
+               health_code_update();
+
+               ret = consumer_send_status_msg(sock, ret_code);
+               if (ret < 0) {
+                       /* Somehow, the session daemon is not responding anymore. */
+                       goto end_nosignal;
+               }
+               break;
+       }
+       case LTTNG_CONSUMER_MKDIR:
+       {
+               DBG("Consumer mkdir %s in session %" PRIu64,
+                               msg.u.mkdir.path,
+                               msg.u.mkdir.session_id);
+               ret = lttng_consumer_mkdir(msg.u.mkdir.path,
+                               msg.u.mkdir.uid,
+                               msg.u.mkdir.gid,
+                               msg.u.mkdir.relayd_id);
+               if (ret < 0) {
+                       ERR("consumer mkdir failed");
+                       ret_code = LTTCOMM_CONSUMERD_CHAN_NOT_FOUND;
+               }
+
+               health_code_update();
+
+               ret = consumer_send_status_msg(sock, ret_code);
+               if (ret < 0) {
+                       /* Somehow, the session daemon is not responding anymore. */
+                       goto end_nosignal;
+               }
+               break;
+       }
        default:
                break;
        }
@@ -1932,7 +2045,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
  */
@@ -1944,6 +2057,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
  *
@@ -2061,7 +2188,7 @@ void lttng_ustconsumer_free_channel(struct lttng_consumer_channel *chan)
        ustctl_destroy_channel(chan->uchan);
        /* Try to rmdir all directories under shm_path root. */
        if (chan->root_shm_path[0]) {
-               (void) run_as_recursive_rmdir(chan->root_shm_path,
+               (void) run_as_rmdir_recursive(chan->root_shm_path,
                                chan->uid, chan->gid);
        }
        free(chan->stream_fds);
@@ -2267,10 +2394,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) {
@@ -2392,8 +2519,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)) -
@@ -2490,6 +2617,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;
                }
 
@@ -2497,6 +2626,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 {
@@ -2614,14 +2745,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;
This page took 0.033189 seconds and 5 git commands to generate.