Map session id of relayd and sessiond in consumer
[lttng-tools.git] / src / common / consumer.c
index 5dc1d92b40685598e1c841b8d3128073aeed65ba..b5e212f27d61c5f08f53ef32fb19ac91c1e55917 100644 (file)
@@ -63,6 +63,20 @@ volatile int consumer_quit;
 static struct lttng_ht *metadata_ht;
 static struct lttng_ht *data_ht;
 
+/*
+ * This hash table contains the mapping between the session id of the sessiond
+ * and the relayd session id. Element of the ht are indexed by sessiond_id.
+ *
+ * Node can be added when a relayd communication is opened in the sessiond
+ * thread.
+ *
+ * Note that a session id of the session daemon is unique to a tracing session
+ * and not to a domain session. However, a domain session has one consumer
+ * which forces the 1-1 mapping between a consumer and a domain session (ex:
+ * UST). This means that we can't have duplicate in this ht.
+ */
+static struct lttng_ht *relayd_session_id_ht;
+
 /*
  * Notify a thread pipe to poll back again. This usually means that some global
  * state has changed so we just send back the thread in a poll wait call.
@@ -216,6 +230,7 @@ static void destroy_relayd(struct consumer_relayd_sock_pair *relayd)
 {
        int ret;
        struct lttng_ht_iter iter;
+       struct lttng_ht_node_ulong *node;
 
        if (relayd == NULL) {
                return;
@@ -223,6 +238,20 @@ static void destroy_relayd(struct consumer_relayd_sock_pair *relayd)
 
        DBG("Consumer destroy and close relayd socket pair");
 
+       lttng_ht_lookup(relayd_session_id_ht,
+                       (void *)((unsigned long) relayd->session_id), &iter);
+       node = lttng_ht_iter_get_node_ulong(&iter);
+       if (node != NULL) {
+               /* We assume the relayd is being or is destroyed */
+               return;
+       }
+
+       ret = lttng_ht_del(relayd_session_id_ht, &iter);
+       if (ret != 0) {
+               /* We assume the relayd is being or is destroyed */
+               return;
+       }
+
        iter.iter.node = &relayd->node.node;
        ret = lttng_ht_del(consumer_data.relayd_ht, &iter);
        if (ret != 0) {
@@ -234,6 +263,27 @@ static void destroy_relayd(struct consumer_relayd_sock_pair *relayd)
        call_rcu(&relayd->node.head, consumer_rcu_free_relayd);
 }
 
+/*
+ * Iterate over the relayd hash table and destroy each element. Finally,
+ * destroy the whole hash table.
+ */
+static void cleanup_relayd_ht(void)
+{
+       struct lttng_ht_iter iter;
+       struct consumer_relayd_sock_pair *relayd;
+
+       rcu_read_lock();
+
+       cds_lfht_for_each_entry(consumer_data.relayd_ht->ht, &iter.iter, relayd,
+                       node.node) {
+               destroy_relayd(relayd);
+       }
+
+       lttng_ht_destroy(consumer_data.relayd_ht);
+
+       rcu_read_unlock();
+}
+
 /*
  * Update the end point status of all streams having the given network sequence
  * index (relayd index).
@@ -764,6 +814,8 @@ void consumer_del_channel(struct lttng_consumer_channel *channel)
        int ret;
        struct lttng_ht_iter iter;
 
+       DBG("Consumer delete channel key %d", channel->key);
+
        pthread_mutex_lock(&consumer_data.lock);
 
        switch (consumer_data.type) {
@@ -1001,8 +1053,8 @@ int lttng_consumer_send_error(
 }
 
 /*
- * Close all the tracefiles and stream fds, should be called when all instances
- * are destroyed.
+ * Close all the tracefiles and stream fds and MUST be called when all
+ * instances are destroyed i.e. when all threads were joined and are ended.
  */
 void lttng_consumer_cleanup(void)
 {
@@ -1021,6 +1073,15 @@ void lttng_consumer_cleanup(void)
        rcu_read_unlock();
 
        lttng_ht_destroy(consumer_data.channel_ht);
+
+       cleanup_relayd_ht();
+
+       /*
+        * This HT contains streams that are freed by either the metadata thread or
+        * the data thread so we do *nothing* on the hash table and simply destroy
+        * it.
+        */
+       lttng_ht_destroy(consumer_data.stream_list_ht);
 }
 
 /*
@@ -1695,7 +1756,6 @@ int lttng_consumer_recv_cmd(struct lttng_consumer_local_data *ctx,
  */
 static void destroy_data_stream_ht(struct lttng_ht *ht)
 {
-       int ret;
        struct lttng_ht_iter iter;
        struct lttng_consumer_stream *stream;
 
@@ -1705,10 +1765,11 @@ static void destroy_data_stream_ht(struct lttng_ht *ht)
 
        rcu_read_lock();
        cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
-               ret = lttng_ht_del(ht, &iter);
-               assert(!ret);
-
-               call_rcu(&stream->node.head, consumer_free_stream);
+               /*
+                * Ignore return value since we are currently cleaning up so any error
+                * can't be handled.
+                */
+               (void) consumer_del_stream(stream, ht);
        }
        rcu_read_unlock();
 
@@ -1722,7 +1783,6 @@ static void destroy_data_stream_ht(struct lttng_ht *ht)
  */
 static void destroy_stream_ht(struct lttng_ht *ht)
 {
-       int ret;
        struct lttng_ht_iter iter;
        struct lttng_consumer_stream *stream;
 
@@ -1732,10 +1792,11 @@ static void destroy_stream_ht(struct lttng_ht *ht)
 
        rcu_read_lock();
        cds_lfht_for_each_entry(ht->ht, &iter.iter, stream, node.node) {
-               ret = lttng_ht_del(ht, &iter);
-               assert(!ret);
-
-               call_rcu(&stream->node.head, consumer_free_stream);
+               /*
+                * Ignore return value since we are currently cleaning up so any error
+                * can't be handled.
+                */
+               (void) consumer_del_metadata_stream(stream, ht);
        }
        rcu_read_unlock();
 
@@ -2011,6 +2072,12 @@ void *consumer_thread_metadata_poll(void *data)
 
        rcu_register_thread();
 
+       metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
+       if (!metadata_ht) {
+               /* ENOMEM at this point. Better to bail out. */
+               goto error;
+       }
+
        DBG("Thread metadata poll started");
 
        /* Size is set to 1 for the consumer_metadata pipe */
@@ -2177,9 +2244,7 @@ end:
        DBG("Metadata poll thread exiting");
        lttng_poll_clean(&events);
 
-       if (metadata_ht) {
-               destroy_stream_ht(metadata_ht);
-       }
+       destroy_stream_ht(metadata_ht);
 
        rcu_unregister_thread();
        return NULL;
@@ -2204,6 +2269,7 @@ void *consumer_thread_data_poll(void *data)
 
        data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        if (data_ht == NULL) {
+               /* ENOMEM at this point. Better to bail out. */
                goto end;
        }
 
@@ -2440,9 +2506,7 @@ end:
                PERROR("close data pipe");
        }
 
-       if (data_ht) {
-               destroy_data_stream_ht(data_ht);
-       }
+       destroy_data_stream_ht(data_ht);
 
        rcu_unregister_thread();
        return NULL;
@@ -2631,11 +2695,7 @@ void lttng_consumer_init(void)
        consumer_data.channel_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        consumer_data.relayd_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
        consumer_data.stream_list_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
-
-       metadata_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
-       assert(metadata_ht);
-       data_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
-       assert(data_ht);
+       relayd_session_id_ht = lttng_ht_new(0, LTTNG_HT_TYPE_ULONG);
 }
 
 /*
@@ -2646,13 +2706,23 @@ void lttng_consumer_init(void)
  */
 int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
                struct lttng_consumer_local_data *ctx, int sock,
-               struct pollfd *consumer_sockpoll, struct lttcomm_sock *relayd_sock)
+               struct pollfd *consumer_sockpoll, struct lttcomm_sock *relayd_sock,
+               unsigned int sessiond_id)
 {
-       int fd, ret = -1;
+       int fd = -1, ret = -1;
+       enum lttng_error_code ret_code = LTTNG_OK;
        struct consumer_relayd_sock_pair *relayd;
+       struct consumer_relayd_session_id *relayd_id_node;
 
        DBG("Consumer adding relayd socket (idx: %d)", net_seq_idx);
 
+       /* First send a status message before receiving the fds. */
+       ret = consumer_send_status_msg(sock, ret_code);
+       if (ret < 0) {
+               /* Somehow, the session daemon is not responding anymore. */
+               goto error;
+       }
+
        /* Get relayd reference if exists. */
        relayd = consumer_find_relayd(net_seq_idx);
        if (relayd == NULL) {
@@ -2675,6 +2745,14 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
        if (ret != sizeof(fd)) {
                lttng_consumer_send_error(ctx, LTTCOMM_CONSUMERD_ERROR_RECV_FD);
                ret = -1;
+               fd = -1;        /* Just in case it gets set with an invalid value. */
+               goto error;
+       }
+
+       /* We have the fds without error. Send status back. */
+       ret = consumer_send_status_msg(sock, ret_code);
+       if (ret < 0) {
+               /* Somehow, the session daemon is not responding anymore. */
                goto error;
        }
 
@@ -2684,31 +2762,61 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
                /* Copy received lttcomm socket */
                lttcomm_copy_sock(&relayd->control_sock, relayd_sock);
                ret = lttcomm_create_sock(&relayd->control_sock);
+               /* Immediately try to close the created socket if valid. */
+               if (relayd->control_sock.fd >= 0) {
+                       if (close(relayd->control_sock.fd)) {
+                               PERROR("close relayd control socket");
+                       }
+               }
+               /* Handle create_sock error. */
                if (ret < 0) {
                        goto error;
                }
 
-               /* Close the created socket fd which is useless */
-               ret = close(relayd->control_sock.fd);
+               /* Assign new file descriptor */
+               relayd->control_sock.fd = fd;
+
+               /*
+                * Create a session on the relayd and store the returned id. No need to
+                * grab the socket lock since the relayd object is not yet visible.
+                */
+               ret = relayd_create_session(&relayd->control_sock,
+                               &relayd->session_id);
                if (ret < 0) {
-                       PERROR("close relayd control socket");
+                       goto error;
                }
 
-               /* Assign new file descriptor */
-               relayd->control_sock.fd = fd;
+               /* Set up a relayd session id node. */
+               relayd_id_node = zmalloc(sizeof(struct consumer_relayd_session_id));
+               if (!relayd_id_node) {
+                       PERROR("zmalloc relayd id node");
+                       goto error;
+               }
+
+               relayd_id_node->relayd_id = relayd->session_id;
+               relayd_id_node->sessiond_id = (uint64_t) sessiond_id;
+
+               /* Indexed by session id of the session daemon. */
+               lttng_ht_node_init_ulong(&relayd_id_node->node,
+                               relayd_id_node->sessiond_id);
+               rcu_read_lock();
+               lttng_ht_add_unique_ulong(relayd_session_id_ht, &relayd_id_node->node);
+               rcu_read_unlock();
+
                break;
        case LTTNG_STREAM_DATA:
                /* Copy received lttcomm socket */
                lttcomm_copy_sock(&relayd->data_sock, relayd_sock);
                ret = lttcomm_create_sock(&relayd->data_sock);
-               if (ret < 0) {
-                       goto error;
+               /* Immediately try to close the created socket if valid. */
+               if (relayd->data_sock.fd >= 0) {
+                       if (close(relayd->data_sock.fd)) {
+                               PERROR("close relayd data socket");
+                       }
                }
-
-               /* Close the created socket fd which is useless */
-               ret = close(relayd->data_sock.fd);
+               /* Handle create_sock error. */
                if (ret < 0) {
-                       PERROR("close relayd control socket");
+                       goto error;
                }
 
                /* Assign new file descriptor */
@@ -2730,9 +2838,15 @@ int consumer_add_relayd_socket(int net_seq_idx, int sock_type,
        add_relayd(relayd);
 
        /* All good! */
-       ret = 0;
+       return 0;
 
 error:
+       /* Close received socket if valid. */
+       if (fd >= 0) {
+               if (close(fd)) {
+                       PERROR("close received socket");
+               }
+       }
        return ret;
 }
 
@@ -2874,3 +2988,17 @@ data_not_pending:
        rcu_read_unlock();
        return 1;
 }
+
+/*
+ * Send a ret code status message to the sessiond daemon.
+ *
+ * Return the sendmsg() return value.
+ */
+int consumer_send_status_msg(int sock, int ret_code)
+{
+       struct lttcomm_consumer_status_msg msg;
+
+       msg.ret_code = ret_code;
+
+       return lttcomm_send_unix_sock(sock, &msg, sizeof(msg));
+}
This page took 0.027292 seconds and 4 git commands to generate.