Implement consumer ring buffer position sampling
[lttng-tools.git] / src / bin / lttng-sessiond / consumer.c
index 41ad46d8689338f3c27c3fc80fb12dd46bbdb53f..4a7287b61ba78f46365b76ffc1fd011525d82064 100644 (file)
@@ -15,7 +15,6 @@
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
-#define _GNU_SOURCE
 #define _LGPL_SOURCE
 #include <assert.h>
 #include <stdio.h>
@@ -564,6 +563,8 @@ struct consumer_output *consumer_copy_output(struct consumer_output *obj)
        output->net_seq_index = obj->net_seq_index;
        memcpy(output->subdir, obj->subdir, PATH_MAX);
        output->snapshot = obj->snapshot;
+       output->relay_major_version = obj->relay_major_version;
+       output->relay_minor_version = obj->relay_minor_version;
        memcpy(&output->dst, &obj->dst, sizeof(output->dst));
        ret = consumer_copy_sockets(output, obj);
        if (ret < 0) {
@@ -714,7 +715,10 @@ int consumer_set_network_uri(struct consumer_output *obj,
                        goto error;
                }
 
-               strncpy(obj->subdir, tmp_path, sizeof(obj->subdir));
+               if (lttng_strncpy(obj->subdir, tmp_path, sizeof(obj->subdir))) {
+                       ret = -LTTNG_ERR_INVALID;
+                       goto error;
+               }
                DBG3("Consumer set network uri subdir path %s", tmp_path);
        }
 
@@ -744,7 +748,6 @@ int consumer_send_fds(struct consumer_socket *sock, int *fds, size_t nb_fd)
        }
 
        ret = consumer_recv_status_reply(sock);
-
 error:
        return ret;
 }
@@ -802,6 +805,7 @@ void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
                unsigned int switch_timer_interval,
                unsigned int read_timer_interval,
                unsigned int live_timer_interval,
+               unsigned int monitor_timer_interval,
                int output,
                int type,
                uint64_t session_id,
@@ -833,6 +837,7 @@ void consumer_init_ask_channel_comm_msg(struct lttcomm_consumer_msg *msg,
        msg->u.ask_channel.switch_timer_interval = switch_timer_interval;
        msg->u.ask_channel.read_timer_interval = read_timer_interval;
        msg->u.ask_channel.live_timer_interval = live_timer_interval;
+       msg->u.ask_channel.monitor_timer_interval = monitor_timer_interval;
        msg->u.ask_channel.output = output;
        msg->u.ask_channel.type = type;
        msg->u.ask_channel.session_id = session_id;
@@ -888,7 +893,8 @@ void consumer_init_channel_comm_msg(struct lttcomm_consumer_msg *msg,
                uint64_t tracefile_size,
                uint64_t tracefile_count,
                unsigned int monitor,
-               unsigned int live_timer_interval)
+               unsigned int live_timer_interval,
+               unsigned int monitor_timer_interval)
 {
        assert(msg);
 
@@ -909,6 +915,7 @@ void consumer_init_channel_comm_msg(struct lttcomm_consumer_msg *msg,
        msg->u.channel.tracefile_count = tracefile_count;
        msg->u.channel.monitor = monitor;
        msg->u.channel.live_timer_interval = live_timer_interval;
+       msg->u.channel.monitor_timer_interval = monitor_timer_interval;
 
        strncpy(msg->u.channel.pathname, pathname,
                        sizeof(msg->u.channel.pathname));
@@ -1044,6 +1051,35 @@ error:
        return ret;
 }
 
+int consumer_send_channel_monitor_pipe(struct consumer_socket *consumer_sock,
+               int pipe)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       /* Code flow error. Safety net. */
+
+       memset(&msg, 0, sizeof(msg));
+       msg.cmd_type = LTTNG_CONSUMER_SET_CHANNEL_MONITOR_PIPE;
+
+       DBG3("Sending set_channel_monitor_pipe command to consumer");
+       ret = consumer_send_msg(consumer_sock, &msg);
+       if (ret < 0) {
+               goto error;
+       }
+
+       DBG3("Sending channel monitoring pipe %d to consumer on socket %d",
+                       pipe, *consumer_sock->fd_ptr);
+       ret = consumer_send_fds(consumer_sock, &pipe, 1);
+       if (ret < 0) {
+               goto error;
+       }
+
+       DBG2("Channel monitoring pipe successfully sent");
+error:
+       return ret;
+}
+
 /*
  * Set consumer subdirectory using the session name and a generated datetime if
  * needed. This is appended to the current subdirectory.
@@ -1085,7 +1121,11 @@ int consumer_set_subdir(struct consumer_output *consumer,
                goto error;
        }
 
-       strncpy(consumer->subdir, tmp_path, sizeof(consumer->subdir));
+       if (lttng_strncpy(consumer->subdir, tmp_path,
+                       sizeof(consumer->subdir))) {
+               ret = -EINVAL;
+               goto error;
+       }
        DBG2("Consumer subdir set to %s", consumer->subdir);
 
 error:
@@ -1093,11 +1133,8 @@ error:
 }
 
 /*
- * Ask the consumer if the data is ready to read (NOT pending) for the specific
- * session id.
- *
- * This function has a different behavior with the consumer i.e. that it waits
- * for a reply from the consumer if yes or no the data is pending.
+ * Ask the consumer if the data is pending for the specific session id.
+ * Returns 1 if data is pending, 0 otherwise, or < 0 on error.
  */
 int consumer_is_data_pending(uint64_t session_id,
                struct consumer_output *consumer)
@@ -1186,6 +1223,38 @@ end:
        return ret;
 }
 
+/*
+ * Send a clear quiescent command to consumer using the given channel key.
+ *
+ * Return 0 on success else a negative value.
+ */
+int consumer_clear_quiescent_channel(struct consumer_socket *socket, uint64_t key)
+{
+       int ret;
+       struct lttcomm_consumer_msg msg;
+
+       assert(socket);
+
+       DBG2("Consumer clear quiescent channel key %" PRIu64, key);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.cmd_type = LTTNG_CONSUMER_CLEAR_QUIESCENT_CHANNEL;
+       msg.u.clear_quiescent_channel.key = key;
+
+       pthread_mutex_lock(socket->lock);
+       health_code_update();
+
+       ret = consumer_send_msg(socket, &msg);
+       if (ret < 0) {
+               goto end;
+       }
+
+end:
+       health_code_update();
+       pthread_mutex_unlock(socket->lock);
+       return ret;
+}
+
 /*
  * Send a close metadata command to consumer using the given channel key.
  * Called with registry lock held.
@@ -1261,7 +1330,7 @@ end:
  */
 int consumer_push_metadata(struct consumer_socket *socket,
                uint64_t metadata_key, char *metadata_str, size_t len,
-               size_t target_offset)
+               size_t target_offset, uint64_t version)
 {
        int ret;
        struct lttcomm_consumer_msg msg;
@@ -1277,6 +1346,7 @@ int consumer_push_metadata(struct consumer_socket *socket,
        msg.u.push_metadata.key = metadata_key;
        msg.u.push_metadata.target_offset = target_offset;
        msg.u.push_metadata.len = len;
+       msg.u.push_metadata.version = version;
 
        health_code_update();
        ret = consumer_send_msg(socket, &msg);
@@ -1356,7 +1426,7 @@ int consumer_snapshot_channel(struct consumer_socket *socket, uint64_t key,
                ret = run_as_mkdir_recursive(msg.u.snapshot_channel.pathname,
                                S_IRWXU | S_IRWXG, uid, gid);
                if (ret < 0) {
-                       if (ret != -EEXIST) {
+                       if (errno != EEXIST) {
                                ERR("Trace directory creation error");
                                goto error;
                        }
@@ -1373,3 +1443,117 @@ error:
        health_code_update();
        return ret;
 }
+
+/*
+ * Ask the consumer the number of discarded events for a channel.
+ */
+int consumer_get_discarded_events(uint64_t session_id, uint64_t channel_key,
+               struct consumer_output *consumer, uint64_t *discarded)
+{
+       int ret;
+       struct consumer_socket *socket;
+       struct lttng_ht_iter iter;
+       struct lttcomm_consumer_msg msg;
+
+       assert(consumer);
+
+       DBG3("Consumer discarded events id %" PRIu64, session_id);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.cmd_type = LTTNG_CONSUMER_DISCARDED_EVENTS;
+       msg.u.discarded_events.session_id = session_id;
+       msg.u.discarded_events.channel_key = channel_key;
+
+       *discarded = 0;
+
+       /* Send command for each consumer */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, socket,
+                       node.node) {
+               uint64_t consumer_discarded = 0;
+               pthread_mutex_lock(socket->lock);
+               ret = consumer_socket_send(socket, &msg, sizeof(msg));
+               if (ret < 0) {
+                       pthread_mutex_unlock(socket->lock);
+                       goto end;
+               }
+
+               /*
+                * No need for a recv reply status because the answer to the
+                * command is the reply status message.
+                */
+               ret = consumer_socket_recv(socket, &consumer_discarded,
+                               sizeof(consumer_discarded));
+               if (ret < 0) {
+                       ERR("get discarded events");
+                       pthread_mutex_unlock(socket->lock);
+                       goto end;
+               }
+               pthread_mutex_unlock(socket->lock);
+               *discarded += consumer_discarded;
+       }
+       ret = 0;
+       DBG("Consumer discarded %" PRIu64 " events in session id %" PRIu64,
+                       *discarded, session_id);
+
+end:
+       rcu_read_unlock();
+       return ret;
+}
+
+/*
+ * Ask the consumer the number of lost packets for a channel.
+ */
+int consumer_get_lost_packets(uint64_t session_id, uint64_t channel_key,
+               struct consumer_output *consumer, uint64_t *lost)
+{
+       int ret;
+       struct consumer_socket *socket;
+       struct lttng_ht_iter iter;
+       struct lttcomm_consumer_msg msg;
+
+       assert(consumer);
+
+       DBG3("Consumer lost packets id %" PRIu64, session_id);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.cmd_type = LTTNG_CONSUMER_LOST_PACKETS;
+       msg.u.lost_packets.session_id = session_id;
+       msg.u.lost_packets.channel_key = channel_key;
+
+       *lost = 0;
+
+       /* Send command for each consumer */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(consumer->socks->ht, &iter.iter, socket,
+                       node.node) {
+               uint64_t consumer_lost = 0;
+               pthread_mutex_lock(socket->lock);
+               ret = consumer_socket_send(socket, &msg, sizeof(msg));
+               if (ret < 0) {
+                       pthread_mutex_unlock(socket->lock);
+                       goto end;
+               }
+
+               /*
+                * No need for a recv reply status because the answer to the
+                * command is the reply status message.
+                */
+               ret = consumer_socket_recv(socket, &consumer_lost,
+                               sizeof(consumer_lost));
+               if (ret < 0) {
+                       ERR("get lost packets");
+                       pthread_mutex_unlock(socket->lock);
+                       goto end;
+               }
+               pthread_mutex_unlock(socket->lock);
+               *lost += consumer_lost;
+       }
+       ret = 0;
+       DBG("Consumer lost %" PRIu64 " packets in session id %" PRIu64,
+                       *lost, session_id);
+
+end:
+       rcu_read_unlock();
+       return ret;
+}
This page took 0.028029 seconds and 4 git commands to generate.