Fix: big relayd cleanup and refactor
[lttng-tools.git] / src / bin / lttng-relayd / session.c
index 07f1d9f03522d22553d11350444acc9754bb3a8f..02cc748e75f6fd8f25f3cf5e47623d7523c1affb 100644 (file)
  * Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
 
+#define _GNU_SOURCE
+#include <common/common.h>
+
+#include "ctf-trace.h"
 #include "session.h"
+#include "stream.h"
+
+/* Global session id used in the session creation. */
+static uint64_t last_relay_session_id;
+
+static void rcu_destroy_session(struct rcu_head *head)
+{
+       struct relay_session *session =
+               caa_container_of(head, struct relay_session, rcu_node);
+
+       free(session);
+}
+
+/*
+ * Create a new session by assigning a new session ID.
+ *
+ * Return allocated session or else NULL.
+ */
+struct relay_session *session_create(void)
+{
+       struct relay_session *session;
+
+       session = zmalloc(sizeof(*session));
+       if (!session) {
+               PERROR("relay session zmalloc");
+               goto error;
+       }
+
+       session->ctf_traces_ht = lttng_ht_new(0, LTTNG_HT_TYPE_STRING);
+       if (!session->ctf_traces_ht) {
+               free(session);
+               goto error;
+       }
+
+       pthread_mutex_init(&session->viewer_ready_lock, NULL);
+       session->id = ++last_relay_session_id;
+       lttng_ht_node_init_u64(&session->session_n, session->id);
+
+error:
+       return session;
+}
 
 /*
  * Lookup a session within the given hash table and session id. RCU read side
 struct relay_session *session_find_by_id(struct lttng_ht *ht, uint64_t id)
 {
        struct relay_session *session = NULL;
-       struct lttng_ht_node_ulong *node;
+       struct lttng_ht_node_u64 *node;
        struct lttng_ht_iter iter;
 
        assert(ht);
 
-       lttng_ht_lookup(ht, (void *)((unsigned long) id), &iter);
-       node = lttng_ht_iter_get_node_ulong(&iter);
+       lttng_ht_lookup(ht, &id, &iter);
+       node = lttng_ht_iter_get_node_u64(&iter);
        if (!node) {
+               DBG("Session find by ID %" PRIu64 " id NOT found", id);
                goto end;
        }
        session = caa_container_of(node, struct relay_session, session_n);
+       DBG("Session find by ID %" PRIu64 " id found", id);
 
 end:
        return session;
 }
+
+/*
+ * Delete session from the given hash table.
+ *
+ * Return lttng ht del error code being 0 on success and 1 on failure.
+ */
+int session_delete(struct lttng_ht *ht, struct relay_session *session)
+{
+       struct lttng_ht_iter iter;
+
+       assert(ht);
+       assert(session);
+
+       iter.iter.node = &session->session_n.node;
+       return lttng_ht_del(ht, &iter);
+}
+
+/*
+ * The caller MUST be from the viewer thread since the viewer refcount is
+ * decremented. With this calue down to 0, it will try to destroy the session.
+ */
+void session_viewer_try_destroy(struct lttng_ht *ht,
+               struct relay_session *session)
+{
+       unsigned long ret_ref;
+
+       assert(session);
+
+       ret_ref = uatomic_add_return(&session->viewer_refcount, -1);
+       if (ret_ref == 0) {
+               session_try_destroy(ht, session);
+       }
+}
+
+/*
+ * Should only be called from the main streaming thread since it does not touch
+ * the viewer refcount. If this refcount is down to 0, destroy the session only
+ * and only if the session deletion succeeds. This is done because the viewer
+ * *and* the streaming thread can both concurently try to destroy the session
+ * thus the first come first serve.
+ */
+void session_try_destroy(struct lttng_ht *ht, struct relay_session *session)
+{
+       int ret = 0;
+       unsigned long ret_ref;
+
+       assert(session);
+
+       ret_ref = uatomic_read(&session->viewer_refcount);
+       if (ret_ref == 0 && session->close_flag) {
+               if (ht) {
+                       ret = session_delete(ht, session);
+               }
+               if (!ret) {
+                       /* Only destroy the session if the deletion was successful. */
+                       session_destroy(session);
+               }
+       }
+}
+
+/*
+ * Destroy a session object.
+ */
+void session_destroy(struct relay_session *session)
+{
+       struct ctf_trace *ctf_trace;
+       struct lttng_ht_iter iter;
+
+       assert(session);
+
+       DBG("Relay destroying session %" PRIu64, session->id);
+
+       /*
+        * Empty the ctf trace hash table which will destroy the stream contained
+        * in that table.
+        */
+       rcu_read_lock();
+       cds_lfht_for_each_entry(session->ctf_traces_ht->ht, &iter.iter, ctf_trace,
+                       node.node) {
+               ctf_trace_delete(session->ctf_traces_ht, ctf_trace);
+               ctf_trace_destroy(ctf_trace);
+       }
+       lttng_ht_destroy(session->ctf_traces_ht);
+       rcu_read_unlock();
+
+       call_rcu(&session->rcu_node, rcu_destroy_session);
+}
This page took 0.024118 seconds and 4 git commands to generate.