X-Git-Url: http://git.efficios.com/?p=lttng-tools.git;a=blobdiff_plain;f=src%2Fbin%2Flttng-sessiond%2Fsession.c;h=38dbf6128c31639b668910ede62fc4a51f19d7c0;hp=1e5a81831c978451b0df61ad19712eea3a3c3fac;hb=8e319828707210e48a5f3e74495881594dba73e8;hpb=890d8fe47755c3bad936389cf48ffa141cff41c9 diff --git a/src/bin/lttng-sessiond/session.c b/src/bin/lttng-sessiond/session.c index 1e5a81831..38dbf6128 100644 --- a/src/bin/lttng-sessiond/session.c +++ b/src/bin/lttng-sessiond/session.c @@ -28,8 +28,11 @@ #include #include +#include #include "session.h" +#include "utils.h" +#include "trace-ust.h" /* * NOTES: @@ -54,6 +57,9 @@ static struct ltt_session_list ltt_session_list = { /* These characters are forbidden in a session name. Used by validate_name. */ static const char *forbidden_name_chars = "/"; +/* Global hash table to keep the sessions, indexed by id. */ +static struct lttng_ht *ltt_sessions_ht_by_id = NULL; + /* * Validate the session name for forbidden characters. * @@ -129,6 +135,14 @@ void session_lock_list(void) pthread_mutex_lock(<t_session_list.lock); } +/* + * Try to acquire session list lock + */ +int session_trylock_list(void) +{ + return pthread_mutex_trylock(<t_session_list.lock); +} + /* * Release session list lock */ @@ -137,6 +151,217 @@ void session_unlock_list(void) pthread_mutex_unlock(<t_session_list.lock); } +/* + * Get the session's consumer destination type. + * + * The caller must hold the session lock. + */ +enum consumer_dst_type session_get_consumer_destination_type( + const struct ltt_session *session) +{ + /* + * The output information is duplicated in both of those session types. + * Hence, it doesn't matter from which it is retrieved. However, it is + * possible for only one of them to be set. + */ + return session->kernel_session ? + session->kernel_session->consumer->type : + session->ust_session->consumer->type; +} + +/* + * Get the session's consumer network hostname. + * The caller must ensure that the destination is of type "net". + * + * The caller must hold the session lock. + */ +const char *session_get_net_consumer_hostname(const struct ltt_session *session) +{ + const char *hostname = NULL; + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + + /* + * hostname is assumed to be the same for both control and data + * connections. + */ + switch (output->dst.net.control.dtype) { + case LTTNG_DST_IPV4: + hostname = output->dst.net.control.dst.ipv4; + break; + case LTTNG_DST_IPV6: + hostname = output->dst.net.control.dst.ipv6; + break; + default: + abort(); + } + return hostname; +} + +/* + * Get the session's consumer network control and data ports. + * The caller must ensure that the destination is of type "net". + * + * The caller must hold the session lock. + */ +void session_get_net_consumer_ports(const struct ltt_session *session, + uint16_t *control_port, uint16_t *data_port) +{ + const struct consumer_output *output; + + output = session->kernel_session ? + session->kernel_session->consumer : + session->ust_session->consumer; + *control_port = output->dst.net.control.port; + *data_port = output->dst.net.data.port; +} + +/* + * Get the location of the latest trace archive produced by a rotation. + * + * The caller must hold the session lock. + */ +struct lttng_trace_archive_location *session_get_trace_archive_location( + struct ltt_session *session) +{ + struct lttng_trace_archive_location *location = NULL; + + if (session->rotation_state != LTTNG_ROTATION_STATE_COMPLETED) { + goto end; + } + + switch (session_get_consumer_destination_type(session)) { + case CONSUMER_DST_LOCAL: + location = lttng_trace_archive_location_local_create( + session->rotation_chunk.current_rotate_path); + break; + case CONSUMER_DST_NET: + { + const char *hostname; + uint16_t control_port, data_port; + + hostname = session_get_net_consumer_hostname(session); + session_get_net_consumer_ports(session, + &control_port, + &data_port); + location = lttng_trace_archive_location_relay_create( + hostname, + LTTNG_TRACE_ARCHIVE_LOCATION_RELAY_PROTOCOL_TYPE_TCP, + control_port, data_port, + session->rotation_chunk.current_rotate_path); + break; + } + default: + abort(); + } +end: + return location; +} + +/* + * Allocate the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +int ltt_sessions_ht_alloc(void) +{ + int ret = 0; + + DBG("Allocating ltt_sessions_ht_by_id"); + ltt_sessions_ht_by_id = lttng_ht_new(0, LTTNG_HT_TYPE_U64); + if (!ltt_sessions_ht_by_id) { + ret = -1; + ERR("Failed to allocate ltt_sessions_ht_by_id"); + goto end; + } +end: + return ret; +} + +/* + * Destroy the ltt_sessions_ht_by_id HT. + * + * The session list lock must be held. + */ +static void ltt_sessions_ht_destroy(void) +{ + if (!ltt_sessions_ht_by_id) { + return; + } + ht_cleanup_push(ltt_sessions_ht_by_id); + ltt_sessions_ht_by_id = NULL; +} + +/* + * Add a ltt_session to the ltt_sessions_ht_by_id. + * If unallocated, the ltt_sessions_ht_by_id HT is allocated. + * The session list lock must be held. + */ +static void add_session_ht(struct ltt_session *ls) +{ + int ret; + + assert(ls); + + if (!ltt_sessions_ht_by_id) { + ret = ltt_sessions_ht_alloc(); + if (ret) { + ERR("Error allocating the sessions HT"); + goto end; + } + } + lttng_ht_node_init_u64(&ls->node, ls->id); + lttng_ht_add_unique_u64(ltt_sessions_ht_by_id, &ls->node); + +end: + return; +} + +/* + * Test if ltt_sessions_ht_by_id is empty. + * Return 1 if empty, 0 if not empty. + * The session list lock must be held. + */ +static int ltt_sessions_ht_empty(void) +{ + int ret; + + if (!ltt_sessions_ht_by_id) { + ret = 1; + goto end; + } + + ret = lttng_ht_get_count(ltt_sessions_ht_by_id) ? 0 : 1; +end: + return ret; +} + +/* + * Remove a ltt_session from the ltt_sessions_ht_by_id. + * If empty, the ltt_sessions_ht_by_id HT is freed. + * The session list lock must be held. + */ +static void del_session_ht(struct ltt_session *ls) +{ + struct lttng_ht_iter iter; + int ret; + + assert(ls); + assert(ltt_sessions_ht_by_id); + + iter.iter.node = &ls->node.node; + ret = lttng_ht_del(ltt_sessions_ht_by_id, &iter); + assert(!ret); + + if (ltt_sessions_ht_empty()) { + DBG("Empty ltt_sessions_ht_by_id, destroying it"); + ltt_sessions_ht_destroy(); + } +} + /* * Acquire session lock */ @@ -159,7 +384,7 @@ void session_unlock(struct ltt_session *session) /* * Return a ltt_session structure ptr that matches name. If no session found, - * NULL is returned. This must be called with the session lock held using + * NULL is returned. This must be called with the session list lock held using * session_lock_list and session_unlock_list. */ struct ltt_session *session_find_by_name(const char *name) @@ -182,6 +407,36 @@ found: return iter; } +/* + * Return an ltt_session that matches the id. If no session is found, + * NULL is returned. This must be called with rcu_read_lock and + * session list lock held (to guarantee the lifetime of the session). + */ +struct ltt_session *session_find_by_id(uint64_t id) +{ + struct lttng_ht_node_u64 *node; + struct lttng_ht_iter iter; + struct ltt_session *ls; + + if (!ltt_sessions_ht_by_id) { + goto end; + } + + lttng_ht_lookup(ltt_sessions_ht_by_id, &id, &iter); + node = lttng_ht_iter_get_node_u64(&iter); + if (node == NULL) { + goto end; + } + ls = caa_container_of(node, struct ltt_session, node); + + DBG3("Session %" PRIu64 " found by id.", id); + return ls; + +end: + DBG3("Session %" PRIu64 " NOT found by id", id); + return NULL; +} + /* * Delete session from the session list and free the memory. * @@ -193,9 +448,10 @@ int session_destroy(struct ltt_session *session) /* Safety check */ assert(session); - DBG("Destroying session %s", session->name); + DBG("Destroying session %s (id %" PRIu64 ")", session->name, session->id); del_session_list(session); pthread_mutex_destroy(&session->lock); + del_session_ht(session); consumer_output_put(session->consumer); snapshot_destroy(&session->snapshot); @@ -264,16 +520,29 @@ int session_create(char *name, uid_t uid, gid_t gid) goto error; } + new_session->rotation_pending_local = false; + new_session->rotation_pending_relay = false; + new_session->rotation_state = LTTNG_ROTATION_STATE_NO_ROTATION; + + new_session->rotation_pending_check_timer_enabled = false; + new_session->rotation_schedule_timer_enabled = false; + /* Add new session to the session list */ session_lock_list(); new_session->id = add_session_list(new_session); + /* + * Add the new session to the ltt_sessions_ht_by_id. + * No ownership is taken by the hash table; it is merely + * a wrapper around the session list used for faster access + * by session id. + */ + add_session_ht(new_session); session_unlock_list(); /* * Consumer is let to NULL since the create_session_uri command will set it * up and, if valid, assign it to the session. */ - DBG("Tracing session %s created with ID %" PRIu64 " by UID %d GID %d", name, new_session->id, new_session->uid, new_session->gid);